@floegence/floe-webapp-core 0.86.11 → 0.86.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/graph/layout.js +72 -71
- package/dist/components/graph/packing.js +35 -35
- package/dist/components/graph/positions.js +47 -46
- package/dist/components/graph/routing.d.ts +2 -2
- package/dist/components/graph/routing.js +188 -185
- package/dist/components/graph/types.d.ts +2 -0
- package/package.json +1 -1
|
@@ -1,48 +1,49 @@
|
|
|
1
|
-
import { applyGraphPositions as
|
|
1
|
+
import { applyGraphPositions as G } from "./positions.js";
|
|
2
2
|
import { computePackedGraphLayout as k } from "./packing.js";
|
|
3
|
-
function $(
|
|
4
|
-
const
|
|
5
|
-
if (!t ||
|
|
6
|
-
|
|
7
|
-
}, i = new Map(
|
|
8
|
-
for (const t of
|
|
3
|
+
function $(d) {
|
|
4
|
+
const r = /* @__PURE__ */ new Set(), c = (t) => {
|
|
5
|
+
if (!t || r.has(t)) throw new Error(`Duplicate or empty graph ID: ${t}`);
|
|
6
|
+
r.add(t);
|
|
7
|
+
}, i = new Map(d.nodes.map((t) => [t.id, t]));
|
|
8
|
+
for (const t of d.nodes) {
|
|
9
9
|
if (c(t.id), ![t.width, t.height].every((n) => Number.isFinite(n) && n > 0))
|
|
10
10
|
throw new Error(`Invalid dimensions for graph node: ${t.id}`);
|
|
11
11
|
for (const n of t.ports ?? []) c(n.id);
|
|
12
12
|
const s = /* @__PURE__ */ new Set([t.id]);
|
|
13
|
-
let
|
|
14
|
-
for (;
|
|
15
|
-
const n = i.get(
|
|
13
|
+
let o = t.parentId;
|
|
14
|
+
for (; o !== void 0; ) {
|
|
15
|
+
const n = i.get(o);
|
|
16
16
|
if (!n || n.kind !== "group")
|
|
17
17
|
throw new Error(`Invalid parent for graph node: ${t.id}`);
|
|
18
|
-
if (s.has(
|
|
19
|
-
s.add(
|
|
18
|
+
if (s.has(o)) throw new Error(`Cyclic graph containment: ${t.id}`);
|
|
19
|
+
s.add(o), o = n.parentId;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
for (const t of
|
|
22
|
+
for (const t of d.edges) {
|
|
23
23
|
c(t.id);
|
|
24
|
-
for (const [s,
|
|
24
|
+
for (const [s, o] of [
|
|
25
25
|
[t.source, t.sourcePort],
|
|
26
26
|
[t.target, t.targetPort]
|
|
27
27
|
]) {
|
|
28
28
|
const n = i.get(s);
|
|
29
|
-
if (!n ||
|
|
29
|
+
if (!n || o !== void 0 && !n.ports?.some((h) => h.id === o))
|
|
30
30
|
throw new Error(`Invalid endpoint for graph edge: ${t.id}`);
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
async function P(
|
|
35
|
-
$(
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
async function P(d, r, c) {
|
|
35
|
+
if ($(d), r.edgeClearance !== void 0 && (!Number.isFinite(r.edgeClearance) || r.edgeClearance < 0))
|
|
36
|
+
throw new Error("Graph edge clearance must be finite and nonnegative");
|
|
37
|
+
const i = N(d, r);
|
|
38
|
+
if (r.aspectRatio !== void 0 && (!Number.isFinite(r.aspectRatio) || r.aspectRatio <= 0))
|
|
38
39
|
throw new Error("Graph layout aspect ratio must be finite and positive");
|
|
39
|
-
const t =
|
|
40
|
-
if (![...Object.values(t),
|
|
40
|
+
const t = r.groupPadding ?? { top: 64, right: 28, bottom: 28, left: 28 };
|
|
41
|
+
if (![...Object.values(t), r.spacing ?? 64].every((e) => Number.isFinite(e) && e >= 0))
|
|
41
42
|
throw new Error("Graph layout spacing must be finite and nonnegative");
|
|
42
|
-
if (
|
|
43
|
+
if (r.layers && (O(d, r.layers), r.positionMode === "fixed" && r.positions?.length))
|
|
43
44
|
throw new Error("Fixed positions cannot be combined with graph layers");
|
|
44
|
-
if (
|
|
45
|
-
return k(i,
|
|
45
|
+
if (r.aspectRatio !== void 0 || r.layers)
|
|
46
|
+
return k(i, r, c);
|
|
46
47
|
const s = /* @__PURE__ */ new Map();
|
|
47
48
|
for (const e of i.nodes)
|
|
48
49
|
s.set(e.id, {
|
|
@@ -50,29 +51,29 @@ async function P(a, o, c) {
|
|
|
50
51
|
width: e.width,
|
|
51
52
|
height: e.height,
|
|
52
53
|
...e.kind === "group" ? { children: [] } : {},
|
|
53
|
-
ports: e.ports?.map((
|
|
54
|
-
id:
|
|
54
|
+
ports: e.ports?.map((a) => ({
|
|
55
|
+
id: a.id,
|
|
55
56
|
width: 1,
|
|
56
57
|
height: 1,
|
|
57
|
-
layoutOptions: { "elk.port.side":
|
|
58
|
+
layoutOptions: { "elk.port.side": a.side }
|
|
58
59
|
})),
|
|
59
60
|
layoutOptions: {
|
|
60
61
|
"elk.portConstraints": "FIXED_ORDER",
|
|
61
62
|
"elk.padding": `[top=${t.top},left=${t.left},bottom=${t.bottom},right=${t.right}]`
|
|
62
63
|
}
|
|
63
64
|
});
|
|
64
|
-
const
|
|
65
|
+
const o = [];
|
|
65
66
|
for (const e of i.nodes)
|
|
66
|
-
(e.parentId ? s.get(e.parentId).children :
|
|
67
|
+
(e.parentId ? s.get(e.parentId).children : o).push(s.get(e.id));
|
|
67
68
|
const n = /* @__PURE__ */ new Set([
|
|
68
|
-
...i.nodes.flatMap((e) => [e.id, ...(e.ports ?? []).map((
|
|
69
|
+
...i.nodes.flatMap((e) => [e.id, ...(e.ports ?? []).map((a) => a.id)]),
|
|
69
70
|
...i.edges.map((e) => e.id)
|
|
70
71
|
]);
|
|
71
72
|
let h = "$graph";
|
|
72
73
|
for (; n.has(h); ) h += "$";
|
|
73
74
|
const p = await c.layout({
|
|
74
75
|
id: h,
|
|
75
|
-
children:
|
|
76
|
+
children: o,
|
|
76
77
|
edges: i.edges.map((e) => ({
|
|
77
78
|
id: e.id,
|
|
78
79
|
sources: [e.sourcePort ?? e.source],
|
|
@@ -80,20 +81,20 @@ async function P(a, o, c) {
|
|
|
80
81
|
})),
|
|
81
82
|
layoutOptions: {
|
|
82
83
|
"elk.algorithm": "layered",
|
|
83
|
-
"elk.direction":
|
|
84
|
+
"elk.direction": r.direction ?? "RIGHT",
|
|
84
85
|
"elk.edgeRouting": "ORTHOGONAL",
|
|
85
86
|
"elk.hierarchyHandling": "INCLUDE_CHILDREN",
|
|
86
|
-
"elk.spacing.nodeNode": String(
|
|
87
|
-
"elk.layered.spacing.nodeNodeBetweenLayers": String(
|
|
87
|
+
"elk.spacing.nodeNode": String(r.spacing ?? 64),
|
|
88
|
+
"elk.layered.spacing.nodeNodeBetweenLayers": String(r.spacing ?? 64),
|
|
88
89
|
"elk.layered.considerModelOrder.strategy": "NODES_AND_EDGES",
|
|
89
90
|
"elk.randomSeed": "1"
|
|
90
91
|
}
|
|
91
|
-
}), y = /* @__PURE__ */ new Map(),
|
|
92
|
-
for (const
|
|
93
|
-
const g =
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
(
|
|
92
|
+
}), y = /* @__PURE__ */ new Map(), E = /* @__PURE__ */ new Map(), x = (e) => {
|
|
93
|
+
for (const a of e.edges ?? []) {
|
|
94
|
+
const g = a.container ?? e.id, f = y.get(g) ?? { x: 0, y: 0 };
|
|
95
|
+
E.set(
|
|
96
|
+
a.id,
|
|
97
|
+
(a.sections ?? []).map(
|
|
97
98
|
(l) => [l.startPoint, ...l.bendPoints ?? [], l.endPoint].map((m) => ({
|
|
98
99
|
x: m.x + f.x,
|
|
99
100
|
y: m.y + f.y
|
|
@@ -101,55 +102,55 @@ async function P(a, o, c) {
|
|
|
101
102
|
)
|
|
102
103
|
);
|
|
103
104
|
}
|
|
104
|
-
for (const
|
|
105
|
-
}, v = (e,
|
|
106
|
-
const f =
|
|
105
|
+
for (const a of e.children ?? []) x(a);
|
|
106
|
+
}, v = (e, a, g) => {
|
|
107
|
+
const f = a + (e.x ?? 0), l = g + (e.y ?? 0);
|
|
107
108
|
y.set(e.id, { x: f, y: l, width: e.width ?? 0, height: e.height ?? 0 });
|
|
108
109
|
for (const m of e.children ?? []) v(m, f, l);
|
|
109
110
|
};
|
|
110
111
|
for (const e of p.children ?? []) v(e, 0, 0);
|
|
111
|
-
|
|
112
|
-
const w = (!
|
|
113
|
-
const
|
|
114
|
-
return { ...e, ...
|
|
112
|
+
x(p);
|
|
113
|
+
const w = (!r.positions?.length || r.positionMode === "compact") && r.anchor && y.get(r.anchor.nodeId), u = w ? r.anchor.position.x - w.x : 0, I = w ? r.anchor.position.y - w.y : 0, b = i.nodes.map((e) => {
|
|
114
|
+
const a = y.get(e.id);
|
|
115
|
+
return { ...e, ...a, x: a.x + u, y: a.y + I };
|
|
115
116
|
});
|
|
116
|
-
return
|
|
117
|
+
return G(
|
|
117
118
|
{
|
|
118
|
-
nodes:
|
|
119
|
+
nodes: b,
|
|
119
120
|
edges: i.edges.map((e) => ({
|
|
120
121
|
...e,
|
|
121
|
-
sections: (
|
|
122
|
-
(
|
|
122
|
+
sections: (E.get(e.id) ?? []).map(
|
|
123
|
+
(a) => a.map((g) => ({ x: g.x + u, y: g.y + I }))
|
|
123
124
|
)
|
|
124
125
|
})),
|
|
125
126
|
bounds: { x: u, y: I, width: p.width ?? 0, height: p.height ?? 0 }
|
|
126
127
|
},
|
|
127
|
-
|
|
128
|
+
r,
|
|
128
129
|
i.nodes
|
|
129
130
|
);
|
|
130
131
|
}
|
|
131
|
-
function
|
|
132
|
-
if (
|
|
133
|
-
const c =
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
c === "RIGHT" || c === "LEFT" ?
|
|
132
|
+
function N(d, r) {
|
|
133
|
+
if (r.positionMode !== "compact" || !r.positions?.length) return d;
|
|
134
|
+
const c = r.direction ?? "RIGHT", i = new Map(
|
|
135
|
+
r.positions.map((o) => [
|
|
136
|
+
o.nodeId,
|
|
137
|
+
c === "RIGHT" || c === "LEFT" ? o.y : o.x
|
|
137
138
|
])
|
|
138
|
-
), t = new Map(
|
|
139
|
-
return { nodes: [...
|
|
140
|
-
const h = (
|
|
141
|
-
return h || p || t.get(
|
|
142
|
-
}), edges:
|
|
139
|
+
), t = new Map(d.nodes.map((o, n) => [o.id, n]));
|
|
140
|
+
return { nodes: [...d.nodes].sort((o, n) => {
|
|
141
|
+
const h = (o.parentId ?? "").localeCompare(n.parentId ?? ""), p = r.layers && !o.parentId && !n.parentId ? 0 : (i.get(o.id) ?? 1 / 0) - (i.get(n.id) ?? 1 / 0);
|
|
142
|
+
return h || p || t.get(o.id) - t.get(n.id);
|
|
143
|
+
}), edges: d.edges };
|
|
143
144
|
}
|
|
144
|
-
function
|
|
145
|
-
const c = new Map(
|
|
146
|
-
for (const [t, s] of
|
|
145
|
+
function O(d, r) {
|
|
146
|
+
const c = new Map(d.nodes.map((t) => [t.id, t])), i = /* @__PURE__ */ new Set();
|
|
147
|
+
for (const [t, s] of r.entries()) {
|
|
147
148
|
if (!s.length) throw new Error(`Graph layer must not be empty: ${t}`);
|
|
148
|
-
for (const
|
|
149
|
-
const n = c.get(
|
|
150
|
-
if (!n || n.parentId) throw new Error(`Graph layer object must be a root node: ${
|
|
151
|
-
if (i.has(
|
|
152
|
-
i.add(
|
|
149
|
+
for (const o of s) {
|
|
150
|
+
const n = c.get(o);
|
|
151
|
+
if (!n || n.parentId) throw new Error(`Graph layer object must be a root node: ${o}`);
|
|
152
|
+
if (i.has(o)) throw new Error(`Graph object appears in multiple layers: ${o}`);
|
|
153
|
+
i.add(o);
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { applyGraphPositions as $ } from "./positions.js";
|
|
2
2
|
import { routeGraphGeometry as P } from "./routing.js";
|
|
3
|
-
async function j(f,
|
|
3
|
+
async function j(f, s, S) {
|
|
4
4
|
const y = new Map(f.nodes.map((e) => [e.id, { ...e, x: 0, y: 0 }])), O = new Map(f.nodes.map((e, d) => [e.id, d])), m = /* @__PURE__ */ new Map();
|
|
5
5
|
for (const e of y.values()) {
|
|
6
6
|
const d = m.get(e.parentId) ?? [];
|
|
@@ -12,22 +12,22 @@ async function j(f, i, S) {
|
|
|
12
12
|
]);
|
|
13
13
|
let T = "$packed";
|
|
14
14
|
for (; p.has(T); ) T += "$";
|
|
15
|
-
const k =
|
|
16
|
-
(
|
|
15
|
+
const k = s.groupPadding ?? { top: 64, right: 28, bottom: 28, left: 28 }, E = s.direction ?? "RIGHT", w = new Map(
|
|
16
|
+
(s.positions ?? []).map((e) => [
|
|
17
17
|
e.nodeId,
|
|
18
18
|
E === "RIGHT" || E === "LEFT" ? e.y : e.x
|
|
19
19
|
])
|
|
20
|
-
), I = (e, d,
|
|
21
|
-
e.x += d, e.y +=
|
|
22
|
-
for (const v of m.get(e.id) ?? []) I(v, d,
|
|
20
|
+
), I = (e, d, i) => {
|
|
21
|
+
e.x += d, e.y += i;
|
|
22
|
+
for (const v of m.get(e.id) ?? []) I(v, d, i);
|
|
23
23
|
}, x = (e, d) => {
|
|
24
|
-
let
|
|
25
|
-
for (;
|
|
26
|
-
|
|
27
|
-
return
|
|
24
|
+
let i = y.get(e);
|
|
25
|
+
for (; i && i.parentId !== d; )
|
|
26
|
+
i = i.parentId ? y.get(i.parentId) : void 0;
|
|
27
|
+
return i;
|
|
28
28
|
}, G = async (e) => {
|
|
29
29
|
const d = [...m.get(e) ?? []];
|
|
30
|
-
(e !== void 0 || !
|
|
30
|
+
(e !== void 0 || !s.layers) && d.sort(
|
|
31
31
|
(o, a) => (w.get(o.id) ?? 1 / 0) - (w.get(a.id) ?? 1 / 0) || O.get(o.id) - O.get(a.id)
|
|
32
32
|
);
|
|
33
33
|
for (const o of d) {
|
|
@@ -36,28 +36,28 @@ async function j(f, i, S) {
|
|
|
36
36
|
o.width = Math.max(o.width, a.width), o.height = Math.max(o.height, a.height);
|
|
37
37
|
}
|
|
38
38
|
if (!d.length) return { width: 0, height: 0 };
|
|
39
|
-
if (e === void 0 &&
|
|
40
|
-
return z(d, f,
|
|
41
|
-
const
|
|
39
|
+
if (e === void 0 && s.layers)
|
|
40
|
+
return z(d, f, s, x, I);
|
|
41
|
+
const i = /* @__PURE__ */ new Map();
|
|
42
42
|
for (const o of f.edges) {
|
|
43
43
|
const a = x(o.source, e), M = x(o.target, e);
|
|
44
44
|
if (!a || !M || a.id === M.id) continue;
|
|
45
45
|
const H = JSON.stringify([a.id, M.id]);
|
|
46
|
-
|
|
46
|
+
i.has(H) || i.set(H, { id: o.id, sources: [a.id], targets: [M.id] });
|
|
47
47
|
}
|
|
48
48
|
const v = await S.layout({
|
|
49
49
|
id: e ?? T,
|
|
50
50
|
children: d.map((o) => ({ id: o.id, width: o.width, height: o.height })),
|
|
51
|
-
edges: [...
|
|
51
|
+
edges: [...i.values()],
|
|
52
52
|
layoutOptions: {
|
|
53
|
-
"elk.algorithm":
|
|
53
|
+
"elk.algorithm": i.size ? "layered" : "rectpacking",
|
|
54
54
|
"elk.direction": E,
|
|
55
55
|
"elk.edgeRouting": "ORTHOGONAL",
|
|
56
56
|
"elk.separateConnectedComponents": "true",
|
|
57
|
-
...
|
|
58
|
-
"elk.spacing.componentComponent": String(
|
|
59
|
-
"elk.spacing.nodeNode": String(
|
|
60
|
-
"elk.layered.spacing.nodeNodeBetweenLayers": String(
|
|
57
|
+
...s.aspectRatio !== void 0 ? { "elk.aspectRatio": String(s.aspectRatio) } : {},
|
|
58
|
+
"elk.spacing.componentComponent": String(s.spacing ?? 64),
|
|
59
|
+
"elk.spacing.nodeNode": String(s.spacing ?? 64),
|
|
60
|
+
"elk.layered.spacing.nodeNodeBetweenLayers": String(s.spacing ?? 64),
|
|
61
61
|
"elk.layered.considerModelOrder.strategy": "NODES_AND_EDGES",
|
|
62
62
|
"elk.padding": e ? `[top=${k.top},left=${k.left},bottom=${k.bottom},right=${k.right}]` : "[top=12,left=12,bottom=12,right=12]",
|
|
63
63
|
"elk.randomSeed": "1"
|
|
@@ -68,23 +68,23 @@ async function j(f, i, S) {
|
|
|
68
68
|
I(a, (o.x ?? 0) - a.x, (o.y ?? 0) - a.y);
|
|
69
69
|
}
|
|
70
70
|
return { width: v.width ?? 0, height: v.height ?? 0 };
|
|
71
|
-
}, u = await G(), R = (!
|
|
71
|
+
}, u = await G(), R = (!s.positions?.length || s.positionMode === "compact" || s.layers) && s.anchor && y.get(s.anchor.nodeId);
|
|
72
72
|
if (R) {
|
|
73
|
-
const e =
|
|
74
|
-
for (const
|
|
73
|
+
const e = s.anchor.position.x - R.x, d = s.anchor.position.y - R.y;
|
|
74
|
+
for (const i of m.get(void 0) ?? []) I(i, e, d);
|
|
75
75
|
}
|
|
76
76
|
const C = {
|
|
77
77
|
nodes: [...y.values()],
|
|
78
78
|
edges: f.edges.map((e) => ({ ...e, sections: [] })),
|
|
79
79
|
bounds: { x: 0, y: 0, ...u }
|
|
80
80
|
};
|
|
81
|
-
return
|
|
81
|
+
return s.positions?.length && s.positionMode !== "compact" && !s.layers ? $(C, s, f.nodes) : P(C, s);
|
|
82
82
|
}
|
|
83
|
-
function z(f,
|
|
83
|
+
function z(f, s, S, y, O) {
|
|
84
84
|
const m = S.direction ?? "RIGHT", p = m === "RIGHT" || m === "LEFT", T = m === "RIGHT" || m === "DOWN", k = new Map(f.map((t, n) => [t.id, n])), E = new Map(
|
|
85
85
|
(S.positions ?? []).filter((t) => k.has(t.nodeId)).map((t) => [t.nodeId, p ? t.y : t.x])
|
|
86
86
|
), w = (t, n) => k.get(t) - k.get(n) || t.localeCompare(n), I = (t, n) => (E.get(t) ?? 1 / 0) - (E.get(n) ?? 1 / 0) || w(t, n), x = new Map(f.map((t) => [t.id, /* @__PURE__ */ new Set()]));
|
|
87
|
-
for (const t of
|
|
87
|
+
for (const t of s.edges) {
|
|
88
88
|
const n = y(t.source, void 0)?.id, r = y(t.target, void 0)?.id;
|
|
89
89
|
n && r && n !== r && (x.get(n)?.add(r), x.get(r)?.add(n));
|
|
90
90
|
}
|
|
@@ -118,25 +118,25 @@ function z(f, i, S, y, O) {
|
|
|
118
118
|
r.has(l) || (r.set(l, r.get(h) + 1), u.set(l, u.get(h)), c.push(l));
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
-
const d = Math.max(G.length, e),
|
|
122
|
-
for (const t of f)
|
|
123
|
-
for (const t of
|
|
121
|
+
const d = Math.max(G.length, e), i = Array.from({ length: d }, () => []);
|
|
122
|
+
for (const t of f) i[u.get(t.id)].push(t);
|
|
123
|
+
for (const t of i) t.sort((n, r) => I(n.id, r.id));
|
|
124
124
|
const v = (t, n) => {
|
|
125
|
-
const r = new Map(
|
|
125
|
+
const r = new Map(i[n].map((h, l) => [h.id, l])), c = new Map(i[t].map((h, l) => [h.id, l])), g = (h) => {
|
|
126
126
|
const l = [...x.get(h) ?? []].flatMap((N) => {
|
|
127
127
|
const b = r.get(N);
|
|
128
128
|
return u.get(N) === n && b !== void 0 ? [b] : [];
|
|
129
129
|
});
|
|
130
130
|
return l.length ? l.reduce((N, b) => N + b, 0) / l.length : c.get(h);
|
|
131
131
|
};
|
|
132
|
-
|
|
132
|
+
i[t].sort((h, l) => g(h.id) - g(l.id) || I(h.id, l.id));
|
|
133
133
|
};
|
|
134
|
-
for (let t = 1; t <
|
|
135
|
-
for (let t =
|
|
134
|
+
for (let t = 1; t < i.length; t++) v(t, t - 1);
|
|
135
|
+
for (let t = i.length - 2; t >= 0; t--) v(t, t + 1);
|
|
136
136
|
const o = S.spacing ?? 64;
|
|
137
137
|
let a = 0, M = 0;
|
|
138
138
|
const H = [], L = [];
|
|
139
|
-
for (const t of
|
|
139
|
+
for (const t of i) {
|
|
140
140
|
let n = 0;
|
|
141
141
|
const r = Math.max(0, ...t.map((c) => p ? c.width : c.height));
|
|
142
142
|
H.push(a), L.push(r);
|
|
@@ -1,75 +1,76 @@
|
|
|
1
|
-
import { routeGraphGeometry as
|
|
2
|
-
function
|
|
3
|
-
if (!
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { routeGraphGeometry as v } from "./routing.js";
|
|
2
|
+
function C(l, x, G) {
|
|
3
|
+
if (!x.positions?.length || x.positionMode === "compact")
|
|
4
|
+
return x.edgeClearance === void 0 ? l : v(l, x);
|
|
5
|
+
const f = new Map(l.nodes.map((t) => [t.id, { ...t }])), M = /* @__PURE__ */ new Map();
|
|
6
|
+
for (const t of x.positions) {
|
|
7
|
+
if (!f.has(t.nodeId) || M.has(t.nodeId) || !Number.isFinite(t.x) || !Number.isFinite(t.y))
|
|
7
8
|
throw new Error(`Invalid graph position: ${t.nodeId}`);
|
|
8
|
-
|
|
9
|
+
M.set(t.nodeId, t);
|
|
9
10
|
}
|
|
10
11
|
const y = /* @__PURE__ */ new Map();
|
|
11
12
|
for (const t of f.values())
|
|
12
13
|
if (t.parentId) {
|
|
13
|
-
const
|
|
14
|
-
|
|
14
|
+
const c = y.get(t.parentId) ?? [];
|
|
15
|
+
c.push(t), y.set(t.parentId, c);
|
|
15
16
|
}
|
|
16
|
-
const
|
|
17
|
-
const g = { x: t.x, y: t.y },
|
|
18
|
-
t.x =
|
|
17
|
+
const m = x.groupPadding ?? { top: 64, left: 28, right: 28, bottom: 28 }, u = x.positionMode === "preferred", I = new Map(G.map((t) => [t.id, t])), b = (t, c, d) => {
|
|
18
|
+
const g = { x: t.x, y: t.y }, p = M.get(t.id);
|
|
19
|
+
t.x = p?.x ?? t.x + c, t.y = p?.y ?? t.y + d;
|
|
19
20
|
const i = y.get(t.id) ?? [];
|
|
20
|
-
for (const
|
|
21
|
+
for (const o of i) b(o, t.x - g.x, t.y - g.y);
|
|
21
22
|
if (!i.length || u) return;
|
|
22
|
-
const
|
|
23
|
-
if (
|
|
23
|
+
const a = Math.min(...i.map((o) => o.x)) - m.left, h = Math.min(...i.map((o) => o.y)) - m.top;
|
|
24
|
+
if (p && (a < t.x || h < t.y))
|
|
24
25
|
throw new Error(`Pinned child lies outside group content: ${t.id}`);
|
|
25
|
-
const
|
|
26
|
+
const e = Math.max(
|
|
26
27
|
t.x + t.width,
|
|
27
|
-
...i.map((
|
|
28
|
+
...i.map((o) => o.x + o.width + m.right)
|
|
28
29
|
), n = Math.max(
|
|
29
30
|
t.y + t.height,
|
|
30
|
-
...i.map((
|
|
31
|
+
...i.map((o) => o.y + o.height + m.bottom)
|
|
31
32
|
);
|
|
32
|
-
|
|
33
|
+
p || (t.x = Math.min(t.x, a), t.y = Math.min(t.y, h)), t.width = e - t.x, t.height = n - t.y;
|
|
33
34
|
};
|
|
34
35
|
for (const t of f.values()) t.parentId || b(t, 0, 0);
|
|
35
36
|
if (u) {
|
|
36
|
-
const t = Math.max(16,
|
|
37
|
-
i.x +=
|
|
38
|
-
for (const
|
|
39
|
-
},
|
|
40
|
-
const
|
|
37
|
+
const t = Math.max(16, x.spacing ?? 64), c = (i, a, h) => {
|
|
38
|
+
i.x += a, i.y += h;
|
|
39
|
+
for (const e of y.get(i.id) ?? []) c(e, a, h);
|
|
40
|
+
}, d = (i) => {
|
|
41
|
+
const a = [];
|
|
41
42
|
for (const h of [...i].sort(
|
|
42
|
-
(
|
|
43
|
+
(e, n) => e.y - n.y || e.x - n.x || e.id.localeCompare(n.id)
|
|
43
44
|
)) {
|
|
44
|
-
const
|
|
45
|
-
for (const
|
|
46
|
-
h.y <
|
|
45
|
+
const e = { x: h.x, y: h.y };
|
|
46
|
+
for (const r of [...a].sort((s, w) => s.x - w.x))
|
|
47
|
+
h.y < r.y + r.height + t && h.y + h.height + t > r.y && e.x < r.x + r.width + t && e.x + h.width + t > r.x && (e.x = r.x + r.width + t);
|
|
47
48
|
const n = { x: h.x, y: h.y };
|
|
48
|
-
for (const
|
|
49
|
-
h.x <
|
|
50
|
-
const
|
|
51
|
-
|
|
49
|
+
for (const r of [...a].sort((s, w) => s.y - w.y))
|
|
50
|
+
h.x < r.x + r.width + t && h.x + h.width + t > r.x && n.y < r.y + r.height + t && n.y + h.height + t > r.y && (n.y = r.y + r.height + t);
|
|
51
|
+
const o = e.x - h.x < n.y - h.y ? e : n;
|
|
52
|
+
c(h, o.x - h.x, o.y - h.y), a.push(h);
|
|
52
53
|
}
|
|
53
54
|
}, g = (i) => {
|
|
54
|
-
const
|
|
55
|
-
if (!
|
|
56
|
-
for (const
|
|
57
|
-
|
|
58
|
-
const h = Math.max(12,
|
|
59
|
-
i.x = Math.min(
|
|
55
|
+
const a = y.get(i.id) ?? [];
|
|
56
|
+
if (!a.length) return;
|
|
57
|
+
for (const s of a) g(s);
|
|
58
|
+
d(a);
|
|
59
|
+
const h = Math.max(12, m.left), e = Math.max(12, m.top), n = Math.max(12, m.right), o = Math.max(12, m.bottom), r = M.get(i.id);
|
|
60
|
+
i.x = Math.min(r?.x ?? 1 / 0, Math.min(...a.map((s) => s.x)) - h), i.y = Math.min(r?.y ?? 1 / 0, Math.min(...a.map((s) => s.y)) - e), i.width = Math.max(
|
|
60
61
|
I.get(i.id).width,
|
|
61
|
-
Math.max(...
|
|
62
|
+
Math.max(...a.map((s) => s.x + s.width)) + n - i.x
|
|
62
63
|
), i.height = Math.max(
|
|
63
64
|
I.get(i.id).height,
|
|
64
|
-
Math.max(...
|
|
65
|
+
Math.max(...a.map((s) => s.y + s.height)) + o - i.y
|
|
65
66
|
);
|
|
66
|
-
},
|
|
67
|
-
for (const i of
|
|
68
|
-
|
|
67
|
+
}, p = [...f.values()].filter((i) => !i.parentId);
|
|
68
|
+
for (const i of p) g(i);
|
|
69
|
+
d(p);
|
|
69
70
|
}
|
|
70
|
-
return
|
|
71
|
+
return v({ ...l, nodes: [...f.values()] }, x);
|
|
71
72
|
}
|
|
72
73
|
export {
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
C as applyGraphPositions,
|
|
75
|
+
v as routeGraphGeometry
|
|
75
76
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { GraphLayout } from './types';
|
|
1
|
+
import type { GraphLayout, GraphLayoutOptions } from './types';
|
|
2
2
|
/** Joint orthogonal routing through the final rectangular geometry. */
|
|
3
|
-
export declare function routeGraphGeometry(layout: GraphLayout): Promise<GraphLayout>;
|
|
3
|
+
export declare function routeGraphGeometry(layout: GraphLayout, options?: Pick<GraphLayoutOptions, 'edgeClearance'>): Promise<GraphLayout>;
|
|
@@ -1,274 +1,277 @@
|
|
|
1
|
-
import { AvoidLib as
|
|
2
|
-
import
|
|
3
|
-
let
|
|
4
|
-
const
|
|
5
|
-
async function
|
|
6
|
-
|
|
7
|
-
if (!
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { AvoidLib as J } from "../../node_modules/.pnpm/libavoid-js@0.5.0-beta.5/node_modules/libavoid-js/dist/index.js";
|
|
2
|
+
import Y from "../../node_modules/.pnpm/libavoid-js@0.5.0-beta.5/node_modules/libavoid-js/dist/libavoid.wasm.js";
|
|
3
|
+
let j;
|
|
4
|
+
const V = { NORTH: 1, SOUTH: 2, WEST: 4, EAST: 8 }, b = ["NORTH", "EAST", "SOUTH", "WEST"], E = (t) => t.delete();
|
|
5
|
+
async function I(t, c = {}) {
|
|
6
|
+
const p = c.edgeClearance ?? 4;
|
|
7
|
+
if (!Number.isFinite(p) || p < 0)
|
|
8
|
+
throw new Error("Graph edge clearance must be finite and nonnegative");
|
|
9
|
+
if (!t.nodes.length) return t;
|
|
10
|
+
if (!t.edges.length) return X(t);
|
|
11
|
+
await (j ??= J.load(Y).catch((o) => {
|
|
12
|
+
throw j = void 0, o;
|
|
10
13
|
}));
|
|
11
|
-
const s =
|
|
12
|
-
const
|
|
13
|
-
for (let i = r.get(
|
|
14
|
-
|
|
15
|
-
return
|
|
16
|
-
},
|
|
17
|
-
for (const
|
|
18
|
-
const
|
|
19
|
-
|
|
14
|
+
const s = J.getInstance(), r = new Map(t.nodes.map((o) => [o.id, o])), m = (o) => {
|
|
15
|
+
const e = [];
|
|
16
|
+
for (let i = r.get(o).parentId; i; i = r.get(i).parentId)
|
|
17
|
+
e.push(i);
|
|
18
|
+
return e;
|
|
19
|
+
}, d = /* @__PURE__ */ new Map();
|
|
20
|
+
for (const o of t.edges) {
|
|
21
|
+
const e = /* @__PURE__ */ new Set([...m(o.source), ...m(o.target)]), i = JSON.stringify([...e].sort()), u = d.get(i) ?? { open: e, edges: [] };
|
|
22
|
+
u.edges.push(o), d.set(i, u);
|
|
20
23
|
}
|
|
21
|
-
const
|
|
22
|
-
for (const { open:
|
|
24
|
+
const S = /* @__PURE__ */ new Map();
|
|
25
|
+
for (const { open: o, edges: e } of d.values()) {
|
|
23
26
|
const i = new s.Router(2);
|
|
24
27
|
try {
|
|
25
|
-
i.setRoutingParameter(s.RoutingParameter.shapeBufferDistance,
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
return
|
|
28
|
+
i.setRoutingParameter(s.RoutingParameter.shapeBufferDistance, p), i.setRoutingParameter(s.RoutingParameter.idealNudgingDistance, 8), i.setRoutingParameter(s.RoutingParameter.crossingPenalty, 80), i.setRoutingParameter(s.RoutingParameter.fixedSharedPathPenalty, 120), i.setRoutingParameter(s.RoutingParameter.portDirectionPenalty, 0), i.setRoutingOption(s.RoutingOption.nudgeOrthogonalSegmentsConnectedToShapes, !1), i.setRoutingOption(s.RoutingOption.nudgeSharedPathsWithCommonEndPoint, !0);
|
|
29
|
+
const u = new Map(
|
|
30
|
+
t.nodes.filter((n) => !o.has(n.id) && m(n.id).every((x) => o.has(x))).map((n) => {
|
|
31
|
+
const x = new s.Point(n.x, n.y), y = new s.Point(n.x + n.width, n.y + n.height), a = new s.Rectangle(x, y), h = new s.ShapeRef(i, a);
|
|
32
|
+
return E(x), E(y), E(a), [n.id, h];
|
|
30
33
|
})
|
|
31
|
-
),
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
const M =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
), v = /* @__PURE__ */ new Map(), l = t.nodes.filter((n) => u.has(n.id)), G = /* @__PURE__ */ new Map();
|
|
35
|
+
e.forEach((n) => {
|
|
36
|
+
const x = r.get(n.source), y = r.get(n.target), a = z(x, y), h = n.sourcePort ? x.ports.find((T) => T.id === n.sourcePort).side : n.targetPort ? D(y.ports.find((T) => T.id === n.targetPort).side) : a.source, g = n.targetPort ? y.ports.find((T) => T.id === n.targetPort).side : n.sourcePort ? D(x.ports.find((T) => T.id === n.sourcePort).side) : a.target, f = [n.source, n.target].sort().join("\0"), w = G.get(f) ?? 0;
|
|
37
|
+
G.set(f, w + 1);
|
|
38
|
+
const M = w % 2 === 0 ? -6 : 6, R = n.source === n.target ? void 0 : _(
|
|
39
|
+
x,
|
|
40
|
+
y,
|
|
41
|
+
l,
|
|
39
42
|
a,
|
|
40
43
|
M,
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
n.sourcePort ? h : void 0,
|
|
45
|
+
n.targetPort ? g : void 0
|
|
43
46
|
);
|
|
44
|
-
|
|
47
|
+
v.set(n.id, {
|
|
45
48
|
sourceSide: R?.source ?? h,
|
|
46
|
-
targetSide: R?.target ??
|
|
49
|
+
targetSide: R?.target ?? g,
|
|
47
50
|
offset: M
|
|
48
51
|
});
|
|
49
52
|
});
|
|
50
|
-
let
|
|
51
|
-
const
|
|
52
|
-
for (const
|
|
53
|
-
const
|
|
54
|
-
if (!
|
|
55
|
-
const
|
|
53
|
+
let U = b.length + 2;
|
|
54
|
+
const O = /* @__PURE__ */ new Map(), P = (n, x) => Math.max(0, Math.min(1, n / x));
|
|
55
|
+
for (const n of t.nodes) {
|
|
56
|
+
const x = u.get(n.id);
|
|
57
|
+
if (!x) continue;
|
|
58
|
+
const y = (a, h, g, f, w) => {
|
|
56
59
|
const M = new s.ShapeConnectionPin(
|
|
57
|
-
|
|
60
|
+
x,
|
|
58
61
|
a,
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
P(h, n.width),
|
|
63
|
+
P(g, n.height),
|
|
61
64
|
!0,
|
|
62
65
|
0,
|
|
63
|
-
|
|
66
|
+
f
|
|
64
67
|
);
|
|
65
|
-
M.setExclusive(
|
|
66
|
-
|
|
68
|
+
M.setExclusive(w), M.setConnectionCost(
|
|
69
|
+
n.width / 2 + n.height / 2 - Math.abs(h - n.width / 2) - Math.abs(g - n.height / 2)
|
|
67
70
|
);
|
|
68
71
|
};
|
|
69
|
-
for (const a of new Set(
|
|
70
|
-
const { x: h, y:
|
|
71
|
-
|
|
72
|
+
for (const a of new Set(n.ports?.map((h) => h.side))) {
|
|
73
|
+
const { x: h, y: g } = W(n, a), f = b.indexOf(a) + 2;
|
|
74
|
+
y(f, h - n.x, g - n.y, V[a], !1), O.set(
|
|
72
75
|
JSON.stringify([
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
n.id,
|
|
77
|
+
P(h - n.x, n.width),
|
|
78
|
+
P(g - n.y, n.height),
|
|
76
79
|
a
|
|
77
80
|
]),
|
|
78
|
-
|
|
81
|
+
f
|
|
79
82
|
);
|
|
80
83
|
}
|
|
81
84
|
}
|
|
82
|
-
const
|
|
83
|
-
const h = r.get(
|
|
84
|
-
if (
|
|
85
|
+
const C = (n, x, y, a) => {
|
|
86
|
+
const h = r.get(n), g = u.get(n);
|
|
87
|
+
if (g && x)
|
|
85
88
|
return new s.ConnEnd(
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
g,
|
|
90
|
+
b.indexOf(h.ports.find((R) => R.id === x).side) + 2
|
|
88
91
|
);
|
|
89
|
-
if (
|
|
90
|
-
const R =
|
|
91
|
-
if (
|
|
92
|
-
const
|
|
93
|
-
return
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
if (g) {
|
|
93
|
+
const R = P(y.x - h.x, h.width), T = P(y.y - h.y, h.height), A = JSON.stringify([n, R, T, a]), F = O.get(A);
|
|
94
|
+
if (F !== void 0) return new s.ConnEnd(g, F);
|
|
95
|
+
const B = U++;
|
|
96
|
+
return O.set(A, B), new s.ShapeConnectionPin(
|
|
97
|
+
g,
|
|
98
|
+
B,
|
|
96
99
|
R,
|
|
97
|
-
|
|
100
|
+
T,
|
|
98
101
|
!0,
|
|
99
102
|
0,
|
|
100
|
-
|
|
101
|
-
).setExclusive(!1), new s.ConnEnd(
|
|
103
|
+
V[a]
|
|
104
|
+
).setExclusive(!1), new s.ConnEnd(g, B);
|
|
102
105
|
}
|
|
103
|
-
const
|
|
104
|
-
return
|
|
105
|
-
},
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
),
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
x:
|
|
116
|
-
y:
|
|
117
|
-
} :
|
|
118
|
-
|
|
119
|
-
),
|
|
120
|
-
if (
|
|
121
|
-
const
|
|
122
|
-
for (const R of [
|
|
123
|
-
const
|
|
124
|
-
M.push_back(
|
|
106
|
+
const f = x ? W(h, h.ports.find((R) => R.id === x).side) : y, w = new s.Point(f.x, f.y), M = new s.ConnEnd(w);
|
|
107
|
+
return E(w), M;
|
|
108
|
+
}, N = e.map((n) => {
|
|
109
|
+
const x = r.get(n.source), y = r.get(n.target), a = v.get(n.id), h = C(
|
|
110
|
+
n.source,
|
|
111
|
+
n.sourcePort,
|
|
112
|
+
n.source === n.target ? { x: x.x + x.width, y: x.y + x.height / 3 } : k(x, a.sourceSide, y, a.offset),
|
|
113
|
+
n.source === n.target ? "EAST" : a.sourceSide
|
|
114
|
+
), g = C(
|
|
115
|
+
n.target,
|
|
116
|
+
n.targetPort,
|
|
117
|
+
n.source === n.target ? {
|
|
118
|
+
x: y.x + y.width,
|
|
119
|
+
y: y.y + y.height * 2 / 3
|
|
120
|
+
} : k(y, a.targetSide, x, a.offset),
|
|
121
|
+
n.source === n.target ? "EAST" : a.targetSide
|
|
122
|
+
), f = new s.ConnRef(i, h, g);
|
|
123
|
+
if (E(h), E(g), n.source === n.target) {
|
|
124
|
+
const w = r.get(n.source), M = new s.CheckpointVector();
|
|
125
|
+
for (const R of [w.y + w.height / 3, w.y + w.height * 2 / 3]) {
|
|
126
|
+
const T = new s.Point(w.x + w.width + Math.max(24, p + 4), R), A = new s.Checkpoint(T);
|
|
127
|
+
M.push_back(A), E(T), E(A);
|
|
125
128
|
}
|
|
126
|
-
|
|
129
|
+
f.setRoutingCheckpoints(M), E(M);
|
|
127
130
|
}
|
|
128
|
-
return { edge:
|
|
131
|
+
return { edge: n, connection: f };
|
|
129
132
|
});
|
|
130
133
|
i.processTransaction();
|
|
131
|
-
for (const { edge:
|
|
132
|
-
const
|
|
133
|
-
const
|
|
134
|
-
return
|
|
134
|
+
for (const { edge: n, connection: x } of N) {
|
|
135
|
+
const y = x.displayRoute(), a = Array.from({ length: y.size() }, (h, g) => {
|
|
136
|
+
const f = y.at(g), w = { x: f.x, y: f.y };
|
|
137
|
+
return E(f), w;
|
|
135
138
|
});
|
|
136
|
-
if (
|
|
137
|
-
throw new Error(`Graph edge cannot be routed: ${
|
|
138
|
-
|
|
139
|
+
if (E(y), !x.hasValidRoute() || a.length < 2 || a.some((h) => !Number.isFinite(h.x) || !Number.isFinite(h.y)) || a.some((h, g) => g > 0 && h.x !== a[g - 1].x && h.y !== a[g - 1].y))
|
|
140
|
+
throw new Error(`Graph edge cannot be routed: ${n.id}`);
|
|
141
|
+
S.set(n.id, a);
|
|
139
142
|
}
|
|
140
143
|
} finally {
|
|
141
144
|
i.delete();
|
|
142
145
|
}
|
|
143
146
|
}
|
|
144
|
-
const
|
|
145
|
-
return
|
|
146
|
-
nodes:
|
|
147
|
-
edges:
|
|
148
|
-
bounds:
|
|
147
|
+
const H = t.edges.map((o) => ({ ...o, sections: [S.get(o.id)] }));
|
|
148
|
+
return X({
|
|
149
|
+
nodes: t.nodes,
|
|
150
|
+
edges: H,
|
|
151
|
+
bounds: t.bounds
|
|
149
152
|
});
|
|
150
153
|
}
|
|
151
|
-
function
|
|
152
|
-
const
|
|
153
|
-
...
|
|
154
|
-
{ x:
|
|
155
|
-
{ x:
|
|
154
|
+
function X(t) {
|
|
155
|
+
const c = [
|
|
156
|
+
...t.nodes.flatMap((r) => [
|
|
157
|
+
{ x: r.x, y: r.y },
|
|
158
|
+
{ x: r.x + r.width, y: r.y + r.height }
|
|
156
159
|
]),
|
|
157
|
-
...
|
|
158
|
-
],
|
|
160
|
+
...t.edges.flatMap((r) => r.sections.flat())
|
|
161
|
+
], p = Math.min(...c.map((r) => r.x)), s = Math.min(...c.map((r) => r.y));
|
|
159
162
|
return {
|
|
160
|
-
nodes:
|
|
161
|
-
edges:
|
|
163
|
+
nodes: t.nodes,
|
|
164
|
+
edges: t.edges,
|
|
162
165
|
bounds: {
|
|
163
|
-
x:
|
|
164
|
-
y:
|
|
165
|
-
width: Math.max(...
|
|
166
|
-
height: Math.max(...
|
|
166
|
+
x: p,
|
|
167
|
+
y: s,
|
|
168
|
+
width: Math.max(...c.map((r) => r.x)) - p,
|
|
169
|
+
height: Math.max(...c.map((r) => r.y)) - s
|
|
167
170
|
}
|
|
168
171
|
};
|
|
169
172
|
}
|
|
170
|
-
function
|
|
173
|
+
function W(t, c) {
|
|
171
174
|
return {
|
|
172
|
-
x:
|
|
173
|
-
y:
|
|
175
|
+
x: c === "WEST" ? t.x : c === "EAST" ? t.x + t.width : t.x + t.width / 2,
|
|
176
|
+
y: c === "NORTH" ? t.y : c === "SOUTH" ? t.y + t.height : t.y + t.height / 2
|
|
174
177
|
};
|
|
175
178
|
}
|
|
176
|
-
function
|
|
179
|
+
function D(t) {
|
|
177
180
|
return {
|
|
178
181
|
NORTH: "SOUTH",
|
|
179
182
|
EAST: "WEST",
|
|
180
183
|
SOUTH: "NORTH",
|
|
181
184
|
WEST: "EAST"
|
|
182
|
-
}[
|
|
185
|
+
}[t];
|
|
183
186
|
}
|
|
184
|
-
function
|
|
185
|
-
let
|
|
186
|
-
const
|
|
187
|
-
for (const
|
|
188
|
-
for (const e of
|
|
189
|
-
const
|
|
190
|
-
[
|
|
191
|
-
[
|
|
187
|
+
function _(t, c, p, s, r, m, d) {
|
|
188
|
+
let S;
|
|
189
|
+
const H = (o, e, i) => i === "NORTH" ? e.x === o.x && e.y < o.y : i === "SOUTH" ? e.x === o.x && e.y > o.y : i === "WEST" ? e.y === o.y && e.x < o.x : e.y === o.y && e.x > o.x;
|
|
190
|
+
for (const o of m ? [m] : b)
|
|
191
|
+
for (const e of d ? [d] : b) {
|
|
192
|
+
const i = m ? W(t, o) : k(t, o, c, r), u = d ? W(c, e) : k(c, e, t, r), v = i.x === u.x || i.y === u.y ? [[i, u]] : [
|
|
193
|
+
[i, { x: u.x, y: i.y }, u],
|
|
194
|
+
[i, { x: i.x, y: u.y }, u]
|
|
192
195
|
];
|
|
193
|
-
for (const l of
|
|
194
|
-
if (
|
|
195
|
-
const
|
|
196
|
-
return
|
|
197
|
-
(
|
|
196
|
+
for (const l of v) {
|
|
197
|
+
if (p.includes(t) && !H(i, l[1], o) || p.includes(c) && !H(u, l.at(-2), e) || l.slice(1).some((O, P) => {
|
|
198
|
+
const C = l[P];
|
|
199
|
+
return p.some(
|
|
200
|
+
(N) => Math.max(C.x, O.x) > N.x && Math.min(C.x, O.x) < N.x + N.width && Math.max(C.y, O.y) > N.y && Math.min(C.y, O.y) < N.y + N.height
|
|
198
201
|
);
|
|
199
202
|
}))
|
|
200
203
|
continue;
|
|
201
|
-
const
|
|
202
|
-
(
|
|
204
|
+
const U = l.slice(1).reduce(
|
|
205
|
+
(O, P, C) => O + Math.abs(P.x - l[C].x) + Math.abs(P.y - l[C].y),
|
|
203
206
|
0
|
|
204
|
-
) + (l.length - 2) * 32 + (
|
|
205
|
-
(!
|
|
207
|
+
) + (l.length - 2) * 32 + (o === s.source ? 0 : 16) + (e === s.target ? 0 : 16);
|
|
208
|
+
(!S || U < S.score) && (S = { source: o, target: e, score: U });
|
|
206
209
|
}
|
|
207
210
|
}
|
|
208
|
-
return
|
|
211
|
+
return S;
|
|
209
212
|
}
|
|
210
|
-
function
|
|
211
|
-
const
|
|
212
|
-
if (
|
|
213
|
-
const e =
|
|
214
|
-
NORTH: e.y -
|
|
215
|
-
EAST:
|
|
216
|
-
SOUTH:
|
|
217
|
-
WEST: e.x -
|
|
218
|
-
},
|
|
219
|
-
return { source:
|
|
213
|
+
function z(t, c) {
|
|
214
|
+
const p = (e, i) => i.x >= e.x && i.y >= e.y && i.x + i.width <= e.x + e.width && i.y + i.height <= e.y + e.height, s = p(t, c) ? t : p(c, t) ? c : void 0;
|
|
215
|
+
if (s) {
|
|
216
|
+
const e = s === t ? c : t, i = {
|
|
217
|
+
NORTH: e.y - s.y,
|
|
218
|
+
EAST: s.x + s.width - e.x - e.width,
|
|
219
|
+
SOUTH: s.y + s.height - e.y - e.height,
|
|
220
|
+
WEST: e.x - s.x
|
|
221
|
+
}, u = [...b].sort((v, l) => i[v] - i[l])[0];
|
|
222
|
+
return { source: u, target: u };
|
|
220
223
|
}
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
+
const r = c.x + c.width / 2 - (t.x + t.width / 2), m = c.y + c.height / 2 - (t.y + t.height / 2), d = Math.max(t.x - (c.x + c.width), c.x - (t.x + t.width), 0), S = Math.max(
|
|
225
|
+
t.y - (c.y + c.height),
|
|
226
|
+
c.y - (t.y + t.height),
|
|
224
227
|
0
|
|
225
|
-
),
|
|
226
|
-
return { source:
|
|
228
|
+
), o = (S === 0 && d > 0 ? !0 : d === 0 && S > 0 ? !1 : d === 0 && S === 0 ? Math.abs(r) >= Math.abs(m) : d <= S) ? r >= 0 ? "EAST" : "WEST" : m >= 0 ? "SOUTH" : "NORTH";
|
|
229
|
+
return { source: o, target: D(o) };
|
|
227
230
|
}
|
|
228
|
-
function
|
|
229
|
-
const
|
|
230
|
-
const
|
|
231
|
-
return
|
|
232
|
-
},
|
|
233
|
-
switch (
|
|
231
|
+
function k(t, c, p, s = 0) {
|
|
232
|
+
const r = (o) => Math.min(8, o / 4), m = (o, e, i) => Math.max(e + r(i), Math.min(e + i - r(i), o)), d = (o, e, i, u) => {
|
|
233
|
+
const v = Math.max(o, i), l = Math.min(o + e, i + u);
|
|
234
|
+
return v < l ? (v + l) / 2 + s : void 0;
|
|
235
|
+
}, S = p.x + p.width / 2, H = p.y + p.height / 2;
|
|
236
|
+
switch (c) {
|
|
234
237
|
case "NORTH":
|
|
235
238
|
return {
|
|
236
|
-
x:
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
239
|
+
x: m(
|
|
240
|
+
d(t.x, t.width, p.x, p.width) ?? S + s,
|
|
241
|
+
t.x,
|
|
242
|
+
t.width
|
|
240
243
|
),
|
|
241
|
-
y:
|
|
244
|
+
y: t.y
|
|
242
245
|
};
|
|
243
246
|
case "EAST":
|
|
244
247
|
return {
|
|
245
|
-
x:
|
|
246
|
-
y:
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
x: t.x + t.width,
|
|
249
|
+
y: m(
|
|
250
|
+
d(t.y, t.height, p.y, p.height) ?? H + s,
|
|
251
|
+
t.y,
|
|
252
|
+
t.height
|
|
250
253
|
)
|
|
251
254
|
};
|
|
252
255
|
case "SOUTH":
|
|
253
256
|
return {
|
|
254
|
-
x:
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
257
|
+
x: m(
|
|
258
|
+
d(t.x, t.width, p.x, p.width) ?? S + s,
|
|
259
|
+
t.x,
|
|
260
|
+
t.width
|
|
258
261
|
),
|
|
259
|
-
y:
|
|
262
|
+
y: t.y + t.height
|
|
260
263
|
};
|
|
261
264
|
case "WEST":
|
|
262
265
|
return {
|
|
263
|
-
x:
|
|
264
|
-
y:
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
266
|
+
x: t.x,
|
|
267
|
+
y: m(
|
|
268
|
+
d(t.y, t.height, p.y, p.height) ?? H + s,
|
|
269
|
+
t.y,
|
|
270
|
+
t.height
|
|
268
271
|
)
|
|
269
272
|
};
|
|
270
273
|
}
|
|
271
274
|
}
|
|
272
275
|
export {
|
|
273
|
-
|
|
276
|
+
I as routeGraphGeometry
|
|
274
277
|
};
|
|
@@ -46,6 +46,8 @@ export interface GraphLayout {
|
|
|
46
46
|
bounds: GraphBounds;
|
|
47
47
|
}
|
|
48
48
|
export interface GraphLayoutOptions {
|
|
49
|
+
/** Clearance around routing obstacles in world units. Defaults to 4; never changes node geometry. */
|
|
50
|
+
edgeClearance?: number;
|
|
49
51
|
/** Desired width/height when packing disconnected objects, including group members. */
|
|
50
52
|
aspectRatio?: number;
|
|
51
53
|
/** Absolute world positions. Descendants move with their group. Invalid positions always fail. */
|