@diagrammo/dgmo 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced.cjs +1482 -502
- package/dist/advanced.d.cts +6 -0
- package/dist/advanced.d.ts +6 -0
- package/dist/advanced.js +1479 -499
- package/dist/auto.cjs +1483 -503
- package/dist/auto.js +116 -139
- package/dist/auto.mjs +1480 -500
- package/dist/cli.cjs +168 -191
- package/dist/index.cjs +1482 -502
- package/dist/index.js +1479 -499
- package/dist/internal.cjs +1482 -502
- package/dist/internal.d.cts +6 -0
- package/dist/internal.d.ts +6 -0
- package/dist/internal.js +1479 -499
- package/package.json +7 -3
- package/src/boxes-and-lines/layout-layered.ts +722 -0
- package/src/boxes-and-lines/layout-search.ts +1200 -0
- package/src/boxes-and-lines/layout.ts +67 -556
- package/src/map/context-labels.ts +45 -14
- package/src/map/layout.ts +16 -6
package/dist/auto.cjs
CHANGED
|
@@ -27527,9 +27527,1342 @@ var init_renderer6 = __esm({
|
|
|
27527
27527
|
}
|
|
27528
27528
|
});
|
|
27529
27529
|
|
|
27530
|
+
// src/boxes-and-lines/layout-layered.ts
|
|
27531
|
+
function rng(s) {
|
|
27532
|
+
return () => {
|
|
27533
|
+
s |= 0;
|
|
27534
|
+
s = s + 1831565813 | 0;
|
|
27535
|
+
let t = Math.imul(s ^ s >>> 15, 1 | s);
|
|
27536
|
+
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
27537
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
27538
|
+
};
|
|
27539
|
+
}
|
|
27540
|
+
function layeredCandidates(parsed, sizes, opts) {
|
|
27541
|
+
if (parsed.groups.length > 0) return [];
|
|
27542
|
+
const nCount = parsed.nodes.length;
|
|
27543
|
+
if (nCount < 3 || nCount > 40) return [];
|
|
27544
|
+
const isTB = parsed.direction === "TB";
|
|
27545
|
+
const nodesep = opts?.nodesep ?? NODESEP;
|
|
27546
|
+
const ranksep = opts?.ranksep ?? RANKSEP;
|
|
27547
|
+
const backEdgeSide = opts?.backEdgeSide ?? "nearest";
|
|
27548
|
+
const restarts = opts?.restarts ?? (nCount <= 14 ? 28 : nCount <= 25 ? 14 : 6);
|
|
27549
|
+
const keepK = opts?.keepK ?? 3;
|
|
27550
|
+
const labels = parsed.nodes.map((n) => n.label);
|
|
27551
|
+
const labelSet = new Set(labels);
|
|
27552
|
+
const edges = parsed.edges.map((e, i) => ({ e, i })).filter(
|
|
27553
|
+
({ e }) => labelSet.has(e.source) && labelSet.has(e.target) && e.source !== e.target
|
|
27554
|
+
);
|
|
27555
|
+
if (edges.length === 0) return [];
|
|
27556
|
+
const adj = /* @__PURE__ */ new Map();
|
|
27557
|
+
for (const l of labels) adj.set(l, []);
|
|
27558
|
+
for (const { e, i } of edges)
|
|
27559
|
+
adj.get(e.source).push({ to: e.target, idx: i });
|
|
27560
|
+
const reversed = /* @__PURE__ */ new Set();
|
|
27561
|
+
const state = /* @__PURE__ */ new Map();
|
|
27562
|
+
for (const l of labels) state.set(l, 0);
|
|
27563
|
+
const dfs = (u) => {
|
|
27564
|
+
state.set(u, 1);
|
|
27565
|
+
for (const { to, idx } of adj.get(u)) {
|
|
27566
|
+
const st = state.get(to);
|
|
27567
|
+
if (st === 1)
|
|
27568
|
+
reversed.add(idx);
|
|
27569
|
+
else if (st === 0) dfs(to);
|
|
27570
|
+
}
|
|
27571
|
+
state.set(u, 2);
|
|
27572
|
+
};
|
|
27573
|
+
for (const l of labels) if (state.get(l) === 0) dfs(l);
|
|
27574
|
+
const dag = edges.map(
|
|
27575
|
+
({ e, i }) => reversed.has(i) ? { from: e.target, to: e.source, idx: i, rev: true } : { from: e.source, to: e.target, idx: i, rev: false }
|
|
27576
|
+
);
|
|
27577
|
+
const outDag = /* @__PURE__ */ new Map();
|
|
27578
|
+
const inDeg = /* @__PURE__ */ new Map();
|
|
27579
|
+
for (const l of labels) {
|
|
27580
|
+
outDag.set(l, []);
|
|
27581
|
+
inDeg.set(l, 0);
|
|
27582
|
+
}
|
|
27583
|
+
for (const d of dag) {
|
|
27584
|
+
outDag.get(d.from).push(d.to);
|
|
27585
|
+
inDeg.set(d.to, (inDeg.get(d.to) ?? 0) + 1);
|
|
27586
|
+
}
|
|
27587
|
+
const rank = /* @__PURE__ */ new Map();
|
|
27588
|
+
for (const l of labels) rank.set(l, 0);
|
|
27589
|
+
const queue = labels.filter((l) => (inDeg.get(l) ?? 0) === 0);
|
|
27590
|
+
const indeg2 = new Map(inDeg);
|
|
27591
|
+
const topo = [];
|
|
27592
|
+
while (queue.length) {
|
|
27593
|
+
const u = queue.shift();
|
|
27594
|
+
topo.push(u);
|
|
27595
|
+
for (const v of outDag.get(u)) {
|
|
27596
|
+
rank.set(v, Math.max(rank.get(v), rank.get(u) + 1));
|
|
27597
|
+
indeg2.set(v, indeg2.get(v) - 1);
|
|
27598
|
+
if (indeg2.get(v) === 0) queue.push(v);
|
|
27599
|
+
}
|
|
27600
|
+
}
|
|
27601
|
+
if (topo.length !== labels.length) return [];
|
|
27602
|
+
const maxRank = Math.max(...labels.map((l) => rank.get(l)));
|
|
27603
|
+
const node = /* @__PURE__ */ new Map();
|
|
27604
|
+
for (const n of parsed.nodes) {
|
|
27605
|
+
const s = sizes.get(n.label) ?? { width: NODE_WIDTH, height: NODE_HEIGHT };
|
|
27606
|
+
node.set(n.label, {
|
|
27607
|
+
id: n.label,
|
|
27608
|
+
dummy: false,
|
|
27609
|
+
rank: rank.get(n.label),
|
|
27610
|
+
cross: 0,
|
|
27611
|
+
thick: isTB ? s.width : s.height,
|
|
27612
|
+
depth: isTB ? s.height : s.width,
|
|
27613
|
+
realW: s.width,
|
|
27614
|
+
realH: s.height
|
|
27615
|
+
});
|
|
27616
|
+
}
|
|
27617
|
+
const segs = [];
|
|
27618
|
+
const chains = [];
|
|
27619
|
+
const backEdges = [];
|
|
27620
|
+
for (const d of dag) {
|
|
27621
|
+
if (d.rev) {
|
|
27622
|
+
backEdges.push({ edgeIdx: d.idx, src: d.to, tgt: d.from });
|
|
27623
|
+
continue;
|
|
27624
|
+
}
|
|
27625
|
+
const r0 = rank.get(d.from);
|
|
27626
|
+
const r1 = rank.get(d.to);
|
|
27627
|
+
const dagChain = [d.from];
|
|
27628
|
+
let prev = d.from;
|
|
27629
|
+
for (let r = r0 + 1; r < r1; r++) {
|
|
27630
|
+
const id = `__d${d.idx}_${r}`;
|
|
27631
|
+
node.set(id, {
|
|
27632
|
+
id,
|
|
27633
|
+
dummy: true,
|
|
27634
|
+
rank: r,
|
|
27635
|
+
cross: 0,
|
|
27636
|
+
thick: DUMMY_THICK,
|
|
27637
|
+
depth: 0,
|
|
27638
|
+
realW: 0,
|
|
27639
|
+
realH: 0
|
|
27640
|
+
});
|
|
27641
|
+
segs.push({ a: prev, b: id });
|
|
27642
|
+
dagChain.push(id);
|
|
27643
|
+
prev = id;
|
|
27644
|
+
}
|
|
27645
|
+
segs.push({ a: prev, b: d.to });
|
|
27646
|
+
dagChain.push(d.to);
|
|
27647
|
+
chains.push({
|
|
27648
|
+
edgeIdx: d.idx,
|
|
27649
|
+
chain: d.rev ? dagChain.slice().reverse() : dagChain
|
|
27650
|
+
});
|
|
27651
|
+
}
|
|
27652
|
+
const ranks = Array.from({ length: maxRank + 1 }, () => []);
|
|
27653
|
+
for (const n of node.values()) ranks[n.rank].push(n.id);
|
|
27654
|
+
const up = /* @__PURE__ */ new Map();
|
|
27655
|
+
const down = /* @__PURE__ */ new Map();
|
|
27656
|
+
for (const id of node.keys()) {
|
|
27657
|
+
up.set(id, []);
|
|
27658
|
+
down.set(id, []);
|
|
27659
|
+
}
|
|
27660
|
+
for (const s of segs) {
|
|
27661
|
+
down.get(s.a).push(s.b);
|
|
27662
|
+
up.get(s.b).push(s.a);
|
|
27663
|
+
}
|
|
27664
|
+
const orderOf = /* @__PURE__ */ new Map();
|
|
27665
|
+
const applyOrder = (ord) => {
|
|
27666
|
+
for (const id of node.keys()) orderOf.set(id, ord.get(id));
|
|
27667
|
+
};
|
|
27668
|
+
const gapCrossings = (r) => {
|
|
27669
|
+
const lower = ranks[r + 1];
|
|
27670
|
+
if (!lower) return 0;
|
|
27671
|
+
const es = [];
|
|
27672
|
+
for (const a of ranks[r]) {
|
|
27673
|
+
const pa = orderOf.get(a);
|
|
27674
|
+
for (const b of down.get(a)) es.push({ p: pa, q: orderOf.get(b) });
|
|
27675
|
+
}
|
|
27676
|
+
let c = 0;
|
|
27677
|
+
for (let i = 0; i < es.length; i++)
|
|
27678
|
+
for (let j = i + 1; j < es.length; j++) {
|
|
27679
|
+
const A = es[i], B = es[j];
|
|
27680
|
+
if ((A.p - B.p) * (A.q - B.q) < 0) c++;
|
|
27681
|
+
}
|
|
27682
|
+
return c;
|
|
27683
|
+
};
|
|
27684
|
+
const totalCrossings = () => {
|
|
27685
|
+
let c = 0;
|
|
27686
|
+
for (let r = 0; r < maxRank; r++) c += gapCrossings(r);
|
|
27687
|
+
return c;
|
|
27688
|
+
};
|
|
27689
|
+
const median = (vals) => {
|
|
27690
|
+
if (vals.length === 0) return -1;
|
|
27691
|
+
vals.sort((x, y) => x - y);
|
|
27692
|
+
const m = Math.floor(vals.length / 2);
|
|
27693
|
+
if (vals.length % 2 === 1) return vals[m];
|
|
27694
|
+
if (vals.length === 2) return (vals[0] + vals[1]) / 2;
|
|
27695
|
+
const left = vals[m - 1] - vals[0];
|
|
27696
|
+
const right = vals[vals.length - 1] - vals[m];
|
|
27697
|
+
return left + right === 0 ? (vals[m - 1] + vals[m]) / 2 : (vals[m - 1] * right + vals[m] * left) / (left + right);
|
|
27698
|
+
};
|
|
27699
|
+
const wmedianRank = (r, useUp) => {
|
|
27700
|
+
const ids = ranks[r];
|
|
27701
|
+
const neigh = useUp ? up : down;
|
|
27702
|
+
const med = /* @__PURE__ */ new Map();
|
|
27703
|
+
for (const id of ids)
|
|
27704
|
+
med.set(id, median(neigh.get(id).map((x) => orderOf.get(x))));
|
|
27705
|
+
const movable = ids.filter((id) => med.get(id) >= 0).sort((a, b) => med.get(a) - med.get(b));
|
|
27706
|
+
const out = new Array(ids.length).fill(null);
|
|
27707
|
+
for (const id of ids) if (med.get(id) < 0) out[orderOf.get(id)] = id;
|
|
27708
|
+
let mi = 0;
|
|
27709
|
+
for (let slot = 0; slot < out.length; slot++)
|
|
27710
|
+
if (out[slot] === null) out[slot] = movable[mi++];
|
|
27711
|
+
const final = out;
|
|
27712
|
+
final.forEach((id, i) => orderOf.set(id, i));
|
|
27713
|
+
ranks[r] = final;
|
|
27714
|
+
};
|
|
27715
|
+
const transpose = () => {
|
|
27716
|
+
let improved = true;
|
|
27717
|
+
let guard = 0;
|
|
27718
|
+
while (improved && guard++ < 12) {
|
|
27719
|
+
improved = false;
|
|
27720
|
+
for (let r = 0; r <= maxRank; r++) {
|
|
27721
|
+
const ids = ranks[r];
|
|
27722
|
+
for (let i = 0; i < ids.length - 1; i++) {
|
|
27723
|
+
const before = (r > 0 ? gapCrossings(r - 1) : 0) + (r < maxRank ? gapCrossings(r) : 0);
|
|
27724
|
+
const a = ids[i], b = ids[i + 1];
|
|
27725
|
+
ids[i] = b;
|
|
27726
|
+
ids[i + 1] = a;
|
|
27727
|
+
orderOf.set(b, i);
|
|
27728
|
+
orderOf.set(a, i + 1);
|
|
27729
|
+
const after = (r > 0 ? gapCrossings(r - 1) : 0) + (r < maxRank ? gapCrossings(r) : 0);
|
|
27730
|
+
if (after < before) {
|
|
27731
|
+
improved = true;
|
|
27732
|
+
} else {
|
|
27733
|
+
ids[i] = a;
|
|
27734
|
+
ids[i + 1] = b;
|
|
27735
|
+
orderOf.set(a, i);
|
|
27736
|
+
orderOf.set(b, i + 1);
|
|
27737
|
+
}
|
|
27738
|
+
}
|
|
27739
|
+
}
|
|
27740
|
+
}
|
|
27741
|
+
};
|
|
27742
|
+
const initOrder = (seed) => {
|
|
27743
|
+
const r = seed === 0 ? null : rng(seed);
|
|
27744
|
+
for (let rr = 0; rr <= maxRank; rr++) {
|
|
27745
|
+
const ids = ranks[rr].slice();
|
|
27746
|
+
if (r) {
|
|
27747
|
+
for (let i = ids.length - 1; i > 0; i--) {
|
|
27748
|
+
const j = Math.floor(r() * (i + 1));
|
|
27749
|
+
[ids[i], ids[j]] = [ids[j], ids[i]];
|
|
27750
|
+
}
|
|
27751
|
+
}
|
|
27752
|
+
ranks[rr] = ids;
|
|
27753
|
+
ids.forEach((id, i) => orderOf.set(id, i));
|
|
27754
|
+
}
|
|
27755
|
+
};
|
|
27756
|
+
const found = [];
|
|
27757
|
+
for (let s = 0; s < restarts; s++) {
|
|
27758
|
+
initOrder(s);
|
|
27759
|
+
let best = totalCrossings();
|
|
27760
|
+
let bestSnap = new Map(orderOf);
|
|
27761
|
+
for (let iter = 0; iter < 8; iter++) {
|
|
27762
|
+
const down1 = iter % 2 === 0;
|
|
27763
|
+
if (down1) for (let r = 1; r <= maxRank; r++) wmedianRank(r, true);
|
|
27764
|
+
else for (let r = maxRank - 1; r >= 0; r--) wmedianRank(r, false);
|
|
27765
|
+
transpose();
|
|
27766
|
+
const c = totalCrossings();
|
|
27767
|
+
if (c < best) {
|
|
27768
|
+
best = c;
|
|
27769
|
+
bestSnap = new Map(orderOf);
|
|
27770
|
+
}
|
|
27771
|
+
if (c === 0) break;
|
|
27772
|
+
}
|
|
27773
|
+
applyOrder(bestSnap);
|
|
27774
|
+
for (let r = 0; r <= maxRank; r++)
|
|
27775
|
+
ranks[r].sort((a, b) => orderOf.get(a) - orderOf.get(b));
|
|
27776
|
+
const sig = ranks.map((r) => r.join(",")).join("|");
|
|
27777
|
+
if (!found.some((f) => f.sig === sig))
|
|
27778
|
+
found.push({ sig, cross: best, order: new Map(bestSnap) });
|
|
27779
|
+
}
|
|
27780
|
+
found.sort((a, b) => a.cross - b.cross);
|
|
27781
|
+
const keep = found.slice(0, keepK);
|
|
27782
|
+
if (keep.length === 0) return [];
|
|
27783
|
+
const results = [];
|
|
27784
|
+
for (const cand of keep) {
|
|
27785
|
+
applyOrder(cand.order);
|
|
27786
|
+
const rk = Array.from({ length: maxRank + 1 }, () => []);
|
|
27787
|
+
for (const n of node.values()) rk[n.rank].push(n.id);
|
|
27788
|
+
for (let r = 0; r <= maxRank; r++)
|
|
27789
|
+
rk[r].sort((a, b) => cand.order.get(a) - cand.order.get(b));
|
|
27790
|
+
results.push(realize(rk));
|
|
27791
|
+
}
|
|
27792
|
+
return results;
|
|
27793
|
+
function realize(rk) {
|
|
27794
|
+
const bandDepth = rk.map(
|
|
27795
|
+
(ids) => Math.max(0, ...ids.map((id) => node.get(id).depth))
|
|
27796
|
+
);
|
|
27797
|
+
const bandCenter = [];
|
|
27798
|
+
let acc = MARGIN3;
|
|
27799
|
+
for (let r = 0; r <= maxRank; r++) {
|
|
27800
|
+
bandCenter[r] = acc + bandDepth[r] / 2;
|
|
27801
|
+
acc += bandDepth[r] + ranksep;
|
|
27802
|
+
}
|
|
27803
|
+
for (let r = 0; r <= maxRank; r++) {
|
|
27804
|
+
let x = MARGIN3;
|
|
27805
|
+
for (const id of rk[r]) {
|
|
27806
|
+
const n = node.get(id);
|
|
27807
|
+
n.cross = x + n.thick / 2;
|
|
27808
|
+
x += n.thick + nodesep;
|
|
27809
|
+
}
|
|
27810
|
+
}
|
|
27811
|
+
const ITER = 18;
|
|
27812
|
+
for (let it = 0; it < ITER; it++) {
|
|
27813
|
+
const downPass = it % 2 === 0;
|
|
27814
|
+
const order = downPass ? Array.from({ length: maxRank + 1 }, (_, i) => i) : Array.from({ length: maxRank + 1 }, (_, i) => maxRank - i);
|
|
27815
|
+
for (const r of order) {
|
|
27816
|
+
const ids = rk[r];
|
|
27817
|
+
const desired = ids.map((id) => {
|
|
27818
|
+
const n = node.get(id);
|
|
27819
|
+
let sw = 0, sx2 = 0;
|
|
27820
|
+
for (const nb of up.get(id)) {
|
|
27821
|
+
const w = weight(n, node.get(nb));
|
|
27822
|
+
sw += w;
|
|
27823
|
+
sx2 += w * node.get(nb).cross;
|
|
27824
|
+
}
|
|
27825
|
+
for (const nb of down.get(id)) {
|
|
27826
|
+
const w = weight(n, node.get(nb));
|
|
27827
|
+
sw += w;
|
|
27828
|
+
sx2 += w * node.get(nb).cross;
|
|
27829
|
+
}
|
|
27830
|
+
return sw > 0 ? sx2 / sw : n.cross;
|
|
27831
|
+
});
|
|
27832
|
+
placeWithSeparation(ids, desired);
|
|
27833
|
+
}
|
|
27834
|
+
}
|
|
27835
|
+
let minC = Infinity;
|
|
27836
|
+
for (const n of node.values()) minC = Math.min(minC, n.cross - n.thick / 2);
|
|
27837
|
+
const shift = MARGIN3 - minC;
|
|
27838
|
+
for (const n of node.values()) n.cross += shift;
|
|
27839
|
+
const coord = (n) => isTB ? { x: n.cross, y: bandCenter[n.rank] } : { x: bandCenter[n.rank], y: n.cross };
|
|
27840
|
+
const layoutNodes = parsed.nodes.map((pn) => {
|
|
27841
|
+
const n = node.get(pn.label);
|
|
27842
|
+
const c = coord(n);
|
|
27843
|
+
return {
|
|
27844
|
+
label: pn.label,
|
|
27845
|
+
x: c.x,
|
|
27846
|
+
y: c.y,
|
|
27847
|
+
width: n.realW,
|
|
27848
|
+
height: n.realH
|
|
27849
|
+
};
|
|
27850
|
+
});
|
|
27851
|
+
const chainById = /* @__PURE__ */ new Map();
|
|
27852
|
+
for (const ch of chains) chainById.set(ch.edgeIdx, ch.chain);
|
|
27853
|
+
let minCross = Infinity, maxCross = -Infinity;
|
|
27854
|
+
for (const n of node.values()) {
|
|
27855
|
+
if (n.dummy) continue;
|
|
27856
|
+
minCross = Math.min(minCross, n.cross - n.thick / 2);
|
|
27857
|
+
maxCross = Math.max(maxCross, n.cross + n.thick / 2);
|
|
27858
|
+
}
|
|
27859
|
+
const GAP = 34;
|
|
27860
|
+
const LANE = 28;
|
|
27861
|
+
const sideOf = (b) => {
|
|
27862
|
+
if (backEdgeSide === "left") return -1;
|
|
27863
|
+
if (backEdgeSide === "right") return 1;
|
|
27864
|
+
const d = node.get(b.src).cross - node.get(b.tgt).cross;
|
|
27865
|
+
return d >= 0 ? 1 : -1;
|
|
27866
|
+
};
|
|
27867
|
+
const backSorted = backEdges.map((b) => ({
|
|
27868
|
+
...b,
|
|
27869
|
+
side: sideOf(b),
|
|
27870
|
+
span: Math.abs(node.get(b.src).rank - node.get(b.tgt).rank)
|
|
27871
|
+
})).sort((a, b) => a.side - b.side || a.span - b.span);
|
|
27872
|
+
const sideCounts = /* @__PURE__ */ new Map();
|
|
27873
|
+
for (const b of backSorted)
|
|
27874
|
+
sideCounts.set(b.side, (sideCounts.get(b.side) ?? 0) + 1);
|
|
27875
|
+
const laneCounter = /* @__PURE__ */ new Map();
|
|
27876
|
+
const backPoints = /* @__PURE__ */ new Map();
|
|
27877
|
+
const faceLim = (depth) => Math.max(0, depth / 2 - 6);
|
|
27878
|
+
const hubIndex = /* @__PURE__ */ new Map();
|
|
27879
|
+
const hubSize = /* @__PURE__ */ new Map();
|
|
27880
|
+
{
|
|
27881
|
+
const counter = /* @__PURE__ */ new Map();
|
|
27882
|
+
for (const b of backSorted) {
|
|
27883
|
+
const key = `${b.side}|${b.tgt}`;
|
|
27884
|
+
const idx = counter.get(key) ?? 0;
|
|
27885
|
+
counter.set(key, idx + 1);
|
|
27886
|
+
hubIndex.set(b.edgeIdx, idx);
|
|
27887
|
+
}
|
|
27888
|
+
for (const [key, v] of counter) hubSize.set(key, v);
|
|
27889
|
+
}
|
|
27890
|
+
for (const b of backSorted) {
|
|
27891
|
+
const s = b.side;
|
|
27892
|
+
const k = laneCounter.get(s) ?? 0;
|
|
27893
|
+
laneCounter.set(s, k + 1);
|
|
27894
|
+
const K = sideCounts.get(s);
|
|
27895
|
+
const src = node.get(b.src);
|
|
27896
|
+
const tgt = node.get(b.tgt);
|
|
27897
|
+
const laneC = s > 0 ? maxCross + GAP + k * LANE : minCross - GAP - k * LANE;
|
|
27898
|
+
const srcCtr = bandCenter[src.rank];
|
|
27899
|
+
const tgtCtr = bandCenter[tgt.rank];
|
|
27900
|
+
const frac = K > 1 ? (k + 1) / (K + 1) : 0;
|
|
27901
|
+
const srcR = srcCtr + frac * faceLim(src.depth);
|
|
27902
|
+
const tgtR = tgtCtr - frac * faceLim(tgt.depth);
|
|
27903
|
+
const m = (c, r) => isTB ? { x: c, y: r } : { x: r, y: c };
|
|
27904
|
+
const off = 10;
|
|
27905
|
+
const srcEdgeC = src.cross + s * (src.thick / 2 + off);
|
|
27906
|
+
const tgtEdgeC = tgt.cross + s * (tgt.thick / 2 + off);
|
|
27907
|
+
const hubK = hubIndex.get(b.edgeIdx);
|
|
27908
|
+
const hubN = hubSize.get(`${s}|${b.tgt}`);
|
|
27909
|
+
if (hubN > 1 && hubK > 0) {
|
|
27910
|
+
const tgtTop = tgtCtr - (tgt.depth / 2 + GAP + (hubK - 1) * LANE);
|
|
27911
|
+
const entryCross = tgt.cross + s * faceLim(tgt.thick) * (hubK / hubN);
|
|
27912
|
+
backPoints.set(b.edgeIdx, [
|
|
27913
|
+
m(src.cross, srcCtr),
|
|
27914
|
+
m(srcEdgeC, srcR),
|
|
27915
|
+
m(laneC, srcR),
|
|
27916
|
+
m(laneC, tgtTop),
|
|
27917
|
+
m(entryCross, tgtTop),
|
|
27918
|
+
m(tgt.cross, tgtCtr)
|
|
27919
|
+
]);
|
|
27920
|
+
} else {
|
|
27921
|
+
backPoints.set(b.edgeIdx, [
|
|
27922
|
+
m(src.cross, srcCtr),
|
|
27923
|
+
m(srcEdgeC, srcR),
|
|
27924
|
+
m(laneC, srcR),
|
|
27925
|
+
m(laneC, tgtR),
|
|
27926
|
+
m(tgtEdgeC, tgtR),
|
|
27927
|
+
m(tgt.cross, tgtCtr)
|
|
27928
|
+
]);
|
|
27929
|
+
}
|
|
27930
|
+
}
|
|
27931
|
+
const layoutEdges = [];
|
|
27932
|
+
for (let i = 0; i < parsed.edges.length; i++) {
|
|
27933
|
+
const e = parsed.edges[i];
|
|
27934
|
+
if (!labelSet.has(e.source) || !labelSet.has(e.target)) continue;
|
|
27935
|
+
let points;
|
|
27936
|
+
if (e.source === e.target) {
|
|
27937
|
+
const c = coord(node.get(e.source));
|
|
27938
|
+
points = [c, c];
|
|
27939
|
+
} else if (backPoints.has(i)) {
|
|
27940
|
+
points = backPoints.get(i);
|
|
27941
|
+
} else {
|
|
27942
|
+
const chain = chainById.get(i);
|
|
27943
|
+
if (!chain) continue;
|
|
27944
|
+
points = chain.map((id) => coord(node.get(id)));
|
|
27945
|
+
}
|
|
27946
|
+
layoutEdges.push({
|
|
27947
|
+
source: e.source,
|
|
27948
|
+
target: e.target,
|
|
27949
|
+
...e.label !== void 0 && { label: e.label },
|
|
27950
|
+
bidirectional: e.bidirectional,
|
|
27951
|
+
lineNumber: e.lineNumber,
|
|
27952
|
+
points,
|
|
27953
|
+
yOffset: 0,
|
|
27954
|
+
parallelCount: 1,
|
|
27955
|
+
metadata: e.metadata
|
|
27956
|
+
});
|
|
27957
|
+
}
|
|
27958
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
27959
|
+
for (const n of layoutNodes) {
|
|
27960
|
+
minX = Math.min(minX, n.x - n.width / 2);
|
|
27961
|
+
minY = Math.min(minY, n.y - n.height / 2);
|
|
27962
|
+
maxX = Math.max(maxX, n.x + n.width / 2);
|
|
27963
|
+
maxY = Math.max(maxY, n.y + n.height / 2);
|
|
27964
|
+
}
|
|
27965
|
+
for (const e of layoutEdges)
|
|
27966
|
+
for (const p of e.points) {
|
|
27967
|
+
minX = Math.min(minX, p.x);
|
|
27968
|
+
minY = Math.min(minY, p.y);
|
|
27969
|
+
maxX = Math.max(maxX, p.x);
|
|
27970
|
+
maxY = Math.max(maxY, p.y);
|
|
27971
|
+
}
|
|
27972
|
+
const sx = MARGIN3 - minX;
|
|
27973
|
+
const sy = MARGIN3 - minY;
|
|
27974
|
+
const shifted = sx !== 0 || sy !== 0 ? {
|
|
27975
|
+
nodes: layoutNodes.map((n) => ({ ...n, x: n.x + sx, y: n.y + sy })),
|
|
27976
|
+
edges: layoutEdges.map((e) => ({
|
|
27977
|
+
...e,
|
|
27978
|
+
points: e.points.map((p) => ({ x: p.x + sx, y: p.y + sy }))
|
|
27979
|
+
}))
|
|
27980
|
+
} : { nodes: layoutNodes, edges: layoutEdges };
|
|
27981
|
+
return {
|
|
27982
|
+
nodes: shifted.nodes,
|
|
27983
|
+
edges: shifted.edges,
|
|
27984
|
+
groups: [],
|
|
27985
|
+
width: maxX + sx + MARGIN3,
|
|
27986
|
+
height: maxY + sy + MARGIN3
|
|
27987
|
+
};
|
|
27988
|
+
}
|
|
27989
|
+
function weight(a, b) {
|
|
27990
|
+
if (a.dummy && b.dummy) return W_DUMMY_DUMMY;
|
|
27991
|
+
if (a.dummy || b.dummy) return W_REAL_DUMMY;
|
|
27992
|
+
return W_REAL_REAL;
|
|
27993
|
+
}
|
|
27994
|
+
function placeWithSeparation(ids, desired) {
|
|
27995
|
+
const n = ids.length;
|
|
27996
|
+
if (n === 0) return;
|
|
27997
|
+
const half = ids.map((id) => node.get(id).thick / 2);
|
|
27998
|
+
const off = [0];
|
|
27999
|
+
for (let i = 1; i < n; i++)
|
|
28000
|
+
off[i] = off[i - 1] + half[i - 1] + nodesep + half[i];
|
|
28001
|
+
const d = desired.map((v, i) => v - off[i]);
|
|
28002
|
+
const blocks = [];
|
|
28003
|
+
for (let i = 0; i < n; i++) {
|
|
28004
|
+
let b = { pos: d[i], count: 1, sumOffset: d[i], first: i };
|
|
28005
|
+
while (blocks.length && blocks[blocks.length - 1].pos >= b.pos) {
|
|
28006
|
+
const prev = blocks.pop();
|
|
28007
|
+
const count = prev.count + b.count;
|
|
28008
|
+
const sumOffset = prev.sumOffset + b.sumOffset;
|
|
28009
|
+
b = { pos: sumOffset / count, count, sumOffset, first: prev.first };
|
|
28010
|
+
}
|
|
28011
|
+
blocks.push(b);
|
|
28012
|
+
}
|
|
28013
|
+
const xs = new Array(n);
|
|
28014
|
+
for (const b of blocks)
|
|
28015
|
+
for (let k = 0; k < b.count; k++) xs[b.first + k] = b.pos;
|
|
28016
|
+
for (let i = 0; i < n; i++) node.get(ids[i]).cross = xs[i] + off[i];
|
|
28017
|
+
}
|
|
28018
|
+
}
|
|
28019
|
+
var NODESEP, RANKSEP, DUMMY_THICK, MARGIN3, W_REAL_REAL, W_REAL_DUMMY, W_DUMMY_DUMMY;
|
|
28020
|
+
var init_layout_layered = __esm({
|
|
28021
|
+
"src/boxes-and-lines/layout-layered.ts"() {
|
|
28022
|
+
"use strict";
|
|
28023
|
+
init_layout5();
|
|
28024
|
+
NODESEP = 50;
|
|
28025
|
+
RANKSEP = 60;
|
|
28026
|
+
DUMMY_THICK = 10;
|
|
28027
|
+
MARGIN3 = 40;
|
|
28028
|
+
W_REAL_REAL = 1;
|
|
28029
|
+
W_REAL_DUMMY = 2;
|
|
28030
|
+
W_DUMMY_DUMMY = 8;
|
|
28031
|
+
}
|
|
28032
|
+
});
|
|
28033
|
+
|
|
28034
|
+
// src/boxes-and-lines/layout-search.ts
|
|
28035
|
+
var layout_search_exports = {};
|
|
28036
|
+
__export(layout_search_exports, {
|
|
28037
|
+
countEdgeNearMiss: () => countEdgeNearMiss,
|
|
28038
|
+
countEdgeNodePierces: () => countEdgeNodePierces,
|
|
28039
|
+
countEdgeOverlaps: () => countEdgeOverlaps,
|
|
28040
|
+
countGroupOverlaps: () => countGroupOverlaps,
|
|
28041
|
+
countSplineCrossings: () => countSplineCrossings,
|
|
28042
|
+
deroutePierces: () => deroutePierces,
|
|
28043
|
+
detectEdgeNodePierces: () => detectEdgeNodePierces,
|
|
28044
|
+
detectEdgeOverlaps: () => detectEdgeOverlaps,
|
|
28045
|
+
detectGroupOverlaps: () => detectGroupOverlaps,
|
|
28046
|
+
layoutBoxesAndLinesSearch: () => layoutBoxesAndLinesSearch,
|
|
28047
|
+
separateGroupBands: () => separateGroupBands
|
|
28048
|
+
});
|
|
28049
|
+
function rng2(s) {
|
|
28050
|
+
return () => {
|
|
28051
|
+
s |= 0;
|
|
28052
|
+
s = s + 1831565813 | 0;
|
|
28053
|
+
let t = Math.imul(s ^ s >>> 15, 1 | s);
|
|
28054
|
+
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
28055
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
28056
|
+
};
|
|
28057
|
+
}
|
|
28058
|
+
function shuffle(a, r) {
|
|
28059
|
+
const x = a.slice();
|
|
28060
|
+
for (let i = x.length - 1; i > 0; i--) {
|
|
28061
|
+
const j = Math.floor(r() * (i + 1));
|
|
28062
|
+
[x[i], x[j]] = [x[j], x[i]];
|
|
28063
|
+
}
|
|
28064
|
+
return x;
|
|
28065
|
+
}
|
|
28066
|
+
function flatten(d) {
|
|
28067
|
+
const toks = d.match(/[MLQC]|-?\d*\.?\d+(?:e-?\d+)?/gi) ?? [];
|
|
28068
|
+
const pts = [];
|
|
28069
|
+
let i = 0, cx = 0, cy = 0, cmd = "";
|
|
28070
|
+
const num = () => parseFloat(toks[i++]);
|
|
28071
|
+
const samp = (p0, c1, c2, p1) => {
|
|
28072
|
+
for (let t = 0; t <= 1; t += 0.12) {
|
|
28073
|
+
const u = 1 - t;
|
|
28074
|
+
if (c2)
|
|
28075
|
+
pts.push({
|
|
28076
|
+
x: u * u * u * p0.x + 3 * u * u * t * c1.x + 3 * u * t * t * c2.x + t * t * t * p1.x,
|
|
28077
|
+
y: u * u * u * p0.y + 3 * u * u * t * c1.y + 3 * u * t * t * c2.y + t * t * t * p1.y
|
|
28078
|
+
});
|
|
28079
|
+
else
|
|
28080
|
+
pts.push({
|
|
28081
|
+
x: u * u * p0.x + 2 * u * t * c1.x + t * t * p1.x,
|
|
28082
|
+
y: u * u * p0.y + 2 * u * t * c1.y + t * t * p1.y
|
|
28083
|
+
});
|
|
28084
|
+
}
|
|
28085
|
+
};
|
|
28086
|
+
while (i < toks.length) {
|
|
28087
|
+
const tk = toks[i];
|
|
28088
|
+
if (/[MLQC]/i.test(tk)) {
|
|
28089
|
+
cmd = tk;
|
|
28090
|
+
i++;
|
|
28091
|
+
}
|
|
28092
|
+
if (cmd === "M" || cmd === "L") {
|
|
28093
|
+
const x = num(), y = num();
|
|
28094
|
+
pts.push({ x, y });
|
|
28095
|
+
cx = x;
|
|
28096
|
+
cy = y;
|
|
28097
|
+
} else if (cmd === "Q") {
|
|
28098
|
+
const c1 = { x: num(), y: num() }, p1 = { x: num(), y: num() };
|
|
28099
|
+
samp({ x: cx, y: cy }, c1, null, p1);
|
|
28100
|
+
cx = p1.x;
|
|
28101
|
+
cy = p1.y;
|
|
28102
|
+
} else if (cmd === "C") {
|
|
28103
|
+
const c1 = { x: num(), y: num() }, c2 = { x: num(), y: num() }, p1 = { x: num(), y: num() };
|
|
28104
|
+
samp({ x: cx, y: cy }, c1, c2, p1);
|
|
28105
|
+
cx = p1.x;
|
|
28106
|
+
cy = p1.y;
|
|
28107
|
+
} else i++;
|
|
28108
|
+
}
|
|
28109
|
+
return pts;
|
|
28110
|
+
}
|
|
28111
|
+
function segPoint(p1, p2, p3, p4) {
|
|
28112
|
+
const den = (p2.x - p1.x) * (p4.y - p3.y) - (p2.y - p1.y) * (p4.x - p3.x);
|
|
28113
|
+
if (Math.abs(den) < 1e-9) return null;
|
|
28114
|
+
const t = ((p3.x - p1.x) * (p4.y - p3.y) - (p3.y - p1.y) * (p4.x - p3.x)) / den, u = ((p3.x - p1.x) * (p2.y - p1.y) - (p3.y - p1.y) * (p2.x - p1.x)) / den;
|
|
28115
|
+
return t > 0 && t < 1 && u > 0 && u < 1 ? { x: p1.x + t * (p2.x - p1.x), y: p1.y + t * (p2.y - p1.y) } : null;
|
|
28116
|
+
}
|
|
28117
|
+
function countSplineCrossings(layout) {
|
|
28118
|
+
const center = /* @__PURE__ */ new Map();
|
|
28119
|
+
for (const n of layout.nodes) center.set(n.label, { x: n.x, y: n.y });
|
|
28120
|
+
for (const g of layout.groups)
|
|
28121
|
+
if (g.collapsed) center.set("__group_" + g.label, { x: g.x, y: g.y });
|
|
28122
|
+
const polys = layout.edges.map((e) => {
|
|
28123
|
+
const pts = e.points.length >= 2 ? flatten(splineGen(e.points) ?? "") : [];
|
|
28124
|
+
let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
|
|
28125
|
+
for (const p of pts) {
|
|
28126
|
+
if (p.x < x0) x0 = p.x;
|
|
28127
|
+
if (p.x > x1) x1 = p.x;
|
|
28128
|
+
if (p.y < y0) y0 = p.y;
|
|
28129
|
+
if (p.y > y1) y1 = p.y;
|
|
28130
|
+
}
|
|
28131
|
+
return { pts, s: e.source, t: e.target, x0, y0, x1, y1 };
|
|
28132
|
+
});
|
|
28133
|
+
const R = 34;
|
|
28134
|
+
let total = 0;
|
|
28135
|
+
for (let a = 0; a < polys.length; a++)
|
|
28136
|
+
for (let b = a + 1; b < polys.length; b++) {
|
|
28137
|
+
const A = polys[a], B = polys[b];
|
|
28138
|
+
if (A.pts.length < 2 || B.pts.length < 2) continue;
|
|
28139
|
+
if (A.x1 < B.x0 || B.x1 < A.x0 || A.y1 < B.y0 || B.y1 < A.y0) continue;
|
|
28140
|
+
const shared = [A.s, A.t].filter((n) => n === B.s || n === B.t).map((n) => center.get(n)).filter(Boolean);
|
|
28141
|
+
const hits = [];
|
|
28142
|
+
for (let i = 1; i < A.pts.length; i++)
|
|
28143
|
+
for (let j = 1; j < B.pts.length; j++) {
|
|
28144
|
+
const p = segPoint(
|
|
28145
|
+
A.pts[i - 1],
|
|
28146
|
+
A.pts[i],
|
|
28147
|
+
B.pts[j - 1],
|
|
28148
|
+
B.pts[j]
|
|
28149
|
+
);
|
|
28150
|
+
if (!p) continue;
|
|
28151
|
+
if (shared.some((c) => Math.hypot(p.x - c.x, p.y - c.y) < R))
|
|
28152
|
+
continue;
|
|
28153
|
+
if (!hits.some((h) => Math.hypot(h.x - p.x, h.y - p.y) < 6))
|
|
28154
|
+
hits.push(p);
|
|
28155
|
+
}
|
|
28156
|
+
total += hits.length;
|
|
28157
|
+
}
|
|
28158
|
+
return total;
|
|
28159
|
+
}
|
|
28160
|
+
function pointSegDist(p, a, b) {
|
|
28161
|
+
const dx = b.x - a.x, dy = b.y - a.y;
|
|
28162
|
+
const len2 = dx * dx + dy * dy;
|
|
28163
|
+
if (len2 < 1e-9) return Math.hypot(p.x - a.x, p.y - a.y);
|
|
28164
|
+
let t = ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2;
|
|
28165
|
+
t = Math.max(0, Math.min(1, t));
|
|
28166
|
+
return Math.hypot(p.x - (a.x + t * dx), p.y - (a.y + t * dy));
|
|
28167
|
+
}
|
|
28168
|
+
function distToPoly(p, poly) {
|
|
28169
|
+
let m = Infinity;
|
|
28170
|
+
for (let i = 1; i < poly.length; i++)
|
|
28171
|
+
m = Math.min(m, pointSegDist(p, poly[i - 1], poly[i]));
|
|
28172
|
+
return m;
|
|
28173
|
+
}
|
|
28174
|
+
function pointRectDist(p, r) {
|
|
28175
|
+
const dx = Math.max(r.x - r.w / 2 - p.x, 0, p.x - (r.x + r.w / 2));
|
|
28176
|
+
const dy = Math.max(r.y - r.h / 2 - p.y, 0, p.y - (r.y + r.h / 2));
|
|
28177
|
+
return Math.hypot(dx, dy);
|
|
28178
|
+
}
|
|
28179
|
+
function detectEdgeOverlaps(layout, opts) {
|
|
28180
|
+
const dist = opts?.dist ?? 8;
|
|
28181
|
+
const minLen = opts?.minLen ?? 16;
|
|
28182
|
+
const nodeClear = opts?.nodeClear ?? 12;
|
|
28183
|
+
const rect = /* @__PURE__ */ new Map();
|
|
28184
|
+
for (const n of layout.nodes)
|
|
28185
|
+
rect.set(n.label, { x: n.x, y: n.y, w: n.width, h: n.height });
|
|
28186
|
+
for (const g of layout.groups)
|
|
28187
|
+
if (g.collapsed)
|
|
28188
|
+
rect.set("__group_" + g.label, {
|
|
28189
|
+
x: g.x,
|
|
28190
|
+
y: g.y,
|
|
28191
|
+
w: g.width,
|
|
28192
|
+
h: g.height
|
|
28193
|
+
});
|
|
28194
|
+
const polys = layout.edges.map((e) => {
|
|
28195
|
+
const pts = e.points.length >= 2 ? flatten(splineGen(e.points) ?? "") : [];
|
|
28196
|
+
let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
|
|
28197
|
+
for (const p of pts) {
|
|
28198
|
+
if (p.x < x0) x0 = p.x;
|
|
28199
|
+
if (p.x > x1) x1 = p.x;
|
|
28200
|
+
if (p.y < y0) y0 = p.y;
|
|
28201
|
+
if (p.y > y1) y1 = p.y;
|
|
28202
|
+
}
|
|
28203
|
+
return { pts, s: e.source, t: e.target, x0, y0, x1, y1 };
|
|
28204
|
+
});
|
|
28205
|
+
const runs = [];
|
|
28206
|
+
for (let a = 0; a < polys.length; a++)
|
|
28207
|
+
for (let b = a + 1; b < polys.length; b++) {
|
|
28208
|
+
const A = polys[a], B = polys[b];
|
|
28209
|
+
if (A.pts.length < 2 || B.pts.length < 2) continue;
|
|
28210
|
+
if (A.x1 + dist < B.x0 || B.x1 + dist < A.x0 || A.y1 + dist < B.y0 || B.y1 + dist < A.y0)
|
|
28211
|
+
continue;
|
|
28212
|
+
const shared = [A.s, A.t].filter((n) => n === B.s || n === B.t).map((n) => rect.get(n)).filter(Boolean);
|
|
28213
|
+
let run2 = [];
|
|
28214
|
+
let runLen = 0;
|
|
28215
|
+
const flush = () => {
|
|
28216
|
+
if (runLen >= minLen && run2.length >= 2)
|
|
28217
|
+
runs.push({
|
|
28218
|
+
mid: run2[Math.floor(run2.length / 2)],
|
|
28219
|
+
length: runLen,
|
|
28220
|
+
pts: run2.slice()
|
|
28221
|
+
});
|
|
28222
|
+
run2 = [];
|
|
28223
|
+
runLen = 0;
|
|
28224
|
+
};
|
|
28225
|
+
for (const p of A.pts) {
|
|
28226
|
+
const nearShared = shared.some((r) => pointRectDist(p, r) < nodeClear);
|
|
28227
|
+
const covered = !nearShared && distToPoly(p, B.pts) < dist;
|
|
28228
|
+
if (covered) {
|
|
28229
|
+
if (run2.length)
|
|
28230
|
+
runLen += Math.hypot(
|
|
28231
|
+
p.x - run2[run2.length - 1].x,
|
|
28232
|
+
p.y - run2[run2.length - 1].y
|
|
28233
|
+
);
|
|
28234
|
+
run2.push(p);
|
|
28235
|
+
} else flush();
|
|
28236
|
+
}
|
|
28237
|
+
flush();
|
|
28238
|
+
}
|
|
28239
|
+
return runs;
|
|
28240
|
+
}
|
|
28241
|
+
function countEdgeOverlaps(layout, opts) {
|
|
28242
|
+
return detectEdgeOverlaps(layout, opts).length;
|
|
28243
|
+
}
|
|
28244
|
+
function detectEdgeNodePierces(layout, opts) {
|
|
28245
|
+
const inset = opts?.inset ?? 6;
|
|
28246
|
+
const minPts = opts?.minPts ?? 2;
|
|
28247
|
+
const rects = [];
|
|
28248
|
+
for (const n of layout.nodes)
|
|
28249
|
+
rects.push({ key: n.label, x: n.x, y: n.y, w: n.width, h: n.height });
|
|
28250
|
+
for (const g of layout.groups)
|
|
28251
|
+
if (g.collapsed)
|
|
28252
|
+
rects.push({
|
|
28253
|
+
key: "__group_" + g.label,
|
|
28254
|
+
x: g.x,
|
|
28255
|
+
y: g.y,
|
|
28256
|
+
w: g.width,
|
|
28257
|
+
h: g.height
|
|
28258
|
+
});
|
|
28259
|
+
const inside = (p, r) => Math.abs(p.x - r.x) < r.w / 2 - inset && Math.abs(p.y - r.y) < r.h / 2 - inset;
|
|
28260
|
+
const out = [];
|
|
28261
|
+
layout.edges.forEach((e, idx) => {
|
|
28262
|
+
if (e.points.length < 2) return;
|
|
28263
|
+
const poly = flatten(splineGen(e.points) ?? "");
|
|
28264
|
+
for (const r of rects) {
|
|
28265
|
+
if (r.key === e.source || r.key === e.target || "__group_" + r.key === e.source || "__group_" + r.key === e.target)
|
|
28266
|
+
continue;
|
|
28267
|
+
const hits = poly.filter((p) => inside(p, r));
|
|
28268
|
+
if (hits.length >= minPts)
|
|
28269
|
+
out.push({ edgeIdx: idx, node: r.key, pts: hits });
|
|
28270
|
+
}
|
|
28271
|
+
});
|
|
28272
|
+
return out;
|
|
28273
|
+
}
|
|
28274
|
+
function countEdgeNodePierces(layout, opts) {
|
|
28275
|
+
return detectEdgeNodePierces(layout, opts).length;
|
|
28276
|
+
}
|
|
28277
|
+
function deroutePierces(layout) {
|
|
28278
|
+
const pierces = detectEdgeNodePierces(layout);
|
|
28279
|
+
if (!pierces.length) return layout;
|
|
28280
|
+
const rect = /* @__PURE__ */ new Map();
|
|
28281
|
+
for (const n of layout.nodes)
|
|
28282
|
+
rect.set(n.label, { x: n.x, y: n.y, w: n.width, h: n.height });
|
|
28283
|
+
for (const g of layout.groups)
|
|
28284
|
+
if (g.collapsed)
|
|
28285
|
+
rect.set("__group_" + g.label, {
|
|
28286
|
+
x: g.x,
|
|
28287
|
+
y: g.y,
|
|
28288
|
+
w: g.width,
|
|
28289
|
+
h: g.height
|
|
28290
|
+
});
|
|
28291
|
+
const byEdge = /* @__PURE__ */ new Map();
|
|
28292
|
+
for (const p of pierces) {
|
|
28293
|
+
const arr = byEdge.get(p.edgeIdx);
|
|
28294
|
+
if (arr) arr.push(p.node);
|
|
28295
|
+
else byEdge.set(p.edgeIdx, [p.node]);
|
|
28296
|
+
}
|
|
28297
|
+
const edges = layout.edges.map((e, idx) => {
|
|
28298
|
+
const nodes = byEdge.get(idx);
|
|
28299
|
+
if (!nodes) return e;
|
|
28300
|
+
let pts = e.points.map((p) => ({ x: p.x, y: p.y }));
|
|
28301
|
+
for (const label of nodes) {
|
|
28302
|
+
const r = rect.get(label);
|
|
28303
|
+
if (r) pts = detourAround(pts, r);
|
|
28304
|
+
}
|
|
28305
|
+
return { ...e, points: pts };
|
|
28306
|
+
});
|
|
28307
|
+
return { ...layout, edges };
|
|
28308
|
+
}
|
|
28309
|
+
function detourAround(pts, r) {
|
|
28310
|
+
if (pts.length < 2) return pts;
|
|
28311
|
+
const c = { x: r.x, y: r.y };
|
|
28312
|
+
let bestSeg = -1;
|
|
28313
|
+
let bestT = 0;
|
|
28314
|
+
let bestD = Infinity;
|
|
28315
|
+
let bestPt = pts[0];
|
|
28316
|
+
for (let i = 0; i < pts.length - 1; i++) {
|
|
28317
|
+
const a2 = pts[i], b2 = pts[i + 1];
|
|
28318
|
+
const dx = b2.x - a2.x, dy = b2.y - a2.y;
|
|
28319
|
+
const len2 = dx * dx + dy * dy || 1e-9;
|
|
28320
|
+
let t = ((c.x - a2.x) * dx + (c.y - a2.y) * dy) / len2;
|
|
28321
|
+
t = Math.max(0, Math.min(1, t));
|
|
28322
|
+
const q = { x: a2.x + t * dx, y: a2.y + t * dy };
|
|
28323
|
+
const d = Math.hypot(q.x - c.x, q.y - c.y);
|
|
28324
|
+
if (d < bestD) {
|
|
28325
|
+
bestD = d;
|
|
28326
|
+
bestSeg = i;
|
|
28327
|
+
bestT = t;
|
|
28328
|
+
bestPt = q;
|
|
28329
|
+
}
|
|
28330
|
+
}
|
|
28331
|
+
if (bestSeg < 0) return pts;
|
|
28332
|
+
let nx = bestPt.x - c.x;
|
|
28333
|
+
let ny = bestPt.y - c.y;
|
|
28334
|
+
if (Math.hypot(nx, ny) < 1) {
|
|
28335
|
+
if (r.w <= r.h) {
|
|
28336
|
+
nx = 1;
|
|
28337
|
+
ny = 0;
|
|
28338
|
+
} else {
|
|
28339
|
+
nx = 0;
|
|
28340
|
+
ny = 1;
|
|
28341
|
+
}
|
|
28342
|
+
}
|
|
28343
|
+
const nlen = Math.hypot(nx, ny) || 1;
|
|
28344
|
+
nx /= nlen;
|
|
28345
|
+
ny /= nlen;
|
|
28346
|
+
const a = pts[bestSeg], b = pts[bestSeg + 1];
|
|
28347
|
+
let ex = b.x - a.x, ey = b.y - a.y;
|
|
28348
|
+
const elen = Math.hypot(ex, ey) || 1;
|
|
28349
|
+
ex /= elen;
|
|
28350
|
+
ey /= elen;
|
|
28351
|
+
const clear = Math.hypot(r.w, r.h) / 2 + 18;
|
|
28352
|
+
const hw = Math.hypot(r.w, r.h) / 2;
|
|
28353
|
+
void bestT;
|
|
28354
|
+
const before = {
|
|
28355
|
+
x: bestPt.x - ex * hw + nx * clear * 0.5,
|
|
28356
|
+
y: bestPt.y - ey * hw + ny * clear * 0.5
|
|
28357
|
+
};
|
|
28358
|
+
const peak = { x: c.x + nx * clear, y: c.y + ny * clear };
|
|
28359
|
+
const after = {
|
|
28360
|
+
x: bestPt.x + ex * hw + nx * clear * 0.5,
|
|
28361
|
+
y: bestPt.y + ey * hw + ny * clear * 0.5
|
|
28362
|
+
};
|
|
28363
|
+
const out = pts.slice(0, bestSeg + 1);
|
|
28364
|
+
out.push(before, peak, after);
|
|
28365
|
+
out.push(...pts.slice(bestSeg + 1));
|
|
28366
|
+
return out;
|
|
28367
|
+
}
|
|
28368
|
+
function countEdgeNearMiss(layout, opts) {
|
|
28369
|
+
const near = opts?.near ?? 14;
|
|
28370
|
+
const tight = opts?.tight ?? 8;
|
|
28371
|
+
const minLen = opts?.minLen ?? 18;
|
|
28372
|
+
const close = detectEdgeOverlaps(layout, { dist: near, minLen }).length;
|
|
28373
|
+
const over = detectEdgeOverlaps(layout, { dist: tight, minLen }).length;
|
|
28374
|
+
return Math.max(0, close - over);
|
|
28375
|
+
}
|
|
28376
|
+
function detectGroupOverlaps(layout, opts) {
|
|
28377
|
+
const margin = opts?.margin ?? 4;
|
|
28378
|
+
const raw = layout.groups.map((g) => ({
|
|
28379
|
+
label: g.label,
|
|
28380
|
+
l: g.x - g.width / 2,
|
|
28381
|
+
r: g.x + g.width / 2,
|
|
28382
|
+
t: g.y - g.height / 2,
|
|
28383
|
+
b: g.y + g.height / 2
|
|
28384
|
+
}));
|
|
28385
|
+
const contains = (outer, inner) => outer.l <= inner.l + margin && outer.r >= inner.r - margin && outer.t <= inner.t + margin && outer.b >= inner.b - margin;
|
|
28386
|
+
const rend = raw.map((a, i) => {
|
|
28387
|
+
const parent = raw.some((b, j) => j !== i && contains(a, b));
|
|
28388
|
+
return parent ? { ...a, t: a.t - GROUP_LABEL_ZONE2 } : a;
|
|
28389
|
+
});
|
|
28390
|
+
const hit = /* @__PURE__ */ new Set();
|
|
28391
|
+
for (let i = 0; i < raw.length; i++)
|
|
28392
|
+
for (let j = i + 1; j < raw.length; j++) {
|
|
28393
|
+
if (contains(raw[i], raw[j]) || contains(raw[j], raw[i])) continue;
|
|
28394
|
+
const a = rend[i], b = rend[j];
|
|
28395
|
+
const dx = Math.max(a.l - b.r, b.l - a.r);
|
|
28396
|
+
const dy = Math.max(a.t - b.b, b.t - a.b);
|
|
28397
|
+
if (Math.max(dx, dy) < margin) {
|
|
28398
|
+
hit.add(raw[i].label);
|
|
28399
|
+
hit.add(raw[j].label);
|
|
28400
|
+
}
|
|
28401
|
+
}
|
|
28402
|
+
return [...hit];
|
|
28403
|
+
}
|
|
28404
|
+
function countGroupOverlaps(layout, opts) {
|
|
28405
|
+
const margin = opts?.margin ?? 4;
|
|
28406
|
+
const raw = layout.groups.map((g) => ({
|
|
28407
|
+
l: g.x - g.width / 2,
|
|
28408
|
+
r: g.x + g.width / 2,
|
|
28409
|
+
t: g.y - g.height / 2,
|
|
28410
|
+
b: g.y + g.height / 2
|
|
28411
|
+
}));
|
|
28412
|
+
const contains = (outer, inner) => outer.l <= inner.l + margin && outer.r >= inner.r - margin && outer.t <= inner.t + margin && outer.b >= inner.b - margin;
|
|
28413
|
+
const rend = raw.map((a, i) => {
|
|
28414
|
+
const parent = raw.some((b, j) => j !== i && contains(a, b));
|
|
28415
|
+
return parent ? { ...a, t: a.t - GROUP_LABEL_ZONE2 } : a;
|
|
28416
|
+
});
|
|
28417
|
+
let count = 0;
|
|
28418
|
+
for (let i = 0; i < raw.length; i++)
|
|
28419
|
+
for (let j = i + 1; j < raw.length; j++) {
|
|
28420
|
+
if (contains(raw[i], raw[j]) || contains(raw[j], raw[i])) continue;
|
|
28421
|
+
const a = rend[i], b = rend[j];
|
|
28422
|
+
const dx = Math.max(a.l - b.r, b.l - a.r);
|
|
28423
|
+
const dy = Math.max(a.t - b.b, b.t - a.b);
|
|
28424
|
+
if (Math.max(dx, dy) < margin) count++;
|
|
28425
|
+
}
|
|
28426
|
+
return count;
|
|
28427
|
+
}
|
|
28428
|
+
function separateGroupBands(layout, parsed) {
|
|
28429
|
+
if (layout.groups.some((g) => g.collapsed)) return layout;
|
|
28430
|
+
if (countGroupOverlaps(layout) === 0) return layout;
|
|
28431
|
+
const parentOf = /* @__PURE__ */ new Map();
|
|
28432
|
+
for (const g of parsed.groups) parentOf.set(g.label, g.parentGroup);
|
|
28433
|
+
const topOf = (label) => {
|
|
28434
|
+
let cur = label;
|
|
28435
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28436
|
+
for (; ; ) {
|
|
28437
|
+
const p = parentOf.get(cur);
|
|
28438
|
+
if (!p || seen.has(p)) return cur;
|
|
28439
|
+
seen.add(cur);
|
|
28440
|
+
cur = p;
|
|
28441
|
+
}
|
|
28442
|
+
};
|
|
28443
|
+
const topLabels = parsed.groups.filter((g) => !g.parentGroup).map((g) => g.label);
|
|
28444
|
+
if (topLabels.length < 2) return layout;
|
|
28445
|
+
const nodeTop = /* @__PURE__ */ new Map();
|
|
28446
|
+
for (const g of parsed.groups)
|
|
28447
|
+
for (const child of g.children)
|
|
28448
|
+
if (!parsed.groups.some((gg) => gg.label === child))
|
|
28449
|
+
nodeTop.set(child, topOf(g.label));
|
|
28450
|
+
const axis = parsed.direction === "TB" ? "x" : "y";
|
|
28451
|
+
const boxByLabel = new Map(layout.groups.map((g) => [g.label, g]));
|
|
28452
|
+
const bands = topLabels.map((label) => {
|
|
28453
|
+
const g = boxByLabel.get(label);
|
|
28454
|
+
const half2 = (axis === "y" ? g.height : g.width) / 2;
|
|
28455
|
+
let lo = (axis === "y" ? g.y : g.x) - half2;
|
|
28456
|
+
const hi = (axis === "y" ? g.y : g.x) + half2;
|
|
28457
|
+
const isParent = parsed.groups.some((c) => c.parentGroup === label);
|
|
28458
|
+
if (axis === "y" && isParent) lo -= GROUP_LABEL_ZONE2;
|
|
28459
|
+
return { label, lo, hi, c: (lo + hi) / 2 };
|
|
28460
|
+
});
|
|
28461
|
+
bands.sort((a, b) => a.c - b.c);
|
|
28462
|
+
const GAP = 16;
|
|
28463
|
+
const half = bands.map((b) => (b.hi - b.lo) / 2);
|
|
28464
|
+
const off = [0];
|
|
28465
|
+
for (let i = 1; i < bands.length; i++)
|
|
28466
|
+
off[i] = off[i - 1] + half[i - 1] + GAP + half[i];
|
|
28467
|
+
const desired = bands.map((b, i) => b.c - off[i]);
|
|
28468
|
+
const blocks = [];
|
|
28469
|
+
for (let i = 0; i < bands.length; i++) {
|
|
28470
|
+
let blk = { pos: desired[i], count: 1, sum: desired[i], first: i };
|
|
28471
|
+
while (blocks.length && blocks[blocks.length - 1].pos >= blk.pos) {
|
|
28472
|
+
const prev = blocks.pop();
|
|
28473
|
+
const count = prev.count + blk.count;
|
|
28474
|
+
const sum = prev.sum + blk.sum;
|
|
28475
|
+
blk = { pos: sum / count, count, sum, first: prev.first };
|
|
28476
|
+
}
|
|
28477
|
+
blocks.push(blk);
|
|
28478
|
+
}
|
|
28479
|
+
const newC = new Array(bands.length);
|
|
28480
|
+
for (const blk of blocks)
|
|
28481
|
+
for (let k = 0; k < blk.count; k++)
|
|
28482
|
+
newC[blk.first + k] = blk.pos + off[blk.first + k];
|
|
28483
|
+
const delta = /* @__PURE__ */ new Map();
|
|
28484
|
+
let moved = false;
|
|
28485
|
+
bands.forEach((b, i) => {
|
|
28486
|
+
const d = newC[i] - b.c;
|
|
28487
|
+
delta.set(b.label, d);
|
|
28488
|
+
if (Math.abs(d) > 0.5) moved = true;
|
|
28489
|
+
});
|
|
28490
|
+
if (!moved) return layout;
|
|
28491
|
+
const nodeDelta = (label) => {
|
|
28492
|
+
const top = nodeTop.get(label);
|
|
28493
|
+
return top ? delta.get(top) ?? 0 : 0;
|
|
28494
|
+
};
|
|
28495
|
+
const shift = (p, d) => axis === "y" ? { x: p.x, y: p.y + d } : { x: p.x + d, y: p.y };
|
|
28496
|
+
const nodes = layout.nodes.map((n) => {
|
|
28497
|
+
const d = nodeDelta(n.label);
|
|
28498
|
+
return d ? { ...n, ...axis === "y" ? { y: n.y + d } : { x: n.x + d } } : n;
|
|
28499
|
+
});
|
|
28500
|
+
const groups = layout.groups.map((g) => {
|
|
28501
|
+
const d = delta.get(topOf(g.label)) ?? 0;
|
|
28502
|
+
return d ? { ...g, ...axis === "y" ? { y: g.y + d } : { x: g.x + d } } : g;
|
|
28503
|
+
});
|
|
28504
|
+
const edges = layout.edges.map((e) => {
|
|
28505
|
+
const ds = nodeDelta(e.source);
|
|
28506
|
+
const dt = nodeDelta(e.target);
|
|
28507
|
+
if (!ds && !dt) return e;
|
|
28508
|
+
const N = e.points.length;
|
|
28509
|
+
const points = e.points.map((p, i) => {
|
|
28510
|
+
const f = N > 1 ? i / (N - 1) : 0;
|
|
28511
|
+
return shift(p, ds * (1 - f) + dt * f);
|
|
28512
|
+
});
|
|
28513
|
+
return { ...e, points };
|
|
28514
|
+
});
|
|
28515
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
28516
|
+
const acc = (x, y) => {
|
|
28517
|
+
if (x < minX) minX = x;
|
|
28518
|
+
if (x > maxX) maxX = x;
|
|
28519
|
+
if (y < minY) minY = y;
|
|
28520
|
+
if (y > maxY) maxY = y;
|
|
28521
|
+
};
|
|
28522
|
+
for (const n of nodes) {
|
|
28523
|
+
acc(n.x - n.width / 2, n.y - n.height / 2);
|
|
28524
|
+
acc(n.x + n.width / 2, n.y + n.height / 2);
|
|
28525
|
+
}
|
|
28526
|
+
for (const g of groups) {
|
|
28527
|
+
acc(g.x - g.width / 2, g.y - g.height / 2 - GROUP_LABEL_ZONE2);
|
|
28528
|
+
acc(g.x + g.width / 2, g.y + g.height / 2);
|
|
28529
|
+
}
|
|
28530
|
+
for (const e of edges) for (const p of e.points) acc(p.x, p.y);
|
|
28531
|
+
const M = 40;
|
|
28532
|
+
const sx = M - minX, sy = M - minY;
|
|
28533
|
+
const reshift = sx !== 0 || sy !== 0;
|
|
28534
|
+
return {
|
|
28535
|
+
nodes: reshift ? nodes.map((n) => ({ ...n, x: n.x + sx, y: n.y + sy })) : nodes,
|
|
28536
|
+
groups: reshift ? groups.map((g) => ({ ...g, x: g.x + sx, y: g.y + sy })) : groups,
|
|
28537
|
+
edges: reshift ? edges.map((e) => ({
|
|
28538
|
+
...e,
|
|
28539
|
+
points: e.points.map((p) => ({ x: p.x + sx, y: p.y + sy }))
|
|
28540
|
+
})) : edges,
|
|
28541
|
+
width: maxX - minX + 2 * M,
|
|
28542
|
+
height: maxY - minY + 2 * M
|
|
28543
|
+
};
|
|
28544
|
+
}
|
|
28545
|
+
function segCross(p1, p2, p3, p4) {
|
|
28546
|
+
const d1x = p2.x - p1.x, d1y = p2.y - p1.y, d2x = p4.x - p3.x, d2y = p4.y - p3.y;
|
|
28547
|
+
const den = d1x * d2y - d1y * d2x;
|
|
28548
|
+
if (Math.abs(den) < 1e-9) return false;
|
|
28549
|
+
const t = ((p3.x - p1.x) * d2y - (p3.y - p1.y) * d2x) / den;
|
|
28550
|
+
const s = ((p3.x - p1.x) * d1y - (p3.y - p1.y) * d1x) / den;
|
|
28551
|
+
return t > 1e-3 && t < 0.999 && s > 1e-3 && s < 0.999;
|
|
28552
|
+
}
|
|
28553
|
+
function countCrossingsFast(layout) {
|
|
28554
|
+
const E = layout.edges.filter((e) => e.points.length >= 2);
|
|
28555
|
+
const bb = E.map((e) => {
|
|
28556
|
+
let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
|
|
28557
|
+
for (const p of e.points) {
|
|
28558
|
+
if (p.x < x0) x0 = p.x;
|
|
28559
|
+
if (p.x > x1) x1 = p.x;
|
|
28560
|
+
if (p.y < y0) y0 = p.y;
|
|
28561
|
+
if (p.y > y1) y1 = p.y;
|
|
28562
|
+
}
|
|
28563
|
+
return { x0, y0, x1, y1 };
|
|
28564
|
+
});
|
|
28565
|
+
let count = 0;
|
|
28566
|
+
for (let i = 0; i < E.length; i++)
|
|
28567
|
+
for (let j = i + 1; j < E.length; j++) {
|
|
28568
|
+
const A = E[i], B = E[j];
|
|
28569
|
+
if (A.source === B.source || A.source === B.target || A.target === B.source || A.target === B.target)
|
|
28570
|
+
continue;
|
|
28571
|
+
const a = bb[i], b = bb[j];
|
|
28572
|
+
if (a.x1 < b.x0 || b.x1 < a.x0 || a.y1 < b.y0 || b.y1 < a.y0) continue;
|
|
28573
|
+
const pa = A.points, pb = B.points;
|
|
28574
|
+
let hit = false;
|
|
28575
|
+
for (let ai = 0; ai < pa.length - 1 && !hit; ai++)
|
|
28576
|
+
for (let bi = 0; bi < pb.length - 1; bi++) {
|
|
28577
|
+
if (segCross(pa[ai], pa[ai + 1], pb[bi], pb[bi + 1])) {
|
|
28578
|
+
hit = true;
|
|
28579
|
+
break;
|
|
28580
|
+
}
|
|
28581
|
+
}
|
|
28582
|
+
if (hit) count++;
|
|
28583
|
+
}
|
|
28584
|
+
return count;
|
|
28585
|
+
}
|
|
28586
|
+
function meanDrift(layout, prev) {
|
|
28587
|
+
if (!prev?.size) return 0;
|
|
28588
|
+
let sum = 0, n = 0;
|
|
28589
|
+
for (const node of layout.nodes) {
|
|
28590
|
+
const p = prev.get(node.label);
|
|
28591
|
+
if (p) {
|
|
28592
|
+
sum += Math.hypot(node.x - p.x, node.y - p.y);
|
|
28593
|
+
n++;
|
|
28594
|
+
}
|
|
28595
|
+
}
|
|
28596
|
+
return n ? sum / n : 0;
|
|
28597
|
+
}
|
|
28598
|
+
function edgeLength(layout) {
|
|
28599
|
+
let total = 0;
|
|
28600
|
+
for (const e of layout.edges)
|
|
28601
|
+
for (let i = 1; i < e.points.length; i++)
|
|
28602
|
+
total += Math.hypot(
|
|
28603
|
+
e.points[i].x - e.points[i - 1].x,
|
|
28604
|
+
e.points[i].y - e.points[i - 1].y
|
|
28605
|
+
);
|
|
28606
|
+
return total;
|
|
28607
|
+
}
|
|
28608
|
+
function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
|
|
28609
|
+
const hideDescriptions = opts?.hideDescriptions ?? false;
|
|
28610
|
+
const collapsedGroupLabels = /* @__PURE__ */ new Set();
|
|
28611
|
+
if (collapseInfo) {
|
|
28612
|
+
const missing = /* @__PURE__ */ new Set();
|
|
28613
|
+
for (const og of collapseInfo.originalGroups)
|
|
28614
|
+
if (!parsed.groups.some((g) => g.label === og.label))
|
|
28615
|
+
missing.add(og.label);
|
|
28616
|
+
for (const label of missing) {
|
|
28617
|
+
const og = collapseInfo.originalGroups.find((g) => g.label === label);
|
|
28618
|
+
const parent = og?.parentGroup;
|
|
28619
|
+
if (!parent || !missing.has(parent)) collapsedGroupLabels.add(label);
|
|
28620
|
+
}
|
|
28621
|
+
}
|
|
28622
|
+
const sizes = /* @__PURE__ */ new Map();
|
|
28623
|
+
let maxDescH = 0;
|
|
28624
|
+
for (const node of parsed.nodes) {
|
|
28625
|
+
const s = hideDescriptions ? { width: NODE_WIDTH, height: NODE_HEIGHT } : computeNodeSize(node, parsed.showValues === true);
|
|
28626
|
+
sizes.set(node.label, s);
|
|
28627
|
+
if (!hideDescriptions && node.description && node.description.length > 0)
|
|
28628
|
+
maxDescH = Math.max(maxDescH, s.height);
|
|
28629
|
+
}
|
|
28630
|
+
if (maxDescH > 0) {
|
|
28631
|
+
for (const node of parsed.nodes)
|
|
28632
|
+
if (node.description && node.description.length > 0) {
|
|
28633
|
+
const s = sizes.get(node.label);
|
|
28634
|
+
sizes.set(node.label, { width: s.width, height: maxDescH });
|
|
28635
|
+
}
|
|
28636
|
+
}
|
|
28637
|
+
const gid = (label) => `__group_${label}`;
|
|
28638
|
+
const rankdir = parsed.direction === "TB" ? "TB" : "LR";
|
|
28639
|
+
function place(cfg) {
|
|
28640
|
+
const r = cfg.seed === void 0 ? null : rng2(cfg.seed + 1);
|
|
28641
|
+
const ord = (a) => r ? shuffle(a, r) : a.slice();
|
|
28642
|
+
const g = new import_dagre4.default.graphlib.Graph({ compound: true, multigraph: true });
|
|
28643
|
+
g.setGraph({
|
|
28644
|
+
rankdir,
|
|
28645
|
+
ranker: cfg.ranker,
|
|
28646
|
+
nodesep: cfg.nodesep,
|
|
28647
|
+
ranksep: cfg.ranksep,
|
|
28648
|
+
edgesep: 20,
|
|
28649
|
+
marginx: 40,
|
|
28650
|
+
marginy: 40
|
|
28651
|
+
});
|
|
28652
|
+
g.setDefaultEdgeLabel(() => ({}));
|
|
28653
|
+
for (const grp of ord(parsed.groups))
|
|
28654
|
+
g.setNode(gid(grp.label), { label: grp.label });
|
|
28655
|
+
for (const node of ord(parsed.nodes)) {
|
|
28656
|
+
const s = sizes.get(node.label);
|
|
28657
|
+
g.setNode(node.label, { width: s.width, height: s.height });
|
|
28658
|
+
}
|
|
28659
|
+
for (const label of collapsedGroupLabels)
|
|
28660
|
+
g.setNode(gid(label), { width: NODE_WIDTH, height: NODE_HEIGHT });
|
|
28661
|
+
for (const grp of parsed.groups) {
|
|
28662
|
+
if (grp.parentGroup && g.hasNode(gid(grp.parentGroup)))
|
|
28663
|
+
g.setParent(gid(grp.label), gid(grp.parentGroup));
|
|
28664
|
+
for (const c of ord(grp.children)) {
|
|
28665
|
+
if (g.hasNode(c)) g.setParent(c, gid(grp.label));
|
|
28666
|
+
}
|
|
28667
|
+
}
|
|
28668
|
+
if (collapseInfo)
|
|
28669
|
+
for (const label of collapsedGroupLabels) {
|
|
28670
|
+
const og = collapseInfo.originalGroups.find((x) => x.label === label);
|
|
28671
|
+
if (og?.parentGroup && !collapsedGroupLabels.has(og.parentGroup) && g.hasNode(gid(og.parentGroup)))
|
|
28672
|
+
g.setParent(gid(label), gid(og.parentGroup));
|
|
28673
|
+
}
|
|
28674
|
+
for (const e of ord(parsed.edges))
|
|
28675
|
+
if (g.hasNode(e.source) && g.hasNode(e.target))
|
|
28676
|
+
g.setEdge(e.source, e.target, {});
|
|
28677
|
+
import_dagre4.default.layout(g);
|
|
28678
|
+
const nodes = parsed.nodes.map((n2) => {
|
|
28679
|
+
const p = g.node(n2.label);
|
|
28680
|
+
return {
|
|
28681
|
+
label: n2.label,
|
|
28682
|
+
x: p.x,
|
|
28683
|
+
y: p.y,
|
|
28684
|
+
width: p.width,
|
|
28685
|
+
height: p.height
|
|
28686
|
+
};
|
|
28687
|
+
});
|
|
28688
|
+
const groups = parsed.groups.map(
|
|
28689
|
+
(grp) => {
|
|
28690
|
+
const p = g.node(gid(grp.label));
|
|
28691
|
+
return {
|
|
28692
|
+
label: grp.label,
|
|
28693
|
+
lineNumber: grp.lineNumber,
|
|
28694
|
+
x: p.x,
|
|
28695
|
+
y: p.y,
|
|
28696
|
+
width: p.width,
|
|
28697
|
+
height: p.height,
|
|
28698
|
+
collapsed: false,
|
|
28699
|
+
childCount: grp.children.length
|
|
28700
|
+
};
|
|
28701
|
+
}
|
|
28702
|
+
);
|
|
28703
|
+
for (const label of collapsedGroupLabels) {
|
|
28704
|
+
const p = g.node(gid(label));
|
|
28705
|
+
groups.push({
|
|
28706
|
+
label,
|
|
28707
|
+
lineNumber: 0,
|
|
28708
|
+
x: p.x,
|
|
28709
|
+
y: p.y,
|
|
28710
|
+
width: p.width,
|
|
28711
|
+
height: p.height,
|
|
28712
|
+
collapsed: true,
|
|
28713
|
+
childCount: collapseInfo?.collapsedChildCounts.get(label) ?? 0
|
|
28714
|
+
});
|
|
28715
|
+
}
|
|
28716
|
+
const edges = parsed.edges.filter((e) => g.hasEdge(e.source, e.target)).map((e) => {
|
|
28717
|
+
const ed = g.edge(e.source, e.target);
|
|
28718
|
+
return {
|
|
28719
|
+
source: e.source,
|
|
28720
|
+
target: e.target,
|
|
28721
|
+
...e.label !== void 0 && { label: e.label },
|
|
28722
|
+
bidirectional: e.bidirectional,
|
|
28723
|
+
lineNumber: e.lineNumber,
|
|
28724
|
+
points: ed?.points ?? [],
|
|
28725
|
+
yOffset: 0,
|
|
28726
|
+
parallelCount: 1,
|
|
28727
|
+
metadata: e.metadata
|
|
28728
|
+
};
|
|
28729
|
+
});
|
|
28730
|
+
const gg = g.graph();
|
|
28731
|
+
return {
|
|
28732
|
+
nodes,
|
|
28733
|
+
edges,
|
|
28734
|
+
groups,
|
|
28735
|
+
width: gg.width ?? 800,
|
|
28736
|
+
height: gg.height ?? 600
|
|
28737
|
+
};
|
|
28738
|
+
}
|
|
28739
|
+
const n = parsed.nodes.length;
|
|
28740
|
+
const seedCount = opts?.seeds ?? (n <= 12 ? 80 : n <= 22 ? 40 : n <= 35 ? 22 : 10);
|
|
28741
|
+
const REFINE_K = opts?.refineK ?? 6;
|
|
28742
|
+
const lambda = opts?.lambda ?? DEFAULT_LAMBDA;
|
|
28743
|
+
const prev = opts?.previousPositions;
|
|
28744
|
+
const RANKERS = ["network-simplex", "tight-tree", "longest-path"];
|
|
28745
|
+
const SPACINGS = [
|
|
28746
|
+
{ nodesep: 50, ranksep: 60 },
|
|
28747
|
+
{ nodesep: 34, ranksep: 46 },
|
|
28748
|
+
{ nodesep: 66, ranksep: 82 }
|
|
28749
|
+
];
|
|
28750
|
+
const configs = [];
|
|
28751
|
+
for (const ranker of RANKERS)
|
|
28752
|
+
for (const sp of SPACINGS) configs.push({ ranker, ...sp });
|
|
28753
|
+
for (let s = 0; s < seedCount; s++)
|
|
28754
|
+
configs.push({
|
|
28755
|
+
ranker: "network-simplex",
|
|
28756
|
+
nodesep: 50,
|
|
28757
|
+
ranksep: 60,
|
|
28758
|
+
seed: s
|
|
28759
|
+
});
|
|
28760
|
+
const badness = (lay, floor) => {
|
|
28761
|
+
const x = countSplineCrossings(lay);
|
|
28762
|
+
if (x > floor) return Infinity;
|
|
28763
|
+
return x + countEdgeOverlaps(lay) + countEdgeNodePierces(lay) + countGroupOverlaps(lay);
|
|
28764
|
+
};
|
|
28765
|
+
const objective = (lay, viol) => viol * 1e6 + edgeLength(lay) + lambda * meanDrift(lay, prev) * 10;
|
|
28766
|
+
const pool = [];
|
|
28767
|
+
for (const cfg of configs) {
|
|
28768
|
+
try {
|
|
28769
|
+
pool.push(place(cfg));
|
|
28770
|
+
} catch {
|
|
28771
|
+
}
|
|
28772
|
+
}
|
|
28773
|
+
if (!pool.length)
|
|
28774
|
+
return place({ ranker: "network-simplex", nodesep: 50, ranksep: 60 });
|
|
28775
|
+
let layered = [];
|
|
28776
|
+
try {
|
|
28777
|
+
layered = layeredCandidates(parsed, sizes);
|
|
28778
|
+
} catch {
|
|
28779
|
+
}
|
|
28780
|
+
pool.sort(
|
|
28781
|
+
(a, b) => objective(a, countCrossingsFast(a)) - objective(b, countCrossingsFast(b))
|
|
28782
|
+
);
|
|
28783
|
+
const refineK = Math.min(REFINE_K, pool.length);
|
|
28784
|
+
let best = pool[0];
|
|
28785
|
+
let bestObj = Infinity;
|
|
28786
|
+
let bestBad = Infinity;
|
|
28787
|
+
const consider = (lay) => {
|
|
28788
|
+
const bad = badness(lay, bestBad);
|
|
28789
|
+
if (bad === Infinity) return;
|
|
28790
|
+
const sc = objective(lay, bad);
|
|
28791
|
+
if (sc < bestObj) {
|
|
28792
|
+
bestObj = sc;
|
|
28793
|
+
bestBad = bad;
|
|
28794
|
+
best = lay;
|
|
28795
|
+
}
|
|
28796
|
+
};
|
|
28797
|
+
for (const lay of pool.slice(0, refineK)) consider(lay);
|
|
28798
|
+
if (bestBad >= ESCALATE_THRESHOLD && n <= ESCALATE_MAX_N) {
|
|
28799
|
+
const extra = [];
|
|
28800
|
+
for (let s = seedCount; s < seedCount + ESCALATE_SEEDS; s++) {
|
|
28801
|
+
try {
|
|
28802
|
+
extra.push(
|
|
28803
|
+
place({
|
|
28804
|
+
ranker: "network-simplex",
|
|
28805
|
+
nodesep: 50,
|
|
28806
|
+
ranksep: 60,
|
|
28807
|
+
seed: s
|
|
28808
|
+
})
|
|
28809
|
+
);
|
|
28810
|
+
} catch {
|
|
28811
|
+
}
|
|
28812
|
+
}
|
|
28813
|
+
extra.sort(
|
|
28814
|
+
(a, b) => objective(a, countCrossingsFast(a)) - objective(b, countCrossingsFast(b))
|
|
28815
|
+
);
|
|
28816
|
+
for (const lay of extra.slice(0, ESCALATE_REFINE)) consider(lay);
|
|
28817
|
+
}
|
|
28818
|
+
for (const lay of layered) {
|
|
28819
|
+
const variants = [lay];
|
|
28820
|
+
const dp = deroutePierces(lay);
|
|
28821
|
+
if (dp !== lay) variants.push(dp);
|
|
28822
|
+
for (const v of variants) {
|
|
28823
|
+
const bad = badness(v, bestBad - 1);
|
|
28824
|
+
if (bad < bestBad) {
|
|
28825
|
+
bestBad = bad;
|
|
28826
|
+
best = v;
|
|
28827
|
+
}
|
|
28828
|
+
}
|
|
28829
|
+
}
|
|
28830
|
+
if (bestBad > 0) {
|
|
28831
|
+
const rerouted = deroutePierces(best);
|
|
28832
|
+
if (rerouted !== best && badness(rerouted, bestBad - 1) < bestBad)
|
|
28833
|
+
best = rerouted;
|
|
28834
|
+
}
|
|
28835
|
+
if (bestBad > 0 && countGroupOverlaps(best) > 0) {
|
|
28836
|
+
const separated = separateGroupBands(best, parsed);
|
|
28837
|
+
if (separated !== best && badness(separated, bestBad - 1) < bestBad)
|
|
28838
|
+
best = separated;
|
|
28839
|
+
}
|
|
28840
|
+
return best;
|
|
28841
|
+
}
|
|
28842
|
+
var import_dagre4, import_d3_shape, DEFAULT_LAMBDA, ESCALATE_THRESHOLD, ESCALATE_MAX_N, ESCALATE_SEEDS, ESCALATE_REFINE, splineGen, GROUP_LABEL_ZONE2;
|
|
28843
|
+
var init_layout_search = __esm({
|
|
28844
|
+
"src/boxes-and-lines/layout-search.ts"() {
|
|
28845
|
+
"use strict";
|
|
28846
|
+
import_dagre4 = __toESM(require("@dagrejs/dagre"), 1);
|
|
28847
|
+
import_d3_shape = require("d3-shape");
|
|
28848
|
+
init_layout5();
|
|
28849
|
+
init_layout_layered();
|
|
28850
|
+
DEFAULT_LAMBDA = 4;
|
|
28851
|
+
ESCALATE_THRESHOLD = 4;
|
|
28852
|
+
ESCALATE_MAX_N = 45;
|
|
28853
|
+
ESCALATE_SEEDS = 18;
|
|
28854
|
+
ESCALATE_REFINE = 10;
|
|
28855
|
+
splineGen = (0, import_d3_shape.line)().x((d) => d.x).y((d) => d.y).curve(import_d3_shape.curveBasis);
|
|
28856
|
+
GROUP_LABEL_ZONE2 = 32;
|
|
28857
|
+
}
|
|
28858
|
+
});
|
|
28859
|
+
|
|
27530
28860
|
// src/boxes-and-lines/layout.ts
|
|
27531
28861
|
var layout_exports5 = {};
|
|
27532
28862
|
__export(layout_exports5, {
|
|
28863
|
+
NODE_HEIGHT: () => NODE_HEIGHT,
|
|
28864
|
+
NODE_WIDTH: () => NODE_WIDTH,
|
|
28865
|
+
computeNodeSize: () => computeNodeSize,
|
|
27533
28866
|
layoutBoxesAndLines: () => layoutBoxesAndLines
|
|
27534
28867
|
});
|
|
27535
28868
|
function splitCamelCase2(word) {
|
|
@@ -27602,417 +28935,21 @@ function computeNodeSize(node, reserveValueRow) {
|
|
|
27602
28935
|
const totalHeight = labelHeight + SEPARATOR_GAP5 + DESC_PADDING + descriptionHeight + DESC_PADDING + (reserveValueRow ? VALUE_ROW_H : 0);
|
|
27603
28936
|
return { width: w, height: Math.max(NODE_HEIGHT, totalHeight) };
|
|
27604
28937
|
}
|
|
27605
|
-
function getElk() {
|
|
27606
|
-
if (!elkInstance) elkInstance = new import_elk_bundled.default();
|
|
27607
|
-
return elkInstance;
|
|
27608
|
-
}
|
|
27609
|
-
function baseOptions() {
|
|
27610
|
-
return {
|
|
27611
|
-
"elk.algorithm": "layered",
|
|
27612
|
-
// INCLUDE_CHILDREN lets ELK route edges across container boundaries.
|
|
27613
|
-
"elk.hierarchyHandling": "INCLUDE_CHILDREN",
|
|
27614
|
-
"elk.edgeRouting": "ORTHOGONAL",
|
|
27615
|
-
"elk.layered.unnecessaryBendpoints": "true",
|
|
27616
|
-
// Let edges leave from top/bottom of nodes (not just the flow-direction
|
|
27617
|
-
// sides) when it reduces crossings.
|
|
27618
|
-
"elk.layered.allowNonFlowPortsToSwitchSides": "true"
|
|
27619
|
-
};
|
|
27620
|
-
}
|
|
27621
|
-
function bkBaseline() {
|
|
27622
|
-
return {
|
|
27623
|
-
...baseOptions(),
|
|
27624
|
-
"elk.layered.nodePlacement.strategy": "BRANDES_KOEPF",
|
|
27625
|
-
"elk.layered.nodePlacement.bk.fixedAlignment": "BALANCED",
|
|
27626
|
-
"elk.layered.nodePlacement.bk.edgeStraightening": "IMPROVE_STRAIGHTNESS",
|
|
27627
|
-
"elk.layered.compaction.connectedComponents": "true",
|
|
27628
|
-
"elk.layered.spacing.nodeNodeBetweenLayers": "90",
|
|
27629
|
-
"elk.spacing.nodeNode": "55",
|
|
27630
|
-
"elk.spacing.edgeNode": "55",
|
|
27631
|
-
"elk.spacing.edgeEdge": "18"
|
|
27632
|
-
};
|
|
27633
|
-
}
|
|
27634
|
-
function getVariants() {
|
|
27635
|
-
const bk = bkBaseline();
|
|
27636
|
-
return [
|
|
27637
|
-
{
|
|
27638
|
-
name: "bk-baseline",
|
|
27639
|
-
options: {
|
|
27640
|
-
...bk,
|
|
27641
|
-
"elk.layered.crossingMinimization.greedySwitch.type": "ONE_SIDED"
|
|
27642
|
-
}
|
|
27643
|
-
},
|
|
27644
|
-
{
|
|
27645
|
-
name: "bk-aggressive",
|
|
27646
|
-
options: {
|
|
27647
|
-
...bk,
|
|
27648
|
-
"elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
|
|
27649
|
-
"elk.layered.thoroughness": "50"
|
|
27650
|
-
}
|
|
27651
|
-
},
|
|
27652
|
-
{
|
|
27653
|
-
name: "bk-wide",
|
|
27654
|
-
options: {
|
|
27655
|
-
...bk,
|
|
27656
|
-
"elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
|
|
27657
|
-
"elk.layered.thoroughness": "50",
|
|
27658
|
-
"elk.spacing.nodeNode": "70",
|
|
27659
|
-
"elk.spacing.edgeNode": "75",
|
|
27660
|
-
"elk.spacing.edgeEdge": "22",
|
|
27661
|
-
"elk.layered.spacing.nodeNodeBetweenLayers": "120"
|
|
27662
|
-
}
|
|
27663
|
-
},
|
|
27664
|
-
{
|
|
27665
|
-
name: "longest-path",
|
|
27666
|
-
options: {
|
|
27667
|
-
...bk,
|
|
27668
|
-
"elk.layered.layering.strategy": "LONGEST_PATH",
|
|
27669
|
-
"elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
|
|
27670
|
-
"elk.layered.thoroughness": "50"
|
|
27671
|
-
}
|
|
27672
|
-
},
|
|
27673
|
-
{
|
|
27674
|
-
name: "bounded-width",
|
|
27675
|
-
options: {
|
|
27676
|
-
...bk,
|
|
27677
|
-
"elk.layered.layering.strategy": "COFFMAN_GRAHAM",
|
|
27678
|
-
"elk.layered.layering.coffmanGraham.layerBound": "3",
|
|
27679
|
-
"elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
|
|
27680
|
-
"elk.layered.thoroughness": "50"
|
|
27681
|
-
}
|
|
27682
|
-
}
|
|
27683
|
-
];
|
|
27684
|
-
}
|
|
27685
|
-
function countCrossings(edges) {
|
|
27686
|
-
let count = 0;
|
|
27687
|
-
for (let i = 0; i < edges.length; i++) {
|
|
27688
|
-
const edgeI = edges[i];
|
|
27689
|
-
const a = edgeI.points;
|
|
27690
|
-
if (a.length < 2) continue;
|
|
27691
|
-
for (let j = i + 1; j < edges.length; j++) {
|
|
27692
|
-
const edgeJ = edges[j];
|
|
27693
|
-
const b = edgeJ.points;
|
|
27694
|
-
if (b.length < 2) continue;
|
|
27695
|
-
if (edgeI.source === edgeJ.source) continue;
|
|
27696
|
-
if (edgeI.source === edgeJ.target) continue;
|
|
27697
|
-
if (edgeI.target === edgeJ.source) continue;
|
|
27698
|
-
if (edgeI.target === edgeJ.target) continue;
|
|
27699
|
-
for (let ai = 0; ai < a.length - 1; ai++) {
|
|
27700
|
-
for (let bi = 0; bi < b.length - 1; bi++) {
|
|
27701
|
-
if (segmentsCross(a[ai], a[ai + 1], b[bi], b[bi + 1])) count++;
|
|
27702
|
-
}
|
|
27703
|
-
}
|
|
27704
|
-
}
|
|
27705
|
-
}
|
|
27706
|
-
return count;
|
|
27707
|
-
}
|
|
27708
|
-
function segmentsCross(p1, p2, p3, p4) {
|
|
27709
|
-
const d1x = p2.x - p1.x;
|
|
27710
|
-
const d1y = p2.y - p1.y;
|
|
27711
|
-
const d2x = p4.x - p3.x;
|
|
27712
|
-
const d2y = p4.y - p3.y;
|
|
27713
|
-
const denom = d1x * d2y - d1y * d2x;
|
|
27714
|
-
if (Math.abs(denom) < 1e-9) return false;
|
|
27715
|
-
const t = ((p3.x - p1.x) * d2y - (p3.y - p1.y) * d2x) / denom;
|
|
27716
|
-
const s = ((p3.x - p1.x) * d1y - (p3.y - p1.y) * d1x) / denom;
|
|
27717
|
-
const EPS = 1e-3;
|
|
27718
|
-
return t > EPS && t < 1 - EPS && s > EPS && s < 1 - EPS;
|
|
27719
|
-
}
|
|
27720
|
-
function countTotalBends(edges) {
|
|
27721
|
-
let bends = 0;
|
|
27722
|
-
for (const e of edges) bends += Math.max(0, e.points.length - 2);
|
|
27723
|
-
return bends;
|
|
27724
|
-
}
|
|
27725
|
-
function scoreLayout(layout) {
|
|
27726
|
-
return {
|
|
27727
|
-
crossings: countCrossings(layout.edges),
|
|
27728
|
-
bends: countTotalBends(layout.edges),
|
|
27729
|
-
area: layout.width * layout.height
|
|
27730
|
-
};
|
|
27731
|
-
}
|
|
27732
|
-
function cmpScore(a, b) {
|
|
27733
|
-
const aBucket = a.crossings <= CROSSINGS_FORGIVENESS ? 0 : a.crossings;
|
|
27734
|
-
const bBucket = b.crossings <= CROSSINGS_FORGIVENESS ? 0 : b.crossings;
|
|
27735
|
-
if (aBucket !== bBucket) return aBucket - bBucket;
|
|
27736
|
-
if (a.area !== b.area) return a.area - b.area;
|
|
27737
|
-
return a.bends - b.bends;
|
|
27738
|
-
}
|
|
27739
28938
|
async function layoutBoxesAndLines(parsed, collapseInfo, layoutOptions) {
|
|
27740
|
-
const
|
|
27741
|
-
const
|
|
27742
|
-
|
|
27743
|
-
|
|
27744
|
-
|
|
27745
|
-
|
|
27746
|
-
|
|
27747
|
-
missingGroups.add(og.label);
|
|
27748
|
-
}
|
|
27749
|
-
}
|
|
27750
|
-
for (const label of missingGroups) {
|
|
27751
|
-
const og = collapseInfo.originalGroups.find((g) => g.label === label);
|
|
27752
|
-
const parentLabel = og?.parentGroup;
|
|
27753
|
-
if (!parentLabel || !missingGroups.has(parentLabel)) {
|
|
27754
|
-
collapsedGroupLabels.add(label);
|
|
27755
|
-
}
|
|
27756
|
-
}
|
|
27757
|
-
}
|
|
27758
|
-
const nodeSizes = /* @__PURE__ */ new Map();
|
|
27759
|
-
let maxDescHeight = 0;
|
|
27760
|
-
for (const node of parsed.nodes) {
|
|
27761
|
-
const size = hideDescriptions ? { width: NODE_WIDTH, height: NODE_HEIGHT } : computeNodeSize(node, parsed.showValues === true);
|
|
27762
|
-
nodeSizes.set(node.label, size);
|
|
27763
|
-
if (!hideDescriptions && node.description && node.description.length > 0) {
|
|
27764
|
-
maxDescHeight = Math.max(maxDescHeight, size.height);
|
|
27765
|
-
}
|
|
27766
|
-
}
|
|
27767
|
-
if (maxDescHeight > 0) {
|
|
27768
|
-
for (const node of parsed.nodes) {
|
|
27769
|
-
if (node.description && node.description.length > 0) {
|
|
27770
|
-
const size = nodeSizes.get(node.label);
|
|
27771
|
-
nodeSizes.set(node.label, { width: size.width, height: maxDescHeight });
|
|
27772
|
-
}
|
|
27773
|
-
}
|
|
27774
|
-
}
|
|
27775
|
-
const expandedGroupSet = new Set(parsed.groups.map((g) => g.label));
|
|
27776
|
-
const gid = (label) => `__group_${label}`;
|
|
27777
|
-
function buildGraph() {
|
|
27778
|
-
const nodeById = /* @__PURE__ */ new Map();
|
|
27779
|
-
const parentOf = /* @__PURE__ */ new Map();
|
|
27780
|
-
for (const node of parsed.nodes) {
|
|
27781
|
-
const size = nodeSizes.get(node.label);
|
|
27782
|
-
nodeById.set(node.label, {
|
|
27783
|
-
id: node.label,
|
|
27784
|
-
width: size.width,
|
|
27785
|
-
height: size.height,
|
|
27786
|
-
labels: [{ text: node.label }]
|
|
27787
|
-
});
|
|
27788
|
-
}
|
|
27789
|
-
for (const group of parsed.groups) {
|
|
27790
|
-
nodeById.set(gid(group.label), {
|
|
27791
|
-
id: gid(group.label),
|
|
27792
|
-
labels: [{ text: group.label }],
|
|
27793
|
-
layoutOptions: {
|
|
27794
|
-
"elk.padding": `[top=${CONTAINER_PAD_TOP2},left=${CONTAINER_PAD_X3},bottom=${CONTAINER_PAD_BOTTOM3},right=${CONTAINER_PAD_X3}]`,
|
|
27795
|
-
// Suggest square-ish containers — has limited effect with
|
|
27796
|
-
// INCLUDE_CHILDREN but doesn't hurt.
|
|
27797
|
-
"elk.aspectRatio": "1.4"
|
|
27798
|
-
},
|
|
27799
|
-
children: [],
|
|
27800
|
-
edges: []
|
|
27801
|
-
});
|
|
27802
|
-
}
|
|
27803
|
-
for (const label of collapsedGroupLabels) {
|
|
27804
|
-
nodeById.set(gid(label), {
|
|
27805
|
-
id: gid(label),
|
|
27806
|
-
width: NODE_WIDTH,
|
|
27807
|
-
height: NODE_HEIGHT,
|
|
27808
|
-
labels: [{ text: label }]
|
|
27809
|
-
});
|
|
27810
|
-
}
|
|
27811
|
-
for (const group of parsed.groups) {
|
|
27812
|
-
if (group.parentGroup && nodeById.has(gid(group.parentGroup))) {
|
|
27813
|
-
parentOf.set(gid(group.label), gid(group.parentGroup));
|
|
27814
|
-
}
|
|
27815
|
-
}
|
|
27816
|
-
if (collapseInfo) {
|
|
27817
|
-
for (const label of collapsedGroupLabels) {
|
|
27818
|
-
const og = collapseInfo.originalGroups.find((g) => g.label === label);
|
|
27819
|
-
if (og?.parentGroup && !collapsedGroupLabels.has(og.parentGroup) && nodeById.has(gid(og.parentGroup))) {
|
|
27820
|
-
parentOf.set(gid(label), gid(og.parentGroup));
|
|
27821
|
-
}
|
|
27822
|
-
}
|
|
27823
|
-
}
|
|
27824
|
-
for (const group of parsed.groups) {
|
|
27825
|
-
for (const child of group.children) {
|
|
27826
|
-
if (expandedGroupSet.has(child)) continue;
|
|
27827
|
-
if (nodeById.has(child)) {
|
|
27828
|
-
parentOf.set(child, gid(group.label));
|
|
27829
|
-
}
|
|
27830
|
-
}
|
|
27831
|
-
}
|
|
27832
|
-
const roots = [];
|
|
27833
|
-
for (const [id, node] of nodeById) {
|
|
27834
|
-
const parentId = parentOf.get(id);
|
|
27835
|
-
if (parentId) {
|
|
27836
|
-
const parent = nodeById.get(parentId);
|
|
27837
|
-
parent.children = parent.children ?? [];
|
|
27838
|
-
parent.children.push(node);
|
|
27839
|
-
} else {
|
|
27840
|
-
roots.push(node);
|
|
27841
|
-
}
|
|
27842
|
-
}
|
|
27843
|
-
const rootEdges = [];
|
|
27844
|
-
for (let i = 0; i < parsed.edges.length; i++) {
|
|
27845
|
-
const edge = parsed.edges[i];
|
|
27846
|
-
if (!nodeById.has(edge.source) || !nodeById.has(edge.target)) continue;
|
|
27847
|
-
rootEdges.push({
|
|
27848
|
-
id: `e${i}`,
|
|
27849
|
-
sources: [edge.source],
|
|
27850
|
-
targets: [edge.target]
|
|
27851
|
-
});
|
|
27852
|
-
}
|
|
27853
|
-
return { roots, rootEdges };
|
|
27854
|
-
}
|
|
27855
|
-
async function runVariant(variant) {
|
|
27856
|
-
const { roots, rootEdges } = buildGraph();
|
|
27857
|
-
const elkRoot = {
|
|
27858
|
-
id: "root",
|
|
27859
|
-
layoutOptions: {
|
|
27860
|
-
...variant.options,
|
|
27861
|
-
"elk.direction": direction,
|
|
27862
|
-
"elk.padding": `[top=${MARGIN3},left=${MARGIN3},bottom=${MARGIN3},right=${MARGIN3}]`
|
|
27863
|
-
},
|
|
27864
|
-
children: roots,
|
|
27865
|
-
edges: rootEdges
|
|
27866
|
-
};
|
|
27867
|
-
const result = await getElk().layout(elkRoot);
|
|
27868
|
-
return extractLayout(result);
|
|
27869
|
-
}
|
|
27870
|
-
function extractLayout(result) {
|
|
27871
|
-
const layoutNodes = [];
|
|
27872
|
-
const layoutGroups = [];
|
|
27873
|
-
const allEdges = [];
|
|
27874
|
-
const containerAbs = /* @__PURE__ */ new Map();
|
|
27875
|
-
function walk(n, offsetX, offsetY, isRoot) {
|
|
27876
|
-
const nx = (n.x ?? 0) + offsetX;
|
|
27877
|
-
const ny = (n.y ?? 0) + offsetY;
|
|
27878
|
-
const nw = n.width ?? 0;
|
|
27879
|
-
const nh = n.height ?? 0;
|
|
27880
|
-
if (isRoot) {
|
|
27881
|
-
containerAbs.set("root", { x: nx, y: ny });
|
|
27882
|
-
} else {
|
|
27883
|
-
const isGroup = n.id.startsWith("__group_");
|
|
27884
|
-
if (isGroup) {
|
|
27885
|
-
const label = n.id.slice("__group_".length);
|
|
27886
|
-
const collapsed = collapsedGroupLabels.has(label);
|
|
27887
|
-
const og = collapseInfo?.originalGroups.find(
|
|
27888
|
-
(g) => g.label === label
|
|
27889
|
-
);
|
|
27890
|
-
const pg = parsed.groups.find((g) => g.label === label);
|
|
27891
|
-
const childCount = collapsed ? collapseInfo?.collapsedChildCounts.get(label) ?? 0 : void 0;
|
|
27892
|
-
layoutGroups.push({
|
|
27893
|
-
label,
|
|
27894
|
-
lineNumber: pg?.lineNumber ?? og?.lineNumber ?? 0,
|
|
27895
|
-
x: nx + nw / 2,
|
|
27896
|
-
y: ny + nh / 2,
|
|
27897
|
-
width: nw,
|
|
27898
|
-
height: nh,
|
|
27899
|
-
collapsed,
|
|
27900
|
-
...childCount !== void 0 && { childCount }
|
|
27901
|
-
});
|
|
27902
|
-
if (!collapsed) containerAbs.set(n.id, { x: nx, y: ny });
|
|
27903
|
-
} else {
|
|
27904
|
-
layoutNodes.push({
|
|
27905
|
-
label: n.id,
|
|
27906
|
-
x: nx + nw / 2,
|
|
27907
|
-
y: ny + nh / 2,
|
|
27908
|
-
width: nw,
|
|
27909
|
-
height: nh
|
|
27910
|
-
});
|
|
27911
|
-
}
|
|
27912
|
-
}
|
|
27913
|
-
if (n.edges) for (const e of n.edges) allEdges.push(e);
|
|
27914
|
-
if (n.children) for (const c of n.children) walk(c, nx, ny, false);
|
|
27915
|
-
}
|
|
27916
|
-
walk(result, 0, 0, true);
|
|
27917
|
-
const edgeYOffsets = new Array(parsed.edges.length).fill(0);
|
|
27918
|
-
const edgeParallelCounts = new Array(parsed.edges.length).fill(1);
|
|
27919
|
-
const parallelGroups = /* @__PURE__ */ new Map();
|
|
27920
|
-
for (let i = 0; i < parsed.edges.length; i++) {
|
|
27921
|
-
const edge = parsed.edges[i];
|
|
27922
|
-
const [a, b] = edge.source < edge.target ? [edge.source, edge.target] : [edge.target, edge.source];
|
|
27923
|
-
const key = `${a}\0${b}`;
|
|
27924
|
-
if (!parallelGroups.has(key)) parallelGroups.set(key, []);
|
|
27925
|
-
parallelGroups.get(key).push(i);
|
|
27926
|
-
}
|
|
27927
|
-
for (const group of parallelGroups.values()) {
|
|
27928
|
-
const capped = group.slice(0, MAX_PARALLEL_EDGES);
|
|
27929
|
-
for (const idx of group.slice(MAX_PARALLEL_EDGES)) {
|
|
27930
|
-
edgeParallelCounts[idx] = 0;
|
|
27931
|
-
}
|
|
27932
|
-
if (capped.length < 2) continue;
|
|
27933
|
-
for (let j = 0; j < capped.length; j++) {
|
|
27934
|
-
const cappedJ = capped[j];
|
|
27935
|
-
edgeYOffsets[cappedJ] = (j - (capped.length - 1) / 2) * PARALLEL_SPACING;
|
|
27936
|
-
edgeParallelCounts[cappedJ] = capped.length;
|
|
27937
|
-
}
|
|
27938
|
-
}
|
|
27939
|
-
const edgeById = /* @__PURE__ */ new Map();
|
|
27940
|
-
for (const e of allEdges) edgeById.set(e.id, e);
|
|
27941
|
-
const layoutEdges = [];
|
|
27942
|
-
for (let i = 0; i < parsed.edges.length; i++) {
|
|
27943
|
-
const edge = parsed.edges[i];
|
|
27944
|
-
if (edgeParallelCounts[i] === 0) continue;
|
|
27945
|
-
const elkEdge = edgeById.get(`e${i}`);
|
|
27946
|
-
if (!elkEdge?.sections || elkEdge.sections.length === 0) continue;
|
|
27947
|
-
const container = elkEdge.container ?? "root";
|
|
27948
|
-
const off = containerAbs.get(container) ?? { x: 0, y: 0 };
|
|
27949
|
-
const s = elkEdge.sections[0];
|
|
27950
|
-
const points = [
|
|
27951
|
-
{ x: s.startPoint.x + off.x, y: s.startPoint.y + off.y },
|
|
27952
|
-
...(s.bendPoints ?? []).map((p) => ({
|
|
27953
|
-
x: p.x + off.x,
|
|
27954
|
-
y: p.y + off.y
|
|
27955
|
-
})),
|
|
27956
|
-
{ x: s.endPoint.x + off.x, y: s.endPoint.y + off.y }
|
|
27957
|
-
];
|
|
27958
|
-
let labelX;
|
|
27959
|
-
let labelY;
|
|
27960
|
-
if (edge.label && points.length >= 2) {
|
|
27961
|
-
const mid = Math.floor(points.length / 2);
|
|
27962
|
-
const midPoint = points[mid];
|
|
27963
|
-
labelX = midPoint.x;
|
|
27964
|
-
labelY = midPoint.y - 10;
|
|
27965
|
-
}
|
|
27966
|
-
layoutEdges.push({
|
|
27967
|
-
source: edge.source,
|
|
27968
|
-
target: edge.target,
|
|
27969
|
-
...edge.label !== void 0 && { label: edge.label },
|
|
27970
|
-
bidirectional: edge.bidirectional,
|
|
27971
|
-
lineNumber: edge.lineNumber,
|
|
27972
|
-
points,
|
|
27973
|
-
...labelX !== void 0 && { labelX },
|
|
27974
|
-
...labelY !== void 0 && { labelY },
|
|
27975
|
-
// In-bounds — i < parsed.edges.length, arrays sized to that length.
|
|
27976
|
-
yOffset: edgeYOffsets[i],
|
|
27977
|
-
parallelCount: edgeParallelCounts[i],
|
|
27978
|
-
metadata: edge.metadata,
|
|
27979
|
-
deferred: true
|
|
27980
|
-
});
|
|
27981
|
-
}
|
|
27982
|
-
let maxX = 0;
|
|
27983
|
-
let maxY = 0;
|
|
27984
|
-
for (const node of layoutNodes) {
|
|
27985
|
-
maxX = Math.max(maxX, node.x + node.width / 2);
|
|
27986
|
-
maxY = Math.max(maxY, node.y + node.height / 2);
|
|
27987
|
-
}
|
|
27988
|
-
for (const group of layoutGroups) {
|
|
27989
|
-
maxX = Math.max(maxX, group.x + group.width / 2);
|
|
27990
|
-
maxY = Math.max(maxY, group.y + group.height / 2);
|
|
28939
|
+
const { layoutBoxesAndLinesSearch: layoutBoxesAndLinesSearch2 } = await Promise.resolve().then(() => (init_layout_search(), layout_search_exports));
|
|
28940
|
+
const searched = layoutBoxesAndLinesSearch2(parsed, collapseInfo, {
|
|
28941
|
+
...layoutOptions?.hideDescriptions !== void 0 && {
|
|
28942
|
+
hideDescriptions: layoutOptions.hideDescriptions
|
|
28943
|
+
},
|
|
28944
|
+
...layoutOptions?.previousPositions !== void 0 && {
|
|
28945
|
+
previousPositions: layoutOptions.previousPositions
|
|
27991
28946
|
}
|
|
27992
|
-
|
|
27993
|
-
|
|
27994
|
-
|
|
27995
|
-
|
|
27996
|
-
|
|
27997
|
-
|
|
27998
|
-
};
|
|
27999
|
-
}
|
|
28000
|
-
const N = parsed.nodes.length + parsed.groups.length;
|
|
28001
|
-
const E = parsed.edges.length;
|
|
28002
|
-
const trivial = N < 8 && E < 10;
|
|
28003
|
-
const variants = trivial ? [getVariants()[1]] : getVariants();
|
|
28004
|
-
const results = await Promise.all(variants.map((v) => runVariant(v)));
|
|
28005
|
-
let best = results[0];
|
|
28006
|
-
let bestScore = scoreLayout(best);
|
|
28007
|
-
for (let i = 1; i < results.length; i++) {
|
|
28008
|
-
const resultI = results[i];
|
|
28009
|
-
const s = scoreLayout(resultI);
|
|
28010
|
-
if (cmpScore(s, bestScore) < 0) {
|
|
28011
|
-
best = resultI;
|
|
28012
|
-
bestScore = s;
|
|
28013
|
-
}
|
|
28014
|
-
}
|
|
28015
|
-
return attachNotes(best, parsed, layoutOptions?.collapsedNotes);
|
|
28947
|
+
});
|
|
28948
|
+
return attachNotes(
|
|
28949
|
+
applyParallelEdgeOffsets(searched),
|
|
28950
|
+
parsed,
|
|
28951
|
+
layoutOptions?.collapsedNotes
|
|
28952
|
+
);
|
|
28016
28953
|
}
|
|
28017
28954
|
function attachNotes(layout, parsed, collapsedNotes) {
|
|
28018
28955
|
const notesSuppressed = parsed.options?.["no-notes"] === "on";
|
|
@@ -28090,21 +29027,47 @@ function attachNotes(layout, parsed, collapsedNotes) {
|
|
|
28090
29027
|
nodes: finalNodes,
|
|
28091
29028
|
edges: finalEdges,
|
|
28092
29029
|
groups: finalGroups,
|
|
28093
|
-
width: bbMaxX + shiftX +
|
|
28094
|
-
height: bbMaxY + shiftY +
|
|
29030
|
+
width: bbMaxX + shiftX + MARGIN4,
|
|
29031
|
+
height: bbMaxY + shiftY + MARGIN4
|
|
29032
|
+
};
|
|
29033
|
+
}
|
|
29034
|
+
function applyParallelEdgeOffsets(layout) {
|
|
29035
|
+
const groups = /* @__PURE__ */ new Map();
|
|
29036
|
+
layout.edges.forEach((e, i) => {
|
|
29037
|
+
const [a, b] = e.source < e.target ? [e.source, e.target] : [e.target, e.source];
|
|
29038
|
+
const key = `${a}\0${b}`;
|
|
29039
|
+
const arr = groups.get(key);
|
|
29040
|
+
if (arr) arr.push(i);
|
|
29041
|
+
else groups.set(key, [i]);
|
|
29042
|
+
});
|
|
29043
|
+
if ([...groups.values()].every((g) => g.length < 2)) return layout;
|
|
29044
|
+
const yOffset = new Array(layout.edges.length).fill(0);
|
|
29045
|
+
const count = new Array(layout.edges.length).fill(1);
|
|
29046
|
+
for (const idxs of groups.values()) {
|
|
29047
|
+
const capped = idxs.slice(0, MAX_PARALLEL_EDGES);
|
|
29048
|
+
for (const drop of idxs.slice(MAX_PARALLEL_EDGES)) count[drop] = 0;
|
|
29049
|
+
if (capped.length < 2) continue;
|
|
29050
|
+
capped.forEach((idx, j) => {
|
|
29051
|
+
yOffset[idx] = (j - (capped.length - 1) / 2) * PARALLEL_SPACING;
|
|
29052
|
+
count[idx] = capped.length;
|
|
29053
|
+
});
|
|
29054
|
+
}
|
|
29055
|
+
return {
|
|
29056
|
+
...layout,
|
|
29057
|
+
edges: layout.edges.map((e, i) => ({
|
|
29058
|
+
...e,
|
|
29059
|
+
yOffset: yOffset[i],
|
|
29060
|
+
parallelCount: count[i]
|
|
29061
|
+
}))
|
|
28095
29062
|
};
|
|
28096
29063
|
}
|
|
28097
|
-
var
|
|
29064
|
+
var MARGIN4, MAX_PARALLEL_EDGES, PARALLEL_SPACING, PHI, NODE_HEIGHT, NODE_WIDTH, DESC_NODE_WIDTH, DESC_FONT_SIZE2, DESC_LINE_HEIGHT2, DESC_PADDING, SEPARATOR_GAP5, MAX_DESC_LINES2, MAX_LABEL_LINES, LABEL_LINE_HEIGHT, LABEL_PAD, VALUE_ROW_FONT, VALUE_ROW_H;
|
|
28098
29065
|
var init_layout5 = __esm({
|
|
28099
29066
|
"src/boxes-and-lines/layout.ts"() {
|
|
28100
29067
|
"use strict";
|
|
28101
|
-
import_elk_bundled = __toESM(require("elkjs/lib/elk.bundled.js"), 1);
|
|
28102
29068
|
init_text_measure();
|
|
28103
29069
|
init_notes();
|
|
28104
|
-
|
|
28105
|
-
CONTAINER_PAD_X3 = 30;
|
|
28106
|
-
CONTAINER_PAD_TOP2 = 40;
|
|
28107
|
-
CONTAINER_PAD_BOTTOM3 = 24;
|
|
29070
|
+
MARGIN4 = 40;
|
|
28108
29071
|
MAX_PARALLEL_EDGES = 5;
|
|
28109
29072
|
PARALLEL_SPACING = 22;
|
|
28110
29073
|
PHI = 1.618;
|
|
@@ -28121,8 +29084,6 @@ var init_layout5 = __esm({
|
|
|
28121
29084
|
LABEL_PAD = 12;
|
|
28122
29085
|
VALUE_ROW_FONT = 11;
|
|
28123
29086
|
VALUE_ROW_H = SEPARATOR_GAP5 + VALUE_ROW_FONT * DESC_LINE_HEIGHT2 + DESC_PADDING;
|
|
28124
|
-
elkInstance = null;
|
|
28125
|
-
CROSSINGS_FORGIVENESS = 1;
|
|
28126
29087
|
}
|
|
28127
29088
|
});
|
|
28128
29089
|
|
|
@@ -28277,7 +29238,7 @@ function layoutMindmap(parsed, _palette, options) {
|
|
|
28277
29238
|
leafWidth: ctx.structural(LEAF_WIDTH),
|
|
28278
29239
|
hGap: ctx.aesthetic(H_GAP2),
|
|
28279
29240
|
vGap: ctx.aesthetic(V_GAP2),
|
|
28280
|
-
margin: ctx.aesthetic(
|
|
29241
|
+
margin: ctx.aesthetic(MARGIN5),
|
|
28281
29242
|
multiRootGap: ctx.aesthetic(MULTI_ROOT_GAP)
|
|
28282
29243
|
};
|
|
28283
29244
|
populateDepthCache(roots);
|
|
@@ -28655,7 +29616,7 @@ function populateDepthCache(roots) {
|
|
|
28655
29616
|
};
|
|
28656
29617
|
walk(roots, 0);
|
|
28657
29618
|
}
|
|
28658
|
-
var ROOT_WIDTH, DEPTH1_WIDTH, LEAF_WIDTH, SINGLE_LABEL_HEIGHT, LABEL_LINE_HEIGHT2, DESC_LINE_HEIGHT3, NODE_V_PAD, H_GAP2, V_GAP2,
|
|
29619
|
+
var ROOT_WIDTH, DEPTH1_WIDTH, LEAF_WIDTH, SINGLE_LABEL_HEIGHT, LABEL_LINE_HEIGHT2, DESC_LINE_HEIGHT3, NODE_V_PAD, H_GAP2, V_GAP2, MARGIN5, MULTI_ROOT_GAP, nodeDepthCache;
|
|
28659
29620
|
var init_layout6 = __esm({
|
|
28660
29621
|
"src/mindmap/layout.ts"() {
|
|
28661
29622
|
"use strict";
|
|
@@ -28671,7 +29632,7 @@ var init_layout6 = __esm({
|
|
|
28671
29632
|
NODE_V_PAD = 10;
|
|
28672
29633
|
H_GAP2 = 40;
|
|
28673
29634
|
V_GAP2 = 12;
|
|
28674
|
-
|
|
29635
|
+
MARGIN5 = 40;
|
|
28675
29636
|
MULTI_ROOT_GAP = 60;
|
|
28676
29637
|
nodeDepthCache = /* @__PURE__ */ new Map();
|
|
28677
29638
|
}
|
|
@@ -30370,7 +31331,7 @@ function layoutC4Context(parsed, activeTagGroup) {
|
|
|
30370
31331
|
}
|
|
30371
31332
|
const contextRels = rollUpContextRelationships(parsed);
|
|
30372
31333
|
const spacing = computeAdaptiveSpacing(contextRels);
|
|
30373
|
-
const g = new
|
|
31334
|
+
const g = new import_dagre5.default.graphlib.Graph();
|
|
30374
31335
|
g.setGraph({
|
|
30375
31336
|
rankdir: "TB",
|
|
30376
31337
|
nodesep: spacing.nodesep,
|
|
@@ -30391,7 +31352,7 @@ function layoutC4Context(parsed, activeTagGroup) {
|
|
|
30391
31352
|
g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
|
|
30392
31353
|
}
|
|
30393
31354
|
}
|
|
30394
|
-
|
|
31355
|
+
import_dagre5.default.layout(g);
|
|
30395
31356
|
reduceCrossings(
|
|
30396
31357
|
g,
|
|
30397
31358
|
validRels.map((r) => ({ source: r.sourceName, target: r.targetName }))
|
|
@@ -30458,8 +31419,8 @@ function layoutC4Context(parsed, activeTagGroup) {
|
|
|
30458
31419
|
}
|
|
30459
31420
|
}
|
|
30460
31421
|
if (nodes.length > 0) {
|
|
30461
|
-
const shiftX =
|
|
30462
|
-
const shiftY =
|
|
31422
|
+
const shiftX = MARGIN6 - minX;
|
|
31423
|
+
const shiftY = MARGIN6 - minY;
|
|
30463
31424
|
for (const node of nodes) {
|
|
30464
31425
|
node.x += shiftX;
|
|
30465
31426
|
node.y += shiftY;
|
|
@@ -30471,12 +31432,12 @@ function layoutC4Context(parsed, activeTagGroup) {
|
|
|
30471
31432
|
}
|
|
30472
31433
|
}
|
|
30473
31434
|
}
|
|
30474
|
-
let totalWidth = nodes.length > 0 ? maxX - minX +
|
|
30475
|
-
let totalHeight = nodes.length > 0 ? maxY - minY +
|
|
31435
|
+
let totalWidth = nodes.length > 0 ? maxX - minX + MARGIN6 * 2 : 0;
|
|
31436
|
+
let totalHeight = nodes.length > 0 ? maxY - minY + MARGIN6 * 2 : 0;
|
|
30476
31437
|
const legendGroups = computeLegendGroups3(parsed.tagGroups);
|
|
30477
31438
|
if (legendGroups.length > 0) {
|
|
30478
|
-
const legendY = totalHeight +
|
|
30479
|
-
let legendX =
|
|
31439
|
+
const legendY = totalHeight + MARGIN6;
|
|
31440
|
+
let legendX = MARGIN6;
|
|
30480
31441
|
for (const lg of legendGroups) {
|
|
30481
31442
|
lg.x = legendX;
|
|
30482
31443
|
lg.y = legendY;
|
|
@@ -30569,7 +31530,7 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
|
|
|
30569
31530
|
}
|
|
30570
31531
|
}
|
|
30571
31532
|
const hasGroups = elementToGroup.size > 0;
|
|
30572
|
-
const g = hasGroups ? new
|
|
31533
|
+
const g = hasGroups ? new import_dagre5.default.graphlib.Graph({ compound: true }) : new import_dagre5.default.graphlib.Graph();
|
|
30573
31534
|
g.setDefaultEdgeLabel(() => ({}));
|
|
30574
31535
|
if (hasGroups) {
|
|
30575
31536
|
const seenGroups = /* @__PURE__ */ new Set();
|
|
@@ -30647,7 +31608,7 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
|
|
|
30647
31608
|
g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
|
|
30648
31609
|
}
|
|
30649
31610
|
}
|
|
30650
|
-
|
|
31611
|
+
import_dagre5.default.layout(g);
|
|
30651
31612
|
const nodeGroupMap = hasGroups ? new Map([...elementToGroup.entries()].map(([k, v]) => [k, v.name])) : void 0;
|
|
30652
31613
|
reduceCrossings(
|
|
30653
31614
|
g,
|
|
@@ -30808,8 +31769,8 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
|
|
|
30808
31769
|
if (pt.y > maxY) maxY = pt.y;
|
|
30809
31770
|
}
|
|
30810
31771
|
}
|
|
30811
|
-
const shiftX =
|
|
30812
|
-
const shiftY =
|
|
31772
|
+
const shiftX = MARGIN6 - minX;
|
|
31773
|
+
const shiftY = MARGIN6 - minY;
|
|
30813
31774
|
for (const node of nodes) {
|
|
30814
31775
|
node.x += shiftX;
|
|
30815
31776
|
node.y += shiftY;
|
|
@@ -30826,12 +31787,12 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
|
|
|
30826
31787
|
pt.y += shiftY;
|
|
30827
31788
|
}
|
|
30828
31789
|
}
|
|
30829
|
-
let totalWidth = maxX - minX +
|
|
30830
|
-
let totalHeight = maxY - minY +
|
|
31790
|
+
let totalWidth = maxX - minX + MARGIN6 * 2;
|
|
31791
|
+
let totalHeight = maxY - minY + MARGIN6 * 2;
|
|
30831
31792
|
const legendGroups = computeLegendGroups3(parsed.tagGroups);
|
|
30832
31793
|
if (legendGroups.length > 0) {
|
|
30833
|
-
const legendY = totalHeight +
|
|
30834
|
-
let legendX =
|
|
31794
|
+
const legendY = totalHeight + MARGIN6;
|
|
31795
|
+
let legendX = MARGIN6;
|
|
30835
31796
|
for (const lg of legendGroups) {
|
|
30836
31797
|
lg.x = legendX;
|
|
30837
31798
|
lg.y = legendY;
|
|
@@ -30976,7 +31937,7 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
|
|
|
30976
31937
|
}
|
|
30977
31938
|
}
|
|
30978
31939
|
const hasGroups = elementToGroup.size > 0;
|
|
30979
|
-
const g = hasGroups ? new
|
|
31940
|
+
const g = hasGroups ? new import_dagre5.default.graphlib.Graph({ compound: true }) : new import_dagre5.default.graphlib.Graph();
|
|
30980
31941
|
g.setDefaultEdgeLabel(() => ({}));
|
|
30981
31942
|
if (hasGroups) {
|
|
30982
31943
|
const seenGroups = /* @__PURE__ */ new Set();
|
|
@@ -31060,7 +32021,7 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
|
|
|
31060
32021
|
g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
|
|
31061
32022
|
}
|
|
31062
32023
|
}
|
|
31063
|
-
|
|
32024
|
+
import_dagre5.default.layout(g);
|
|
31064
32025
|
const nodeGroupMap = hasGroups ? new Map([...elementToGroup.entries()].map(([k, v]) => [k, v.name])) : void 0;
|
|
31065
32026
|
reduceCrossings(
|
|
31066
32027
|
g,
|
|
@@ -31223,8 +32184,8 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
|
|
|
31223
32184
|
if (pt.y > maxY) maxY = pt.y;
|
|
31224
32185
|
}
|
|
31225
32186
|
}
|
|
31226
|
-
const shiftX =
|
|
31227
|
-
const shiftY =
|
|
32187
|
+
const shiftX = MARGIN6 - minX;
|
|
32188
|
+
const shiftY = MARGIN6 - minY;
|
|
31228
32189
|
for (const node of nodes) {
|
|
31229
32190
|
node.x += shiftX;
|
|
31230
32191
|
node.y += shiftY;
|
|
@@ -31241,12 +32202,12 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
|
|
|
31241
32202
|
pt.y += shiftY;
|
|
31242
32203
|
}
|
|
31243
32204
|
}
|
|
31244
|
-
let totalWidth = maxX - minX +
|
|
31245
|
-
let totalHeight = maxY - minY +
|
|
32205
|
+
let totalWidth = maxX - minX + MARGIN6 * 2;
|
|
32206
|
+
let totalHeight = maxY - minY + MARGIN6 * 2;
|
|
31246
32207
|
const legendGroups = computeLegendGroups3(parsed.tagGroups);
|
|
31247
32208
|
if (legendGroups.length > 0) {
|
|
31248
|
-
const legendY = totalHeight +
|
|
31249
|
-
let legendX =
|
|
32209
|
+
const legendY = totalHeight + MARGIN6;
|
|
32210
|
+
let legendX = MARGIN6;
|
|
31250
32211
|
for (const lg of legendGroups) {
|
|
31251
32212
|
lg.x = legendX;
|
|
31252
32213
|
lg.y = legendY;
|
|
@@ -31352,7 +32313,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
|
|
|
31352
32313
|
for (const r of refEntries) {
|
|
31353
32314
|
nameToElement.set(r.element.name, r.element);
|
|
31354
32315
|
}
|
|
31355
|
-
const g = new
|
|
32316
|
+
const g = new import_dagre5.default.graphlib.Graph({ compound: true });
|
|
31356
32317
|
g.setDefaultEdgeLabel(() => ({}));
|
|
31357
32318
|
for (const [infraId] of infraIds) {
|
|
31358
32319
|
g.setNode(infraId, {});
|
|
@@ -31396,7 +32357,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
|
|
|
31396
32357
|
g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
|
|
31397
32358
|
}
|
|
31398
32359
|
}
|
|
31399
|
-
|
|
32360
|
+
import_dagre5.default.layout(g);
|
|
31400
32361
|
const nodeInfraMap = /* @__PURE__ */ new Map();
|
|
31401
32362
|
for (const r of refEntries) nodeInfraMap.set(r.element.name, r.infraId);
|
|
31402
32363
|
reduceCrossings(
|
|
@@ -31534,8 +32495,8 @@ function layoutC4Deployment(parsed, activeTagGroup) {
|
|
|
31534
32495
|
if (pt.y > maxY) maxY = pt.y;
|
|
31535
32496
|
}
|
|
31536
32497
|
}
|
|
31537
|
-
const shiftX =
|
|
31538
|
-
const shiftY =
|
|
32498
|
+
const shiftX = MARGIN6 - minX;
|
|
32499
|
+
const shiftY = MARGIN6 - minY;
|
|
31539
32500
|
for (const node of nodes) {
|
|
31540
32501
|
node.x += shiftX;
|
|
31541
32502
|
node.y += shiftY;
|
|
@@ -31550,12 +32511,12 @@ function layoutC4Deployment(parsed, activeTagGroup) {
|
|
|
31550
32511
|
pt.y += shiftY;
|
|
31551
32512
|
}
|
|
31552
32513
|
}
|
|
31553
|
-
let totalWidth = maxX - minX +
|
|
31554
|
-
let totalHeight = maxY - minY +
|
|
32514
|
+
let totalWidth = maxX - minX + MARGIN6 * 2;
|
|
32515
|
+
let totalHeight = maxY - minY + MARGIN6 * 2;
|
|
31555
32516
|
const legendGroups = computeLegendGroups3(parsed.tagGroups);
|
|
31556
32517
|
if (legendGroups.length > 0) {
|
|
31557
|
-
const legendY = totalHeight +
|
|
31558
|
-
let legendX =
|
|
32518
|
+
const legendY = totalHeight + MARGIN6;
|
|
32519
|
+
let legendX = MARGIN6;
|
|
31559
32520
|
for (const lg of legendGroups) {
|
|
31560
32521
|
lg.x = legendX;
|
|
31561
32522
|
lg.y = legendY;
|
|
@@ -31575,11 +32536,11 @@ function layoutC4Deployment(parsed, activeTagGroup) {
|
|
|
31575
32536
|
height: totalHeight
|
|
31576
32537
|
};
|
|
31577
32538
|
}
|
|
31578
|
-
var
|
|
32539
|
+
var import_dagre5, gNode, gEdge, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TYPE_LABEL_HEIGHT, DIVIDER_GAP, NAME_HEIGHT, NAME_FONT_SIZE, DESC_LINE_HEIGHT5, DESC_FONT_SIZE4, CARD_V_PAD3, CARD_H_PAD3, META_LINE_HEIGHT5, META_FONT_SIZE5, MARGIN6, BOUNDARY_PAD, GROUP_BOUNDARY_PAD, EDGE_NODE_COLLISION_WEIGHT, META_EXCLUDE_KEYS;
|
|
31579
32540
|
var init_layout8 = __esm({
|
|
31580
32541
|
"src/c4/layout.ts"() {
|
|
31581
32542
|
"use strict";
|
|
31582
|
-
|
|
32543
|
+
import_dagre5 = __toESM(require("@dagrejs/dagre"), 1);
|
|
31583
32544
|
init_legend_constants();
|
|
31584
32545
|
init_text_measure();
|
|
31585
32546
|
gNode = (g, name) => g.node(name);
|
|
@@ -31596,7 +32557,7 @@ var init_layout8 = __esm({
|
|
|
31596
32557
|
CARD_H_PAD3 = 20;
|
|
31597
32558
|
META_LINE_HEIGHT5 = 16;
|
|
31598
32559
|
META_FONT_SIZE5 = 11;
|
|
31599
|
-
|
|
32560
|
+
MARGIN6 = 40;
|
|
31600
32561
|
BOUNDARY_PAD = 40;
|
|
31601
32562
|
GROUP_BOUNDARY_PAD = 24;
|
|
31602
32563
|
EDGE_NODE_COLLISION_WEIGHT = 5e3;
|
|
@@ -32664,7 +33625,7 @@ function layoutGraph(graph, options) {
|
|
|
32664
33625
|
if (allNodes.length === 0) {
|
|
32665
33626
|
return { nodes: [], edges: [], groups: [], width: 0, height: 0 };
|
|
32666
33627
|
}
|
|
32667
|
-
const g = new
|
|
33628
|
+
const g = new import_dagre6.default.graphlib.Graph({ compound: true });
|
|
32668
33629
|
g.setGraph({
|
|
32669
33630
|
rankdir: graph.direction,
|
|
32670
33631
|
nodesep: 50,
|
|
@@ -32715,7 +33676,7 @@ function layoutGraph(graph, options) {
|
|
|
32715
33676
|
label: edge.label ?? ""
|
|
32716
33677
|
});
|
|
32717
33678
|
}
|
|
32718
|
-
|
|
33679
|
+
import_dagre6.default.layout(g);
|
|
32719
33680
|
const collapsedGroupIds = collapsedChildCounts ? new Set(collapsedChildCounts.keys()) : /* @__PURE__ */ new Set();
|
|
32720
33681
|
const basePositioned = allNodes.map((node) => {
|
|
32721
33682
|
const pos = g.node(node.id);
|
|
@@ -32911,11 +33872,11 @@ function layoutGraph(graph, options) {
|
|
|
32911
33872
|
height: totalHeight
|
|
32912
33873
|
};
|
|
32913
33874
|
}
|
|
32914
|
-
var
|
|
33875
|
+
var import_dagre6, GROUP_PADDING;
|
|
32915
33876
|
var init_layout9 = __esm({
|
|
32916
33877
|
"src/graph/layout.ts"() {
|
|
32917
33878
|
"use strict";
|
|
32918
|
-
|
|
33879
|
+
import_dagre6 = __toESM(require("@dagrejs/dagre"), 1);
|
|
32919
33880
|
init_notes2();
|
|
32920
33881
|
init_note_box();
|
|
32921
33882
|
init_notes();
|
|
@@ -34721,7 +35682,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
34721
35682
|
};
|
|
34722
35683
|
}
|
|
34723
35684
|
const isLR = computed.direction !== "TB";
|
|
34724
|
-
const g = new
|
|
35685
|
+
const g = new import_dagre7.default.graphlib.Graph();
|
|
34725
35686
|
g.setGraph({
|
|
34726
35687
|
rankdir: computed.direction === "TB" ? "TB" : "LR",
|
|
34727
35688
|
nodesep: isLR ? 70 : 60,
|
|
@@ -34772,7 +35733,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
34772
35733
|
g.setEdge(edge.sourceId, edge.targetId, { label: edge.label });
|
|
34773
35734
|
}
|
|
34774
35735
|
}
|
|
34775
|
-
|
|
35736
|
+
import_dagre7.default.layout(g);
|
|
34776
35737
|
const layoutNodes = computed.nodes.map(
|
|
34777
35738
|
(node) => {
|
|
34778
35739
|
const pos = g.node(node.id);
|
|
@@ -34944,11 +35905,11 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
34944
35905
|
height: totalHeight
|
|
34945
35906
|
};
|
|
34946
35907
|
}
|
|
34947
|
-
var
|
|
35908
|
+
var import_dagre7, MIN_NODE_WIDTH2, NODE_HEADER_HEIGHT, META_LINE_HEIGHT7, NODE_SEPARATOR_GAP, NODE_PAD_BOTTOM, ROLE_DOT_ROW, COLLAPSE_BAR_HEIGHT5, NODE_FONT_SIZE3, META_FONT_SIZE7, EDGE_LABEL_FONT_SIZE8, PADDING_X3, GROUP_PADDING2, GROUP_HEADER_HEIGHT, EDGE_MARGIN, DISPLAY_KEYS, DISPLAY_NAMES, GROUP_GAP;
|
|
34948
35909
|
var init_layout10 = __esm({
|
|
34949
35910
|
"src/infra/layout.ts"() {
|
|
34950
35911
|
"use strict";
|
|
34951
|
-
|
|
35912
|
+
import_dagre7 = __toESM(require("@dagrejs/dagre"), 1);
|
|
34952
35913
|
init_text_measure();
|
|
34953
35914
|
MIN_NODE_WIDTH2 = 140;
|
|
34954
35915
|
NODE_HEADER_HEIGHT = 28;
|
|
@@ -36515,17 +37476,17 @@ function mulberry32(seed) {
|
|
|
36515
37476
|
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
36516
37477
|
};
|
|
36517
37478
|
}
|
|
36518
|
-
function standardNormal(
|
|
37479
|
+
function standardNormal(rng3) {
|
|
36519
37480
|
let u = 0;
|
|
36520
37481
|
let v = 0;
|
|
36521
|
-
while (u === 0) u =
|
|
36522
|
-
while (v === 0) v =
|
|
37482
|
+
while (u === 0) u = rng3();
|
|
37483
|
+
while (v === 0) v = rng3();
|
|
36523
37484
|
return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v);
|
|
36524
37485
|
}
|
|
36525
|
-
function gamma(shape,
|
|
37486
|
+
function gamma(shape, rng3) {
|
|
36526
37487
|
if (shape < 1) {
|
|
36527
|
-
const u =
|
|
36528
|
-
return gamma(shape + 1,
|
|
37488
|
+
const u = rng3();
|
|
37489
|
+
return gamma(shape + 1, rng3) * Math.pow(u, 1 / shape);
|
|
36529
37490
|
}
|
|
36530
37491
|
const d = shape - 1 / 3;
|
|
36531
37492
|
const c = 1 / Math.sqrt(9 * d);
|
|
@@ -36533,29 +37494,29 @@ function gamma(shape, rng) {
|
|
|
36533
37494
|
let x;
|
|
36534
37495
|
let v;
|
|
36535
37496
|
do {
|
|
36536
|
-
x = standardNormal(
|
|
37497
|
+
x = standardNormal(rng3);
|
|
36537
37498
|
v = 1 + c * x;
|
|
36538
37499
|
} while (v <= 0);
|
|
36539
37500
|
v = v * v * v;
|
|
36540
|
-
const u =
|
|
37501
|
+
const u = rng3();
|
|
36541
37502
|
if (u < 1 - 0.0331 * x * x * x * x) return d * v;
|
|
36542
37503
|
if (Math.log(u) < x * x / 2 + d * (1 - v + Math.log(v))) return d * v;
|
|
36543
37504
|
}
|
|
36544
37505
|
}
|
|
36545
|
-
function sampleBeta(alpha, beta,
|
|
36546
|
-
const x = gamma(alpha,
|
|
36547
|
-
const y = gamma(beta,
|
|
37506
|
+
function sampleBeta(alpha, beta, rng3) {
|
|
37507
|
+
const x = gamma(alpha, rng3);
|
|
37508
|
+
const y = gamma(beta, rng3);
|
|
36548
37509
|
return x / (x + y);
|
|
36549
37510
|
}
|
|
36550
|
-
function sampleBetaPert(o, m, p,
|
|
37511
|
+
function sampleBetaPert(o, m, p, rng3) {
|
|
36551
37512
|
if (o === p) return m;
|
|
36552
37513
|
const range = p - o;
|
|
36553
37514
|
const alpha = 1 + 4 * (m - o) / range;
|
|
36554
37515
|
const beta = 1 + 4 * (p - m) / range;
|
|
36555
|
-
return o + sampleBeta(alpha, beta,
|
|
37516
|
+
return o + sampleBeta(alpha, beta, rng3) * range;
|
|
36556
37517
|
}
|
|
36557
37518
|
function simulate(resolved, expanded, _predecessors, _successors, topo, terminals, poisoned, opts) {
|
|
36558
|
-
const
|
|
37519
|
+
const rng3 = mulberry32(opts.seed);
|
|
36559
37520
|
const expById = /* @__PURE__ */ new Map();
|
|
36560
37521
|
for (const e of expanded) expById.set(e.id, e);
|
|
36561
37522
|
const completionTimes = new Array(opts.trials);
|
|
@@ -36578,7 +37539,7 @@ function simulate(resolved, expanded, _predecessors, _successors, topo, terminal
|
|
|
36578
37539
|
} else if (exp.o === exp.p) {
|
|
36579
37540
|
duration = exp.m;
|
|
36580
37541
|
} else {
|
|
36581
|
-
duration = sampleBetaPert(exp.o, exp.m, exp.p,
|
|
37542
|
+
duration = sampleBetaPert(exp.o, exp.m, exp.p, rng3);
|
|
36582
37543
|
}
|
|
36583
37544
|
let esLower = 0;
|
|
36584
37545
|
let efLower = -Infinity;
|
|
@@ -37684,7 +38645,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
|
|
|
37684
38645
|
}
|
|
37685
38646
|
}
|
|
37686
38647
|
const dagreId = (id) => memberToGroup.get(id) ?? id;
|
|
37687
|
-
const g = new
|
|
38648
|
+
const g = new import_dagre8.default.graphlib.Graph();
|
|
37688
38649
|
g.setGraph({
|
|
37689
38650
|
rankdir: resolved.options.direction,
|
|
37690
38651
|
nodesep: 50,
|
|
@@ -37723,7 +38684,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
|
|
|
37723
38684
|
seenEdges.add(k);
|
|
37724
38685
|
g.setEdge(src, tgt, {});
|
|
37725
38686
|
}
|
|
37726
|
-
|
|
38687
|
+
import_dagre8.default.layout(g);
|
|
37727
38688
|
const swimApplied = applySwimLanes(
|
|
37728
38689
|
g,
|
|
37729
38690
|
resolved,
|
|
@@ -38069,7 +39030,7 @@ function reduceCrossings2(g, direction) {
|
|
|
38069
39030
|
buckets.get(key).push(id);
|
|
38070
39031
|
}
|
|
38071
39032
|
const edges = g.edges().map((e) => ({ v: e.v, w: e.w }));
|
|
38072
|
-
const
|
|
39033
|
+
const countCrossings = () => {
|
|
38073
39034
|
let total = 0;
|
|
38074
39035
|
for (let i = 0; i < edges.length; i++) {
|
|
38075
39036
|
const a = edges[i];
|
|
@@ -38082,13 +39043,13 @@ function reduceCrossings2(g, direction) {
|
|
|
38082
39043
|
const b1 = g.node(b.v);
|
|
38083
39044
|
const b2 = g.node(b.w);
|
|
38084
39045
|
if (!b1 || !b2) continue;
|
|
38085
|
-
if (
|
|
39046
|
+
if (segmentsCross(a1, a2, b1, b2)) total++;
|
|
38086
39047
|
}
|
|
38087
39048
|
}
|
|
38088
39049
|
return total;
|
|
38089
39050
|
};
|
|
38090
39051
|
const MAX_ITER = 8;
|
|
38091
|
-
let baseline =
|
|
39052
|
+
let baseline = countCrossings();
|
|
38092
39053
|
if (baseline === 0) return;
|
|
38093
39054
|
for (let iter = 0; iter < MAX_ITER; iter++) {
|
|
38094
39055
|
let improved = false;
|
|
@@ -38106,7 +39067,7 @@ function reduceCrossings2(g, direction) {
|
|
|
38106
39067
|
const bv = bn[slotAxis];
|
|
38107
39068
|
an[slotAxis] = bv;
|
|
38108
39069
|
bn[slotAxis] = av;
|
|
38109
|
-
const after =
|
|
39070
|
+
const after = countCrossings();
|
|
38110
39071
|
if (after < baseline) {
|
|
38111
39072
|
baseline = after;
|
|
38112
39073
|
improved = true;
|
|
@@ -38127,7 +39088,7 @@ function reduceCrossings2(g, direction) {
|
|
|
38127
39088
|
data.points = smoothEdge(src, tgt, direction);
|
|
38128
39089
|
}
|
|
38129
39090
|
}
|
|
38130
|
-
function
|
|
39091
|
+
function segmentsCross(a1, a2, b1, b2) {
|
|
38131
39092
|
const ccw = (p, q, r) => (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x);
|
|
38132
39093
|
const d1 = ccw(b1, b2, a1);
|
|
38133
39094
|
const d2 = ccw(b1, b2, a2);
|
|
@@ -38135,11 +39096,11 @@ function segmentsCross2(a1, a2, b1, b2) {
|
|
|
38135
39096
|
const d4 = ccw(a1, a2, b2);
|
|
38136
39097
|
return (d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d32 > 0 && d4 < 0 || d32 < 0 && d4 > 0);
|
|
38137
39098
|
}
|
|
38138
|
-
var
|
|
39099
|
+
var import_dagre8, DEFAULT_NODE_HEIGHT, MILESTONE_NODE_HEIGHT, COLLAPSED_GROUP_HEIGHT, DIAGRAM_PADDING10, GROUP_PADDING3, GROUP_TOP_PADDING, SWIMLANE_SLOT_SEP, SWIMLANE_GAP, NODE_CELL_FONT_SIZE, NODE_NAME_FONT_SIZE, MILESTONE_NAME_FONT_SIZE, CELL_PAD_X, NAME_PAD_X, NAME_PIN_WIDTH, MIN_CELL_WIDTH, MIN_NODE_WIDTH3, MAX_NODE_WIDTH2, MIN_MILESTONE_WIDTH, MAX_MILESTONE_WIDTH;
|
|
38139
39100
|
var init_layout11 = __esm({
|
|
38140
39101
|
"src/pert/layout.ts"() {
|
|
38141
39102
|
"use strict";
|
|
38142
|
-
|
|
39103
|
+
import_dagre8 = __toESM(require("@dagrejs/dagre"), 1);
|
|
38143
39104
|
init_internal();
|
|
38144
39105
|
init_text_measure();
|
|
38145
39106
|
DEFAULT_NODE_HEIGHT = 90;
|
|
@@ -47669,10 +48630,10 @@ function tierBand(maxSpanDeg) {
|
|
|
47669
48630
|
}
|
|
47670
48631
|
function labelBudget(width, height, band) {
|
|
47671
48632
|
const bandCap = {
|
|
47672
|
-
world:
|
|
47673
|
-
continental:
|
|
47674
|
-
regional:
|
|
47675
|
-
local:
|
|
48633
|
+
world: 7,
|
|
48634
|
+
continental: 6,
|
|
48635
|
+
regional: 5,
|
|
48636
|
+
local: 4
|
|
47676
48637
|
};
|
|
47677
48638
|
const area2 = Math.floor(Math.sqrt(Math.max(0, width * height)) / 150);
|
|
47678
48639
|
return Math.max(0, Math.min(area2, bandCap[band]));
|
|
@@ -47805,8 +48766,11 @@ function placeContextLabels(args) {
|
|
|
47805
48766
|
color: waterColor,
|
|
47806
48767
|
fontSize: FONT,
|
|
47807
48768
|
// water names keep the base font (no footprint to scale on)
|
|
47808
|
-
//
|
|
47809
|
-
|
|
48769
|
+
// Orientation-value bands (lower = earlier): MAJOR water (oceans + major
|
|
48770
|
+
// seas, tier ≤ 1) leads at `tier*10+kind` (0..~16); MINOR water (tier ≥ 2:
|
|
48771
|
+
// smaller seas, bays, gulfs, straits) drops to band 2 (2000+) — BELOW the
|
|
48772
|
+
// country band (1000+), so a big country outranks a minor basin.
|
|
48773
|
+
sort: (tier <= 1 ? 0 : 2e3) + tier * 10 + KIND_ORDER[kind]
|
|
47810
48774
|
});
|
|
47811
48775
|
}
|
|
47812
48776
|
const ranked = countries.map((c) => {
|
|
@@ -47819,7 +48783,7 @@ function placeContextLabels(args) {
|
|
|
47819
48783
|
let ci = 0;
|
|
47820
48784
|
for (const r of ranked) {
|
|
47821
48785
|
const { c, w, h, area: area2 } = r;
|
|
47822
|
-
if (w > width * 0.66
|
|
48786
|
+
if (!c.curatedAnchor && w > width * 0.66 && h > height * 0.66) continue;
|
|
47823
48787
|
if (!insideViewport(c.anchor, width, height)) continue;
|
|
47824
48788
|
const sizeFrac = Math.sqrt(area2) / canvasLinear;
|
|
47825
48789
|
const t = Math.min(
|
|
@@ -47844,15 +48808,23 @@ function placeContextLabels(args) {
|
|
|
47844
48808
|
letterSpacing: 0,
|
|
47845
48809
|
color,
|
|
47846
48810
|
fontSize,
|
|
47847
|
-
//
|
|
47848
|
-
|
|
48811
|
+
// Band 1 (orientation-value ranking): above MINOR water (band 2, 2000+) but
|
|
48812
|
+
// below MAJOR water — oceans + major seas (band 0, ≤~16). So a big country
|
|
48813
|
+
// (US, Canada, Russia) outranks a minor sea/bay (Sargasso, Bahía de
|
|
48814
|
+
// Campeche) yet never displaces an ocean. Larger area = earlier within the
|
|
48815
|
+
// band (`ci` is the area-desc rank index).
|
|
48816
|
+
sort: 1e3 + ci++
|
|
47849
48817
|
});
|
|
47850
48818
|
}
|
|
47851
48819
|
candidates.sort((a, b) => a.sort - b.sort);
|
|
47852
48820
|
const placed = [];
|
|
47853
48821
|
const placedRects = [];
|
|
48822
|
+
const countryCount = candidates.reduce((n, c) => n + (c.italic ? 0 : 1), 0);
|
|
48823
|
+
const waterCap = budget - Math.min(2, countryCount);
|
|
48824
|
+
let waterPlaced = 0;
|
|
47854
48825
|
for (const cand of candidates) {
|
|
47855
48826
|
if (placed.length >= budget) break;
|
|
48827
|
+
if (cand.italic && waterPlaced >= waterCap) continue;
|
|
47856
48828
|
const rect = rectAround(
|
|
47857
48829
|
cand.cx,
|
|
47858
48830
|
cand.cy,
|
|
@@ -47879,6 +48851,7 @@ function placeContextLabels(args) {
|
|
|
47879
48851
|
if (collides(rect)) continue;
|
|
47880
48852
|
if (placedRects.some((r) => overlapsPadded(rect, r, CONTEXT_PAD))) continue;
|
|
47881
48853
|
placedRects.push(rect);
|
|
48854
|
+
if (cand.italic) waterPlaced++;
|
|
47882
48855
|
placed.push({
|
|
47883
48856
|
x: cand.cx,
|
|
47884
48857
|
y: cand.cy,
|
|
@@ -49841,16 +50814,16 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
49841
50814
|
countryCandidates.push({
|
|
49842
50815
|
name: f.properties?.name ?? iso,
|
|
49843
50816
|
bbox: [x0, y0, x1, y1],
|
|
49844
|
-
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
50817
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null,
|
|
50818
|
+
curatedAnchor: !!anchorLngLat
|
|
49845
50819
|
});
|
|
49846
50820
|
}
|
|
49847
50821
|
const framedStateContainers = (resolved.poiFrameContainers ?? []).some(
|
|
49848
50822
|
(id) => id.startsWith("US-")
|
|
49849
50823
|
);
|
|
49850
50824
|
if (usLayer && framedStateContainers) {
|
|
49851
|
-
const containerSet = new Set(resolved.poiFrameContainers);
|
|
49852
50825
|
for (const [iso, f] of usLayer) {
|
|
49853
|
-
if (
|
|
50826
|
+
if (regionById.has(iso)) continue;
|
|
49854
50827
|
const viewF = cullFeatureToView(f);
|
|
49855
50828
|
if (!viewF) continue;
|
|
49856
50829
|
const b = path.bounds(viewF);
|
|
@@ -49980,8 +50953,15 @@ var init_layout15 = __esm({
|
|
|
49980
50953
|
W_MAX = 8;
|
|
49981
50954
|
FONT2 = 11;
|
|
49982
50955
|
WORLD_LABEL_ANCHORS = {
|
|
49983
|
-
US: [-98.5, 39.5]
|
|
50956
|
+
US: [-98.5, 39.5],
|
|
49984
50957
|
// CONUS geographic centre (near Lebanon, Kansas)
|
|
50958
|
+
// Russia crosses the antimeridian (Chukotka at ~170°W), so on a non-global
|
|
50959
|
+
// (e.g. Europe) projection its geometry smears across the whole frame and the
|
|
50960
|
+
// area-weighted centroid lands mid-map (over Europe) — useless as a label
|
|
50961
|
+
// anchor. Pin it to European Russia (~Volga) so a Europe view labels visible
|
|
50962
|
+
// western Russia on its eastern margin; on a world view this still sits over
|
|
50963
|
+
// Russian land. (See the curated-anchor smear-gate bypass in context-labels.)
|
|
50964
|
+
RU: [45, 58]
|
|
49985
50965
|
};
|
|
49986
50966
|
MAX_CLUSTER_EXTENT_FACTOR = 0.18;
|
|
49987
50967
|
MAX_COLUMN_ROWS = 7;
|
|
@@ -60706,7 +61686,7 @@ pre.dgmo, code.language-dgmo, pre > code.language-dgmo,
|
|
|
60706
61686
|
|
|
60707
61687
|
// src/auto/index.ts
|
|
60708
61688
|
init_safe_href();
|
|
60709
|
-
var VERSION = "0.
|
|
61689
|
+
var VERSION = "0.28.0";
|
|
60710
61690
|
var DEFAULTS = {
|
|
60711
61691
|
theme: "auto",
|
|
60712
61692
|
palette: "slate",
|