MCPcopy Create free account
hub / github.com/ScaleML/AgentSPEX / resolveOverlaps

Function resolveOverlaps

yaml-flow-editor/src/utils/layout.ts:134–188  ·  view source on GitHub ↗
(
  nodes: FlowNode[],
  nodeDimensions: Map<string, { width: number; height: number }>,
  direction: 'TB' | 'LR',
  pad: number = DEFAULT_PADDING
)

Source from the content-addressed store, hash-verified

132}
133
134function resolveOverlaps(
135 nodes: FlowNode[],
136 nodeDimensions: Map<string, { width: number; height: number }>,
137 direction: 'TB' | 'LR',
138 pad: number = DEFAULT_PADDING
139): FlowNode[] {
140 // Deterministic, lightweight overlap resolution pass.
141 // Dagre generally avoids overlaps, but our zig-zag xOffset can re-introduce them.
142 const out = nodes.map((n) => ({ ...n, position: { ...n.position } }));
143
144 const getBox = (n: FlowNode): Box => {
145 const dim = nodeDimensions.get(n.id) || { width: DEFAULT_NODE_WIDTH, height: DEFAULT_NODE_HEIGHT };
146 return { id: n.id, x: n.position.x, y: n.position.y, w: dim.width, h: dim.height };
147 };
148
149 // We only push nodes "forward" (down in TB, right in LR) to preserve flow direction.
150 const maxIters = 10;
151 for (let iter = 0; iter < maxIters; iter++) {
152 let moved = false;
153
154 const sorted = [...out].sort((a, b) =>
155 direction === 'TB' ? a.position.y - b.position.y : a.position.x - b.position.x
156 );
157
158 const placed: FlowNode[] = [];
159 for (const n of sorted) {
160 const dim = nodeDimensions.get(n.id) || { width: DEFAULT_NODE_WIDTH, height: DEFAULT_NODE_HEIGHT };
161 let nextPos = { ...n.position };
162
163 for (const p of placed) {
164 const a = { id: n.id, x: nextPos.x, y: nextPos.y, w: dim.width, h: dim.height };
165 const pb = getBox(p);
166 if (!boxesOverlap(a, pb, pad)) continue;
167
168 if (direction === 'TB') {
169 // push down below the placed node
170 nextPos.y = Math.max(nextPos.y, pb.y + pb.h + pad);
171 } else {
172 // LR layout: preserve rankdir by avoiding large x drift; push down instead.
173 nextPos.y = Math.max(nextPos.y, pb.y + pb.h + pad);
174 }
175 }
176
177 if (nextPos.x !== n.position.x || nextPos.y !== n.position.y) {
178 n.position = nextPos;
179 moved = true;
180 }
181 placed.push(n);
182 }
183
184 if (!moved) break;
185 }
186
187 return out;
188}
189
190/**
191 * Get the set of node IDs that belong to the same connected (task) flow as the given node.

Callers 1

getLayoutedElementsFunction · 0.85

Calls 3

getBoxFunction · 0.85
boxesOverlapFunction · 0.85
getMethod · 0.80

Tested by

no test coverage detected