@floegence/floe-webapp-core 0.86.5 → 0.86.7
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/packing.js +9 -8
- package/dist/components/graph/positions.d.ts +2 -3
- package/dist/components/graph/positions.js +55 -154
- package/dist/components/graph/routing.d.ts +3 -0
- package/dist/components/graph/routing.js +165 -0
- package/dist/libavoid.wasm +0 -0
- package/dist/licenses/graph-notice.txt +11 -0
- package/dist/licenses/libavoid-sources.tar.gz +0 -0
- package/dist/licenses/libavoid.txt +505 -0
- package/dist/node_modules/.pnpm/libavoid-js@0.5.0-beta.5/node_modules/libavoid-js/dist/index.js +1005 -0
- package/dist/node_modules/.pnpm/libavoid-js@0.5.0-beta.5/node_modules/libavoid-js/dist/libavoid.wasm.js +4 -0
- package/package.json +2 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { applyGraphPositions as b
|
|
2
|
-
|
|
1
|
+
import { applyGraphPositions as b } from "./positions.js";
|
|
2
|
+
import { routeGraphGeometry as G } from "./routing.js";
|
|
3
|
+
async function N(d, n, k) {
|
|
3
4
|
const a = new Map(d.nodes.map((e) => [e.id, { ...e, x: 0, y: 0 }])), r = /* @__PURE__ */ new Map();
|
|
4
5
|
for (const e of a.values()) {
|
|
5
6
|
const i = r.get(e.parentId) ?? [];
|
|
@@ -14,22 +15,22 @@ async function O(d, n, k) {
|
|
|
14
15
|
const g = n.groupPadding ?? { top: 64, right: 28, bottom: 28, left: 28 }, p = (e, i, o) => {
|
|
15
16
|
e.x += i, e.y += o;
|
|
16
17
|
for (const c of r.get(e.id) ?? []) p(c, i, o);
|
|
17
|
-
},
|
|
18
|
+
}, m = (e, i) => {
|
|
18
19
|
let o = a.get(e);
|
|
19
20
|
for (; o && o.parentId !== i; )
|
|
20
21
|
o = o.parentId ? a.get(o.parentId) : void 0;
|
|
21
22
|
return o;
|
|
22
|
-
},
|
|
23
|
+
}, y = async (e) => {
|
|
23
24
|
const i = r.get(e) ?? [];
|
|
24
25
|
for (const t of i) {
|
|
25
26
|
if (!r.has(t.id)) continue;
|
|
26
|
-
const s = await
|
|
27
|
+
const s = await y(t.id);
|
|
27
28
|
t.width = Math.max(t.width, s.width), t.height = Math.max(t.height, s.height);
|
|
28
29
|
}
|
|
29
30
|
if (!i.length) return { width: 0, height: 0 };
|
|
30
31
|
const o = /* @__PURE__ */ new Map();
|
|
31
32
|
for (const t of d.edges) {
|
|
32
|
-
const s =
|
|
33
|
+
const s = m(t.source, e), h = m(t.target, e);
|
|
33
34
|
if (!s || !h || s.id === h.id) continue;
|
|
34
35
|
const w = JSON.stringify([s.id, h.id]);
|
|
35
36
|
o.has(w) || o.set(w, { id: t.id, sources: [s.id], targets: [h.id] });
|
|
@@ -57,7 +58,7 @@ async function O(d, n, k) {
|
|
|
57
58
|
p(s, (t.x ?? 0) - s.x, (t.y ?? 0) - s.y);
|
|
58
59
|
}
|
|
59
60
|
return { width: c.width ?? 0, height: c.height ?? 0 };
|
|
60
|
-
}, S = await
|
|
61
|
+
}, S = await y(), f = !n.positions?.length && n.anchor && a.get(n.anchor.nodeId);
|
|
61
62
|
if (f) {
|
|
62
63
|
const e = n.anchor.position.x - f.x, i = n.anchor.position.y - f.y;
|
|
63
64
|
for (const o of r.get(void 0) ?? []) p(o, e, i);
|
|
@@ -70,5 +71,5 @@ async function O(d, n, k) {
|
|
|
70
71
|
return n.positions?.length ? b(u, n, d.nodes) : G(u);
|
|
71
72
|
}
|
|
72
73
|
export {
|
|
73
|
-
|
|
74
|
+
N as computePackedGraphLayout
|
|
74
75
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { GraphLayout, GraphLayoutOptions, GraphNode } from './types';
|
|
2
|
+
export { routeGraphGeometry } from './routing';
|
|
2
3
|
/** Apply explicit fixed or preferred positions, then route the resulting geometry once. */
|
|
3
|
-
export declare function applyGraphPositions(layout: GraphLayout, options: GraphLayoutOptions, input: readonly GraphNode[]): GraphLayout
|
|
4
|
-
/** Shared routing and bounds for explicit positions and packed compound geometry. */
|
|
5
|
-
export declare function routeGraphGeometry(layout: GraphLayout): GraphLayout;
|
|
4
|
+
export declare function applyGraphPositions(layout: GraphLayout, options: GraphLayoutOptions, input: readonly GraphNode[]): GraphLayout | Promise<GraphLayout>;
|
|
@@ -1,174 +1,75 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
(c) => r.x === a.x ? r.x > c.left && r.x < c.right && Math.max(r.y, a.y) > c.top && Math.min(r.y, a.y) < c.bottom : r.y > c.top && r.y < c.bottom && Math.max(r.x, a.x) > c.left && Math.min(r.x, a.x) < c.right
|
|
8
|
-
);
|
|
9
|
-
function P(r, a, w) {
|
|
10
|
-
if (w.some((e) => S(r, e) || S(a, e)))
|
|
11
|
-
throw new Error("Pinned graph positions obstruct an edge endpoint");
|
|
12
|
-
const c = [
|
|
13
|
-
.../* @__PURE__ */ new Set([r.x, a.x, ...w.flatMap((e) => [e.left, e.right])])
|
|
14
|
-
].sort((e, i) => e - i), m = [
|
|
15
|
-
.../* @__PURE__ */ new Set([r.y, a.y, ...w.flatMap((e) => [e.top, e.bottom])])
|
|
16
|
-
].sort((e, i) => e - i), l = (e) => ({ x: c[e % c.length], y: m[Math.floor(e / c.length)] }), g = m.indexOf(r.y) * c.length + c.indexOf(r.x), n = m.indexOf(a.y) * c.length + c.indexOf(a.x), M = /* @__PURE__ */ new Map([[g, 0]]), d = /* @__PURE__ */ new Map(), t = [], u = (e) => {
|
|
17
|
-
let i = t.length;
|
|
18
|
-
for (t.push(e); i > 0; ) {
|
|
19
|
-
const x = i - 1 >> 1;
|
|
20
|
-
if (t[x].score <= e.score) break;
|
|
21
|
-
t[i] = t[x], i = x;
|
|
22
|
-
}
|
|
23
|
-
t[i] = e;
|
|
24
|
-
}, I = () => {
|
|
25
|
-
const e = t[0], i = t.pop();
|
|
26
|
-
if (t.length) {
|
|
27
|
-
let x = 0;
|
|
28
|
-
for (; x * 2 + 1 < t.length; ) {
|
|
29
|
-
let h = x * 2 + 1;
|
|
30
|
-
if (h + 1 < t.length && t[h + 1].score < t[h].score && h++, t[h].score >= i.score) break;
|
|
31
|
-
t[x] = t[h], x = h;
|
|
32
|
-
}
|
|
33
|
-
t[x] = i;
|
|
34
|
-
}
|
|
35
|
-
return e;
|
|
36
|
-
};
|
|
37
|
-
u({ id: g, score: 0, cost: 0 });
|
|
38
|
-
let v = 0;
|
|
39
|
-
for (; t.length && v++ < 5e4; ) {
|
|
40
|
-
const e = I();
|
|
41
|
-
if (e.cost !== M.get(e.id)) continue;
|
|
42
|
-
if (e.id === n) {
|
|
43
|
-
const y = [l(n)];
|
|
44
|
-
let o = n;
|
|
45
|
-
for (; o !== g; )
|
|
46
|
-
o = d.get(o), y.push(l(o));
|
|
47
|
-
return y.reverse(), y.filter((p, f) => {
|
|
48
|
-
const E = y[f - 1], b = y[f + 1];
|
|
49
|
-
return !E || !b || !(E.x === p.x && p.x === b.x || E.y === p.y && p.y === b.y);
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
const i = l(e.id), x = e.id % c.length, h = Math.floor(e.id / c.length), s = [
|
|
53
|
-
x ? e.id - 1 : -1,
|
|
54
|
-
x + 1 < c.length ? e.id + 1 : -1,
|
|
55
|
-
h ? e.id - c.length : -1,
|
|
56
|
-
h + 1 < m.length ? e.id + c.length : -1
|
|
57
|
-
];
|
|
58
|
-
for (const y of s) {
|
|
59
|
-
if (y < 0) continue;
|
|
60
|
-
const o = l(y), p = e.cost + Math.abs(i.x - o.x) + Math.abs(i.y - o.y);
|
|
61
|
-
p >= (M.get(y) ?? 1 / 0) || !O(i, o, w) || (M.set(y, p), d.set(y, e.id), u({ id: y, cost: p, score: p + Math.abs(o.x - a.x) + Math.abs(o.y - a.y) }));
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
throw new Error("Pinned graph positions cannot be routed within the layout budget");
|
|
65
|
-
}
|
|
66
|
-
function k(r, a, w) {
|
|
67
|
-
if (!a.positions?.length) return r;
|
|
68
|
-
const c = new Map(r.nodes.map((t) => [t.id, { ...t }])), m = /* @__PURE__ */ new Map();
|
|
69
|
-
for (const t of a.positions) {
|
|
70
|
-
if (!c.has(t.nodeId) || m.has(t.nodeId) || !Number.isFinite(t.x) || !Number.isFinite(t.y))
|
|
1
|
+
import { routeGraphGeometry as G } from "./routing.js";
|
|
2
|
+
function E(d, c, v) {
|
|
3
|
+
if (!c.positions?.length) return d;
|
|
4
|
+
const f = new Map(d.nodes.map((t) => [t.id, { ...t }])), l = /* @__PURE__ */ new Map();
|
|
5
|
+
for (const t of c.positions) {
|
|
6
|
+
if (!f.has(t.nodeId) || l.has(t.nodeId) || !Number.isFinite(t.x) || !Number.isFinite(t.y))
|
|
71
7
|
throw new Error(`Invalid graph position: ${t.nodeId}`);
|
|
72
|
-
|
|
8
|
+
l.set(t.nodeId, t);
|
|
73
9
|
}
|
|
74
|
-
const
|
|
75
|
-
for (const t of
|
|
10
|
+
const y = /* @__PURE__ */ new Map();
|
|
11
|
+
for (const t of f.values())
|
|
76
12
|
if (t.parentId) {
|
|
77
|
-
const
|
|
78
|
-
|
|
13
|
+
const m = y.get(t.parentId) ?? [];
|
|
14
|
+
m.push(t), y.set(t.parentId, m);
|
|
79
15
|
}
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
t.x =
|
|
83
|
-
const i =
|
|
84
|
-
for (const
|
|
85
|
-
if (!i.length ||
|
|
86
|
-
const
|
|
87
|
-
if (
|
|
16
|
+
const x = c.groupPadding ?? { top: 64, left: 28, right: 28, bottom: 28 }, u = c.positionMode === "preferred", I = new Map(v.map((t) => [t.id, t])), b = (t, m, M) => {
|
|
17
|
+
const g = { x: t.x, y: t.y }, p = l.get(t.id);
|
|
18
|
+
t.x = p?.x ?? t.x + m, t.y = p?.y ?? t.y + M;
|
|
19
|
+
const i = y.get(t.id) ?? [];
|
|
20
|
+
for (const a of i) b(a, t.x - g.x, t.y - g.y);
|
|
21
|
+
if (!i.length || u) return;
|
|
22
|
+
const o = Math.min(...i.map((a) => a.x)) - x.left, h = Math.min(...i.map((a) => a.y)) - x.top;
|
|
23
|
+
if (p && (o < t.x || h < t.y))
|
|
88
24
|
throw new Error(`Pinned child lies outside group content: ${t.id}`);
|
|
89
25
|
const s = Math.max(
|
|
90
26
|
t.x + t.width,
|
|
91
|
-
...i.map((
|
|
92
|
-
),
|
|
27
|
+
...i.map((a) => a.x + a.width + x.right)
|
|
28
|
+
), n = Math.max(
|
|
93
29
|
t.y + t.height,
|
|
94
|
-
...i.map((
|
|
30
|
+
...i.map((a) => a.y + a.height + x.bottom)
|
|
95
31
|
);
|
|
96
|
-
|
|
32
|
+
p || (t.x = Math.min(t.x, o), t.y = Math.min(t.y, h)), t.width = s - t.x, t.height = n - t.y;
|
|
97
33
|
};
|
|
98
|
-
for (const t of
|
|
99
|
-
if (
|
|
100
|
-
const t = Math.max(16,
|
|
101
|
-
i.x +=
|
|
102
|
-
for (const s of
|
|
103
|
-
},
|
|
104
|
-
const
|
|
34
|
+
for (const t of f.values()) t.parentId || b(t, 0, 0);
|
|
35
|
+
if (u) {
|
|
36
|
+
const t = Math.max(16, c.spacing ?? 64), m = (i, o, h) => {
|
|
37
|
+
i.x += o, i.y += h;
|
|
38
|
+
for (const s of y.get(i.id) ?? []) m(s, o, h);
|
|
39
|
+
}, M = (i) => {
|
|
40
|
+
const o = [];
|
|
105
41
|
for (const h of [...i].sort(
|
|
106
|
-
(s,
|
|
42
|
+
(s, n) => s.y - n.y || s.x - n.x || s.id.localeCompare(n.id)
|
|
107
43
|
)) {
|
|
108
44
|
const s = { x: h.x, y: h.y };
|
|
109
|
-
for (const
|
|
110
|
-
h.y <
|
|
111
|
-
const
|
|
112
|
-
for (const
|
|
113
|
-
h.x <
|
|
114
|
-
const
|
|
115
|
-
|
|
45
|
+
for (const r of [...o].sort((e, w) => e.x - w.x))
|
|
46
|
+
h.y < r.y + r.height + t && h.y + h.height + t > r.y && s.x < r.x + r.width + t && s.x + h.width + t > r.x && (s.x = r.x + r.width + t);
|
|
47
|
+
const n = { x: h.x, y: h.y };
|
|
48
|
+
for (const r of [...o].sort((e, w) => e.y - w.y))
|
|
49
|
+
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);
|
|
50
|
+
const a = s.x - h.x < n.y - h.y ? s : n;
|
|
51
|
+
m(h, a.x - h.x, a.y - h.y), o.push(h);
|
|
116
52
|
}
|
|
117
|
-
},
|
|
118
|
-
const
|
|
119
|
-
if (!
|
|
120
|
-
for (const
|
|
121
|
-
|
|
122
|
-
const h = Math.max(12,
|
|
123
|
-
i.x = Math.min(
|
|
124
|
-
|
|
125
|
-
Math.max(...
|
|
53
|
+
}, g = (i) => {
|
|
54
|
+
const o = y.get(i.id) ?? [];
|
|
55
|
+
if (!o.length) return;
|
|
56
|
+
for (const e of o) g(e);
|
|
57
|
+
M(o);
|
|
58
|
+
const h = Math.max(12, x.left), s = Math.max(12, x.top), n = Math.max(12, x.right), a = Math.max(12, x.bottom), r = l.get(i.id);
|
|
59
|
+
i.x = Math.min(r?.x ?? 1 / 0, Math.min(...o.map((e) => e.x)) - h), i.y = Math.min(r?.y ?? 1 / 0, Math.min(...o.map((e) => e.y)) - s), i.width = Math.max(
|
|
60
|
+
I.get(i.id).width,
|
|
61
|
+
Math.max(...o.map((e) => e.x + e.width)) + n - i.x
|
|
126
62
|
), i.height = Math.max(
|
|
127
|
-
|
|
128
|
-
Math.max(...
|
|
63
|
+
I.get(i.id).height,
|
|
64
|
+
Math.max(...o.map((e) => e.y + e.height)) + a - i.y
|
|
129
65
|
);
|
|
130
|
-
},
|
|
131
|
-
for (const i of
|
|
132
|
-
|
|
66
|
+
}, p = [...f.values()].filter((i) => !i.parentId);
|
|
67
|
+
for (const i of p) g(i);
|
|
68
|
+
M(p);
|
|
133
69
|
}
|
|
134
|
-
return
|
|
135
|
-
}
|
|
136
|
-
function N(r) {
|
|
137
|
-
if (!r.nodes.length) return r;
|
|
138
|
-
const a = new Map(r.nodes.map((n) => [n.id, n])), w = r.edges.map((n) => {
|
|
139
|
-
const M = a.get(n.source), d = a.get(n.target), t = (s, y, o) => s.ports?.find((p) => p.id === y)?.side ?? o, u = M.x + M.width / 2 <= d.x + d.width / 2, I = (s, y) => {
|
|
140
|
-
const o = { x: s.x + s.width / 2, y: s.y + s.height / 2 };
|
|
141
|
-
return y === "NORTH" ? [
|
|
142
|
-
{ x: o.x, y: s.y },
|
|
143
|
-
{ x: o.x, y: s.y - 8 }
|
|
144
|
-
] : y === "SOUTH" ? [
|
|
145
|
-
{ x: o.x, y: s.y + s.height },
|
|
146
|
-
{ x: o.x, y: s.y + s.height + 8 }
|
|
147
|
-
] : y === "WEST" ? [
|
|
148
|
-
{ x: s.x, y: o.y },
|
|
149
|
-
{ x: s.x - 8, y: o.y }
|
|
150
|
-
] : [
|
|
151
|
-
{ x: s.x + s.width, y: o.y },
|
|
152
|
-
{ x: s.x + s.width + 8, y: o.y }
|
|
153
|
-
];
|
|
154
|
-
}, [v, e] = I(M, t(M, n.sourcePort, u ? "EAST" : "WEST")), [i, x] = I(
|
|
155
|
-
d,
|
|
156
|
-
t(d, n.targetPort, M === d ? "NORTH" : u ? "WEST" : "EAST")
|
|
157
|
-
), h = [...a.values()].filter((s) => s.kind !== "group").map((s) => T(s, 4));
|
|
158
|
-
return { ...n, sections: [[v, ...P(e, x, h), i]] };
|
|
159
|
-
}), c = [...a.values()], m = w.flatMap((n) => n.sections.flat()), l = Math.min(...c.map((n) => n.x), ...m.map((n) => n.x)), g = Math.min(...c.map((n) => n.y), ...m.map((n) => n.y));
|
|
160
|
-
return {
|
|
161
|
-
nodes: c,
|
|
162
|
-
edges: w,
|
|
163
|
-
bounds: {
|
|
164
|
-
x: l,
|
|
165
|
-
y: g,
|
|
166
|
-
width: Math.max(...c.map((n) => n.x + n.width), ...m.map((n) => n.x)) - l,
|
|
167
|
-
height: Math.max(...c.map((n) => n.y + n.height), ...m.map((n) => n.y)) - g
|
|
168
|
-
}
|
|
169
|
-
};
|
|
70
|
+
return G({ ...d, nodes: [...f.values()] });
|
|
170
71
|
}
|
|
171
72
|
export {
|
|
172
|
-
|
|
173
|
-
|
|
73
|
+
E as applyGraphPositions,
|
|
74
|
+
G as routeGraphGeometry
|
|
174
75
|
};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { AvoidLib as H } from "../../node_modules/.pnpm/libavoid-js@0.5.0-beta.5/node_modules/libavoid-js/dist/index.js";
|
|
2
|
+
import _ from "../../node_modules/.pnpm/libavoid-js@0.5.0-beta.5/node_modules/libavoid-js/dist/libavoid.wasm.js";
|
|
3
|
+
let U;
|
|
4
|
+
const F = { NORTH: 1, SOUTH: 2, WEST: 4, EAST: 8 }, v = ["NORTH", "EAST", "SOUTH", "WEST"], m = (s) => s.delete();
|
|
5
|
+
async function L(s) {
|
|
6
|
+
if (!s.nodes.length) return s;
|
|
7
|
+
if (!s.edges.length) return W(s);
|
|
8
|
+
await (U ??= H.load(_).catch((g) => {
|
|
9
|
+
throw U = void 0, g;
|
|
10
|
+
}));
|
|
11
|
+
const n = H.getInstance(), x = new Map(s.nodes.map((g) => [g.id, g])), S = (g) => {
|
|
12
|
+
const y = [];
|
|
13
|
+
for (let a = x.get(g).parentId; a; a = x.get(a).parentId)
|
|
14
|
+
y.push(a);
|
|
15
|
+
return y;
|
|
16
|
+
}, i = /* @__PURE__ */ new Map();
|
|
17
|
+
for (const g of s.edges) {
|
|
18
|
+
const y = /* @__PURE__ */ new Set([...S(g.source), ...S(g.target)]), a = JSON.stringify([...y].sort()), O = i.get(a) ?? { open: y, edges: [] };
|
|
19
|
+
O.edges.push(g), i.set(a, O);
|
|
20
|
+
}
|
|
21
|
+
const k = /* @__PURE__ */ new Map();
|
|
22
|
+
for (const { open: g, edges: y } of i.values()) {
|
|
23
|
+
const a = new n.Router(2);
|
|
24
|
+
try {
|
|
25
|
+
a.setRoutingParameter(n.RoutingParameter.shapeBufferDistance, 4), a.setRoutingParameter(n.RoutingParameter.idealNudgingDistance, 8), a.setRoutingParameter(n.RoutingParameter.crossingPenalty, 80), a.setRoutingParameter(n.RoutingParameter.fixedSharedPathPenalty, 120), a.setRoutingParameter(n.RoutingParameter.portDirectionPenalty, 0), a.setRoutingOption(n.RoutingOption.nudgeOrthogonalSegmentsConnectedToShapes, !1), a.setRoutingOption(n.RoutingOption.nudgeSharedPathsWithCommonEndPoint, !0);
|
|
26
|
+
const O = new Map(
|
|
27
|
+
s.nodes.filter((t) => !g.has(t.id) && S(t.id).every((r) => g.has(r))).map((t) => {
|
|
28
|
+
const r = new n.Point(t.x, t.y), c = new n.Point(t.x + t.width, t.y + t.height), h = new n.Rectangle(r, c), o = new n.ShapeRef(a, h);
|
|
29
|
+
return m(r), m(c), m(h), [t.id, o];
|
|
30
|
+
})
|
|
31
|
+
);
|
|
32
|
+
for (const t of s.nodes) {
|
|
33
|
+
const r = O.get(t.id);
|
|
34
|
+
if (!r) continue;
|
|
35
|
+
const c = y.flatMap(
|
|
36
|
+
(e) => e.source === t.id ? [x.get(e.target)] : e.target === t.id ? [x.get(e.source)] : []
|
|
37
|
+
);
|
|
38
|
+
if (!c.length) continue;
|
|
39
|
+
const h = (e, f, p, M) => {
|
|
40
|
+
const T = Math.max(e, p), R = Math.min(e + f, p + M), A = Math.min(8, f / 4);
|
|
41
|
+
return T < R ? (T + R) / 2 : Math.max(e + A, Math.min(e + f - A, p + M / 2));
|
|
42
|
+
}, o = (e, f) => {
|
|
43
|
+
const p = Math.min(8, e / 4);
|
|
44
|
+
return [
|
|
45
|
+
.../* @__PURE__ */ new Set([
|
|
46
|
+
e / 2,
|
|
47
|
+
p,
|
|
48
|
+
e - p,
|
|
49
|
+
...f.flatMap(
|
|
50
|
+
(M) => Array.from(
|
|
51
|
+
{ length: c.length + 1 },
|
|
52
|
+
(T, R) => Math.max(p, Math.min(e - p, M + (R - c.length / 2) * 8))
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
])
|
|
56
|
+
];
|
|
57
|
+
}, u = o(
|
|
58
|
+
t.width,
|
|
59
|
+
c.map((e) => h(t.x, t.width, e.x, e.width) - t.x)
|
|
60
|
+
), w = o(
|
|
61
|
+
t.height,
|
|
62
|
+
c.map((e) => h(t.y, t.height, e.y, e.height) - t.y)
|
|
63
|
+
), l = (t.ports ?? []).map((e) => E(t, e.side)), P = y.some((e) => e.source === t.id && e.target === t.id), C = [
|
|
64
|
+
...l,
|
|
65
|
+
...P ? [
|
|
66
|
+
{ x: t.x + t.width, y: t.y + t.height / 3 },
|
|
67
|
+
{ x: t.x + t.width, y: t.y + t.height * 2 / 3 }
|
|
68
|
+
] : []
|
|
69
|
+
], b = (e, f, p, M, T) => {
|
|
70
|
+
const R = new n.ShapeConnectionPin(
|
|
71
|
+
r,
|
|
72
|
+
e,
|
|
73
|
+
f / t.width,
|
|
74
|
+
p / t.height,
|
|
75
|
+
!0,
|
|
76
|
+
0,
|
|
77
|
+
M
|
|
78
|
+
);
|
|
79
|
+
R.setExclusive(T), R.setConnectionCost(
|
|
80
|
+
t.width / 2 + t.height / 2 - Math.abs(f - t.width / 2) - Math.abs(p - t.height / 2)
|
|
81
|
+
);
|
|
82
|
+
}, d = (e, f, p) => {
|
|
83
|
+
C.some((M) => M.x === t.x + e && M.y === t.y + f) || b(1, e, f, p, !0);
|
|
84
|
+
};
|
|
85
|
+
for (const e of u)
|
|
86
|
+
d(e, 0, 1), d(e, t.height, 2);
|
|
87
|
+
for (const e of w)
|
|
88
|
+
d(0, e, 4), d(t.width, e, 8);
|
|
89
|
+
for (const e of new Set(t.ports?.map((f) => f.side))) {
|
|
90
|
+
const { x: f, y: p } = E(t, e);
|
|
91
|
+
b(v.indexOf(e) + 2, f - t.x, p - t.y, F[e], !1);
|
|
92
|
+
}
|
|
93
|
+
P && (b(6, t.width, t.height / 3, 8, !1), b(7, t.width, t.height * 2 / 3, 8, !1));
|
|
94
|
+
}
|
|
95
|
+
const N = (t, r, c, h) => {
|
|
96
|
+
const o = x.get(t), u = O.get(t);
|
|
97
|
+
if (u)
|
|
98
|
+
return new n.ConnEnd(
|
|
99
|
+
u,
|
|
100
|
+
r ? v.indexOf(o.ports.find((d) => d.id === r).side) + 2 : t === c ? h ? 7 : 6 : 1
|
|
101
|
+
);
|
|
102
|
+
const w = x.get(c), l = v.map((d) => E(o, d));
|
|
103
|
+
l.sort((d, e) => B(d, w) - B(e, w));
|
|
104
|
+
const P = r ? E(o, o.ports.find((d) => d.id === r).side) : l[0], C = new n.Point(P.x, P.y), b = new n.ConnEnd(C);
|
|
105
|
+
return m(C), b;
|
|
106
|
+
}, G = y.map((t) => {
|
|
107
|
+
const r = N(t.source, t.sourcePort, t.target, !1), c = N(t.target, t.targetPort, t.source, !0), h = new n.ConnRef(a, r, c);
|
|
108
|
+
if (m(r), m(c), t.source === t.target) {
|
|
109
|
+
const o = x.get(t.source), u = new n.CheckpointVector();
|
|
110
|
+
for (const w of [o.y + o.height / 3, o.y + o.height * 2 / 3]) {
|
|
111
|
+
const l = new n.Point(o.x + o.width + 24, w), P = new n.Checkpoint(l);
|
|
112
|
+
u.push_back(P), m(l), m(P);
|
|
113
|
+
}
|
|
114
|
+
h.setRoutingCheckpoints(u), m(u);
|
|
115
|
+
}
|
|
116
|
+
return { edge: t, connection: h };
|
|
117
|
+
});
|
|
118
|
+
a.processTransaction();
|
|
119
|
+
for (const { edge: t, connection: r } of G) {
|
|
120
|
+
const c = r.displayRoute(), h = Array.from({ length: c.size() }, (o, u) => {
|
|
121
|
+
const w = c.at(u), l = { x: w.x, y: w.y };
|
|
122
|
+
return m(w), l;
|
|
123
|
+
});
|
|
124
|
+
if (m(c), !r.hasValidRoute() || h.length < 2 || h.some((o) => !Number.isFinite(o.x) || !Number.isFinite(o.y)) || h.some((o, u) => u > 0 && o.x !== h[u - 1].x && o.y !== h[u - 1].y))
|
|
125
|
+
throw new Error(`Graph edge cannot be routed: ${t.id}`);
|
|
126
|
+
k.set(t.id, h);
|
|
127
|
+
}
|
|
128
|
+
} finally {
|
|
129
|
+
a.delete();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const D = s.edges.map((g) => ({ ...g, sections: [k.get(g.id)] }));
|
|
133
|
+
return W({ nodes: s.nodes, edges: D, bounds: s.bounds });
|
|
134
|
+
}
|
|
135
|
+
function W(s) {
|
|
136
|
+
const n = [
|
|
137
|
+
...s.nodes.flatMap((i) => [
|
|
138
|
+
{ x: i.x, y: i.y },
|
|
139
|
+
{ x: i.x + i.width, y: i.y + i.height }
|
|
140
|
+
]),
|
|
141
|
+
...s.edges.flatMap((i) => i.sections.flat())
|
|
142
|
+
], x = Math.min(...n.map((i) => i.x)), S = Math.min(...n.map((i) => i.y));
|
|
143
|
+
return {
|
|
144
|
+
nodes: s.nodes,
|
|
145
|
+
edges: s.edges,
|
|
146
|
+
bounds: {
|
|
147
|
+
x,
|
|
148
|
+
y: S,
|
|
149
|
+
width: Math.max(...n.map((i) => i.x)) - x,
|
|
150
|
+
height: Math.max(...n.map((i) => i.y)) - S
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function E(s, n) {
|
|
155
|
+
return {
|
|
156
|
+
x: n === "WEST" ? s.x : n === "EAST" ? s.x + s.width : s.x + s.width / 2,
|
|
157
|
+
y: n === "NORTH" ? s.y : n === "SOUTH" ? s.y + s.height : s.y + s.height / 2
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function B(s, n) {
|
|
161
|
+
return Math.max(n.x - s.x, 0, s.x - n.x - n.width) + Math.max(n.y - s.y, 0, s.y - n.y - n.height);
|
|
162
|
+
}
|
|
163
|
+
export {
|
|
164
|
+
L as routeGraphGeometry
|
|
165
|
+
};
|
|
Binary file
|
|
@@ -3,3 +3,14 @@ Copyright (c) 2017 Kiel University and others.
|
|
|
3
3
|
Licensed under the Eclipse Public License 2.0. A copy is in elkjs.txt.
|
|
4
4
|
Unmodified upstream source is available at https://github.com/kieler/elkjs/tree/0.12.0
|
|
5
5
|
and https://registry.npmjs.org/elkjs/-/elkjs-0.12.0.tgz.
|
|
6
|
+
|
|
7
|
+
Orthogonal routing uses libavoid-js 0.5.0-beta.5 and its separate unmodified
|
|
8
|
+
libavoid.wasm library. libavoid is Copyright (C) Monash University and others;
|
|
9
|
+
libavoid-js is maintained by Vladyslav Hnatiuk. Licensed under LGPL-2.1-or-later;
|
|
10
|
+
a copy is in libavoid.txt. Corresponding source and build instructions are
|
|
11
|
+
included in libavoid-sources.tar.gz. The unmodified source revisions are:
|
|
12
|
+
https://github.com/Aksem/libavoid-js/tree/5062a42fbd82fff562afeebcbb7b1ed45eed8e75
|
|
13
|
+
https://github.com/Aksem/adaptagrams/tree/0ab3467b4ed3523bb3e404a0dd7da7647d9eb13d
|
|
14
|
+
The separate WASM library can be replaced with an API-compatible build.
|
|
15
|
+
Extract the source archive, enter libavoid-js, and run python3 tools/generate.py
|
|
16
|
+
(requires Docker), npm install, and npm run build to rebuild the library.
|
|
Binary file
|