diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/diagram/ElkDiagramRenderer.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/diagram/ElkDiagramRenderer.java index 502c83e5..42fae5a2 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/diagram/ElkDiagramRenderer.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/diagram/ElkDiagramRenderer.java @@ -12,6 +12,7 @@ import org.eclipse.elk.alg.layered.options.LayeredMetaDataProvider; import org.eclipse.elk.core.RecursiveGraphLayoutEngine; import org.eclipse.elk.core.options.CoreOptions; import org.eclipse.elk.core.options.Direction; +import org.eclipse.elk.core.options.EdgeRouting; import org.eclipse.elk.core.options.HierarchyHandling; import org.eclipse.elk.alg.layered.options.NodePlacementStrategy; import org.eclipse.elk.core.util.BasicProgressMonitor; @@ -188,6 +189,7 @@ public class ElkDiagramRenderer implements DiagramRenderer { rootNode.setProperty(CoreOptions.SPACING_NODE_NODE, NODE_SPACING); rootNode.setProperty(CoreOptions.SPACING_EDGE_NODE, EDGE_SPACING); rootNode.setProperty(CoreOptions.HIERARCHY_HANDLING, HierarchyHandling.INCLUDE_CHILDREN); + rootNode.setProperty(CoreOptions.EDGE_ROUTING, EdgeRouting.POLYLINE); rootNode.setProperty(org.eclipse.elk.alg.layered.options.LayeredOptions.NODE_PLACEMENT_STRATEGY, NodePlacementStrategy.LINEAR_SEGMENTS); @@ -305,27 +307,34 @@ public class ElkDiagramRenderer implements DiagramRenderer { } } - // Extract edges + // Extract edges from main root + all handler roots List positionedEdges = new ArrayList<>(); - for (ElkEdge elkEdge : collectAllEdges(rootNode)) { + List allEdges = collectAllEdges(rootNode); + for (ElkNode hr : handlerRoots) { + allEdges.addAll(collectAllEdges(hr)); + } + for (ElkEdge elkEdge : allEdges) { String sourceId = elkEdge.getSources().isEmpty() ? "" : elkEdge.getSources().get(0).getIdentifier(); String targetId = elkEdge.getTargets().isEmpty() ? "" : elkEdge.getTargets().get(0).getIdentifier(); + // Determine which root this edge belongs to for coordinate calculation + ElkNode edgeRoot = getElkRoot(elkEdge.getContainingNode()); + List points = new ArrayList<>(); for (ElkEdgeSection section : elkEdge.getSections()) { points.add(new double[]{ - section.getStartX() + getAbsoluteX(elkEdge.getContainingNode(), rootNode), - section.getStartY() + getAbsoluteY(elkEdge.getContainingNode(), rootNode) + section.getStartX() + getAbsoluteX(elkEdge.getContainingNode(), edgeRoot), + section.getStartY() + getAbsoluteY(elkEdge.getContainingNode(), edgeRoot) }); for (ElkBendPoint bp : section.getBendPoints()) { points.add(new double[]{ - bp.getX() + getAbsoluteX(elkEdge.getContainingNode(), rootNode), - bp.getY() + getAbsoluteY(elkEdge.getContainingNode(), rootNode) + bp.getX() + getAbsoluteX(elkEdge.getContainingNode(), edgeRoot), + bp.getY() + getAbsoluteY(elkEdge.getContainingNode(), edgeRoot) }); } points.add(new double[]{ - section.getEndX() + getAbsoluteX(elkEdge.getContainingNode(), rootNode), - section.getEndY() + getAbsoluteY(elkEdge.getContainingNode(), rootNode) + section.getEndX() + getAbsoluteX(elkEdge.getContainingNode(), edgeRoot), + section.getEndY() + getAbsoluteY(elkEdge.getContainingNode(), edgeRoot) }); } diff --git a/ui/src/components/ProcessDiagram/DiagramEdge.tsx b/ui/src/components/ProcessDiagram/DiagramEdge.tsx index 3b0a8b41..ce820fd3 100644 --- a/ui/src/components/ProcessDiagram/DiagramEdge.tsx +++ b/ui/src/components/ProcessDiagram/DiagramEdge.tsx @@ -11,19 +11,11 @@ export function DiagramEdge({ edge, offsetY = 0, traversed }: DiagramEdgeProps) const pts = edge.points; if (!pts || pts.length < 2) return null; - // Build SVG path: move to first point, then cubic bezier or line to rest + // Build SVG path: move to first point, then line segments through all waypoints. + // ELK bend points are waypoints, not bezier control points. let d = `M ${pts[0][0]} ${pts[0][1] + offsetY}`; - - if (pts.length === 2) { - d += ` L ${pts[1][0]} ${pts[1][1] + offsetY}`; - } else if (pts.length === 4) { - // 4 points: start, control1, control2, end → cubic bezier - d += ` C ${pts[1][0]} ${pts[1][1] + offsetY}, ${pts[2][0]} ${pts[2][1] + offsetY}, ${pts[3][0]} ${pts[3][1] + offsetY}`; - } else { - // Multiple points: connect with line segments through intermediate points - for (let i = 1; i < pts.length; i++) { - d += ` L ${pts[i][0]} ${pts[i][1] + offsetY}`; - } + for (let i = 1; i < pts.length; i++) { + d += ` L ${pts[i][0]} ${pts[i][1] + offsetY}`; } return (