From 01f14cc3f7299f70b8404a732957d50fb9cdd119 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Sat, 24 Jan 2026 16:33:56 -0800 Subject: [PATCH] Reorder top-level location boxes after ELK layout Co-Authored-By: Claude Opus 4.5 --- static/index.html | 56 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/static/index.html b/static/index.html index e610d4c..2766cd4 100644 --- a/static/index.html +++ b/static/index.html @@ -104,10 +104,12 @@ return chain; } + let topLevelOrder = []; + function doLayout() { - cy.layout({ + const layout = cy.layout({ name: 'elk', - fit: true, + fit: false, padding: 50, nodeDimensionsIncludeLabels: true, elk: { @@ -119,8 +121,44 @@ 'elk.layered.spacing.nodeNodeBetweenLayers': 100, 'elk.layered.crossingMinimization.strategy': 'LAYER_SWEEP', 'elk.hierarchyHandling': 'INCLUDE_CHILDREN' + }, + stop: function() { + reorderTopLevel(); + cy.fit(50); } - }).run(); + }); + layout.run(); + } + + function reorderTopLevel() { + if (topLevelOrder.length < 2) return; + + const boxes = topLevelOrder.map(locId => { + const node = cy.getElementById(locId); + if (node.empty()) return null; + const bb = node.boundingBox(); + return { id: locId, bb: bb, height: bb.y2 - bb.y1 }; + }).filter(b => b !== null); + + if (boxes.length < 2) return; + + const minY = Math.min(...boxes.map(b => b.bb.y1)); + const gap = 50; + + let targetY = minY; + const targets = boxes.map(box => { + const result = { id: box.id, deltaY: targetY - box.bb.y1 }; + targetY += box.height + gap; + return result; + }); + + targets.forEach(target => { + const node = cy.getElementById(target.id); + node.descendants().filter(n => !n.isParent()).forEach(n => { + const pos = n.position(); + n.position({ x: pos.x, y: pos.y + target.deltaY }); + }); + }); } async function init() { @@ -216,6 +254,18 @@ }); }); + // Find top-level locations and sort by config order + topLevelOrder = sortedLocations + .filter(locId => { + const meta = locationMeta.get(locId); + return !meta.parentId; + }) + .sort((a, b) => { + const metaA = locationMeta.get(a); + const metaB = locationMeta.get(b); + return metaA.order - metaB.order; + }); + cy = cytoscape({ container: document.getElementById('cy'), elements: elements,