fix: straight edge routing and handler section edge extraction
Backend: - Set POLYLINE edge routing on ELK root — eliminates curved/bent edges between horizontally aligned nodes - Collect edges from handler section roots (not just main root) so internal handler edges are included in the layout output - Use correct root reference for coordinate calculation per edge Frontend: - Render ALL edge points as line segments (polylines), not cubic bezier. ELK bend points are waypoints, not bezier control points — the cubic bezier interpretation caused false curves. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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<PositionedEdge> positionedEdges = new ArrayList<>();
|
||||
for (ElkEdge elkEdge : collectAllEdges(rootNode)) {
|
||||
List<ElkEdge> 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<double[]> 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)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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 (
|
||||
|
||||
Reference in New Issue
Block a user