@weasel-js/diagram 1.15.0 → 1.15.2
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/README.md +114 -5
- package/dist/{chunk-GR2DK4S2.js → chunk-6YQSQXQT.js} +1485 -266
- package/dist/chunk-6YQSQXQT.js.map +1 -0
- package/dist/{chunk-FDCODMFW.js → chunk-7BV2MBED.js} +906 -606
- package/dist/chunk-7BV2MBED.js.map +1 -0
- package/dist/{chunk-IYUU5KUY.js → chunk-FQVZWS24.js} +11 -101
- package/dist/chunk-FQVZWS24.js.map +1 -0
- package/dist/{chunk-AXL4JQBM.js → chunk-LPTNAYER.js} +3 -3
- package/dist/{chunk-AXL4JQBM.js.map → chunk-LPTNAYER.js.map} +1 -1
- package/dist/{chunk-DE7UILJA.js → chunk-QGL6QJE4.js} +183 -23
- package/dist/chunk-QGL6QJE4.js.map +1 -0
- package/dist/{dataTypes-BIkhAOc4.d.ts → dataTypes-1ch6cMtq.d.ts} +12 -3
- package/dist/effect-audio.d.ts +2 -2
- package/dist/effect-audio.js +7 -11
- package/dist/effect-audio.js.map +1 -1
- package/dist/effect.d.ts +5 -5
- package/dist/effect.js +13 -20
- package/dist/effect.js.map +1 -1
- package/dist/icons.table.js +44 -0
- package/dist/icons.table.js.map +1 -1
- package/dist/icons.table.json +44 -0
- package/dist/index.d.ts +932 -37
- package/dist/index.js +707 -34
- package/dist/index.js.map +1 -1
- package/dist/{labelTrait-BBjRgxbz.d.ts → labelTrait-moIciyXr.d.ts} +4 -0
- package/dist/layout.d.ts +3 -3
- package/dist/{layout.entry-CbmGuqE-.d.ts → layout.entry-zstuljAl.d.ts} +2 -2
- package/dist/layout.js +2 -2
- package/dist/{stageTypes-UiO25hcn.d.ts → stageTypes-B7oF8Lww.d.ts} +1 -1
- package/dist/{types-B0n2CNTW.d.ts → types-D5ybp8Xh.d.ts} +32 -1
- package/package.json +12 -11
- package/dist/chunk-DE7UILJA.js.map +0 -1
- package/dist/chunk-FDCODMFW.js.map +0 -1
- package/dist/chunk-GR2DK4S2.js.map +0 -1
- package/dist/chunk-IYUU5KUY.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { boundsOfPath, transformPath, ellipsePath,
|
|
1
|
+
import { boundsOfPath, transformPath, ellipsePath, pathFromD, polylineFromPoints, worldCoords, PATH_M as PATH_M$1, PATH_CMD_LENGTHS, measurePath, forEachSegment, PATH_L as PATH_L$1, nearestOnLine, PATH_Q as PATH_Q$1, nearestOnQuadratic, PATH_C as PATH_C$1, nearestOnCubic } from '@weasel-js/geom';
|
|
2
2
|
import { PathBuilder, rectPath, polygonFromPoints, AUTO_POSE_DESCRIPTOR, rotatePoint, PATH_M, PATH_L, PATH_C, flattenCubic, PATH_Q, PATH_Z, pointAlongPath } from '@weasel-js/core/math';
|
|
3
3
|
import { cssFamilyName } from '@weasel-js/font/metrics';
|
|
4
4
|
import { createSimulation } from '@weasel-js/simulation';
|
|
@@ -372,7 +372,34 @@ var doubleEllipse = {
|
|
|
372
372
|
},
|
|
373
373
|
boxForContent: (c) => ({ width: c.width * Math.SQRT2 + RING * 2, height: c.height * Math.SQRT2 + RING * 2 })
|
|
374
374
|
};
|
|
375
|
-
var
|
|
375
|
+
var HEAD = 0.24;
|
|
376
|
+
var NECK = 0.04;
|
|
377
|
+
var SHOULDER = 18;
|
|
378
|
+
var FOOT = 6;
|
|
379
|
+
function personParts({ y, width: w, height: h }) {
|
|
380
|
+
const d = Math.min(HEAD * h, 0.4 * w);
|
|
381
|
+
const top = y + d + NECK * h;
|
|
382
|
+
const body = y + h - top;
|
|
383
|
+
return { d, top, body, shoulder: Math.min(SHOULDER, w / 4, body / 2), foot: Math.min(FOOT, w / 6, body / 4) };
|
|
384
|
+
}
|
|
385
|
+
var person = {
|
|
386
|
+
path: (b) => {
|
|
387
|
+
const { x, y, width: w, height: h } = b;
|
|
388
|
+
const { d, top, shoulder: r, foot: f } = personParts(b);
|
|
389
|
+
const k = r * KAPPA;
|
|
390
|
+
const q = f * KAPPA;
|
|
391
|
+
const p = new PathBuilder().moveTo(x + r, top).lineTo(x + w - r, top).curveTo(x + w - r + k, top, x + w, top + r - k, x + w, top + r).lineTo(x + w, y + h - f).curveTo(x + w, y + h - f + q, x + w - f + q, y + h, x + w - f, y + h).lineTo(x + f, y + h).curveTo(x + f - q, y + h, x, y + h - f + q, x, y + h - f).lineTo(x, top + r).curveTo(x, top + r - k, x + r - k, top, x + r, top).close().moveTo(x + w / 2 + d / 2, y + d / 2);
|
|
392
|
+
arc(p, x + w / 2, y + d / 2, d / 2, 0, Math.PI * 2);
|
|
393
|
+
return p.close().build();
|
|
394
|
+
},
|
|
395
|
+
content: (b) => {
|
|
396
|
+
const { top, body, shoulder } = personParts(b);
|
|
397
|
+
const i = shoulder * BITE;
|
|
398
|
+
return { x: b.x + i, y: top + i, width: b.width - i * 2, height: body - i * 2 };
|
|
399
|
+
},
|
|
400
|
+
boxForContent: (c) => ({ width: c.width + SHOULDER * BITE * 2, height: (c.height + SHOULDER * BITE * 2) / (1 - HEAD - NECK) })
|
|
401
|
+
};
|
|
402
|
+
var FIGURE_OUTLINES = { roundRect, triangle, octagon, cloud, actor, doubleEllipse, person };
|
|
376
403
|
|
|
377
404
|
// src/outlines/bpmn.ts
|
|
378
405
|
var STRIP = 32;
|
|
@@ -474,6 +501,10 @@ var globe = device(
|
|
|
474
501
|
ring2(0.5, 0.6, 0.4),
|
|
475
502
|
"M0.1 0.6H0.9M0.1536 0.4H0.8464M0.1536 0.8H0.8464M0.5 0.2V1M0.5 0.2A0.17 0.4 0 0 0 0.5 1A0.17 0.4 0 0 0 0.5 0.2"
|
|
476
503
|
);
|
|
504
|
+
var disk = device(
|
|
505
|
+
"M0.1 0.42H0.9Q0.94 0.42 0.94 0.46V0.96Q0.94 1 0.9 1H0.1Q0.06 1 0.06 0.96V0.46Q0.06 0.42 0.1 0.42Z",
|
|
506
|
+
`${ring2(0.42, 0.71, 0.22)}${ring2(0.42, 0.71, 0.03)}${ring2(0.8, 0.53, 0.03)}M0.78 0.55L0.5 0.8`
|
|
507
|
+
);
|
|
477
508
|
var NETWORK_OUTLINES = {
|
|
478
509
|
server,
|
|
479
510
|
router,
|
|
@@ -484,7 +515,8 @@ var NETWORK_OUTLINES = {
|
|
|
484
515
|
phone,
|
|
485
516
|
printer,
|
|
486
517
|
user,
|
|
487
|
-
globe
|
|
518
|
+
globe,
|
|
519
|
+
disk
|
|
488
520
|
};
|
|
489
521
|
var ICON = { width: 14, height: 12, tab: { width: 6, height: 3 }, margin: 6 };
|
|
490
522
|
var ICON_SIDE = ICON.margin * 2 + ICON.width + ICON.tab.width / 2;
|
|
@@ -520,6 +552,88 @@ var doubleRect = {
|
|
|
520
552
|
boxForContent: (c) => ({ width: c.width + GAP * 2, height: c.height + GAP * 2 })
|
|
521
553
|
};
|
|
522
554
|
var MODELING_OUTLINES = { component, doubleRect };
|
|
555
|
+
function square({ x, y, width: w, height: h }) {
|
|
556
|
+
const side = Math.min(w, h);
|
|
557
|
+
return { x: x + (w - side) / 2, y: y + (h - side) / 2, width: side, height: side };
|
|
558
|
+
}
|
|
559
|
+
function scaled(b, k) {
|
|
560
|
+
const w = b.width * k;
|
|
561
|
+
const h = b.height * k;
|
|
562
|
+
return { x: b.x + (b.width - w) / 2, y: b.y + (b.height - h) / 2, width: w, height: h };
|
|
563
|
+
}
|
|
564
|
+
var BULLSEYE = 0.55;
|
|
565
|
+
var BAR = 6;
|
|
566
|
+
var circle = (b) => ellipsePath(square(b));
|
|
567
|
+
var start = {
|
|
568
|
+
path: circle,
|
|
569
|
+
solid: circle
|
|
570
|
+
};
|
|
571
|
+
var end = {
|
|
572
|
+
path: circle,
|
|
573
|
+
solid: (b) => ellipsePath(scaled(square(b), BULLSEYE))
|
|
574
|
+
};
|
|
575
|
+
function barOf({ x, y, width: w, height: h }) {
|
|
576
|
+
if (w >= h) {
|
|
577
|
+
const t2 = Math.min(BAR, h);
|
|
578
|
+
return { x, y: y + (h - t2) / 2, width: w, height: t2 };
|
|
579
|
+
}
|
|
580
|
+
const t = Math.min(BAR, w);
|
|
581
|
+
return { x: x + (w - t) / 2, y, width: t, height: h };
|
|
582
|
+
}
|
|
583
|
+
var bar = {
|
|
584
|
+
path: (b) => {
|
|
585
|
+
const r = barOf(b);
|
|
586
|
+
return rectPath(r.x, r.y, r.width, r.height);
|
|
587
|
+
},
|
|
588
|
+
solid: (b) => {
|
|
589
|
+
const r = barOf(b);
|
|
590
|
+
return rectPath(r.x, r.y, r.width, r.height);
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
var STATE_OUTLINES = { start, end, bar };
|
|
594
|
+
var SHARE2 = 0.75;
|
|
595
|
+
var ring3 = (cx, cy, rx, ry) => `M${cx + rx} ${cy}A${rx} ${ry} 0 1 1 ${cx - rx} ${cy}A${rx} ${ry} 0 1 1 ${cx + rx} ${cy}Z`;
|
|
596
|
+
var boundary = figureOver(outlineFromD(`${ring3(0.7, 0.5, 0.4 / 1.5, 0.4)}M0.04 0.1V0.9M0.04 0.5H${0.7 - 0.4 / 1.5}`), 1.5, SHARE2);
|
|
597
|
+
var control = figureOver(outlineFromD(ring3(0.5, 0.55, 0.42, 0.42), { detail: "M0.6 0.02L0.46 0.13L0.6 0.24" }), 1, SHARE2);
|
|
598
|
+
var entity = figureOver(outlineFromD(`${ring3(0.5, 0.45, 0.42, 0.42)}M0.08 0.97H0.92`), 1, SHARE2);
|
|
599
|
+
var offsetOf = (w, h) => Math.min(6, w / 8, h / 8);
|
|
600
|
+
var collections = {
|
|
601
|
+
path: ({ x, y, width: w, height: h }) => {
|
|
602
|
+
const o = offsetOf(w, h);
|
|
603
|
+
return new PathBuilder().moveTo(x + o, y).lineTo(x + w, y).lineTo(x + w, y + h - o).lineTo(x + w - o, y + h - o).lineTo(x + w - o, y + h).lineTo(x, y + h).lineTo(x, y + o).lineTo(x + o, y + o).close().build();
|
|
604
|
+
},
|
|
605
|
+
detail: ({ x, y, width: w, height: h }) => {
|
|
606
|
+
const o = offsetOf(w, h);
|
|
607
|
+
return new PathBuilder().moveTo(x + o, y + o).lineTo(x + w - o, y + o).lineTo(x + w - o, y + h - o).build();
|
|
608
|
+
},
|
|
609
|
+
content: ({ x, y, width: w, height: h }) => {
|
|
610
|
+
const o = offsetOf(w, h);
|
|
611
|
+
return { x, y: y + o, width: w - o, height: h - o };
|
|
612
|
+
},
|
|
613
|
+
boxForContent: (c) => ({ width: c.width + 6, height: c.height + 6 })
|
|
614
|
+
};
|
|
615
|
+
var capOf2 = (w, h) => Math.min(w * 0.12, h * 0.3);
|
|
616
|
+
var queue = {
|
|
617
|
+
path: ({ x, y, width: w, height: h }) => {
|
|
618
|
+
const r = capOf2(w, h);
|
|
619
|
+
const cy = y + h / 2;
|
|
620
|
+
const ry = h / 2;
|
|
621
|
+
return new PathBuilder().moveTo(x + r, y).lineTo(x + w - r, y).curveTo(x + w - r + r * KAPPA, y, x + w, cy - ry * KAPPA, x + w, cy).curveTo(x + w, cy + ry * KAPPA, x + w - r + r * KAPPA, y + h, x + w - r, y + h).lineTo(x + r, y + h).curveTo(x + r - r * KAPPA, y + h, x, cy + ry * KAPPA, x, cy).curveTo(x, cy - ry * KAPPA, x + r - r * KAPPA, y, x + r, y).close().build();
|
|
622
|
+
},
|
|
623
|
+
detail: ({ x, y, width: w, height: h }) => {
|
|
624
|
+
const r = capOf2(w, h);
|
|
625
|
+
const cy = y + h / 2;
|
|
626
|
+
const ry = h / 2;
|
|
627
|
+
const rim = x + w - r;
|
|
628
|
+
return new PathBuilder().moveTo(rim, y).curveTo(rim - r * KAPPA, y, rim - r, cy - ry * KAPPA, rim - r, cy).curveTo(rim - r, cy + ry * KAPPA, rim - r * KAPPA, y + h, rim, y + h).build();
|
|
629
|
+
},
|
|
630
|
+
content: ({ x, y, width: w, height: h }) => {
|
|
631
|
+
const r = capOf2(w, h);
|
|
632
|
+
return { x: x + r, y, width: Math.max(w - r * 3, 0), height: h };
|
|
633
|
+
},
|
|
634
|
+
boxForContent: (c) => ({ width: c.width / 0.64, height: c.height })
|
|
635
|
+
};
|
|
636
|
+
var PARTICIPANT_OUTLINES = { boundary, control, entity, collections, queue };
|
|
523
637
|
|
|
524
638
|
// src/outlines/table.ts
|
|
525
639
|
var BUILTINS = {
|
|
@@ -528,7 +642,9 @@ var BUILTINS = {
|
|
|
528
642
|
...STORAGE_OUTLINES,
|
|
529
643
|
...NETWORK_OUTLINES,
|
|
530
644
|
...BPMN_OUTLINES,
|
|
531
|
-
...MODELING_OUTLINES
|
|
645
|
+
...MODELING_OUTLINES,
|
|
646
|
+
...STATE_OUTLINES,
|
|
647
|
+
...PARTICIPANT_OUTLINES
|
|
532
648
|
};
|
|
533
649
|
var table = new Map(
|
|
534
650
|
Object.entries(BUILTINS).map(([name, def]) => [name, [def]])
|
|
@@ -563,6 +679,10 @@ function outlineDetail(outline, bounds) {
|
|
|
563
679
|
if (typeof outline !== "string" || bounds.width <= 0 || bounds.height <= 0) return null;
|
|
564
680
|
return resolveOutline(outline).detail?.(bounds) ?? null;
|
|
565
681
|
}
|
|
682
|
+
function outlineSolid(outline, bounds) {
|
|
683
|
+
if (typeof outline !== "string" || bounds.width <= 0 || bounds.height <= 0) return null;
|
|
684
|
+
return resolveOutline(outline).solid?.(bounds) ?? null;
|
|
685
|
+
}
|
|
566
686
|
function contentBox(outline, bounds) {
|
|
567
687
|
if (typeof outline !== "string") return bounds;
|
|
568
688
|
return resolveOutline(outline).content?.(bounds) ?? bounds;
|
|
@@ -681,6 +801,7 @@ var dataKeyReader = (node) => {
|
|
|
681
801
|
if (trait === null || typeof trait !== "object") return null;
|
|
682
802
|
if ("from" in trait && "to" in trait) return null;
|
|
683
803
|
if ("label" in trait || "anchor" in trait || "mark" in trait) return null;
|
|
804
|
+
if ("seq" in trait || "sequence" in trait) return null;
|
|
684
805
|
if (trait.container?.role === "lane") return null;
|
|
685
806
|
return trait;
|
|
686
807
|
};
|
|
@@ -753,7 +874,7 @@ function placerOf(node, pose, opts) {
|
|
|
753
874
|
const cx = bounds.x + bounds.width / 2;
|
|
754
875
|
const cy = bounds.y + bounds.height / 2;
|
|
755
876
|
const poly = trait.outline === void 0 || bounds.width <= 0 || bounds.height <= 0 ? null : outlinePolyline(trait.outline, bounds);
|
|
756
|
-
const
|
|
877
|
+
const place2 = (spec, at2, given) => {
|
|
757
878
|
const anchored = {
|
|
758
879
|
x: bounds.x + at2.u * bounds.width,
|
|
759
880
|
y: bounds.y + at2.v * bounds.height
|
|
@@ -772,7 +893,7 @@ function placerOf(node, pose, opts) {
|
|
|
772
893
|
...extrasOf(spec)
|
|
773
894
|
};
|
|
774
895
|
};
|
|
775
|
-
return { specs: trait.ports ?? DEFAULT_PORTS, place };
|
|
896
|
+
return { specs: trait.ports ?? DEFAULT_PORTS, place: place2 };
|
|
776
897
|
}
|
|
777
898
|
function extrasOf(spec) {
|
|
778
899
|
return {
|
|
@@ -1271,10 +1392,10 @@ function packClusters(graph, rows, preferred2, axes, nodeGap) {
|
|
|
1271
1392
|
}
|
|
1272
1393
|
return items.map((item, i) => ({ item, i })).sort((a, b) => a.item.center - b.item.center || a.i - b.i).map(({ item }) => item);
|
|
1273
1394
|
});
|
|
1274
|
-
const settle2 = (byRow,
|
|
1395
|
+
const settle2 = (byRow, start3, nodeFloor, origin) => {
|
|
1275
1396
|
const nodeAt = /* @__PURE__ */ new Map();
|
|
1276
1397
|
let ends2 = [];
|
|
1277
|
-
for (let pass = 0; pass <=
|
|
1398
|
+
for (let pass = 0; pass <= start3.size; pass++) {
|
|
1278
1399
|
let raised = false;
|
|
1279
1400
|
ends2 = byRow.map((items) => {
|
|
1280
1401
|
let cursor = origin;
|
|
@@ -1285,10 +1406,10 @@ function packClusters(graph, rows, preferred2, axes, nodeGap) {
|
|
|
1285
1406
|
cursor = x2 + width(item.node) + nodeGap;
|
|
1286
1407
|
continue;
|
|
1287
1408
|
}
|
|
1288
|
-
const s =
|
|
1409
|
+
const s = start3.get(item.span);
|
|
1289
1410
|
const x = Math.max(s, cursor);
|
|
1290
1411
|
if (x > s) {
|
|
1291
|
-
|
|
1412
|
+
start3.set(item.span, x);
|
|
1292
1413
|
raised = true;
|
|
1293
1414
|
}
|
|
1294
1415
|
cursor = x + outer(item.span) + nodeGap;
|
|
@@ -1324,15 +1445,15 @@ function packClusters(graph, rows, preferred2, axes, nodeGap) {
|
|
|
1324
1445
|
return blockOf(span).width + inset2.crossLo + inset2.crossHi;
|
|
1325
1446
|
}
|
|
1326
1447
|
const roots = spans.filter((s) => s.parent === void 0);
|
|
1327
|
-
const
|
|
1328
|
-
const { nodeAt: at2 } = settle2(itemsByRow(void 0, roots),
|
|
1329
|
-
const
|
|
1448
|
+
const start2 = new Map(roots.map((s) => [s, centerOf.get(s) - outer(s) / 2]));
|
|
1449
|
+
const { nodeAt: at2 } = settle2(itemsByRow(void 0, roots), start2, pref, -Infinity);
|
|
1450
|
+
const place2 = (span, from) => {
|
|
1330
1451
|
const origin = from + insets.get(span).crossLo;
|
|
1331
1452
|
const block = blockOf(span);
|
|
1332
1453
|
for (const [id, local] of block.nodeAt) at2.set(id, origin + local);
|
|
1333
|
-
for (const [child, local] of block.childAt)
|
|
1454
|
+
for (const [child, local] of block.childAt) place2(child, origin + local);
|
|
1334
1455
|
};
|
|
1335
|
-
for (const root of roots)
|
|
1456
|
+
for (const root of roots) place2(root, start2.get(root));
|
|
1336
1457
|
return at2;
|
|
1337
1458
|
}
|
|
1338
1459
|
function centersOf(spans, rows, center2) {
|
|
@@ -1426,24 +1547,24 @@ function subpathOf(path, index) {
|
|
|
1426
1547
|
if (path.kind !== "polygon") return index === 0 ? path : null;
|
|
1427
1548
|
const { commands, coords } = path;
|
|
1428
1549
|
let seen = -1;
|
|
1429
|
-
let
|
|
1550
|
+
let start2 = -1;
|
|
1430
1551
|
let startCoord = 0;
|
|
1431
1552
|
let coord2 = 0;
|
|
1432
1553
|
for (let i = 0; i <= commands.length; i++) {
|
|
1433
1554
|
const cmd = commands[i];
|
|
1434
1555
|
if (i === commands.length || cmd === PATH_M$1) {
|
|
1435
1556
|
if (seen === index) {
|
|
1436
|
-
if (
|
|
1557
|
+
if (start2 === 0 && i === commands.length) return path;
|
|
1437
1558
|
return {
|
|
1438
1559
|
kind: "polygon",
|
|
1439
1560
|
fillRule: path.fillRule,
|
|
1440
|
-
commands: commands.slice(
|
|
1561
|
+
commands: commands.slice(start2, i),
|
|
1441
1562
|
coords: coords.slice(startCoord, coord2),
|
|
1442
1563
|
...path.origin ? { origin: path.origin } : {}
|
|
1443
1564
|
};
|
|
1444
1565
|
}
|
|
1445
1566
|
seen++;
|
|
1446
|
-
|
|
1567
|
+
start2 = i;
|
|
1447
1568
|
startCoord = coord2;
|
|
1448
1569
|
}
|
|
1449
1570
|
if (cmd !== void 0) coord2 += PATH_CMD_LENGTHS[cmd] ?? 0;
|
|
@@ -1503,7 +1624,12 @@ function labelCenter(whole, label, size) {
|
|
|
1503
1624
|
const at2 = label.placed ?? label;
|
|
1504
1625
|
const station = typeof at2.at === "object" ? nearestStation(path, at2.at.near) ?? pointAlongPath(path, 0.5) : pointAlongPath(path, typeof at2.at === "number" ? at2.at : NAMED[at2.at] ?? 0.5);
|
|
1505
1626
|
if (station === null) return null;
|
|
1506
|
-
|
|
1627
|
+
const beside = besideStation(station.point, station.tangent, at2.offset ?? 0, size);
|
|
1628
|
+
const end2 = label.placed !== void 0 || label.inset === void 0 ? 0 : label.at === "start" ? 1 : label.at === "end" ? -1 : 0;
|
|
1629
|
+
if (end2 === 0) return beside;
|
|
1630
|
+
const { x: tx, y: ty } = station.tangent;
|
|
1631
|
+
const reach = end2 * (label.inset + (Math.abs(tx) * size.width + Math.abs(ty) * size.height) / 2);
|
|
1632
|
+
return { x: beside.x + tx * reach, y: beside.y + ty * reach };
|
|
1507
1633
|
}
|
|
1508
1634
|
function halfDepth(tangent, size) {
|
|
1509
1635
|
return (Math.abs(tangent.y) * size.width + Math.abs(tangent.x) * size.height) / 2;
|
|
@@ -1546,8 +1672,8 @@ function labelSpotAt(whole, center2, size) {
|
|
|
1546
1672
|
}
|
|
1547
1673
|
|
|
1548
1674
|
// src/edgeTrait.ts
|
|
1549
|
-
function layoutOwnsPort(
|
|
1550
|
-
return
|
|
1675
|
+
function layoutOwnsPort(end2) {
|
|
1676
|
+
return end2.port === void 0 || end2.port === end2.laidOut;
|
|
1551
1677
|
}
|
|
1552
1678
|
function layoutOwnsRoute(edge) {
|
|
1553
1679
|
const points = edge.waypoints ?? [];
|
|
@@ -1567,8 +1693,6 @@ function diagramEdgeOf(node) {
|
|
|
1567
1693
|
if (edge === null || typeof edge !== "object") return null;
|
|
1568
1694
|
return "from" in edge && "to" in edge ? edge : null;
|
|
1569
1695
|
}
|
|
1570
|
-
|
|
1571
|
-
// src/avoid/holds.ts
|
|
1572
1696
|
var EPS2 = 1e-6;
|
|
1573
1697
|
function runsAlong(d, normal, sign) {
|
|
1574
1698
|
const len = Math.hypot(d.x, d.y) * Math.hypot(normal.x, normal.y);
|
|
@@ -1577,11 +1701,8 @@ function runsAlong(d, normal, sign) {
|
|
|
1577
1701
|
return Math.abs(cross) <= EPS2 * len && sign * (d.x * normal.x + d.y * normal.y) > 0;
|
|
1578
1702
|
}
|
|
1579
1703
|
function onSegment(p, a, b) {
|
|
1580
|
-
const
|
|
1581
|
-
|
|
1582
|
-
const len2 = dx * dx + dy * dy;
|
|
1583
|
-
const t = len2 === 0 ? 0 : Math.max(0, Math.min(1, ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2));
|
|
1584
|
-
return Math.hypot(a.x + t * dx - p.x, a.y + t * dy - p.y) <= EPS2 * Math.max(1, Math.sqrt(len2)) ? t : null;
|
|
1704
|
+
const { t, dist } = nearestOnLine(p.x, p.y, a.x, a.y, b.x, b.y);
|
|
1705
|
+
return dist <= EPS2 * Math.max(1, Math.hypot(b.x - a.x, b.y - a.y)) ? t : null;
|
|
1585
1706
|
}
|
|
1586
1707
|
function routeHolds(from, to, waypoints, route) {
|
|
1587
1708
|
const points = [from.point, ...route, to.point];
|
|
@@ -1605,442 +1726,180 @@ function routeHolds(from, to, waypoints, route) {
|
|
|
1605
1726
|
return true;
|
|
1606
1727
|
}
|
|
1607
1728
|
|
|
1608
|
-
// src/
|
|
1609
|
-
function
|
|
1610
|
-
const
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1729
|
+
// src/layered/cycles.ts
|
|
1730
|
+
function backEdges(graph) {
|
|
1731
|
+
const back = /* @__PURE__ */ new Set();
|
|
1732
|
+
const done = /* @__PURE__ */ new Set();
|
|
1733
|
+
const onStack = /* @__PURE__ */ new Set();
|
|
1734
|
+
const walk = (id) => {
|
|
1735
|
+
if (done.has(id)) return;
|
|
1736
|
+
onStack.add(id);
|
|
1737
|
+
for (const edge of graph.outgoing(id)) {
|
|
1738
|
+
if (edge.to === id) continue;
|
|
1739
|
+
if (onStack.has(edge.to)) back.add(edge.id);
|
|
1740
|
+
else walk(edge.to);
|
|
1741
|
+
}
|
|
1742
|
+
onStack.delete(id);
|
|
1743
|
+
done.add(id);
|
|
1744
|
+
};
|
|
1745
|
+
for (const node of graph.nodes) walk(node.id);
|
|
1746
|
+
return back;
|
|
1623
1747
|
}
|
|
1624
|
-
function
|
|
1625
|
-
const
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
for (const m of members) {
|
|
1637
|
-
m.vx += (cx - m.x) * strength * alpha;
|
|
1638
|
-
m.vy += (cy - m.y) * strength * alpha;
|
|
1639
|
-
}
|
|
1748
|
+
function ranksOf(graph, back) {
|
|
1749
|
+
const ranks = /* @__PURE__ */ new Map();
|
|
1750
|
+
const resolving = /* @__PURE__ */ new Set();
|
|
1751
|
+
const rankOf = (id) => {
|
|
1752
|
+
const known = ranks.get(id);
|
|
1753
|
+
if (known !== void 0) return known;
|
|
1754
|
+
if (resolving.has(id)) return 0;
|
|
1755
|
+
resolving.add(id);
|
|
1756
|
+
let rank = 0;
|
|
1757
|
+
for (const edge of graph.incoming(id)) {
|
|
1758
|
+
if (back.has(edge.id) || edge.from === id) continue;
|
|
1759
|
+
rank = Math.max(rank, rankOf(edge.from) + 1);
|
|
1640
1760
|
}
|
|
1761
|
+
resolving.delete(id);
|
|
1762
|
+
ranks.set(id, rank);
|
|
1763
|
+
return rank;
|
|
1641
1764
|
};
|
|
1765
|
+
for (const node of graph.nodes) rankOf(node.id);
|
|
1766
|
+
return ranks;
|
|
1642
1767
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1768
|
+
|
|
1769
|
+
// src/route.ts
|
|
1770
|
+
var FACES = {
|
|
1771
|
+
down: { out: "s", in: "n" },
|
|
1772
|
+
up: { out: "n", in: "s" },
|
|
1773
|
+
right: { out: "e", in: "w" },
|
|
1774
|
+
left: { out: "w", in: "e" }
|
|
1775
|
+
};
|
|
1776
|
+
function layeredRoutes(input) {
|
|
1777
|
+
const { ranks, members, compass } = input;
|
|
1778
|
+
const faces = FACES[input.direction ?? "down"];
|
|
1779
|
+
const span = (id) => {
|
|
1780
|
+
const rs = (members.get(id) ?? [id]).map((m) => ranks.get(m)).filter((r) => r !== void 0);
|
|
1781
|
+
return rs.length === 0 ? null : [Math.min(...rs), Math.max(...rs)];
|
|
1782
|
+
};
|
|
1783
|
+
const routes = /* @__PURE__ */ new Map();
|
|
1784
|
+
for (const edge of input.edges) {
|
|
1785
|
+
const from = span(edge.from);
|
|
1786
|
+
const to = span(edge.to);
|
|
1787
|
+
const route = {};
|
|
1788
|
+
if (from !== null && to !== null && (from[1] < to[0] || to[1] < from[0])) {
|
|
1789
|
+
const ahead = from[1] < to[0];
|
|
1790
|
+
if (compass.has(edge.from)) route.fromPort = ahead ? faces.out : faces.in;
|
|
1791
|
+
if (compass.has(edge.to)) route.toPort = ahead ? faces.in : faces.out;
|
|
1792
|
+
}
|
|
1793
|
+
const waypoints = input.waypoints.get(edge.id);
|
|
1794
|
+
if (waypoints !== void 0 && waypoints.length > 0) {
|
|
1795
|
+
route.waypoints = waypoints;
|
|
1796
|
+
const label = input.labels?.get(edge.id);
|
|
1797
|
+
if (label !== void 0) route.labelAt = label;
|
|
1798
|
+
}
|
|
1799
|
+
if (route.fromPort !== void 0 || route.toPort !== void 0 || route.waypoints !== void 0) {
|
|
1800
|
+
routes.set(edge.id, route);
|
|
1801
|
+
}
|
|
1653
1802
|
}
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1803
|
+
return routes;
|
|
1804
|
+
}
|
|
1805
|
+
function layeredPorts(graph, ranks, direction) {
|
|
1806
|
+
const faces = FACES[direction ?? "down"];
|
|
1807
|
+
const compass = new Set(graph.groups?.map((g) => g.id) ?? []);
|
|
1808
|
+
for (const node of graph.nodes) {
|
|
1809
|
+
if (hasCompassPort(node, faces.out) && hasCompassPort(node, faces.in)) compass.add(node.id);
|
|
1660
1810
|
}
|
|
1661
|
-
const
|
|
1662
|
-
|
|
1811
|
+
const edges = /* @__PURE__ */ new Map();
|
|
1812
|
+
for (const e of graph.edges) {
|
|
1813
|
+
const id = e.origin?.id ?? e.id;
|
|
1814
|
+
if (!edges.has(id)) edges.set(id, { id, from: e.origin?.from ?? e.from, to: e.origin?.to ?? e.to });
|
|
1815
|
+
}
|
|
1816
|
+
const routes = layeredRoutes({
|
|
1817
|
+
edges: [...edges.values()],
|
|
1818
|
+
ranks,
|
|
1819
|
+
waypoints: /* @__PURE__ */ new Map(),
|
|
1820
|
+
members: new Map((graph.groups ?? []).map((g) => [g.id, g.members])),
|
|
1821
|
+
compass,
|
|
1822
|
+
...direction !== void 0 ? { direction } : {}
|
|
1823
|
+
});
|
|
1824
|
+
return new Map([...routes].map(([id, r]) => [id, {
|
|
1825
|
+
...r.fromPort !== void 0 ? { from: r.fromPort } : {},
|
|
1826
|
+
...r.toPort !== void 0 ? { to: r.toPort } : {}
|
|
1827
|
+
}]));
|
|
1663
1828
|
}
|
|
1664
|
-
function
|
|
1665
|
-
const
|
|
1666
|
-
|
|
1667
|
-
if (gapX <= 0 || gapY <= 0) return null;
|
|
1668
|
-
const dx = b.x0 + b.x1 - (a.x0 + a.x1);
|
|
1669
|
-
const dy = b.y0 + b.y1 - (a.y0 + a.y1);
|
|
1670
|
-
return gapX < gapY ? { x: (Math.sign(dx) || 1) * gapX, y: 0 } : { x: 0, y: (Math.sign(dy) || 1) * gapY };
|
|
1829
|
+
function hasCompassPort(node, face) {
|
|
1830
|
+
const point = COMPASS[face];
|
|
1831
|
+
return (node.ports ?? DEFAULT_PORTS).some((p) => p.id === face && p.at.u === point.u && p.at.v === point.v);
|
|
1671
1832
|
}
|
|
1672
|
-
function
|
|
1673
|
-
|
|
1674
|
-
|
|
1833
|
+
function authoredOver(edges, plan) {
|
|
1834
|
+
return new Map(edges.map((e) => {
|
|
1835
|
+
const ports = plan.ports?.get(e.id);
|
|
1836
|
+
const planned = plan.waypoints?.get(e.id);
|
|
1837
|
+
const fromPort = e.fromPort ?? ports?.from;
|
|
1838
|
+
const toPort = e.toPort ?? ports?.to;
|
|
1839
|
+
const waypoints = e.waypoints ?? (planned !== void 0 && planned.length > 0 ? planned : void 0);
|
|
1840
|
+
const labelAt = e.waypoints === void 0 && waypoints !== void 0 ? plan.labels?.get(e.id) : void 0;
|
|
1841
|
+
return [e.id, {
|
|
1842
|
+
...fromPort ? { fromPort } : {},
|
|
1843
|
+
...toPort ? { toPort } : {},
|
|
1844
|
+
...waypoints ? { waypoints } : {},
|
|
1845
|
+
...labelAt !== void 0 ? { labelAt } : {}
|
|
1846
|
+
}];
|
|
1847
|
+
}));
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
// src/layered/rank.ts
|
|
1851
|
+
var GROUP_WEIGHT = 4;
|
|
1852
|
+
function ranksByLength(graph, back) {
|
|
1853
|
+
const index = /* @__PURE__ */ new Map();
|
|
1854
|
+
graph.nodes.forEach((node, i) => index.set(node.id, i));
|
|
1855
|
+
const arcs = [];
|
|
1856
|
+
for (const edge of graph.edges) {
|
|
1857
|
+
const from = index.get(edge.from);
|
|
1858
|
+
const to = index.get(edge.to);
|
|
1859
|
+
if (from === void 0 || to === void 0 || from === to) continue;
|
|
1860
|
+
arcs.push(back.has(edge.id) ? { tail: to, head: from, weight: 1, minlen: 1 } : { tail: from, head: to, weight: 1, minlen: 1 });
|
|
1675
1861
|
}
|
|
1676
|
-
|
|
1862
|
+
let count = graph.nodes.length;
|
|
1863
|
+
for (const group of graph.groups ?? []) {
|
|
1864
|
+
const members = [...new Set(group.members.map((id) => index.get(id)).filter((i) => i !== void 0))];
|
|
1865
|
+
if (members.length < 2) continue;
|
|
1866
|
+
const [top, bottom] = [count, count + 1];
|
|
1867
|
+
count += 2;
|
|
1868
|
+
for (const m of members) {
|
|
1869
|
+
arcs.push({ tail: top, head: m, weight: GROUP_WEIGHT, minlen: 0 });
|
|
1870
|
+
arcs.push({ tail: m, head: bottom, weight: GROUP_WEIGHT, minlen: 0 });
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
const real = graph.nodes.length;
|
|
1874
|
+
const start2 = longestPath(count, arcs);
|
|
1875
|
+
const ranks = /* @__PURE__ */ new Map();
|
|
1876
|
+
for (const part of components(count, arcs)) {
|
|
1877
|
+
const rank = part.nodes.map((g) => start2[g]);
|
|
1878
|
+
simplex(part.arcs, rank);
|
|
1879
|
+
const own = part.nodes.flatMap((g, i) => g < real ? [i] : []);
|
|
1880
|
+
const min = Math.min(...own.map((i) => rank[i]));
|
|
1881
|
+
for (const i of own) ranks.set(graph.nodes[part.nodes[i]].id, rank[i] - min);
|
|
1882
|
+
}
|
|
1883
|
+
return ranks;
|
|
1677
1884
|
}
|
|
1678
|
-
function
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1885
|
+
function longestPath(count, arcs) {
|
|
1886
|
+
const rank = new Array(count).fill(0);
|
|
1887
|
+
const pending = new Array(count).fill(0);
|
|
1888
|
+
const out = Array.from({ length: count }, () => []);
|
|
1889
|
+
for (const arc2 of arcs) {
|
|
1890
|
+
pending[arc2.head]++;
|
|
1891
|
+
out[arc2.tail].push(arc2);
|
|
1892
|
+
}
|
|
1893
|
+
const ready = [];
|
|
1894
|
+
for (let i = 0; i < count; i++) if (pending[i] === 0) ready.push(i);
|
|
1895
|
+
for (let k = 0; k < ready.length; k++) {
|
|
1896
|
+
const u = ready[k];
|
|
1897
|
+
for (const { head: v, minlen } of out[u]) {
|
|
1898
|
+
rank[v] = Math.max(rank[v], rank[u] + minlen);
|
|
1899
|
+
if (--pending[v] === 0) ready.push(v);
|
|
1900
|
+
}
|
|
1682
1901
|
}
|
|
1683
|
-
|
|
1684
|
-
function separateGroups(groups, bodies, byId, padding) {
|
|
1685
|
-
const resolved = resolve(groups, byId);
|
|
1686
|
-
const memberSets = resolved.map((g) => new Set(g.members));
|
|
1687
|
-
return () => {
|
|
1688
|
-
const boxes = resolved.map(boxOf);
|
|
1689
|
-
for (let i = 0; i < resolved.length; i++) {
|
|
1690
|
-
for (let j = i + 1; j < resolved.length; j++) {
|
|
1691
|
-
if (holds(resolved[i], resolved[j]) || holds(resolved[j], resolved[i])) continue;
|
|
1692
|
-
const push = clearance(boxes[i], boxes[j], padding);
|
|
1693
|
-
if (push === null) continue;
|
|
1694
|
-
shove(resolved[i].members, -push.x / 2, -push.y / 2);
|
|
1695
|
-
shove(resolved[j].members, push.x / 2, push.y / 2);
|
|
1696
|
-
}
|
|
1697
|
-
for (const body of bodies) {
|
|
1698
|
-
if (memberSets[i].has(body)) continue;
|
|
1699
|
-
const box = { x0: body.x - body.hw, y0: body.y - body.hh, x1: body.x + body.hw, y1: body.y + body.hh };
|
|
1700
|
-
const push = clearance(boxes[i], box, padding);
|
|
1701
|
-
if (push === null) continue;
|
|
1702
|
-
shove(resolved[i].members, -push.x / 2, -push.y / 2);
|
|
1703
|
-
body.vx += push.x / 2;
|
|
1704
|
-
body.vy += push.y / 2;
|
|
1705
|
-
}
|
|
1706
|
-
}
|
|
1707
|
-
};
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
|
-
// src/force.ts
|
|
1711
|
-
var DEFAULTS = {
|
|
1712
|
-
iterations: 300,
|
|
1713
|
-
linkDistance: 160,
|
|
1714
|
-
linkStrength: 0.35,
|
|
1715
|
-
charge: -3e3,
|
|
1716
|
-
gravity: 0.02,
|
|
1717
|
-
padding: 24,
|
|
1718
|
-
groupStrength: 0.2
|
|
1719
|
-
};
|
|
1720
|
-
var GOLDEN = Math.PI * (3 - Math.sqrt(5));
|
|
1721
|
-
var NUDGE2 = 0.5;
|
|
1722
|
-
function charge(bodies, strength) {
|
|
1723
|
-
return (alpha) => {
|
|
1724
|
-
for (let i = 0; i < bodies.length; i++) {
|
|
1725
|
-
const a = bodies[i];
|
|
1726
|
-
for (let j = i + 1; j < bodies.length; j++) {
|
|
1727
|
-
const b = bodies[j];
|
|
1728
|
-
const dx = b.x - a.x;
|
|
1729
|
-
const dy = b.y - a.y;
|
|
1730
|
-
const d2 = dx * dx + dy * dy;
|
|
1731
|
-
if (d2 === 0) continue;
|
|
1732
|
-
const w = strength * alpha / d2;
|
|
1733
|
-
a.vx += dx * w;
|
|
1734
|
-
a.vy += dy * w;
|
|
1735
|
-
b.vx -= dx * w;
|
|
1736
|
-
b.vy -= dy * w;
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1739
|
-
};
|
|
1740
|
-
}
|
|
1741
|
-
function links(bodies, graph, distance, strength) {
|
|
1742
|
-
return (alpha) => {
|
|
1743
|
-
for (const edge of graph.edges) {
|
|
1744
|
-
const a = bodies.get(edge.from);
|
|
1745
|
-
const b = bodies.get(edge.to);
|
|
1746
|
-
if (a === void 0 || b === void 0 || a === b) continue;
|
|
1747
|
-
const dx = b.x - a.x;
|
|
1748
|
-
const dy = b.y - a.y;
|
|
1749
|
-
const d = Math.hypot(dx, dy);
|
|
1750
|
-
if (d === 0) continue;
|
|
1751
|
-
const pull = (d - distance) / d * alpha * strength;
|
|
1752
|
-
a.vx += dx * pull;
|
|
1753
|
-
a.vy += dy * pull;
|
|
1754
|
-
b.vx -= dx * pull;
|
|
1755
|
-
b.vy -= dy * pull;
|
|
1756
|
-
}
|
|
1757
|
-
};
|
|
1758
|
-
}
|
|
1759
|
-
function separateBoxes(bodies, padding) {
|
|
1760
|
-
return () => {
|
|
1761
|
-
for (let i = 0; i < bodies.length; i++) {
|
|
1762
|
-
const a = bodies[i];
|
|
1763
|
-
for (let j = i + 1; j < bodies.length; j++) {
|
|
1764
|
-
const b = bodies[j];
|
|
1765
|
-
const dx = b.x - a.x;
|
|
1766
|
-
const dy = b.y - a.y;
|
|
1767
|
-
const gapX = a.hw + b.hw + padding - Math.abs(dx);
|
|
1768
|
-
const gapY = a.hh + b.hh + padding - Math.abs(dy);
|
|
1769
|
-
if (gapX <= 0 || gapY <= 0) continue;
|
|
1770
|
-
if (gapX < gapY) {
|
|
1771
|
-
const push = (Math.sign(dx) || 1) * gapX * 0.5;
|
|
1772
|
-
a.vx -= push;
|
|
1773
|
-
b.vx += push;
|
|
1774
|
-
} else {
|
|
1775
|
-
const push = (Math.sign(dy) || 1) * gapY * 0.5;
|
|
1776
|
-
a.vy -= push;
|
|
1777
|
-
b.vy += push;
|
|
1778
|
-
}
|
|
1779
|
-
}
|
|
1780
|
-
}
|
|
1781
|
-
};
|
|
1782
|
-
}
|
|
1783
|
-
function gravity(bodies, at2, strength) {
|
|
1784
|
-
return (alpha) => {
|
|
1785
|
-
for (const body of bodies) {
|
|
1786
|
-
body.vx += (at2.x - body.x) * strength * alpha;
|
|
1787
|
-
body.vy += (at2.y - body.y) * strength * alpha;
|
|
1788
|
-
}
|
|
1789
|
-
};
|
|
1790
|
-
}
|
|
1791
|
-
function forceRelaxation(graph, opts = {}) {
|
|
1792
|
-
const {
|
|
1793
|
-
linkDistance = DEFAULTS.linkDistance,
|
|
1794
|
-
linkStrength = DEFAULTS.linkStrength,
|
|
1795
|
-
charge: chargeStrength = DEFAULTS.charge,
|
|
1796
|
-
gravity: gravityStrength = DEFAULTS.gravity,
|
|
1797
|
-
padding = DEFAULTS.padding,
|
|
1798
|
-
groupStrength = DEFAULTS.groupStrength
|
|
1799
|
-
} = opts;
|
|
1800
|
-
const pinned = pinnedSet(graph, opts);
|
|
1801
|
-
const bodies = graph.nodes.map((node) => {
|
|
1802
|
-
const body = {
|
|
1803
|
-
id: node.id,
|
|
1804
|
-
x: center(node.bounds, "x"),
|
|
1805
|
-
y: center(node.bounds, "y"),
|
|
1806
|
-
hw: node.bounds.width / 2,
|
|
1807
|
-
hh: node.bounds.height / 2
|
|
1808
|
-
};
|
|
1809
|
-
if (pinned.has(node.id)) {
|
|
1810
|
-
body.fx = body.x;
|
|
1811
|
-
body.fy = body.y;
|
|
1812
|
-
}
|
|
1813
|
-
return body;
|
|
1814
|
-
});
|
|
1815
|
-
separate(bodies);
|
|
1816
|
-
const byId = new Map(bodies.map((b) => [b.id, b]));
|
|
1817
|
-
const centroid = {
|
|
1818
|
-
x: bodies.reduce((sum, b) => sum + b.x, 0) / bodies.length,
|
|
1819
|
-
y: bodies.reduce((sum, b) => sum + b.y, 0) / bodies.length
|
|
1820
|
-
};
|
|
1821
|
-
const groups = graph.groups ?? [];
|
|
1822
|
-
const sim = createSimulation({
|
|
1823
|
-
nodes: bodies,
|
|
1824
|
-
forces: [
|
|
1825
|
-
charge(bodies, chargeStrength),
|
|
1826
|
-
links(byId, graph, linkDistance, linkStrength),
|
|
1827
|
-
gravity(bodies, centroid, gravityStrength),
|
|
1828
|
-
separateBoxes(bodies, padding),
|
|
1829
|
-
...groups.length > 0 ? [groupCohesion(groups, byId, groupStrength), separateGroups(groups, bodies, byId, padding)] : []
|
|
1830
|
-
]
|
|
1831
|
-
});
|
|
1832
|
-
return {
|
|
1833
|
-
bodies,
|
|
1834
|
-
byId,
|
|
1835
|
-
pinned,
|
|
1836
|
-
sim,
|
|
1837
|
-
placed() {
|
|
1838
|
-
const placed = /* @__PURE__ */ new Map();
|
|
1839
|
-
for (const node of graph.nodes) {
|
|
1840
|
-
const body = byId.get(node.id);
|
|
1841
|
-
placed.set(node.id, {
|
|
1842
|
-
x: body.x - node.bounds.width / 2,
|
|
1843
|
-
y: body.y - node.bounds.height / 2
|
|
1844
|
-
});
|
|
1845
|
-
}
|
|
1846
|
-
return placed;
|
|
1847
|
-
}
|
|
1848
|
-
};
|
|
1849
|
-
}
|
|
1850
|
-
var force = (graph, opts = {}) => {
|
|
1851
|
-
if (graph.nodes.length === 0) return /* @__PURE__ */ new Map();
|
|
1852
|
-
const relaxation = forceRelaxation(graph, opts);
|
|
1853
|
-
relaxation.sim.tick(opts.iterations ?? DEFAULTS.iterations);
|
|
1854
|
-
return translated(graph, relaxation.placed(), relaxation.pinned, opts.tolerance);
|
|
1855
|
-
};
|
|
1856
|
-
function separate(bodies) {
|
|
1857
|
-
const seen = /* @__PURE__ */ new Map();
|
|
1858
|
-
bodies.forEach((body, i) => {
|
|
1859
|
-
const key = `${body.x},${body.y}`;
|
|
1860
|
-
const nth = seen.get(key) ?? 0;
|
|
1861
|
-
seen.set(key, nth + 1);
|
|
1862
|
-
if (nth === 0 || body.fx != null || body.fy != null) return;
|
|
1863
|
-
const angle = GOLDEN * i;
|
|
1864
|
-
const radius = NUDGE2 * nth;
|
|
1865
|
-
body.x += Math.cos(angle) * radius;
|
|
1866
|
-
body.y += Math.sin(angle) * radius;
|
|
1867
|
-
});
|
|
1868
|
-
}
|
|
1869
|
-
|
|
1870
|
-
// src/layered/cycles.ts
|
|
1871
|
-
function backEdges(graph) {
|
|
1872
|
-
const back = /* @__PURE__ */ new Set();
|
|
1873
|
-
const done = /* @__PURE__ */ new Set();
|
|
1874
|
-
const onStack = /* @__PURE__ */ new Set();
|
|
1875
|
-
const walk = (id) => {
|
|
1876
|
-
if (done.has(id)) return;
|
|
1877
|
-
onStack.add(id);
|
|
1878
|
-
for (const edge of graph.outgoing(id)) {
|
|
1879
|
-
if (edge.to === id) continue;
|
|
1880
|
-
if (onStack.has(edge.to)) back.add(edge.id);
|
|
1881
|
-
else walk(edge.to);
|
|
1882
|
-
}
|
|
1883
|
-
onStack.delete(id);
|
|
1884
|
-
done.add(id);
|
|
1885
|
-
};
|
|
1886
|
-
for (const node of graph.nodes) walk(node.id);
|
|
1887
|
-
return back;
|
|
1888
|
-
}
|
|
1889
|
-
function ranksOf(graph, back) {
|
|
1890
|
-
const ranks = /* @__PURE__ */ new Map();
|
|
1891
|
-
const resolving = /* @__PURE__ */ new Set();
|
|
1892
|
-
const rankOf = (id) => {
|
|
1893
|
-
const known = ranks.get(id);
|
|
1894
|
-
if (known !== void 0) return known;
|
|
1895
|
-
if (resolving.has(id)) return 0;
|
|
1896
|
-
resolving.add(id);
|
|
1897
|
-
let rank = 0;
|
|
1898
|
-
for (const edge of graph.incoming(id)) {
|
|
1899
|
-
if (back.has(edge.id) || edge.from === id) continue;
|
|
1900
|
-
rank = Math.max(rank, rankOf(edge.from) + 1);
|
|
1901
|
-
}
|
|
1902
|
-
resolving.delete(id);
|
|
1903
|
-
ranks.set(id, rank);
|
|
1904
|
-
return rank;
|
|
1905
|
-
};
|
|
1906
|
-
for (const node of graph.nodes) rankOf(node.id);
|
|
1907
|
-
return ranks;
|
|
1908
|
-
}
|
|
1909
|
-
|
|
1910
|
-
// src/route.ts
|
|
1911
|
-
var FACES = {
|
|
1912
|
-
down: { out: "s", in: "n" },
|
|
1913
|
-
up: { out: "n", in: "s" },
|
|
1914
|
-
right: { out: "e", in: "w" },
|
|
1915
|
-
left: { out: "w", in: "e" }
|
|
1916
|
-
};
|
|
1917
|
-
function layeredRoutes(input) {
|
|
1918
|
-
const { ranks, members, compass } = input;
|
|
1919
|
-
const faces = FACES[input.direction ?? "down"];
|
|
1920
|
-
const span = (id) => {
|
|
1921
|
-
const rs = (members.get(id) ?? [id]).map((m) => ranks.get(m)).filter((r) => r !== void 0);
|
|
1922
|
-
return rs.length === 0 ? null : [Math.min(...rs), Math.max(...rs)];
|
|
1923
|
-
};
|
|
1924
|
-
const routes = /* @__PURE__ */ new Map();
|
|
1925
|
-
for (const edge of input.edges) {
|
|
1926
|
-
const from = span(edge.from);
|
|
1927
|
-
const to = span(edge.to);
|
|
1928
|
-
const route = {};
|
|
1929
|
-
if (from !== null && to !== null && (from[1] < to[0] || to[1] < from[0])) {
|
|
1930
|
-
const ahead = from[1] < to[0];
|
|
1931
|
-
if (compass.has(edge.from)) route.fromPort = ahead ? faces.out : faces.in;
|
|
1932
|
-
if (compass.has(edge.to)) route.toPort = ahead ? faces.in : faces.out;
|
|
1933
|
-
}
|
|
1934
|
-
const waypoints = input.waypoints.get(edge.id);
|
|
1935
|
-
if (waypoints !== void 0 && waypoints.length > 0) {
|
|
1936
|
-
route.waypoints = waypoints;
|
|
1937
|
-
const label = input.labels?.get(edge.id);
|
|
1938
|
-
if (label !== void 0) route.labelAt = label;
|
|
1939
|
-
}
|
|
1940
|
-
if (route.fromPort !== void 0 || route.toPort !== void 0 || route.waypoints !== void 0) {
|
|
1941
|
-
routes.set(edge.id, route);
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
|
-
return routes;
|
|
1945
|
-
}
|
|
1946
|
-
function layeredPorts(graph, ranks, direction) {
|
|
1947
|
-
const faces = FACES[direction ?? "down"];
|
|
1948
|
-
const compass = new Set(graph.groups?.map((g) => g.id) ?? []);
|
|
1949
|
-
for (const node of graph.nodes) {
|
|
1950
|
-
if (hasCompassPort(node, faces.out) && hasCompassPort(node, faces.in)) compass.add(node.id);
|
|
1951
|
-
}
|
|
1952
|
-
const edges = /* @__PURE__ */ new Map();
|
|
1953
|
-
for (const e of graph.edges) {
|
|
1954
|
-
const id = e.origin?.id ?? e.id;
|
|
1955
|
-
if (!edges.has(id)) edges.set(id, { id, from: e.origin?.from ?? e.from, to: e.origin?.to ?? e.to });
|
|
1956
|
-
}
|
|
1957
|
-
const routes = layeredRoutes({
|
|
1958
|
-
edges: [...edges.values()],
|
|
1959
|
-
ranks,
|
|
1960
|
-
waypoints: /* @__PURE__ */ new Map(),
|
|
1961
|
-
members: new Map((graph.groups ?? []).map((g) => [g.id, g.members])),
|
|
1962
|
-
compass,
|
|
1963
|
-
...direction !== void 0 ? { direction } : {}
|
|
1964
|
-
});
|
|
1965
|
-
return new Map([...routes].map(([id, r]) => [id, {
|
|
1966
|
-
...r.fromPort !== void 0 ? { from: r.fromPort } : {},
|
|
1967
|
-
...r.toPort !== void 0 ? { to: r.toPort } : {}
|
|
1968
|
-
}]));
|
|
1969
|
-
}
|
|
1970
|
-
function hasCompassPort(node, face) {
|
|
1971
|
-
const point = COMPASS[face];
|
|
1972
|
-
return (node.ports ?? DEFAULT_PORTS).some((p) => p.id === face && p.at.u === point.u && p.at.v === point.v);
|
|
1973
|
-
}
|
|
1974
|
-
function authoredOver(edges, plan) {
|
|
1975
|
-
return new Map(edges.map((e) => {
|
|
1976
|
-
const ports = plan.ports?.get(e.id);
|
|
1977
|
-
const planned = plan.waypoints?.get(e.id);
|
|
1978
|
-
const fromPort = e.fromPort ?? ports?.from;
|
|
1979
|
-
const toPort = e.toPort ?? ports?.to;
|
|
1980
|
-
const waypoints = e.waypoints ?? (planned !== void 0 && planned.length > 0 ? planned : void 0);
|
|
1981
|
-
const labelAt = e.waypoints === void 0 && waypoints !== void 0 ? plan.labels?.get(e.id) : void 0;
|
|
1982
|
-
return [e.id, {
|
|
1983
|
-
...fromPort ? { fromPort } : {},
|
|
1984
|
-
...toPort ? { toPort } : {},
|
|
1985
|
-
...waypoints ? { waypoints } : {},
|
|
1986
|
-
...labelAt !== void 0 ? { labelAt } : {}
|
|
1987
|
-
}];
|
|
1988
|
-
}));
|
|
1989
|
-
}
|
|
1990
|
-
|
|
1991
|
-
// src/layered/rank.ts
|
|
1992
|
-
var GROUP_WEIGHT = 4;
|
|
1993
|
-
function ranksByLength(graph, back) {
|
|
1994
|
-
const index = /* @__PURE__ */ new Map();
|
|
1995
|
-
graph.nodes.forEach((node, i) => index.set(node.id, i));
|
|
1996
|
-
const arcs = [];
|
|
1997
|
-
for (const edge of graph.edges) {
|
|
1998
|
-
const from = index.get(edge.from);
|
|
1999
|
-
const to = index.get(edge.to);
|
|
2000
|
-
if (from === void 0 || to === void 0 || from === to) continue;
|
|
2001
|
-
arcs.push(back.has(edge.id) ? { tail: to, head: from, weight: 1, minlen: 1 } : { tail: from, head: to, weight: 1, minlen: 1 });
|
|
2002
|
-
}
|
|
2003
|
-
let count = graph.nodes.length;
|
|
2004
|
-
for (const group of graph.groups ?? []) {
|
|
2005
|
-
const members = [...new Set(group.members.map((id) => index.get(id)).filter((i) => i !== void 0))];
|
|
2006
|
-
if (members.length < 2) continue;
|
|
2007
|
-
const [top, bottom] = [count, count + 1];
|
|
2008
|
-
count += 2;
|
|
2009
|
-
for (const m of members) {
|
|
2010
|
-
arcs.push({ tail: top, head: m, weight: GROUP_WEIGHT, minlen: 0 });
|
|
2011
|
-
arcs.push({ tail: m, head: bottom, weight: GROUP_WEIGHT, minlen: 0 });
|
|
2012
|
-
}
|
|
2013
|
-
}
|
|
2014
|
-
const real = graph.nodes.length;
|
|
2015
|
-
const start = longestPath(count, arcs);
|
|
2016
|
-
const ranks = /* @__PURE__ */ new Map();
|
|
2017
|
-
for (const part of components(count, arcs)) {
|
|
2018
|
-
const rank = part.nodes.map((g) => start[g]);
|
|
2019
|
-
simplex(part.arcs, rank);
|
|
2020
|
-
const own = part.nodes.flatMap((g, i) => g < real ? [i] : []);
|
|
2021
|
-
const min = Math.min(...own.map((i) => rank[i]));
|
|
2022
|
-
for (const i of own) ranks.set(graph.nodes[part.nodes[i]].id, rank[i] - min);
|
|
2023
|
-
}
|
|
2024
|
-
return ranks;
|
|
2025
|
-
}
|
|
2026
|
-
function longestPath(count, arcs) {
|
|
2027
|
-
const rank = new Array(count).fill(0);
|
|
2028
|
-
const pending = new Array(count).fill(0);
|
|
2029
|
-
const out = Array.from({ length: count }, () => []);
|
|
2030
|
-
for (const arc2 of arcs) {
|
|
2031
|
-
pending[arc2.head]++;
|
|
2032
|
-
out[arc2.tail].push(arc2);
|
|
2033
|
-
}
|
|
2034
|
-
const ready = [];
|
|
2035
|
-
for (let i = 0; i < count; i++) if (pending[i] === 0) ready.push(i);
|
|
2036
|
-
for (let k = 0; k < ready.length; k++) {
|
|
2037
|
-
const u = ready[k];
|
|
2038
|
-
for (const { head: v, minlen } of out[u]) {
|
|
2039
|
-
rank[v] = Math.max(rank[v], rank[u] + minlen);
|
|
2040
|
-
if (--pending[v] === 0) ready.push(v);
|
|
2041
|
-
}
|
|
2042
|
-
}
|
|
2043
|
-
return rank;
|
|
1902
|
+
return rank;
|
|
2044
1903
|
}
|
|
2045
1904
|
function components(count, arcs) {
|
|
2046
1905
|
const near = Array.from({ length: count }, () => []);
|
|
@@ -2194,16 +2053,16 @@ function tighten(rank, arcs, inTree) {
|
|
|
2194
2053
|
const adj = treeAdjacency(rank.length, arcs, inTree);
|
|
2195
2054
|
const seen = rank.map(() => false);
|
|
2196
2055
|
seen[0] = true;
|
|
2197
|
-
const
|
|
2198
|
-
for (let k = 0; k <
|
|
2199
|
-
const v =
|
|
2056
|
+
const queue2 = [0];
|
|
2057
|
+
for (let k = 0; k < queue2.length; k++) {
|
|
2058
|
+
const v = queue2[k];
|
|
2200
2059
|
for (const a of adj[v]) {
|
|
2201
2060
|
const arc2 = arcs[a];
|
|
2202
2061
|
const w = arc2.tail === v ? arc2.head : arc2.tail;
|
|
2203
2062
|
if (seen[w]) continue;
|
|
2204
2063
|
seen[w] = true;
|
|
2205
2064
|
rank[w] = arc2.tail === v ? rank[v] + arc2.minlen : rank[v] - arc2.minlen;
|
|
2206
|
-
|
|
2065
|
+
queue2.push(w);
|
|
2207
2066
|
}
|
|
2208
2067
|
}
|
|
2209
2068
|
}
|
|
@@ -2302,13 +2161,13 @@ function expand(graph, nodeRanks, back, opts) {
|
|
|
2302
2161
|
if (a === null || b === null || a[1] >= b[0]) continue;
|
|
2303
2162
|
if (d.authored && b[0] - a[1] > 1) continue;
|
|
2304
2163
|
const group = sharedGroup(from, to);
|
|
2305
|
-
const
|
|
2306
|
-
const
|
|
2164
|
+
const start2 = crossCenter(from);
|
|
2165
|
+
const end2 = crossCenter(to);
|
|
2307
2166
|
const crossings = b[0] - a[1] - 1;
|
|
2308
2167
|
const now = d.waypoints?.length === crossings * 2 ? d.waypoints : void 0;
|
|
2309
2168
|
const seed = (j) => {
|
|
2310
2169
|
if (now !== void 0) return now[(d.back ? crossings - 1 - j : j) * 2][axes.cross];
|
|
2311
|
-
return
|
|
2170
|
+
return start2 + (end2 - start2) * (j + 1) / (crossings + 1);
|
|
2312
2171
|
};
|
|
2313
2172
|
const labelRow = labeled.labelRow.get(d.id);
|
|
2314
2173
|
let prev = inRank(from, a[1]);
|
|
@@ -2409,22 +2268,22 @@ function settlePlaces(rows, hops) {
|
|
|
2409
2268
|
if (!hops.some((h) => h.fromPlaces !== void 0 || h.toPlaces !== void 0)) return [...hops];
|
|
2410
2269
|
const pos = /* @__PURE__ */ new Map();
|
|
2411
2270
|
for (const row of rows) row.forEach((n, i) => pos.set(n.id, i));
|
|
2412
|
-
const
|
|
2271
|
+
const sides2 = sidesOf(hops);
|
|
2413
2272
|
return hops.map((h) => {
|
|
2414
2273
|
if (h.fromPlaces === void 0 && h.toPlaces === void 0) return h;
|
|
2415
2274
|
const { fromPlaces, toPlaces, ...rest } = h;
|
|
2416
2275
|
return {
|
|
2417
2276
|
...rest,
|
|
2418
|
-
...fromPlaces !== void 0 ? { fromAt: placeAmong(fromPlaces, h.to,
|
|
2419
|
-
...toPlaces !== void 0 ? { toAt: placeAmong(toPlaces, h.from,
|
|
2277
|
+
...fromPlaces !== void 0 ? { fromAt: placeAmong(fromPlaces, h.to, sides2.down.get(h.from) ?? [], pos) } : {},
|
|
2278
|
+
...toPlaces !== void 0 ? { toAt: placeAmong(toPlaces, h.from, sides2.up.get(h.to) ?? [], pos) } : {}
|
|
2420
2279
|
};
|
|
2421
2280
|
});
|
|
2422
2281
|
}
|
|
2423
2282
|
|
|
2424
2283
|
// src/layered/order.ts
|
|
2425
|
-
function ends(p, pos,
|
|
2426
|
-
const fa = p.fromPlaces === void 0 ? p.fromAt : placeAmong(p.fromPlaces, p.to,
|
|
2427
|
-
const fb = p.toPlaces === void 0 ? p.toAt : placeAmong(p.toPlaces, p.from,
|
|
2284
|
+
function ends(p, pos, sides2) {
|
|
2285
|
+
const fa = p.fromPlaces === void 0 ? p.fromAt : placeAmong(p.fromPlaces, p.to, sides2.down.get(p.from) ?? [], pos);
|
|
2286
|
+
const fb = p.toPlaces === void 0 ? p.toAt : placeAmong(p.toPlaces, p.from, sides2.up.get(p.to) ?? [], pos);
|
|
2428
2287
|
return [at(pos.get(p.from), fa), at(pos.get(p.to), fb)];
|
|
2429
2288
|
}
|
|
2430
2289
|
var at = (pos, frac) => pos + 0.25 + frac / 2;
|
|
@@ -2445,16 +2304,16 @@ function positions(rows) {
|
|
|
2445
2304
|
for (const row of rows) row.forEach((n, i) => pos.set(n.id, i));
|
|
2446
2305
|
return pos;
|
|
2447
2306
|
}
|
|
2448
|
-
function pairCrossings(pairs, pos,
|
|
2449
|
-
const met = pairs.map((p) => ends(p, pos,
|
|
2307
|
+
function pairCrossings(pairs, pos, sides2) {
|
|
2308
|
+
const met = pairs.map((p) => ends(p, pos, sides2)).sort((p, q) => p[0] - q[0] || p[1] - q[1]);
|
|
2450
2309
|
const lows = [...new Set(met.map(([, b]) => b))].sort((p, q) => p - q);
|
|
2451
2310
|
const slot = new Map(lows.map((b, i) => [b, i]));
|
|
2452
2311
|
const width = lows.length;
|
|
2453
2312
|
const tree2 = new Array(width + 1).fill(0);
|
|
2454
2313
|
let seen = 0;
|
|
2455
2314
|
let count = 0;
|
|
2456
|
-
for (const [,
|
|
2457
|
-
const b = slot.get(
|
|
2315
|
+
for (const [, end2] of met) {
|
|
2316
|
+
const b = slot.get(end2);
|
|
2458
2317
|
let atMost = 0;
|
|
2459
2318
|
for (let i = b + 1; i > 0; i -= i & -i) atMost += tree2[i];
|
|
2460
2319
|
count += seen - atMost;
|
|
@@ -2463,9 +2322,9 @@ function pairCrossings(pairs, pos, sides) {
|
|
|
2463
2322
|
}
|
|
2464
2323
|
return count;
|
|
2465
2324
|
}
|
|
2466
|
-
function total(rows, byRank, pos,
|
|
2325
|
+
function total(rows, byRank, pos, sides2) {
|
|
2467
2326
|
let sum = 0;
|
|
2468
|
-
for (let r = 0; r + 1 < rows.length; r++) sum += pairCrossings(byRank[r], pos,
|
|
2327
|
+
for (let r = 0; r + 1 < rows.length; r++) sum += pairCrossings(byRank[r], pos, sides2);
|
|
2469
2328
|
return sum;
|
|
2470
2329
|
}
|
|
2471
2330
|
function chainsOf(groups) {
|
|
@@ -2517,10 +2376,10 @@ function sortRank(row, key, chainOf, places = /* @__PURE__ */ new Map()) {
|
|
|
2517
2376
|
});
|
|
2518
2377
|
const out = [];
|
|
2519
2378
|
const flatten = (block) => {
|
|
2520
|
-
const
|
|
2379
|
+
const place2 = block.group === void 0 ? void 0 : places.get(block.group);
|
|
2521
2380
|
const items = block.items.map((item) => {
|
|
2522
|
-
if (
|
|
2523
|
-
const k =
|
|
2381
|
+
if (place2 !== void 0) {
|
|
2382
|
+
const k = place2.get("id" in item ? item.id : item.group) ?? Infinity;
|
|
2524
2383
|
return { item, k, first: "id" in item ? firstOf.get(item) : item.first };
|
|
2525
2384
|
}
|
|
2526
2385
|
if ("id" in item) return { item, k: keyOf.get(item), first: firstOf.get(item) };
|
|
@@ -2600,15 +2459,15 @@ function orderRows(rows, hops, opts = {}) {
|
|
|
2600
2459
|
}
|
|
2601
2460
|
}
|
|
2602
2461
|
const seeded = rows.map((row) => sortRank(row, (_, i) => i, chainOf, places));
|
|
2603
|
-
const
|
|
2604
|
-
const work = { rows: seeded, pos: positions(seeded), ups, downs, sides, chainOf, places };
|
|
2462
|
+
const sides2 = sidesOf(hops);
|
|
2463
|
+
const work = { rows: seeded, pos: positions(seeded), ups, downs, sides: sides2, chainOf, places };
|
|
2605
2464
|
let best = seeded.map((row) => [...row]);
|
|
2606
|
-
let fewest = total(work.rows, byRank, work.pos,
|
|
2465
|
+
let fewest = total(work.rows, byRank, work.pos, sides2);
|
|
2607
2466
|
for (let sweep = 0, stale = 0; sweep < maxSweeps && stale < patience && fewest > 0; sweep++) {
|
|
2608
2467
|
if (sweep % 2 === 0) for (let r = 1; r < work.rows.length; r++) reorder(work, r, ups);
|
|
2609
2468
|
else for (let r = work.rows.length - 2; r >= 0; r--) reorder(work, r, downs);
|
|
2610
2469
|
transpose(work);
|
|
2611
|
-
const n = total(work.rows, byRank, work.pos,
|
|
2470
|
+
const n = total(work.rows, byRank, work.pos, sides2);
|
|
2612
2471
|
if (n < fewest) {
|
|
2613
2472
|
fewest = n;
|
|
2614
2473
|
best = work.rows.map((row) => [...row]);
|
|
@@ -2645,9 +2504,9 @@ function levelRoutes(input) {
|
|
|
2645
2504
|
out.ports.set(id, named(graph, [from, face], [to, face]));
|
|
2646
2505
|
out.waypoints.set(id, around(a, b, others, axes, input.rankGap));
|
|
2647
2506
|
} else {
|
|
2648
|
-
const
|
|
2507
|
+
const sides2 = SIDES[axes.cross];
|
|
2649
2508
|
const ahead = center(a, axes.cross) < center(b, axes.cross);
|
|
2650
|
-
out.ports.set(id, named(graph, [from, ahead ?
|
|
2509
|
+
out.ports.set(id, named(graph, [from, ahead ? sides2.high : sides2.low], [to, ahead ? sides2.low : sides2.high]));
|
|
2651
2510
|
}
|
|
2652
2511
|
}
|
|
2653
2512
|
return out;
|
|
@@ -2916,11 +2775,11 @@ function holdPins(input) {
|
|
|
2916
2775
|
if (pins.length < 2) return { crossAt: new Map(input.crossAt), gaps: [...input.gaps], depths: natural, rankAt, unheld };
|
|
2917
2776
|
const anchor = pins[0];
|
|
2918
2777
|
const a = rowOf.get(anchor.id);
|
|
2919
|
-
let
|
|
2920
|
-
for (let r = 0; r < a; r++)
|
|
2921
|
-
const bandInput = { natural, gaps: input.gaps, minGaps: input.minGaps, home: { rank: a, lo:
|
|
2778
|
+
let start2 = 0;
|
|
2779
|
+
for (let r = 0; r < a; r++) start2 += natural[r] + input.gaps[r];
|
|
2780
|
+
const bandInput = { natural, gaps: input.gaps, minGaps: input.minGaps, home: { rank: a, lo: start2 } };
|
|
2922
2781
|
const anchorExt = extent(anchor.bounds, axes.rank);
|
|
2923
|
-
const anchorRank =
|
|
2782
|
+
const anchorRank = start2 + (natural[a] - anchorExt) / 2;
|
|
2924
2783
|
const anchorWorld = worldOf({ cross: input.crossAt.get(anchor.id), rank: anchorRank }, anchorExt, axes);
|
|
2925
2784
|
const target = (id) => {
|
|
2926
2785
|
const node = graph.node(id);
|
|
@@ -3284,107 +3143,369 @@ function layeredPlan(graph, opts = {}) {
|
|
|
3284
3143
|
}, graph, opts);
|
|
3285
3144
|
return { ...last, moves };
|
|
3286
3145
|
}
|
|
3287
|
-
function routed(edge, plan) {
|
|
3288
|
-
const { waypoints: _, ...rest } = edge;
|
|
3289
|
-
const route = plan.waypoints.get(edge.origin?.id ?? edge.id);
|
|
3290
|
-
return route === void 0 ? rest : { ...rest, waypoints: route };
|
|
3146
|
+
function routed(edge, plan) {
|
|
3147
|
+
const { waypoints: _, ...rest } = edge;
|
|
3148
|
+
const route = plan.waypoints.get(edge.origin?.id ?? edge.id);
|
|
3149
|
+
return route === void 0 ? rest : { ...rest, waypoints: route };
|
|
3150
|
+
}
|
|
3151
|
+
function planOnce(graph, opts = {}) {
|
|
3152
|
+
const axes = axesFor(opts.direction);
|
|
3153
|
+
const nodeGap = opts.nodeGap ?? DEFAULT_NODE_GAP;
|
|
3154
|
+
const rankGap = opts.rankGap ?? DEFAULT_RANK_GAP;
|
|
3155
|
+
const finding = opts.order === "barycenter";
|
|
3156
|
+
const back = backEdges(graph);
|
|
3157
|
+
const ranks = ranksByLength(graph, back);
|
|
3158
|
+
const expanded = expand(graph, ranks, back, { axes, nodeGap });
|
|
3159
|
+
let rows = finding ? orderRows(expanded.rows, expanded.hops, { groups: graph.groups ?? [] }) : expanded.rows;
|
|
3160
|
+
const grouped = (graph.groups?.length ?? 0) > 0;
|
|
3161
|
+
const pinned = pinnedSet(graph, opts);
|
|
3162
|
+
const across = () => {
|
|
3163
|
+
const preferred2 = placeAcross(rows, settlePlaces(rows, expanded.hops), axes.cross, nodeGap);
|
|
3164
|
+
return grouped ? packClusters(graph, rows, preferred2, axes, nodeGap) : preferred2;
|
|
3165
|
+
};
|
|
3166
|
+
let packed = across();
|
|
3167
|
+
for (let turn = 0; turn < rows.length; turn++) {
|
|
3168
|
+
const turned = turnOutward({ graph, rows, crossAt: packed, axes, pinned, hops: expanded.hops });
|
|
3169
|
+
if (turned === void 0) break;
|
|
3170
|
+
rows = turned;
|
|
3171
|
+
packed = across();
|
|
3172
|
+
}
|
|
3173
|
+
const spaced = grouped ? rankGaps(graph, rows, axes, rankGap) : rows.slice(1).map(() => rankGap);
|
|
3174
|
+
const minGaps = spaced.map((gap) => gap - rankGap + rankGap * MIN_GAP);
|
|
3175
|
+
for (const r of expanded.labelRows) {
|
|
3176
|
+
spaced[r - 1] = spaced[r - 1] - rankGap * (1 - LABEL_GAP);
|
|
3177
|
+
spaced[r] = spaced[r] - rankGap * (1 - LABEL_GAP);
|
|
3178
|
+
}
|
|
3179
|
+
const { crossAt, gaps, depths: depths2, rankAt, unheld } = holdPins({ graph, rows, crossAt: packed, gaps: spaced, pinned, axes, nodeGap, minGaps });
|
|
3180
|
+
const slots = /* @__PURE__ */ new Map();
|
|
3181
|
+
const bands = [];
|
|
3182
|
+
let along = 0;
|
|
3183
|
+
for (const [i, row] of rows.entries()) {
|
|
3184
|
+
const depth = depths2[i];
|
|
3185
|
+
bands.push([along, along + depth]);
|
|
3186
|
+
for (const node of row) {
|
|
3187
|
+
slots.set(node.id, { cross: crossAt.get(node.id), rank: rankAt.get(node.id) ?? along + (depth - extent(node.bounds, axes.rank)) / 2 });
|
|
3188
|
+
}
|
|
3189
|
+
along += depth + (gaps[i] ?? 0);
|
|
3190
|
+
}
|
|
3191
|
+
const placed = /* @__PURE__ */ new Map();
|
|
3192
|
+
for (const node of graph.nodes) {
|
|
3193
|
+
const slot = slots.get(node.id);
|
|
3194
|
+
if (slot !== void 0) placed.set(node.id, worldOf(slot, extent(node.bounds, axes.rank), axes));
|
|
3195
|
+
}
|
|
3196
|
+
const moves = translated(graph, placed, pinned, opts.tolerance);
|
|
3197
|
+
const offset = anchorOffset(graph, placed, pinned);
|
|
3198
|
+
const displaced = /* @__PURE__ */ new Set();
|
|
3199
|
+
for (const id of pinned) {
|
|
3200
|
+
const at2 = placed.get(id);
|
|
3201
|
+
const node = graph.node(id);
|
|
3202
|
+
if (at2 === void 0 || node === void 0) continue;
|
|
3203
|
+
if (Math.abs(at2.x + offset.x - node.bounds.x) > 0.5 || Math.abs(at2.y + offset.y - node.bounds.y) > 0.5) displaced.add(id);
|
|
3204
|
+
}
|
|
3205
|
+
const waypoints = /* @__PURE__ */ new Map();
|
|
3206
|
+
const labels = /* @__PURE__ */ new Map();
|
|
3207
|
+
const rankOf = /* @__PURE__ */ new Map();
|
|
3208
|
+
rows.forEach((row, r) => row.forEach((n) => rankOf.set(n.id, r)));
|
|
3209
|
+
const reach = boxReach(graph, rows, axes);
|
|
3210
|
+
const widthOf = new Map(rows.flat().map((n) => [n.id, extent(n.bounds, axes.cross)]));
|
|
3211
|
+
for (const [edge, chain2] of expanded.chains) {
|
|
3212
|
+
if (chain2.ends.some((id) => displaced.has(id))) continue;
|
|
3213
|
+
const beside = chain2.ids.indexOf(expanded.labels.get(edge) ?? "");
|
|
3214
|
+
const points = [];
|
|
3215
|
+
for (const id of chain2.ids) {
|
|
3216
|
+
const cross = crossAt.get(id) + (expanded.wires.get(id) ?? widthOf.get(id) / 2);
|
|
3217
|
+
const r = rankOf.get(id);
|
|
3218
|
+
const [lo, hi] = [bands[r][0] - reach.lo[r], bands[r][1] + reach.hi[r]];
|
|
3219
|
+
for (const rank of chain2.back ? [hi, lo] : [lo, hi]) {
|
|
3220
|
+
const at2 = worldOf({ cross, rank }, 0, axes);
|
|
3221
|
+
points.push({ x: at2.x + offset.x, y: at2.y + offset.y });
|
|
3222
|
+
}
|
|
3223
|
+
}
|
|
3224
|
+
waypoints.set(edge, points);
|
|
3225
|
+
if (beside >= 0) {
|
|
3226
|
+
const [a, b] = [points[beside * 2], points[beside * 2 + 1]];
|
|
3227
|
+
labels.set(edge, { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 });
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
const ports = layeredPorts(graph, ranks, opts.direction);
|
|
3231
|
+
const boxes = new Map(graph.nodes.map((n) => [n.id, { ...n.bounds, ...moves.get(n.id) }]));
|
|
3232
|
+
const level = levelRoutes({ graph, boxes, axes, rankGap, ...opts.direction !== void 0 ? { direction: opts.direction } : {} });
|
|
3233
|
+
for (const [edge, named2] of level.ports) {
|
|
3234
|
+
ports.set(edge, named2);
|
|
3235
|
+
waypoints.delete(edge);
|
|
3236
|
+
labels.delete(edge);
|
|
3237
|
+
}
|
|
3238
|
+
for (const [edge, points] of level.waypoints) waypoints.set(edge, points);
|
|
3239
|
+
return { moves, ranks, back, waypoints, labels, ports, unheld };
|
|
3240
|
+
}
|
|
3241
|
+
|
|
3242
|
+
// src/layered.ts
|
|
3243
|
+
var layered = Object.assign(
|
|
3244
|
+
(graph, opts = {}) => layeredPlan(graph, opts).moves,
|
|
3245
|
+
{ plan: layeredPlan }
|
|
3246
|
+
);
|
|
3247
|
+
|
|
3248
|
+
// src/forceGroups.ts
|
|
3249
|
+
function resolve(groups, byId) {
|
|
3250
|
+
const out = [];
|
|
3251
|
+
for (const group of groups) {
|
|
3252
|
+
const members = group.members.map((id) => byId.get(id)).filter((b) => b !== void 0);
|
|
3253
|
+
if (members.length > 0) out.push({ members, group, children: [] });
|
|
3254
|
+
}
|
|
3255
|
+
const byGroup = new Map(out.map((g) => [g.group.id, g]));
|
|
3256
|
+
for (const g of out) {
|
|
3257
|
+
const parent = g.group.parent === void 0 ? void 0 : byGroup.get(g.group.parent);
|
|
3258
|
+
if (parent === void 0) continue;
|
|
3259
|
+
g.parent = parent;
|
|
3260
|
+
parent.children.push(g);
|
|
3261
|
+
}
|
|
3262
|
+
return out;
|
|
3263
|
+
}
|
|
3264
|
+
function groupCohesion(groups, byId, strength) {
|
|
3265
|
+
const resolved = resolve(groups, byId);
|
|
3266
|
+
return (alpha) => {
|
|
3267
|
+
for (const { members } of resolved) {
|
|
3268
|
+
let cx = 0;
|
|
3269
|
+
let cy = 0;
|
|
3270
|
+
for (const m of members) {
|
|
3271
|
+
cx += m.x;
|
|
3272
|
+
cy += m.y;
|
|
3273
|
+
}
|
|
3274
|
+
cx /= members.length;
|
|
3275
|
+
cy /= members.length;
|
|
3276
|
+
for (const m of members) {
|
|
3277
|
+
m.vx += (cx - m.x) * strength * alpha;
|
|
3278
|
+
m.vy += (cy - m.y) * strength * alpha;
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3281
|
+
};
|
|
3282
|
+
}
|
|
3283
|
+
function boxOf(g) {
|
|
3284
|
+
let x0 = Infinity;
|
|
3285
|
+
let y0 = Infinity;
|
|
3286
|
+
let x1 = -Infinity;
|
|
3287
|
+
let y1 = -Infinity;
|
|
3288
|
+
for (const m of g.members) {
|
|
3289
|
+
x0 = Math.min(x0, m.x - m.hw);
|
|
3290
|
+
y0 = Math.min(y0, m.y - m.hh);
|
|
3291
|
+
x1 = Math.max(x1, m.x + m.hw);
|
|
3292
|
+
y1 = Math.max(y1, m.y + m.hh);
|
|
3293
|
+
}
|
|
3294
|
+
for (const child of g.children) {
|
|
3295
|
+
const b = boxOf(child);
|
|
3296
|
+
x0 = Math.min(x0, b.x0);
|
|
3297
|
+
y0 = Math.min(y0, b.y0);
|
|
3298
|
+
x1 = Math.max(x1, b.x1);
|
|
3299
|
+
y1 = Math.max(y1, b.y1);
|
|
3300
|
+
}
|
|
3301
|
+
const { inset: inset2 } = g.group;
|
|
3302
|
+
return { x0: x0 - inset2.left, y0: y0 - inset2.top, x1: x1 + inset2.right, y1: y1 + inset2.bottom };
|
|
3303
|
+
}
|
|
3304
|
+
function clearance(a, b, padding) {
|
|
3305
|
+
const gapX = Math.min(a.x1, b.x1) - Math.max(a.x0, b.x0) + padding;
|
|
3306
|
+
const gapY = Math.min(a.y1, b.y1) - Math.max(a.y0, b.y0) + padding;
|
|
3307
|
+
if (gapX <= 0 || gapY <= 0) return null;
|
|
3308
|
+
const dx = b.x0 + b.x1 - (a.x0 + a.x1);
|
|
3309
|
+
const dy = b.y0 + b.y1 - (a.y0 + a.y1);
|
|
3310
|
+
return gapX < gapY ? { x: (Math.sign(dx) || 1) * gapX, y: 0 } : { x: 0, y: (Math.sign(dy) || 1) * gapY };
|
|
3311
|
+
}
|
|
3312
|
+
function holds(outer, inner) {
|
|
3313
|
+
for (let at2 = inner.parent; at2 !== void 0; at2 = at2.parent) {
|
|
3314
|
+
if (at2 === outer) return true;
|
|
3315
|
+
}
|
|
3316
|
+
return false;
|
|
3317
|
+
}
|
|
3318
|
+
function shove(bodies, x, y) {
|
|
3319
|
+
for (const body of bodies) {
|
|
3320
|
+
body.vx += x;
|
|
3321
|
+
body.vy += y;
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
function separateGroups(groups, bodies, byId, padding) {
|
|
3325
|
+
const resolved = resolve(groups, byId);
|
|
3326
|
+
const memberSets = resolved.map((g) => new Set(g.members));
|
|
3327
|
+
return () => {
|
|
3328
|
+
const boxes = resolved.map(boxOf);
|
|
3329
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
3330
|
+
for (let j = i + 1; j < resolved.length; j++) {
|
|
3331
|
+
if (holds(resolved[i], resolved[j]) || holds(resolved[j], resolved[i])) continue;
|
|
3332
|
+
const push = clearance(boxes[i], boxes[j], padding);
|
|
3333
|
+
if (push === null) continue;
|
|
3334
|
+
shove(resolved[i].members, -push.x / 2, -push.y / 2);
|
|
3335
|
+
shove(resolved[j].members, push.x / 2, push.y / 2);
|
|
3336
|
+
}
|
|
3337
|
+
for (const body of bodies) {
|
|
3338
|
+
if (memberSets[i].has(body)) continue;
|
|
3339
|
+
const box = { x0: body.x - body.hw, y0: body.y - body.hh, x1: body.x + body.hw, y1: body.y + body.hh };
|
|
3340
|
+
const push = clearance(boxes[i], box, padding);
|
|
3341
|
+
if (push === null) continue;
|
|
3342
|
+
shove(resolved[i].members, -push.x / 2, -push.y / 2);
|
|
3343
|
+
body.vx += push.x / 2;
|
|
3344
|
+
body.vy += push.y / 2;
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
};
|
|
3348
|
+
}
|
|
3349
|
+
|
|
3350
|
+
// src/force.ts
|
|
3351
|
+
var DEFAULTS = {
|
|
3352
|
+
iterations: 300,
|
|
3353
|
+
linkDistance: 160,
|
|
3354
|
+
linkStrength: 0.35,
|
|
3355
|
+
charge: -3e3,
|
|
3356
|
+
gravity: 0.02,
|
|
3357
|
+
padding: 24,
|
|
3358
|
+
groupStrength: 0.2
|
|
3359
|
+
};
|
|
3360
|
+
var GOLDEN = Math.PI * (3 - Math.sqrt(5));
|
|
3361
|
+
var NUDGE2 = 0.5;
|
|
3362
|
+
function charge(bodies, strength) {
|
|
3363
|
+
return (alpha) => {
|
|
3364
|
+
for (let i = 0; i < bodies.length; i++) {
|
|
3365
|
+
const a = bodies[i];
|
|
3366
|
+
for (let j = i + 1; j < bodies.length; j++) {
|
|
3367
|
+
const b = bodies[j];
|
|
3368
|
+
const dx = b.x - a.x;
|
|
3369
|
+
const dy = b.y - a.y;
|
|
3370
|
+
const d2 = dx * dx + dy * dy;
|
|
3371
|
+
if (d2 === 0) continue;
|
|
3372
|
+
const w = strength * alpha / d2;
|
|
3373
|
+
a.vx += dx * w;
|
|
3374
|
+
a.vy += dy * w;
|
|
3375
|
+
b.vx -= dx * w;
|
|
3376
|
+
b.vy -= dy * w;
|
|
3377
|
+
}
|
|
3378
|
+
}
|
|
3379
|
+
};
|
|
3380
|
+
}
|
|
3381
|
+
function links(bodies, graph, distance, strength) {
|
|
3382
|
+
return (alpha) => {
|
|
3383
|
+
for (const edge of graph.edges) {
|
|
3384
|
+
const a = bodies.get(edge.from);
|
|
3385
|
+
const b = bodies.get(edge.to);
|
|
3386
|
+
if (a === void 0 || b === void 0 || a === b) continue;
|
|
3387
|
+
const dx = b.x - a.x;
|
|
3388
|
+
const dy = b.y - a.y;
|
|
3389
|
+
const d = Math.hypot(dx, dy);
|
|
3390
|
+
if (d === 0) continue;
|
|
3391
|
+
const pull = (d - distance) / d * alpha * strength;
|
|
3392
|
+
a.vx += dx * pull;
|
|
3393
|
+
a.vy += dy * pull;
|
|
3394
|
+
b.vx -= dx * pull;
|
|
3395
|
+
b.vy -= dy * pull;
|
|
3396
|
+
}
|
|
3397
|
+
};
|
|
3398
|
+
}
|
|
3399
|
+
function separateBoxes(bodies, padding) {
|
|
3400
|
+
return () => {
|
|
3401
|
+
for (let i = 0; i < bodies.length; i++) {
|
|
3402
|
+
const a = bodies[i];
|
|
3403
|
+
for (let j = i + 1; j < bodies.length; j++) {
|
|
3404
|
+
const b = bodies[j];
|
|
3405
|
+
const dx = b.x - a.x;
|
|
3406
|
+
const dy = b.y - a.y;
|
|
3407
|
+
const gapX = a.hw + b.hw + padding - Math.abs(dx);
|
|
3408
|
+
const gapY = a.hh + b.hh + padding - Math.abs(dy);
|
|
3409
|
+
if (gapX <= 0 || gapY <= 0) continue;
|
|
3410
|
+
if (gapX < gapY) {
|
|
3411
|
+
const push = (Math.sign(dx) || 1) * gapX * 0.5;
|
|
3412
|
+
a.vx -= push;
|
|
3413
|
+
b.vx += push;
|
|
3414
|
+
} else {
|
|
3415
|
+
const push = (Math.sign(dy) || 1) * gapY * 0.5;
|
|
3416
|
+
a.vy -= push;
|
|
3417
|
+
b.vy += push;
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
};
|
|
3291
3422
|
}
|
|
3292
|
-
function
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
const ranks = ranksByLength(graph, back);
|
|
3299
|
-
const expanded = expand(graph, ranks, back, { axes, nodeGap });
|
|
3300
|
-
let rows = finding ? orderRows(expanded.rows, expanded.hops, { groups: graph.groups ?? [] }) : expanded.rows;
|
|
3301
|
-
const grouped = (graph.groups?.length ?? 0) > 0;
|
|
3302
|
-
const pinned = pinnedSet(graph, opts);
|
|
3303
|
-
const across = () => {
|
|
3304
|
-
const preferred2 = placeAcross(rows, settlePlaces(rows, expanded.hops), axes.cross, nodeGap);
|
|
3305
|
-
return grouped ? packClusters(graph, rows, preferred2, axes, nodeGap) : preferred2;
|
|
3423
|
+
function gravity(bodies, at2, strength) {
|
|
3424
|
+
return (alpha) => {
|
|
3425
|
+
for (const body of bodies) {
|
|
3426
|
+
body.vx += (at2.x - body.x) * strength * alpha;
|
|
3427
|
+
body.vy += (at2.y - body.y) * strength * alpha;
|
|
3428
|
+
}
|
|
3306
3429
|
};
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3430
|
+
}
|
|
3431
|
+
function forceRelaxation(graph, opts = {}) {
|
|
3432
|
+
const {
|
|
3433
|
+
linkDistance = DEFAULTS.linkDistance,
|
|
3434
|
+
linkStrength = DEFAULTS.linkStrength,
|
|
3435
|
+
charge: chargeStrength = DEFAULTS.charge,
|
|
3436
|
+
gravity: gravityStrength = DEFAULTS.gravity,
|
|
3437
|
+
padding = DEFAULTS.padding,
|
|
3438
|
+
groupStrength = DEFAULTS.groupStrength
|
|
3439
|
+
} = opts;
|
|
3440
|
+
const pinned = pinnedSet(graph, opts);
|
|
3441
|
+
const bodies = graph.nodes.map((node) => {
|
|
3442
|
+
const body = {
|
|
3443
|
+
id: node.id,
|
|
3444
|
+
x: center(node.bounds, "x"),
|
|
3445
|
+
y: center(node.bounds, "y"),
|
|
3446
|
+
hw: node.bounds.width / 2,
|
|
3447
|
+
hh: node.bounds.height / 2
|
|
3448
|
+
};
|
|
3449
|
+
if (pinned.has(node.id)) {
|
|
3450
|
+
body.fx = body.x;
|
|
3451
|
+
body.fy = body.y;
|
|
3329
3452
|
}
|
|
3330
|
-
|
|
3331
|
-
}
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
const
|
|
3339
|
-
const
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
points.push({ x: at2.x + offset.x, y: at2.y + offset.y });
|
|
3453
|
+
return body;
|
|
3454
|
+
});
|
|
3455
|
+
separate(bodies);
|
|
3456
|
+
const byId = new Map(bodies.map((b) => [b.id, b]));
|
|
3457
|
+
const centroid = {
|
|
3458
|
+
x: bodies.reduce((sum, b) => sum + b.x, 0) / bodies.length,
|
|
3459
|
+
y: bodies.reduce((sum, b) => sum + b.y, 0) / bodies.length
|
|
3460
|
+
};
|
|
3461
|
+
const groups = graph.groups ?? [];
|
|
3462
|
+
const sim = createSimulation({
|
|
3463
|
+
nodes: bodies,
|
|
3464
|
+
forces: [
|
|
3465
|
+
charge(bodies, chargeStrength),
|
|
3466
|
+
links(byId, graph, linkDistance, linkStrength),
|
|
3467
|
+
gravity(bodies, centroid, gravityStrength),
|
|
3468
|
+
separateBoxes(bodies, padding),
|
|
3469
|
+
...groups.length > 0 ? [groupCohesion(groups, byId, groupStrength), separateGroups(groups, bodies, byId, padding)] : []
|
|
3470
|
+
]
|
|
3471
|
+
});
|
|
3472
|
+
return {
|
|
3473
|
+
bodies,
|
|
3474
|
+
byId,
|
|
3475
|
+
pinned,
|
|
3476
|
+
sim,
|
|
3477
|
+
placed() {
|
|
3478
|
+
const placed = /* @__PURE__ */ new Map();
|
|
3479
|
+
for (const node of graph.nodes) {
|
|
3480
|
+
const body = byId.get(node.id);
|
|
3481
|
+
placed.set(node.id, {
|
|
3482
|
+
x: body.x - node.bounds.width / 2,
|
|
3483
|
+
y: body.y - node.bounds.height / 2
|
|
3484
|
+
});
|
|
3363
3485
|
}
|
|
3486
|
+
return placed;
|
|
3364
3487
|
}
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3488
|
+
};
|
|
3489
|
+
}
|
|
3490
|
+
var force = (graph, opts = {}) => {
|
|
3491
|
+
if (graph.nodes.length === 0) return /* @__PURE__ */ new Map();
|
|
3492
|
+
const relaxation = forceRelaxation(graph, opts);
|
|
3493
|
+
relaxation.sim.tick(opts.iterations ?? DEFAULTS.iterations);
|
|
3494
|
+
return translated(graph, relaxation.placed(), relaxation.pinned, opts.tolerance);
|
|
3495
|
+
};
|
|
3496
|
+
function separate(bodies) {
|
|
3497
|
+
const seen = /* @__PURE__ */ new Map();
|
|
3498
|
+
bodies.forEach((body, i) => {
|
|
3499
|
+
const key = `${body.x},${body.y}`;
|
|
3500
|
+
const nth = seen.get(key) ?? 0;
|
|
3501
|
+
seen.set(key, nth + 1);
|
|
3502
|
+
if (nth === 0 || body.fx != null || body.fy != null) return;
|
|
3503
|
+
const angle = GOLDEN * i;
|
|
3504
|
+
const radius = NUDGE2 * nth;
|
|
3505
|
+
body.x += Math.cos(angle) * radius;
|
|
3506
|
+
body.y += Math.sin(angle) * radius;
|
|
3507
|
+
});
|
|
3381
3508
|
}
|
|
3382
|
-
|
|
3383
|
-
// src/layered.ts
|
|
3384
|
-
var layered = Object.assign(
|
|
3385
|
-
(graph, opts = {}) => layeredPlan(graph, opts).moves,
|
|
3386
|
-
{ plan: layeredPlan }
|
|
3387
|
-
);
|
|
3388
3509
|
|
|
3389
3510
|
// src/chainGroups.ts
|
|
3390
3511
|
function depths(groups) {
|
|
@@ -3446,8 +3567,8 @@ function nearest(members, from, index) {
|
|
|
3446
3567
|
}
|
|
3447
3568
|
return best;
|
|
3448
3569
|
}
|
|
3449
|
-
function clearColumns(graph, ordered, index, owner,
|
|
3450
|
-
const level = new Map(
|
|
3570
|
+
function clearColumns(graph, ordered, index, owner, start2) {
|
|
3571
|
+
const level = new Map(start2);
|
|
3451
3572
|
const columns = /* @__PURE__ */ new Map();
|
|
3452
3573
|
for (const node of graph.nodes) {
|
|
3453
3574
|
if (index.has(node.id)) continue;
|
|
@@ -3482,19 +3603,19 @@ function lineGaps(graph, line, hanging, rankGap, axes, packed) {
|
|
|
3482
3603
|
return bandGaps(graph, columns, axes, columns.slice(1).map(() => rankGap), (id) => packed.get(id)?.rank);
|
|
3483
3604
|
}
|
|
3484
3605
|
function levelGaps(graph, hanging, levelSize, axes, before, base) {
|
|
3485
|
-
const
|
|
3486
|
-
for (const node of graph.nodes) (
|
|
3606
|
+
const levels2 = Array.from(levelSize, () => []);
|
|
3607
|
+
for (const node of graph.nodes) (levels2[hanging.level.get(node.id)] ??= []).push(node);
|
|
3487
3608
|
const outward = { rank: axes.cross, cross: axes.rank, sign: before ? -1 : 1 };
|
|
3488
3609
|
const from = [0];
|
|
3489
3610
|
for (let k = 1; k < levelSize.length; k++) from[k] = from[k - 1] + (levelSize[k - 1] ?? 0);
|
|
3490
|
-
return bandGaps(graph,
|
|
3611
|
+
return bandGaps(graph, levels2, outward, base, (id) => {
|
|
3491
3612
|
const node = graph.node(id);
|
|
3492
3613
|
const at2 = hanging.level.get(id);
|
|
3493
3614
|
if (node === void 0 || at2 === void 0) return void 0;
|
|
3494
3615
|
return at2 === 0 ? (levelSize[0] - extent(node.bounds, outward.rank)) / 2 : from[at2];
|
|
3495
3616
|
});
|
|
3496
3617
|
}
|
|
3497
|
-
function bandGaps(graph, bands, axes, gaps,
|
|
3618
|
+
function bandGaps(graph, bands, axes, gaps, start2) {
|
|
3498
3619
|
const insets = rankGaps(graph, bands, axes, 0);
|
|
3499
3620
|
const out = gaps.map((gap, i) => gap + (insets[i] ?? 0));
|
|
3500
3621
|
const groups = graph.groups ?? [];
|
|
@@ -3507,7 +3628,7 @@ function bandGaps(graph, bands, axes, gaps, start) {
|
|
|
3507
3628
|
const span = (id, now) => {
|
|
3508
3629
|
let [lo, hi] = [Infinity, -Infinity];
|
|
3509
3630
|
for (const m of byId.get(id).members) {
|
|
3510
|
-
const at2 =
|
|
3631
|
+
const at2 = start2(m);
|
|
3511
3632
|
const band = bandOf.get(m);
|
|
3512
3633
|
const node = graph.node(m);
|
|
3513
3634
|
if (at2 === void 0 || band === void 0 || node === void 0) continue;
|
|
@@ -3517,7 +3638,7 @@ function bandGaps(graph, bands, axes, gaps, start) {
|
|
|
3517
3638
|
return { lo, hi };
|
|
3518
3639
|
};
|
|
3519
3640
|
widenForMinWidth(deepestFirst(groups).map((g) => {
|
|
3520
|
-
const placed = g.members.flatMap((id) => bandOf.has(id) &&
|
|
3641
|
+
const placed = g.members.flatMap((id) => bandOf.has(id) && start2(id) !== void 0 ? [bandOf.get(id)] : []);
|
|
3521
3642
|
return {
|
|
3522
3643
|
id: g.id,
|
|
3523
3644
|
...g.minWidth !== void 0 ? { minWidth: g.minWidth } : {},
|
|
@@ -3589,8 +3710,8 @@ function sidesOf2(graph, hanging, moves, axes, before) {
|
|
|
3589
3710
|
return byLine;
|
|
3590
3711
|
}
|
|
3591
3712
|
var SIDE_TRACK_GAP = 12;
|
|
3592
|
-
function turning(
|
|
3593
|
-
const sideways =
|
|
3713
|
+
function turning(sides2) {
|
|
3714
|
+
const sideways = sides2.filter((s) => Math.abs(s.hung - s.port) > 0.5);
|
|
3594
3715
|
return [
|
|
3595
3716
|
sideways.filter((s) => s.hung < s.port).sort((a, b) => a.port - b.port),
|
|
3596
3717
|
sideways.filter((s) => s.hung > s.port).sort((a, b) => b.port - a.port)
|
|
@@ -3598,18 +3719,18 @@ function turning(sides) {
|
|
|
3598
3719
|
}
|
|
3599
3720
|
function tracksNeeded(graph, hanging, moves, axes, before) {
|
|
3600
3721
|
let most = 0;
|
|
3601
|
-
for (const
|
|
3602
|
-
const [low, high] = turning(
|
|
3722
|
+
for (const sides2 of sidesOf2(graph, hanging, moves, axes, before).values()) {
|
|
3723
|
+
const [low, high] = turning(sides2);
|
|
3603
3724
|
most = Math.max(most, low.length, high.length);
|
|
3604
3725
|
}
|
|
3605
3726
|
return most;
|
|
3606
3727
|
}
|
|
3607
3728
|
function sideRoutes(graph, hanging, moves, axes, before) {
|
|
3608
3729
|
const out = /* @__PURE__ */ new Map();
|
|
3609
|
-
for (const
|
|
3610
|
-
const [low, high] = turning(
|
|
3611
|
-
const lineEdge =
|
|
3612
|
-
const hungEdge = before ? Math.max(...
|
|
3730
|
+
for (const sides2 of sidesOf2(graph, hanging, moves, axes, before).values()) {
|
|
3731
|
+
const [low, high] = turning(sides2);
|
|
3732
|
+
const lineEdge = sides2[0].lineEdge;
|
|
3733
|
+
const hungEdge = before ? Math.max(...sides2.map((s) => s.hungEdge)) : Math.min(...sides2.map((s) => s.hungEdge));
|
|
3613
3734
|
const step = (hungEdge - lineEdge) / (Math.max(low.length, high.length) + 1);
|
|
3614
3735
|
for (const run of [low, high]) {
|
|
3615
3736
|
run.forEach((s, k) => {
|
|
@@ -3661,12 +3782,12 @@ function lineOf(graph, ids) {
|
|
|
3661
3782
|
if (given.length > 0) return given;
|
|
3662
3783
|
const back = backEdges(graph);
|
|
3663
3784
|
const ranks = ranksOf(graph, back);
|
|
3664
|
-
let
|
|
3785
|
+
let end2;
|
|
3665
3786
|
for (const node of graph.nodes) {
|
|
3666
|
-
if (
|
|
3787
|
+
if (end2 === void 0 || ranks.get(node.id) > ranks.get(end2.id)) end2 = node;
|
|
3667
3788
|
}
|
|
3668
3789
|
const line = [];
|
|
3669
|
-
for (let at2 =
|
|
3790
|
+
for (let at2 = end2; at2 !== void 0; ) {
|
|
3670
3791
|
line.unshift(at2);
|
|
3671
3792
|
const rank = ranks.get(at2.id);
|
|
3672
3793
|
const edge = graph.incoming(at2.id).find((e) => !back.has(e.id) && ranks.get(e.from) === rank - 1);
|
|
@@ -3728,10 +3849,10 @@ function chainPlan(graph, opts = {}) {
|
|
|
3728
3849
|
};
|
|
3729
3850
|
const slots = (rank, level2) => slotsFor(line, rows, levelSize, axes, { node: nodeGap, rank, level: level2 }, before);
|
|
3730
3851
|
const gaps = grouped ? lineGaps(graph, line, hanging, rankGap, axes, slots(line.map(() => 0), [])) : line.map(() => rankGap);
|
|
3731
|
-
const
|
|
3732
|
-
let moves =
|
|
3852
|
+
const place2 = (side2) => settle(graph, slots(gaps, across(side2)), opts);
|
|
3853
|
+
let moves = place2(nodeGap);
|
|
3733
3854
|
const side = (tracksNeeded(graph, hanging, moves, axes, before) + 1) * SIDE_TRACK_GAP;
|
|
3734
|
-
if (side > nodeGap) moves =
|
|
3855
|
+
if (side > nodeGap) moves = place2(side);
|
|
3735
3856
|
return { moves, waypoints: sideRoutes(graph, hanging, moves, axes, before) };
|
|
3736
3857
|
}
|
|
3737
3858
|
function slotsFor(line, rows, levelSize, axes, gaps, before) {
|
|
@@ -3766,6 +3887,97 @@ function slotsFor(line, rows, levelSize, axes, gaps, before) {
|
|
|
3766
3887
|
return slots;
|
|
3767
3888
|
}
|
|
3768
3889
|
|
|
3890
|
+
// src/grid.ts
|
|
3891
|
+
function levels(graph) {
|
|
3892
|
+
const order = graphOrder(graph);
|
|
3893
|
+
const groups = graph.groups ?? [];
|
|
3894
|
+
const first = new Map(groups.map((g) => [g.id, Math.min(...g.members.map(order))]));
|
|
3895
|
+
const at2 = (id) => first.get(id) ?? order(id);
|
|
3896
|
+
const out = /* @__PURE__ */ new Map();
|
|
3897
|
+
const add = (level, id) => out.set(level, [...out.get(level) ?? [], id]);
|
|
3898
|
+
for (const n of graph.nodes) add(n.group ?? null, n.id);
|
|
3899
|
+
for (const g of groups) add(g.parent ?? null, g.id);
|
|
3900
|
+
for (const ids of out.values()) ids.sort((a, b) => at2(a) - at2(b));
|
|
3901
|
+
return out;
|
|
3902
|
+
}
|
|
3903
|
+
function deal(ids, sizeOf, columns, grid2) {
|
|
3904
|
+
const items = [];
|
|
3905
|
+
let row = 0;
|
|
3906
|
+
let col = 0;
|
|
3907
|
+
for (const id of ids) {
|
|
3908
|
+
col += Math.max(0, Math.floor(grid2.skips?.[id] ?? 0));
|
|
3909
|
+
row += Math.floor(col / columns);
|
|
3910
|
+
col %= columns;
|
|
3911
|
+
const span = Math.min(columns, Math.max(1, Math.floor(grid2.spans?.[id] ?? 1)));
|
|
3912
|
+
if (col + span > columns) {
|
|
3913
|
+
row++;
|
|
3914
|
+
col = 0;
|
|
3915
|
+
}
|
|
3916
|
+
items.push({ id, size: sizeOf(id), row, col, span });
|
|
3917
|
+
col += span;
|
|
3918
|
+
}
|
|
3919
|
+
return { items, columns };
|
|
3920
|
+
}
|
|
3921
|
+
function place(cells, gap, rowGap) {
|
|
3922
|
+
const width = Math.max(0, ...cells.items.map((i) => (i.size.width - (i.span - 1) * gap) / i.span));
|
|
3923
|
+
const rows = [];
|
|
3924
|
+
for (const i of cells.items) rows[i.row] = Math.max(rows[i.row] ?? 0, i.size.height);
|
|
3925
|
+
const tops = [];
|
|
3926
|
+
let y = 0;
|
|
3927
|
+
for (let r = 0; r < rows.length; r++) {
|
|
3928
|
+
tops[r] = y;
|
|
3929
|
+
y += (rows[r] ?? 0) + rowGap;
|
|
3930
|
+
}
|
|
3931
|
+
const at2 = /* @__PURE__ */ new Map();
|
|
3932
|
+
for (const i of cells.items) {
|
|
3933
|
+
const across = i.span * width + (i.span - 1) * gap;
|
|
3934
|
+
at2.set(i.id, { x: i.col * (width + gap) + (across - i.size.width) / 2, y: tops[i.row] + ((rows[i.row] ?? 0) - i.size.height) / 2 });
|
|
3935
|
+
}
|
|
3936
|
+
const used = Math.max(0, ...cells.items.map((i) => i.col + i.span));
|
|
3937
|
+
return { at: at2, size: { width: used === 0 ? 0 : used * width + (used - 1) * gap, height: rows.length === 0 ? 0 : y - rowGap } };
|
|
3938
|
+
}
|
|
3939
|
+
var grid = (graph, opts = {}) => {
|
|
3940
|
+
const gap = opts.nodeGap ?? DEFAULT_NODE_GAP;
|
|
3941
|
+
const rowGap = opts.rankGap ?? gap;
|
|
3942
|
+
const spec = opts.grid ?? {};
|
|
3943
|
+
const byLevel = levels(graph);
|
|
3944
|
+
const groups = new Map((graph.groups ?? []).map((g) => [g.id, g]));
|
|
3945
|
+
const inner = /* @__PURE__ */ new Map();
|
|
3946
|
+
const sizeOf = (id) => {
|
|
3947
|
+
const g = groups.get(id);
|
|
3948
|
+
if (g === void 0) return graph.node(id).bounds;
|
|
3949
|
+
const laid = layOut(id);
|
|
3950
|
+
return {
|
|
3951
|
+
width: Math.max(g.minWidth ?? 0, laid.size.width + g.inset.left + g.inset.right),
|
|
3952
|
+
height: laid.size.height + g.inset.top + g.inset.bottom
|
|
3953
|
+
};
|
|
3954
|
+
};
|
|
3955
|
+
const layOut = (level) => {
|
|
3956
|
+
const done = level === null ? void 0 : inner.get(level);
|
|
3957
|
+
if (done !== void 0) return done;
|
|
3958
|
+
const ids = byLevel.get(level) ?? [];
|
|
3959
|
+
const columns = Math.max(1, Math.floor((level === null ? spec.columns : spec.groupColumns?.[level]) ?? ids.length));
|
|
3960
|
+
const laid = place(deal(ids, sizeOf, columns, spec), gap, rowGap);
|
|
3961
|
+
if (level !== null) inner.set(level, laid);
|
|
3962
|
+
return laid;
|
|
3963
|
+
};
|
|
3964
|
+
const placed = /* @__PURE__ */ new Map();
|
|
3965
|
+
const put = (level, origin) => {
|
|
3966
|
+
for (const [id, p] of layOut(level).at) {
|
|
3967
|
+
const corner = { x: origin.x + p.x, y: origin.y + p.y };
|
|
3968
|
+
const g = groups.get(id);
|
|
3969
|
+
if (g === void 0) {
|
|
3970
|
+
placed.set(id, corner);
|
|
3971
|
+
continue;
|
|
3972
|
+
}
|
|
3973
|
+
const slack = sizeOf(id).width - (inner.get(id).size.width + g.inset.left + g.inset.right);
|
|
3974
|
+
put(id, { x: corner.x + g.inset.left + slack / 2, y: corner.y + g.inset.top });
|
|
3975
|
+
}
|
|
3976
|
+
};
|
|
3977
|
+
put(null, { x: 0, y: 0 });
|
|
3978
|
+
return translated(graph, placed, pinnedSet(graph, opts), opts.tolerance);
|
|
3979
|
+
};
|
|
3980
|
+
|
|
3769
3981
|
// src/tree.ts
|
|
3770
3982
|
function forestOf(graph, crossAxis) {
|
|
3771
3983
|
const order = graphOrder(graph);
|
|
@@ -3866,6 +4078,94 @@ var treeOnce = (graph, opts = {}) => {
|
|
|
3866
4078
|
return settle(graph, slots, opts);
|
|
3867
4079
|
};
|
|
3868
4080
|
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
4081
|
+
// src/radial.ts
|
|
4082
|
+
var radial = (graph, opts = {}) => {
|
|
4083
|
+
const nodeGap = opts.nodeGap ?? DEFAULT_NODE_GAP;
|
|
4084
|
+
const rankGap = opts.rankGap ?? DEFAULT_RANK_GAP;
|
|
4085
|
+
const { roots, children } = forestOf(graph, "y");
|
|
4086
|
+
const blocks = subtreeBlocks(children, "y", nodeGap);
|
|
4087
|
+
const order = graphOrder(graph);
|
|
4088
|
+
const placed = /* @__PURE__ */ new Map();
|
|
4089
|
+
let top = 0;
|
|
4090
|
+
for (const root of roots) {
|
|
4091
|
+
const tree2 = mindMap(root, children, order, blocks, nodeGap, rankGap);
|
|
4092
|
+
for (const [id, p] of tree2.at) placed.set(id, { x: p.x, y: p.y - tree2.top + top });
|
|
4093
|
+
top += tree2.bottom - tree2.top + nodeGap;
|
|
4094
|
+
}
|
|
4095
|
+
return translated(graph, placed, pinnedSet(graph, opts), opts.tolerance);
|
|
4096
|
+
};
|
|
4097
|
+
function mindMap(root, children, order, blocks, nodeGap, rankGap) {
|
|
4098
|
+
const at2 = /* @__PURE__ */ new Map([[root.id, { x: -root.bounds.width / 2, y: -root.bounds.height / 2 }]]);
|
|
4099
|
+
let top = -root.bounds.height / 2;
|
|
4100
|
+
let bottom = root.bounds.height / 2;
|
|
4101
|
+
const [right, left] = sides(root, children, order);
|
|
4102
|
+
for (const [sign, branches] of [[1, right], [-1, left]]) {
|
|
4103
|
+
if (branches.length === 0) continue;
|
|
4104
|
+
const span = branches.reduce((sum, b) => sum + blocks.span(b), 0) + (branches.length - 1) * nodeGap;
|
|
4105
|
+
const ys = /* @__PURE__ */ new Map();
|
|
4106
|
+
let cursor = -span / 2;
|
|
4107
|
+
for (const branch of branches) {
|
|
4108
|
+
blocks.lay(branch, cursor, ys);
|
|
4109
|
+
cursor += blocks.span(branch) + nodeGap;
|
|
4110
|
+
}
|
|
4111
|
+
top = Math.min(top, -span / 2);
|
|
4112
|
+
bottom = Math.max(bottom, span / 2);
|
|
4113
|
+
for (const [id, x] of sideColumns(branches, children, root.bounds.width / 2 + rankGap, rankGap, sign)) {
|
|
4114
|
+
at2.set(id, { x, y: ys.get(id) });
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
return { at: at2, top, bottom };
|
|
4118
|
+
}
|
|
4119
|
+
function sides(root, children, order) {
|
|
4120
|
+
const weight = (node) => 1 + (children.get(node.id) ?? []).reduce((sum, k) => sum + weight(k), 0);
|
|
4121
|
+
const kids = children.get(root.id) ?? [];
|
|
4122
|
+
const half = root.bounds.width / 2;
|
|
4123
|
+
const mid = root.bounds.x + half;
|
|
4124
|
+
const standing = (k) => {
|
|
4125
|
+
const c = k.bounds.x + k.bounds.width / 2 - mid;
|
|
4126
|
+
return c > half ? 1 : c < -half ? -1 : 0;
|
|
4127
|
+
};
|
|
4128
|
+
const stands = new Map(kids.map((k) => [k, standing(k)]));
|
|
4129
|
+
const arranged = [...stands.values()].includes(1) && [...stands.values()].includes(-1);
|
|
4130
|
+
const right = /* @__PURE__ */ new Set();
|
|
4131
|
+
let r = 0;
|
|
4132
|
+
let l = 0;
|
|
4133
|
+
const dealt = arranged ? kids.filter((k) => stands.get(k) !== 0) : [];
|
|
4134
|
+
for (const k of dealt) {
|
|
4135
|
+
if (stands.get(k) === 1) {
|
|
4136
|
+
right.add(k);
|
|
4137
|
+
r += weight(k);
|
|
4138
|
+
} else l += weight(k);
|
|
4139
|
+
}
|
|
4140
|
+
for (const child of kids.filter((k) => !dealt.includes(k)).sort((a, b) => order(a.id) - order(b.id))) {
|
|
4141
|
+
const w = weight(child);
|
|
4142
|
+
if (r <= l) {
|
|
4143
|
+
right.add(child);
|
|
4144
|
+
r += w;
|
|
4145
|
+
} else l += w;
|
|
4146
|
+
}
|
|
4147
|
+
return [kids.filter((k) => right.has(k)), kids.filter((k) => !right.has(k))];
|
|
4148
|
+
}
|
|
4149
|
+
function sideColumns(branches, children, from, rankGap, sign) {
|
|
4150
|
+
const rows = [];
|
|
4151
|
+
const visit = (node, depth) => {
|
|
4152
|
+
(rows[depth] ??= []).push(node);
|
|
4153
|
+
for (const kid of children.get(node.id) ?? []) visit(kid, depth + 1);
|
|
4154
|
+
};
|
|
4155
|
+
for (const branch of branches) visit(branch, 0);
|
|
4156
|
+
const xs = /* @__PURE__ */ new Map();
|
|
4157
|
+
let start2 = from;
|
|
4158
|
+
for (const row of rows) {
|
|
4159
|
+
const band = Math.max(...row.map((n) => n.bounds.width));
|
|
4160
|
+
for (const node of row) {
|
|
4161
|
+
const near = start2 + (band - node.bounds.width) / 2;
|
|
4162
|
+
xs.set(node.id, sign === 1 ? near : -near - node.bounds.width);
|
|
4163
|
+
}
|
|
4164
|
+
start2 += band + rankGap;
|
|
4165
|
+
}
|
|
4166
|
+
return xs;
|
|
4167
|
+
}
|
|
4168
|
+
|
|
4169
|
+
export { COMPASS, DEFAULT_GROUP_INSET, DEFAULT_NODE_GAP, DEFAULT_PORTS, DEFAULT_RANK_GAP, DEVICE_SIZE, DIAGRAM_TRAIT_KEY, DIVIDER_HEIGHT, EVENT_SIZE, GATEWAY_SIZE, PORT_LABEL_GAP, SIDE_TRACK_GAP, anchorOffset, authoredOver, axesFor, backEdges, bodyOutline, bodyTrait, boxForContent, buildBody, canvasMeasure, center, chain, contentBox, createDiagramNodes, dataKeyReader, diagramEdgeOf, diagramNodeOf, expandGroupEdges, extent, footprintNode, force, forceRelaxation, forestOf, graphOrder, grid, grownBy, insetOf, isPinned, isPromise, labelCenter, labelSpotAt, layered, layeredPlan, layeredRoutes, layoutBody, layoutOwnsPort, layoutOwnsRoute, layoutRowPorts, layoutWritesRoute, marginOf, measureBody, outlineDetail, outlineFromD, outlinePath, outlinePolyline, outlineSolid, packAcross, packClusters, pinnedSet, planOf, plannerPlan, portLabelBox, portLabelsOf, portOf, portSitesOf, portsOf, portsOnOutline, radial, rankGaps, ranksByLength, ranksOf, rayHit, registerOutline, resolveOutline, routeHolds, rowHeights, samePoints, seededOrder, settle, sizeToBody, subpathOf, subtreeBlocks, translated, tree, untilSettled, widenForMinWidth };
|
|
4170
|
+
//# sourceMappingURL=chunk-7BV2MBED.js.map
|
|
4171
|
+
//# sourceMappingURL=chunk-7BV2MBED.js.map
|