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
+12 -1
View File
@@ -23,11 +23,12 @@ interface EdgeModalProps {
onClose: () => void
onSubmit: (data: EdgeData) => void
onDelete?: () => void
onClearWaypoints?: () => void
initial?: Partial<EdgeData>
title?: string
}
export function EdgeModal({ open, onClose, onSubmit, onDelete, initial, title = 'Connect Nodes' }: EdgeModalProps) {
export function EdgeModal({ open, onClose, onSubmit, onDelete, onClearWaypoints, initial, title = 'Connect Nodes' }: EdgeModalProps) {
const [type, setType] = useState<EdgeType>(initial?.type ?? 'ethernet')
const [label, setLabel] = useState(initial?.label ?? '')
const [vlanId, setVlanId] = useState(initial?.vlan_id?.toString() ?? '')
@@ -175,6 +176,16 @@ export function EdgeModal({ open, onClose, onSubmit, onDelete, initial, title =
</label>
</div>
{onClearWaypoints && initial?.waypoints && initial.waypoints.length > 0 && (
<button
type="button"
onClick={() => { onClearWaypoints(); onClose() }}
className="text-[10px] text-muted-foreground hover:text-[#e3b341] transition-colors text-left"
>
Clear path ({initial.waypoints.length} point{initial.waypoints.length !== 1 ? 's' : ''})
</button>
)}
<div className="flex justify-between gap-2 pt-1">
{onDelete ? (
<Button type="button" variant="ghost" size="sm" className="text-[#f85149] hover:text-[#f85149] hover:bg-[#f85149]/10" onClick={handleDelete}>