feat: add interactive edge waypoints with smooth path editing

- Drag waypoints to reshape edges; double-click a waypoint to remove it
- + handles at segment midpoints to insert new waypoints
- Bezier style: catmull-rom smooth curves through waypoints
- Smooth style: rounded-corner polyline with soft 45° snap (snaps within 15px)
  - First + handle biased to source axis for perpendicular node exit
  - snap45both: ray-intersection solver ensures both adjacent segments snap to 45° simultaneously
- Clear path button in EdgeModal when waypoints exist
- Waypoints serialised/deserialised with canvas state
This commit is contained in:
Pouzor
2026-04-08 22:42:18 +02:00
parent 9d9fdd61e9
commit 9e8bab5dec
9 changed files with 687 additions and 11 deletions
+3 -1
View File
@@ -1,5 +1,5 @@
import type { Node, Edge } from '@xyflow/react'
import type { NodeData, EdgeData } from '@/types'
import type { NodeData, EdgeData, Waypoint } from '@/types'
import { normalizeHandle } from '@/utils/handleUtils'
// ── Types ────────────────────────────────────────────────────────────────────
@@ -46,6 +46,7 @@ export interface ApiEdge {
animated?: boolean | 'snake' | 'flow' | 'none'
source_handle?: string | null
target_handle?: string | null
waypoints?: Waypoint[] | null
}
// ── Serialization (RF node → API save payload) ───────────────────────────────
@@ -121,6 +122,7 @@ export function serializeEdge(e: Edge<EdgeData>): Record<string, unknown> {
animated: e.data?.animated ?? false,
source_handle: normalizeHandle(e.sourceHandle),
target_handle: normalizeHandle(e.targetHandle),
waypoints: e.data?.waypoints?.length ? e.data.waypoints : null,
}
}