@weasel-js/diagram 1.9.3 → 1.10.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/README.md +2 -2
- package/dist/{chunk-ERT3XWBS.js → chunk-BWQJYEA3.js} +241 -66
- package/dist/chunk-BWQJYEA3.js.map +1 -0
- package/dist/index.d.ts +132 -161
- package/dist/index.js +168 -51
- package/dist/index.js.map +1 -1
- package/dist/layout.d.ts +2 -1
- package/dist/{layout.entry-KHbx5uGC.d.ts → layout.entry-CIdRpG2i.d.ts} +74 -103
- package/dist/layout.js +1 -1
- package/package.json +6 -3
- package/dist/chunk-ERT3XWBS.js.map +0 -1
package/README.md
CHANGED
|
@@ -129,7 +129,7 @@ without a canvas. The layout defaults to `layered`, picked by name or passed as
|
|
|
129
129
|
any `LayoutFn`; `layoutOptions` merge over `order: 'barycenter'`, and
|
|
130
130
|
`'none'` leaves every node at its `at`.
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
The data owns the
|
|
133
133
|
diagram: a new `specs` array is reconciled into the scene the view already
|
|
134
134
|
holds (`reconcileSpecs` in core), so the view, the pick and anything moved
|
|
135
135
|
since survive it. Editing reports rather than writes —
|
|
@@ -157,7 +157,7 @@ readable; the rest is a pan away.
|
|
|
157
157
|
|
|
158
158
|
## Design notes
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
Decisions the code cannot explain on its own.
|
|
161
161
|
|
|
162
162
|
**`dependsOn: 'children'` is deliberately absent from the reverse dependents
|
|
163
163
|
index.** Deleting a node deletes everything that names it in `dependsOn`, and a
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { rectPath, polygonFromPoints, PathBuilder, PATH_M, PATH_L, PATH_C, flattenCubic, PATH_Q, PATH_Z, AUTO_POSE_DESCRIPTOR, rotatePoint
|
|
2
|
-
import { cssFamilyName } from '@weasel-js/
|
|
1
|
+
import { rectPath, polygonFromPoints, PathBuilder, PATH_M, PATH_L, PATH_C, flattenCubic, PATH_Q, PATH_Z, AUTO_POSE_DESCRIPTOR, rotatePoint } from '@weasel-js/core/math';
|
|
2
|
+
import { cssFamilyName } from '@weasel-js/font';
|
|
3
|
+
import { createSimulation } from '@weasel-js/simulation';
|
|
3
4
|
|
|
4
5
|
// src/outline.ts
|
|
5
6
|
var LEAN = 0.2;
|
|
@@ -487,6 +488,30 @@ function settle(graph, slots, opts = {}) {
|
|
|
487
488
|
}
|
|
488
489
|
return translated(graph, placed, pinned, tolerance);
|
|
489
490
|
}
|
|
491
|
+
function untilSettled(once, graph, opts = {}, passes = 8) {
|
|
492
|
+
const first = once(graph, opts);
|
|
493
|
+
if (first.size === 0) return first;
|
|
494
|
+
const at = new Map(first);
|
|
495
|
+
for (let pass = 1; pass < passes; pass++) {
|
|
496
|
+
const nodes = graph.nodes.map((node) => {
|
|
497
|
+
const to = at.get(node.id);
|
|
498
|
+
return to === void 0 ? node : { ...node, bounds: { ...node.bounds, x: to.x, y: to.y } };
|
|
499
|
+
});
|
|
500
|
+
const byId = new Map(nodes.map((n) => [n.id, n]));
|
|
501
|
+
const next = once({ ...graph, nodes, node: (id) => byId.get(id) }, opts);
|
|
502
|
+
if (next.size === 0) break;
|
|
503
|
+
for (const [id, to] of next) at.set(id, to);
|
|
504
|
+
}
|
|
505
|
+
const tolerance = opts.tolerance ?? DEFAULT_TOLERANCE;
|
|
506
|
+
const out = /* @__PURE__ */ new Map();
|
|
507
|
+
for (const node of graph.nodes) {
|
|
508
|
+
const to = at.get(node.id);
|
|
509
|
+
if (to === void 0) continue;
|
|
510
|
+
if (Math.abs(to.x - node.bounds.x) <= tolerance && Math.abs(to.y - node.bounds.y) <= tolerance) continue;
|
|
511
|
+
out.set(node.id, to);
|
|
512
|
+
}
|
|
513
|
+
return out;
|
|
514
|
+
}
|
|
490
515
|
function translated(graph, placed, pinned, tolerance = DEFAULT_TOLERANCE) {
|
|
491
516
|
const anchor = anchorDelta(graph, placed, pinned);
|
|
492
517
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -565,10 +590,14 @@ function rankGaps(graph, rows, axes, rankGap) {
|
|
|
565
590
|
const gaps = rows.slice(1).map(() => rankGap);
|
|
566
591
|
const ends = /* @__PURE__ */ new Map();
|
|
567
592
|
const starts = /* @__PURE__ */ new Map();
|
|
593
|
+
const reach = (span, side) => {
|
|
594
|
+
const own = canonical(span.group.inset, axes)[side === "lo" ? "rankLo" : "rankHi"];
|
|
595
|
+
const flush = span.children.filter((c) => c[side] === span[side]);
|
|
596
|
+
return own + Math.max(0, ...flush.map((c) => reach(c, side)));
|
|
597
|
+
};
|
|
568
598
|
for (const span of groupSpans(graph, rows)) {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
starts.set(span.lo, Math.max(starts.get(span.lo) ?? 0, inset.rankLo));
|
|
599
|
+
ends.set(span.hi, Math.max(ends.get(span.hi) ?? 0, reach(span, "hi")));
|
|
600
|
+
starts.set(span.lo, Math.max(starts.get(span.lo) ?? 0, reach(span, "lo")));
|
|
572
601
|
}
|
|
573
602
|
for (let i = 0; i < gaps.length; i++) {
|
|
574
603
|
gaps[i] = Math.max(gaps[i], rankGap + (ends.get(i) ?? 0) + (starts.get(i + 1) ?? 0));
|
|
@@ -579,92 +608,125 @@ function groupSpans(graph, rows) {
|
|
|
579
608
|
const rankOf = /* @__PURE__ */ new Map();
|
|
580
609
|
rows.forEach((row, i) => row.forEach((n) => rankOf.set(n.id, i)));
|
|
581
610
|
const spans = [];
|
|
611
|
+
const byId = /* @__PURE__ */ new Map();
|
|
582
612
|
for (const group of graph.groups ?? []) {
|
|
583
613
|
const ranks = group.members.map((id) => rankOf.get(id)).filter((r) => r !== void 0);
|
|
584
614
|
if (ranks.length === 0) continue;
|
|
585
|
-
|
|
615
|
+
const span = { group, lo: Math.min(...ranks), hi: Math.max(...ranks), children: [] };
|
|
616
|
+
spans.push(span);
|
|
617
|
+
byId.set(group.id, span);
|
|
618
|
+
}
|
|
619
|
+
for (const span of spans) {
|
|
620
|
+
const parent = span.group.parent === void 0 ? void 0 : byId.get(span.group.parent);
|
|
621
|
+
if (parent === void 0) continue;
|
|
622
|
+
span.parent = parent;
|
|
623
|
+
parent.children.push(span);
|
|
586
624
|
}
|
|
587
625
|
return spans;
|
|
588
626
|
}
|
|
589
627
|
function packClusters(graph, rows, preferred, axes, nodeGap) {
|
|
590
628
|
const spans = groupSpans(graph, rows);
|
|
591
|
-
const
|
|
592
|
-
|
|
629
|
+
const spanById = new Map(spans.map((s) => [s.group.id, s]));
|
|
630
|
+
const spanOf = (n) => n.group === void 0 ? void 0 : spanById.get(n.group);
|
|
593
631
|
const width = (n) => extent(n.bounds, axes.cross);
|
|
594
632
|
const pref = (n) => preferred.get(n.id) ?? 0;
|
|
595
|
-
const packedWidth = (ns) => ns.reduce((s, n) => s + width(n), 0) + Math.max(0, ns.length - 1) * nodeGap;
|
|
596
633
|
const insets = new Map(spans.map((s) => [s, canonical(s.group.inset, axes)]));
|
|
597
|
-
const inner = /* @__PURE__ */ new Map();
|
|
598
634
|
const centerOf = /* @__PURE__ */ new Map();
|
|
599
635
|
for (const span of spans) {
|
|
600
|
-
|
|
636
|
+
const inside = new Set(span.group.members);
|
|
601
637
|
let sum = 0;
|
|
602
638
|
let count = 0;
|
|
603
639
|
for (const row of rows) {
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
for (const n of members) {
|
|
640
|
+
for (const n of row) {
|
|
641
|
+
if (!inside.has(n.id)) continue;
|
|
607
642
|
sum += pref(n) + width(n) / 2;
|
|
608
643
|
count++;
|
|
609
644
|
}
|
|
610
645
|
}
|
|
611
|
-
inner.set(span, widest);
|
|
612
646
|
centerOf.set(span, count === 0 ? 0 : sum / count);
|
|
613
647
|
}
|
|
614
|
-
const
|
|
615
|
-
const itemsByRow = rows.map((row, r) => {
|
|
648
|
+
const itemsByRow = (owner, among) => rows.map((row, r) => {
|
|
616
649
|
const items = [];
|
|
617
650
|
for (const node of row) {
|
|
618
|
-
if (
|
|
651
|
+
if (spanOf(node) === owner) items.push({ kind: "node", node, center: pref(node) + width(node) / 2 });
|
|
619
652
|
}
|
|
620
|
-
for (const span of
|
|
621
|
-
if (r
|
|
622
|
-
items.push({
|
|
623
|
-
kind: "group",
|
|
624
|
-
span,
|
|
625
|
-
members: row.filter((n) => spanOf.get(n.id) === span),
|
|
626
|
-
center: centerOf.get(span)
|
|
627
|
-
});
|
|
653
|
+
for (const span of among) {
|
|
654
|
+
if (r >= span.lo && r <= span.hi) items.push({ kind: "group", span, center: centerOf.get(span) });
|
|
628
655
|
}
|
|
629
656
|
return items.map((item, i) => ({ item, i })).sort((a, b) => a.item.center - b.item.center || a.i - b.i).map(({ item }) => item);
|
|
630
657
|
});
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
let
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
658
|
+
const settle2 = (byRow, start2, nodeFloor, origin) => {
|
|
659
|
+
const nodeAt = /* @__PURE__ */ new Map();
|
|
660
|
+
let ends = [];
|
|
661
|
+
for (let pass = 0; pass <= start2.size; pass++) {
|
|
662
|
+
let raised = false;
|
|
663
|
+
ends = byRow.map((items) => {
|
|
664
|
+
let cursor = origin;
|
|
665
|
+
for (const item of items) {
|
|
666
|
+
if (item.kind === "node") {
|
|
667
|
+
const x2 = Math.max(nodeFloor(item.node), cursor);
|
|
668
|
+
nodeAt.set(item.node.id, x2);
|
|
669
|
+
cursor = x2 + width(item.node) + nodeGap;
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
const s = start2.get(item.span);
|
|
673
|
+
const x = Math.max(s, cursor);
|
|
674
|
+
if (x > s) {
|
|
675
|
+
start2.set(item.span, x);
|
|
676
|
+
raised = true;
|
|
677
|
+
}
|
|
678
|
+
cursor = x + outer(item.span) + nodeGap;
|
|
643
679
|
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
start.set(item.span, x);
|
|
648
|
-
raised = true;
|
|
649
|
-
}
|
|
650
|
-
const inset = insets.get(item.span);
|
|
651
|
-
let m = x + inset.crossLo + (inner.get(item.span) - packedWidth(item.members)) / 2;
|
|
652
|
-
for (const node of item.members) {
|
|
653
|
-
at.set(node.id, m);
|
|
654
|
-
m += width(node) + nodeGap;
|
|
655
|
-
}
|
|
656
|
-
cursor = x + outer(item.span) + nodeGap;
|
|
657
|
-
}
|
|
680
|
+
return items.length === 0 ? origin : cursor - nodeGap;
|
|
681
|
+
});
|
|
682
|
+
if (!raised) break;
|
|
658
683
|
}
|
|
659
|
-
|
|
684
|
+
return { nodeAt, ends };
|
|
685
|
+
};
|
|
686
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
687
|
+
const blockOf = (span) => {
|
|
688
|
+
const known = blocks.get(span);
|
|
689
|
+
if (known !== void 0) return known;
|
|
690
|
+
const byRow = itemsByRow(span, span.children);
|
|
691
|
+
const childAt = new Map(span.children.map((c) => [c, 0]));
|
|
692
|
+
const { nodeAt, ends } = settle2(byRow, childAt, () => 0, 0);
|
|
693
|
+
const block = { width: Math.max(0, ...ends), nodeAt, childAt };
|
|
694
|
+
byRow.forEach((items, r) => {
|
|
695
|
+
if (items.some((item) => item.kind === "group")) return;
|
|
696
|
+
const shift = (block.width - ends[r]) / 2;
|
|
697
|
+
for (const item of items) {
|
|
698
|
+
if (item.kind === "node") nodeAt.set(item.node.id, nodeAt.get(item.node.id) + shift);
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
blocks.set(span, block);
|
|
702
|
+
return block;
|
|
703
|
+
};
|
|
704
|
+
function outer(span) {
|
|
705
|
+
const inset = insets.get(span);
|
|
706
|
+
return blockOf(span).width + inset.crossLo + inset.crossHi;
|
|
660
707
|
}
|
|
708
|
+
const roots = spans.filter((s) => s.parent === void 0);
|
|
709
|
+
const start = new Map(roots.map((s) => [s, centerOf.get(s) - outer(s) / 2]));
|
|
710
|
+
const { nodeAt: at } = settle2(itemsByRow(void 0, roots), start, pref, -Infinity);
|
|
711
|
+
const place = (span, from) => {
|
|
712
|
+
const origin = from + insets.get(span).crossLo;
|
|
713
|
+
const block = blockOf(span);
|
|
714
|
+
for (const [id, local] of block.nodeAt) at.set(id, origin + local);
|
|
715
|
+
for (const [child, local] of block.childAt) place(child, origin + local);
|
|
716
|
+
};
|
|
717
|
+
for (const root of roots) place(root, start.get(root));
|
|
661
718
|
return at;
|
|
662
719
|
}
|
|
663
720
|
function expandGroupEdges(edges, groups) {
|
|
664
721
|
const byId = new Map(groups.map((g) => [g.id, g]));
|
|
665
722
|
if (byId.size === 0) return [...edges];
|
|
666
|
-
const
|
|
667
|
-
|
|
723
|
+
const within = (id, group) => {
|
|
724
|
+
if (!byId.has(id)) return group.members.includes(id);
|
|
725
|
+
for (let at = byId.get(id); at !== void 0; at = at.parent === void 0 ? void 0 : byId.get(at.parent)) {
|
|
726
|
+
if (at === group) return true;
|
|
727
|
+
}
|
|
728
|
+
return false;
|
|
729
|
+
};
|
|
668
730
|
const entries = /* @__PURE__ */ new Map();
|
|
669
731
|
const exits = /* @__PURE__ */ new Map();
|
|
670
732
|
for (const g of groups) {
|
|
@@ -690,9 +752,8 @@ function expandGroupEdges(edges, groups) {
|
|
|
690
752
|
out.push(e);
|
|
691
753
|
continue;
|
|
692
754
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
if (fromOwner !== void 0 && fromOwner === toOwner) continue;
|
|
755
|
+
if (fromGroup !== void 0 && within(e.to, byId.get(fromGroup))) continue;
|
|
756
|
+
if (toGroup !== void 0 && within(e.from, byId.get(toGroup))) continue;
|
|
696
757
|
const froms = fromGroup !== void 0 ? exits.get(fromGroup) : [e.from];
|
|
697
758
|
const tos = toGroup !== void 0 ? entries.get(toGroup) : [e.to];
|
|
698
759
|
let k = 0;
|
|
@@ -702,13 +763,118 @@ function expandGroupEdges(edges, groups) {
|
|
|
702
763
|
}
|
|
703
764
|
return out;
|
|
704
765
|
}
|
|
766
|
+
|
|
767
|
+
// src/forceGroups.ts
|
|
768
|
+
function resolve(groups, byId) {
|
|
769
|
+
const out = [];
|
|
770
|
+
for (const group of groups) {
|
|
771
|
+
const members = group.members.map((id) => byId.get(id)).filter((b) => b !== void 0);
|
|
772
|
+
if (members.length > 0) out.push({ members, group, children: [] });
|
|
773
|
+
}
|
|
774
|
+
const byGroup = new Map(out.map((g) => [g.group.id, g]));
|
|
775
|
+
for (const g of out) {
|
|
776
|
+
const parent = g.group.parent === void 0 ? void 0 : byGroup.get(g.group.parent);
|
|
777
|
+
if (parent === void 0) continue;
|
|
778
|
+
g.parent = parent;
|
|
779
|
+
parent.children.push(g);
|
|
780
|
+
}
|
|
781
|
+
return out;
|
|
782
|
+
}
|
|
783
|
+
function groupCohesion(groups, byId, strength) {
|
|
784
|
+
const resolved = resolve(groups, byId);
|
|
785
|
+
return (alpha) => {
|
|
786
|
+
for (const { members } of resolved) {
|
|
787
|
+
let cx = 0;
|
|
788
|
+
let cy = 0;
|
|
789
|
+
for (const m of members) {
|
|
790
|
+
cx += m.x;
|
|
791
|
+
cy += m.y;
|
|
792
|
+
}
|
|
793
|
+
cx /= members.length;
|
|
794
|
+
cy /= members.length;
|
|
795
|
+
for (const m of members) {
|
|
796
|
+
m.vx += (cx - m.x) * strength * alpha;
|
|
797
|
+
m.vy += (cy - m.y) * strength * alpha;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
function boxOf(g) {
|
|
803
|
+
let x0 = Infinity;
|
|
804
|
+
let y0 = Infinity;
|
|
805
|
+
let x1 = -Infinity;
|
|
806
|
+
let y1 = -Infinity;
|
|
807
|
+
for (const m of g.members) {
|
|
808
|
+
x0 = Math.min(x0, m.x - m.hw);
|
|
809
|
+
y0 = Math.min(y0, m.y - m.hh);
|
|
810
|
+
x1 = Math.max(x1, m.x + m.hw);
|
|
811
|
+
y1 = Math.max(y1, m.y + m.hh);
|
|
812
|
+
}
|
|
813
|
+
for (const child of g.children) {
|
|
814
|
+
const b = boxOf(child);
|
|
815
|
+
x0 = Math.min(x0, b.x0);
|
|
816
|
+
y0 = Math.min(y0, b.y0);
|
|
817
|
+
x1 = Math.max(x1, b.x1);
|
|
818
|
+
y1 = Math.max(y1, b.y1);
|
|
819
|
+
}
|
|
820
|
+
const { inset } = g.group;
|
|
821
|
+
return { x0: x0 - inset.left, y0: y0 - inset.top, x1: x1 + inset.right, y1: y1 + inset.bottom };
|
|
822
|
+
}
|
|
823
|
+
function clearance(a, b, padding) {
|
|
824
|
+
const gapX = Math.min(a.x1, b.x1) - Math.max(a.x0, b.x0) + padding;
|
|
825
|
+
const gapY = Math.min(a.y1, b.y1) - Math.max(a.y0, b.y0) + padding;
|
|
826
|
+
if (gapX <= 0 || gapY <= 0) return null;
|
|
827
|
+
const dx = b.x0 + b.x1 - (a.x0 + a.x1);
|
|
828
|
+
const dy = b.y0 + b.y1 - (a.y0 + a.y1);
|
|
829
|
+
return gapX < gapY ? { x: (Math.sign(dx) || 1) * gapX, y: 0 } : { x: 0, y: (Math.sign(dy) || 1) * gapY };
|
|
830
|
+
}
|
|
831
|
+
function holds(outer, inner) {
|
|
832
|
+
for (let at = inner.parent; at !== void 0; at = at.parent) {
|
|
833
|
+
if (at === outer) return true;
|
|
834
|
+
}
|
|
835
|
+
return false;
|
|
836
|
+
}
|
|
837
|
+
function shove(bodies, x, y) {
|
|
838
|
+
for (const body of bodies) {
|
|
839
|
+
body.vx += x;
|
|
840
|
+
body.vy += y;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
function separateGroups(groups, bodies, byId, padding) {
|
|
844
|
+
const resolved = resolve(groups, byId);
|
|
845
|
+
const memberSets = resolved.map((g) => new Set(g.members));
|
|
846
|
+
return () => {
|
|
847
|
+
const boxes = resolved.map(boxOf);
|
|
848
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
849
|
+
for (let j = i + 1; j < resolved.length; j++) {
|
|
850
|
+
if (holds(resolved[i], resolved[j]) || holds(resolved[j], resolved[i])) continue;
|
|
851
|
+
const push = clearance(boxes[i], boxes[j], padding);
|
|
852
|
+
if (push === null) continue;
|
|
853
|
+
shove(resolved[i].members, -push.x / 2, -push.y / 2);
|
|
854
|
+
shove(resolved[j].members, push.x / 2, push.y / 2);
|
|
855
|
+
}
|
|
856
|
+
for (const body of bodies) {
|
|
857
|
+
if (memberSets[i].has(body)) continue;
|
|
858
|
+
const box = { x0: body.x - body.hw, y0: body.y - body.hh, x1: body.x + body.hw, y1: body.y + body.hh };
|
|
859
|
+
const push = clearance(boxes[i], box, padding);
|
|
860
|
+
if (push === null) continue;
|
|
861
|
+
shove(resolved[i].members, -push.x / 2, -push.y / 2);
|
|
862
|
+
body.vx += push.x / 2;
|
|
863
|
+
body.vy += push.y / 2;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
// src/force.ts
|
|
705
870
|
var DEFAULTS = {
|
|
706
871
|
iterations: 300,
|
|
707
872
|
linkDistance: 160,
|
|
708
873
|
linkStrength: 0.35,
|
|
709
874
|
charge: -3e3,
|
|
710
875
|
gravity: 0.02,
|
|
711
|
-
padding: 24
|
|
876
|
+
padding: 24,
|
|
877
|
+
groupStrength: 0.2
|
|
712
878
|
};
|
|
713
879
|
var GOLDEN = Math.PI * (3 - Math.sqrt(5));
|
|
714
880
|
var NUDGE = 0.5;
|
|
@@ -787,7 +953,8 @@ function forceRelaxation(graph, opts = {}) {
|
|
|
787
953
|
linkStrength = DEFAULTS.linkStrength,
|
|
788
954
|
charge: chargeStrength = DEFAULTS.charge,
|
|
789
955
|
gravity: gravityStrength = DEFAULTS.gravity,
|
|
790
|
-
padding = DEFAULTS.padding
|
|
956
|
+
padding = DEFAULTS.padding,
|
|
957
|
+
groupStrength = DEFAULTS.groupStrength
|
|
791
958
|
} = opts;
|
|
792
959
|
const pinned = pinnedSet(graph, opts);
|
|
793
960
|
const bodies = graph.nodes.map((node) => {
|
|
@@ -810,13 +977,15 @@ function forceRelaxation(graph, opts = {}) {
|
|
|
810
977
|
x: bodies.reduce((sum, b) => sum + b.x, 0) / bodies.length,
|
|
811
978
|
y: bodies.reduce((sum, b) => sum + b.y, 0) / bodies.length
|
|
812
979
|
};
|
|
980
|
+
const groups = graph.groups ?? [];
|
|
813
981
|
const sim = createSimulation({
|
|
814
982
|
nodes: bodies,
|
|
815
983
|
forces: [
|
|
816
984
|
charge(bodies, chargeStrength),
|
|
817
985
|
links(byId, graph, linkDistance, linkStrength),
|
|
818
986
|
gravity(bodies, centroid, gravityStrength),
|
|
819
|
-
separateBoxes(bodies, padding)
|
|
987
|
+
separateBoxes(bodies, padding),
|
|
988
|
+
...groups.length > 0 ? [groupCohesion(groups, byId, groupStrength), separateGroups(groups, bodies, byId, padding)] : []
|
|
820
989
|
]
|
|
821
990
|
});
|
|
822
991
|
return {
|
|
@@ -920,7 +1089,12 @@ function ranksOf(graph, back) {
|
|
|
920
1089
|
for (const node of graph.nodes) rankOf(node.id);
|
|
921
1090
|
return ranks;
|
|
922
1091
|
}
|
|
923
|
-
var layered = (graph, opts = {}) =>
|
|
1092
|
+
var layered = (graph, opts = {}) => (
|
|
1093
|
+
// Barycenter ordering reorders on every run by design, so it has no
|
|
1094
|
+
// arrangement to settle on.
|
|
1095
|
+
(graph.groups?.length ?? 0) > 0 && opts.order !== "barycenter" ? untilSettled(layeredOnce, graph, opts) : layeredOnce(graph, opts)
|
|
1096
|
+
);
|
|
1097
|
+
var layeredOnce = (graph, opts = {}) => {
|
|
924
1098
|
const axes = axesFor(opts.direction);
|
|
925
1099
|
const nodeGap = opts.nodeGap ?? DEFAULT_NODE_GAP;
|
|
926
1100
|
const rankGap = opts.rankGap ?? DEFAULT_RANK_GAP;
|
|
@@ -997,7 +1171,8 @@ function forestOf(graph, crossAxis) {
|
|
|
997
1171
|
}
|
|
998
1172
|
return { roots, children, depth };
|
|
999
1173
|
}
|
|
1000
|
-
var tree = (graph, opts = {}) =>
|
|
1174
|
+
var tree = (graph, opts = {}) => (graph.groups?.length ?? 0) > 0 ? untilSettled(treeOnce, graph, opts) : treeOnce(graph, opts);
|
|
1175
|
+
var treeOnce = (graph, opts = {}) => {
|
|
1001
1176
|
const axes = axesFor(opts.direction);
|
|
1002
1177
|
const nodeGap = opts.nodeGap ?? DEFAULT_NODE_GAP;
|
|
1003
1178
|
const rankGap = opts.rankGap ?? DEFAULT_RANK_GAP;
|
|
@@ -1060,6 +1235,6 @@ var tree = (graph, opts = {}) => {
|
|
|
1060
1235
|
return settle(graph, slots, opts);
|
|
1061
1236
|
};
|
|
1062
1237
|
|
|
1063
|
-
export { COMPASS, DEFAULT_GROUP_INSET, DEFAULT_NODE_GAP, DEFAULT_PORTS, DEFAULT_RANK_GAP, DIAGRAM_TRAIT_KEY, axesFor, backEdges, bodyOutline, bodyTrait, boxForContent, buildBody, canvasMeasure, center, contentBox, createDiagramNodes, dataKeyReader, diagramNodeOf, expandGroupEdges, extent, force, forceRelaxation, forestOf, graphOrder, insetOf, isPinned, layered, layoutBody, layoutRowPorts, measureBody, outlinePath, outlinePolyline, packAcross, packClusters, pinnedSet, portOf, portsOf, portsOnOutline, rankGaps, ranksOf, rayHit, seededOrder, settle, sizeToBody, translated, tree };
|
|
1064
|
-
//# sourceMappingURL=chunk-
|
|
1065
|
-
//# sourceMappingURL=chunk-
|
|
1238
|
+
export { COMPASS, DEFAULT_GROUP_INSET, DEFAULT_NODE_GAP, DEFAULT_PORTS, DEFAULT_RANK_GAP, DIAGRAM_TRAIT_KEY, axesFor, backEdges, bodyOutline, bodyTrait, boxForContent, buildBody, canvasMeasure, center, contentBox, createDiagramNodes, dataKeyReader, diagramNodeOf, expandGroupEdges, extent, force, forceRelaxation, forestOf, graphOrder, insetOf, isPinned, layered, layoutBody, layoutRowPorts, measureBody, outlinePath, outlinePolyline, packAcross, packClusters, pinnedSet, portOf, portsOf, portsOnOutline, rankGaps, ranksOf, rayHit, seededOrder, settle, sizeToBody, translated, tree, untilSettled };
|
|
1239
|
+
//# sourceMappingURL=chunk-BWQJYEA3.js.map
|
|
1240
|
+
//# sourceMappingURL=chunk-BWQJYEA3.js.map
|