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 1c695763..2332370f 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 @@ -355,8 +355,25 @@ public class ElkDiagramRenderer implements DiagramRenderer { positionedEdges.add(new PositionedEdge(sourceId, targetId, label, points)); } - double totalWidth = rootNode.getWidth(); - double totalHeight = rootNode.getHeight(); + // Compute bounding box from actual positioned node coordinates + // (not rootNode dimensions, which ignore handler roots) + double totalWidth = 0; + double totalHeight = 0; + for (PositionedNode pn : positionedNodes) { + double right = pn.x() + pn.width(); + double bottom = pn.y() + pn.height(); + if (right > totalWidth) totalWidth = right; + if (bottom > totalHeight) totalHeight = bottom; + // Also check children bounds for compounds + if (pn.children() != null) { + for (PositionedNode child : pn.children()) { + double cr = pn.x() + child.x() + child.width(); + double cb = pn.y() + child.y() + child.height(); + if (cr > totalWidth) totalWidth = cr; + if (cb > totalHeight) totalHeight = cb; + } + } + } DiagramLayout layout = new DiagramLayout(totalWidth, totalHeight, positionedNodes, positionedEdges); return new LayoutResult(layout, nodeColors, compoundInfos); @@ -572,19 +589,25 @@ public class ElkDiagramRenderer implements DiagramRenderer { return current; } + /** Proper lowest common ancestor of two ELK nodes. */ private ElkNode findCommonParent(ElkNode a, ElkNode b) { - if (a.getParent() == b.getParent()) { - return a.getParent(); + // Collect all ancestors of 'a' (including a itself) + Set ancestorsOfA = new HashSet<>(); + ElkNode current = a; + while (current != null) { + ancestorsOfA.add(current); + current = current.getParent(); } - // If one is the parent of the other - if (a.getParent() != null && a.getParent() == b) return b; - if (b.getParent() != null && b.getParent() == a) return a; - // Default: root (grandparent) - ElkNode parent = a.getParent(); - while (parent != null && parent.getParent() != null) { - parent = parent.getParent(); + // Walk up from 'b' until we find a common ancestor + current = b; + while (current != null) { + if (ancestorsOfA.contains(current)) { + return current; + } + current = current.getParent(); } - return parent != null ? parent : a.getParent(); + // Fallback: root of 'a' + return getElkRoot(a); } private double getAbsoluteX(ElkNode node, ElkNode root) {