@floegence/floe-webapp-core 0.86.5 → 0.86.8

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.
@@ -1,174 +1,75 @@
1
- const T = (r, a = 0) => ({
2
- left: r.x - a,
3
- top: r.y - a,
4
- right: r.x + r.width + a,
5
- bottom: r.y + r.height + a
6
- }), S = (r, a) => r.x > a.left && r.x < a.right && r.y > a.top && r.y < a.bottom, O = (r, a, w) => !w.some(
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, p, v) {
3
+ if (!p.positions?.length || p.positionMode === "compact") return d;
4
+ const f = new Map(d.nodes.map((t) => [t.id, { ...t }])), l = /* @__PURE__ */ new Map();
5
+ for (const t of p.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
- m.set(t.nodeId, t);
8
+ l.set(t.nodeId, t);
73
9
  }
74
- const l = /* @__PURE__ */ new Map();
75
- for (const t of c.values())
10
+ const y = /* @__PURE__ */ new Map();
11
+ for (const t of f.values())
76
12
  if (t.parentId) {
77
- const u = l.get(t.parentId) ?? [];
78
- u.push(t), l.set(t.parentId, u);
13
+ const m = y.get(t.parentId) ?? [];
14
+ m.push(t), y.set(t.parentId, m);
79
15
  }
80
- const g = a.groupPadding ?? { top: 64, left: 28, right: 28, bottom: 28 }, n = a.positionMode === "preferred", M = new Map(w.map((t) => [t.id, t])), d = (t, u, I) => {
81
- const v = { x: t.x, y: t.y }, e = m.get(t.id);
82
- t.x = e?.x ?? t.x + u, t.y = e?.y ?? t.y + I;
83
- const i = l.get(t.id) ?? [];
84
- for (const o of i) d(o, t.x - v.x, t.y - v.y);
85
- if (!i.length || n) return;
86
- const x = Math.min(...i.map((o) => o.x)) - g.left, h = Math.min(...i.map((o) => o.y)) - g.top;
87
- if (e && (x < t.x || h < t.y))
16
+ const x = p.groupPadding ?? { top: 64, left: 28, right: 28, bottom: 28 }, u = p.positionMode === "preferred", I = new Map(v.map((t) => [t.id, t])), b = (t, m, M) => {
17
+ const g = { x: t.x, y: t.y }, c = l.get(t.id);
18
+ t.x = c?.x ?? t.x + m, t.y = c?.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 r = Math.min(...i.map((a) => a.x)) - x.left, h = Math.min(...i.map((a) => a.y)) - x.top;
23
+ if (c && (r < 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((o) => o.x + o.width + g.right)
92
- ), y = Math.max(
27
+ ...i.map((a) => a.x + a.width + x.right)
28
+ ), n = Math.max(
93
29
  t.y + t.height,
94
- ...i.map((o) => o.y + o.height + g.bottom)
30
+ ...i.map((a) => a.y + a.height + x.bottom)
95
31
  );
96
- e || (t.x = Math.min(t.x, x), t.y = Math.min(t.y, h)), t.width = s - t.x, t.height = y - t.y;
32
+ c || (t.x = Math.min(t.x, r), t.y = Math.min(t.y, h)), t.width = s - t.x, t.height = n - t.y;
97
33
  };
98
- for (const t of c.values()) t.parentId || d(t, 0, 0);
99
- if (n) {
100
- const t = Math.max(16, a.spacing ?? 64), u = (i, x, h) => {
101
- i.x += x, i.y += h;
102
- for (const s of l.get(i.id) ?? []) u(s, x, h);
103
- }, I = (i) => {
104
- const x = [];
34
+ for (const t of f.values()) t.parentId || b(t, 0, 0);
35
+ if (u) {
36
+ const t = Math.max(16, p.spacing ?? 64), m = (i, r, h) => {
37
+ i.x += r, i.y += h;
38
+ for (const s of y.get(i.id) ?? []) m(s, r, h);
39
+ }, M = (i) => {
40
+ const r = [];
105
41
  for (const h of [...i].sort(
106
- (s, y) => s.y - y.y || s.x - y.x || s.id.localeCompare(y.id)
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 p of [...x].sort((f, E) => f.x - E.x))
110
- h.y < p.y + p.height + t && h.y + h.height + t > p.y && s.x < p.x + p.width + t && s.x + h.width + t > p.x && (s.x = p.x + p.width + t);
111
- const y = { x: h.x, y: h.y };
112
- for (const p of [...x].sort((f, E) => f.y - E.y))
113
- h.x < p.x + p.width + t && h.x + h.width + t > p.x && y.y < p.y + p.height + t && y.y + h.height + t > p.y && (y.y = p.y + p.height + t);
114
- const o = s.x - h.x < y.y - h.y ? s : y;
115
- u(h, o.x - h.x, o.y - h.y), x.push(h);
45
+ for (const o of [...r].sort((e, w) => e.x - w.x))
46
+ h.y < o.y + o.height + t && h.y + h.height + t > o.y && s.x < o.x + o.width + t && s.x + h.width + t > o.x && (s.x = o.x + o.width + t);
47
+ const n = { x: h.x, y: h.y };
48
+ for (const o of [...r].sort((e, w) => e.y - w.y))
49
+ h.x < o.x + o.width + t && h.x + h.width + t > o.x && n.y < o.y + o.height + t && n.y + h.height + t > o.y && (n.y = o.y + o.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), r.push(h);
116
52
  }
117
- }, v = (i) => {
118
- const x = l.get(i.id) ?? [];
119
- if (!x.length) return;
120
- for (const f of x) v(f);
121
- I(x);
122
- const h = Math.max(12, g.left), s = Math.max(12, g.top), y = Math.max(12, g.right), o = Math.max(12, g.bottom), p = m.get(i.id);
123
- i.x = Math.min(p?.x ?? 1 / 0, Math.min(...x.map((f) => f.x)) - h), i.y = Math.min(p?.y ?? 1 / 0, Math.min(...x.map((f) => f.y)) - s), i.width = Math.max(
124
- M.get(i.id).width,
125
- Math.max(...x.map((f) => f.x + f.width)) + y - i.x
53
+ }, g = (i) => {
54
+ const r = y.get(i.id) ?? [];
55
+ if (!r.length) return;
56
+ for (const e of r) g(e);
57
+ M(r);
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), o = l.get(i.id);
59
+ i.x = Math.min(o?.x ?? 1 / 0, Math.min(...r.map((e) => e.x)) - h), i.y = Math.min(o?.y ?? 1 / 0, Math.min(...r.map((e) => e.y)) - s), i.width = Math.max(
60
+ I.get(i.id).width,
61
+ Math.max(...r.map((e) => e.x + e.width)) + n - i.x
126
62
  ), i.height = Math.max(
127
- M.get(i.id).height,
128
- Math.max(...x.map((f) => f.y + f.height)) + o - i.y
63
+ I.get(i.id).height,
64
+ Math.max(...r.map((e) => e.y + e.height)) + a - i.y
129
65
  );
130
- }, e = [...c.values()].filter((i) => !i.parentId);
131
- for (const i of e) v(i);
132
- I(e);
66
+ }, c = [...f.values()].filter((i) => !i.parentId);
67
+ for (const i of c) g(i);
68
+ M(c);
133
69
  }
134
- return N({ ...r, nodes: [...c.values()] });
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
- k as applyGraphPositions,
173
- N as routeGraphGeometry
73
+ E as applyGraphPositions,
74
+ G as routeGraphGeometry
174
75
  };
@@ -0,0 +1,3 @@
1
+ import type { GraphLayout } from './types';
2
+ /** Joint orthogonal routing through the final rectangular geometry. */
3
+ export declare function routeGraphGeometry(layout: GraphLayout): Promise<GraphLayout>;
@@ -0,0 +1,202 @@
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 W from "../../node_modules/.pnpm/libavoid-js@0.5.0-beta.5/node_modules/libavoid-js/dist/libavoid.wasm.js";
3
+ let N;
4
+ const B = { NORTH: 1, SOUTH: 2, WEST: 4, EAST: 8 }, v = ["NORTH", "EAST", "SOUTH", "WEST"], m = (t) => t.delete();
5
+ async function F(t) {
6
+ if (!t.nodes.length) return t;
7
+ if (!t.edges.length) return C(t);
8
+ await (N ??= H.load(W).catch((h) => {
9
+ throw N = void 0, h;
10
+ }));
11
+ const e = H.getInstance(), s = new Map(t.nodes.map((h) => [h.id, h])), d = (h) => {
12
+ const y = [];
13
+ for (let r = s.get(h).parentId; r; r = s.get(r).parentId)
14
+ y.push(r);
15
+ return y;
16
+ }, i = /* @__PURE__ */ new Map();
17
+ for (const h of t.edges) {
18
+ const y = /* @__PURE__ */ new Set([...d(h.source), ...d(h.target)]), r = JSON.stringify([...y].sort()), S = i.get(r) ?? { open: y, edges: [] };
19
+ S.edges.push(h), i.set(r, S);
20
+ }
21
+ const f = /* @__PURE__ */ new Map();
22
+ for (const { open: h, edges: y } of i.values()) {
23
+ const r = new e.Router(2);
24
+ try {
25
+ r.setRoutingParameter(e.RoutingParameter.shapeBufferDistance, 4), r.setRoutingParameter(e.RoutingParameter.idealNudgingDistance, 8), r.setRoutingParameter(e.RoutingParameter.crossingPenalty, 80), r.setRoutingParameter(e.RoutingParameter.fixedSharedPathPenalty, 120), r.setRoutingParameter(e.RoutingParameter.portDirectionPenalty, 0), r.setRoutingOption(e.RoutingOption.nudgeOrthogonalSegmentsConnectedToShapes, !1), r.setRoutingOption(e.RoutingOption.nudgeSharedPathsWithCommonEndPoint, !0);
26
+ const S = new Map(
27
+ t.nodes.filter((n) => !h.has(n.id) && d(n.id).every((a) => h.has(a))).map((n) => {
28
+ const a = new e.Point(n.x, n.y), p = new e.Point(n.x + n.width, n.y + n.height), o = new e.Rectangle(a, p), c = new e.ShapeRef(r, o);
29
+ return m(a), m(p), m(o), [n.id, c];
30
+ })
31
+ ), P = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map();
32
+ y.forEach((n) => {
33
+ const a = s.get(n.source), p = s.get(n.target), o = D(a, p), c = n.sourcePort ? a.ports.find((u) => u.id === n.sourcePort).side : n.targetPort ? O(p.ports.find((u) => u.id === n.targetPort).side) : o.source, g = n.targetPort ? p.ports.find((u) => u.id === n.targetPort).side : n.sourcePort ? O(a.ports.find((u) => u.id === n.sourcePort).side) : o.target, w = [n.source, n.target].sort().join("\0"), x = R.get(w) ?? 0;
34
+ R.set(w, x + 1), P.set(n.id, {
35
+ sourceSide: c,
36
+ targetSide: g,
37
+ offset: x % 2 === 0 ? -6 : 6
38
+ });
39
+ });
40
+ for (const n of t.nodes) {
41
+ const a = S.get(n.id);
42
+ if (!a) continue;
43
+ const p = (o, c, g, w, x) => {
44
+ const u = new e.ShapeConnectionPin(
45
+ a,
46
+ o,
47
+ c / n.width,
48
+ g / n.height,
49
+ !0,
50
+ 0,
51
+ w
52
+ );
53
+ u.setExclusive(x), u.setConnectionCost(
54
+ n.width / 2 + n.height / 2 - Math.abs(c - n.width / 2) - Math.abs(g - n.height / 2)
55
+ );
56
+ };
57
+ for (const o of new Set(n.ports?.map((c) => c.side))) {
58
+ const { x: c, y: g } = A(n, o);
59
+ p(v.indexOf(o) + 2, c - n.x, g - n.y, B[o], !1);
60
+ }
61
+ }
62
+ const l = (n, a, p) => {
63
+ const o = s.get(n), c = S.get(n);
64
+ if (c && a)
65
+ return new e.ConnEnd(
66
+ c,
67
+ v.indexOf(o.ports.find((u) => u.id === a).side) + 2
68
+ );
69
+ const g = a ? A(o, o.ports.find((u) => u.id === a).side) : p, w = new e.Point(g.x, g.y), x = new e.ConnEnd(w);
70
+ return m(w), x;
71
+ }, M = y.map((n) => {
72
+ const a = s.get(n.source), p = s.get(n.target), o = P.get(n.id), c = l(
73
+ n.source,
74
+ n.sourcePort,
75
+ n.source === n.target ? { x: a.x + a.width, y: a.y + a.height / 3 } : k(a, o.sourceSide, p, o.offset)
76
+ ), g = l(
77
+ n.target,
78
+ n.targetPort,
79
+ n.source === n.target ? {
80
+ x: p.x + p.width,
81
+ y: p.y + p.height * 2 / 3
82
+ } : k(p, o.targetSide, a, o.offset)
83
+ ), w = new e.ConnRef(r, c, g);
84
+ if (m(c), m(g), n.source === n.target) {
85
+ const x = s.get(n.source), u = new e.CheckpointVector();
86
+ for (const U of [x.y + x.height / 3, x.y + x.height * 2 / 3]) {
87
+ const E = new e.Point(x.x + x.width + 24, U), b = new e.Checkpoint(E);
88
+ u.push_back(b), m(E), m(b);
89
+ }
90
+ w.setRoutingCheckpoints(u), m(u);
91
+ }
92
+ return { edge: n, connection: w };
93
+ });
94
+ r.processTransaction();
95
+ for (const { edge: n, connection: a } of M) {
96
+ const p = a.displayRoute(), o = Array.from({ length: p.size() }, (c, g) => {
97
+ const w = p.at(g), x = { x: w.x, y: w.y };
98
+ return m(w), x;
99
+ });
100
+ if (m(p), !a.hasValidRoute() || o.length < 2 || o.some((c) => !Number.isFinite(c.x) || !Number.isFinite(c.y)) || o.some((c, g) => g > 0 && c.x !== o[g - 1].x && c.y !== o[g - 1].y))
101
+ throw new Error(`Graph edge cannot be routed: ${n.id}`);
102
+ f.set(n.id, o);
103
+ }
104
+ } finally {
105
+ r.delete();
106
+ }
107
+ }
108
+ const T = t.edges.map((h) => ({ ...h, sections: [f.get(h.id)] }));
109
+ return C({
110
+ nodes: t.nodes,
111
+ edges: T,
112
+ bounds: t.bounds
113
+ });
114
+ }
115
+ function C(t) {
116
+ const e = [
117
+ ...t.nodes.flatMap((i) => [
118
+ { x: i.x, y: i.y },
119
+ { x: i.x + i.width, y: i.y + i.height }
120
+ ]),
121
+ ...t.edges.flatMap((i) => i.sections.flat())
122
+ ], s = Math.min(...e.map((i) => i.x)), d = Math.min(...e.map((i) => i.y));
123
+ return {
124
+ nodes: t.nodes,
125
+ edges: t.edges,
126
+ bounds: {
127
+ x: s,
128
+ y: d,
129
+ width: Math.max(...e.map((i) => i.x)) - s,
130
+ height: Math.max(...e.map((i) => i.y)) - d
131
+ }
132
+ };
133
+ }
134
+ function A(t, e) {
135
+ return {
136
+ x: e === "WEST" ? t.x : e === "EAST" ? t.x + t.width : t.x + t.width / 2,
137
+ y: e === "NORTH" ? t.y : e === "SOUTH" ? t.y + t.height : t.y + t.height / 2
138
+ };
139
+ }
140
+ function O(t) {
141
+ return {
142
+ NORTH: "SOUTH",
143
+ EAST: "WEST",
144
+ SOUTH: "NORTH",
145
+ WEST: "EAST"
146
+ }[t];
147
+ }
148
+ function D(t, e) {
149
+ const s = e.x + e.width / 2 - (t.x + t.width / 2), d = e.y + e.height / 2 - (t.y + t.height / 2), i = Math.max(t.x - (e.x + e.width), e.x - (t.x + t.width), 0), f = Math.max(
150
+ t.y - (e.y + e.height),
151
+ e.y - (t.y + t.height),
152
+ 0
153
+ ), h = (f === 0 && i > 0 ? !0 : i === 0 && f > 0 ? !1 : i === 0 && f === 0 ? Math.abs(s) >= Math.abs(d) : i <= f) ? s >= 0 ? "EAST" : "WEST" : d >= 0 ? "SOUTH" : "NORTH";
154
+ return { source: h, target: O(h) };
155
+ }
156
+ function k(t, e, s, d = 0) {
157
+ const i = (r) => Math.min(8, r / 4), f = (r, S, P) => Math.max(S + i(P), Math.min(S + P - i(P), r)), T = (r, S, P, R) => {
158
+ const l = Math.max(r, P), M = Math.min(r + S, P + R);
159
+ return l < M ? (l + M) / 2 + d : void 0;
160
+ }, h = s.x + s.width / 2, y = s.y + s.height / 2;
161
+ switch (e) {
162
+ case "NORTH":
163
+ return {
164
+ x: f(
165
+ T(t.x, t.width, s.x, s.width) ?? h + d,
166
+ t.x,
167
+ t.width
168
+ ),
169
+ y: t.y
170
+ };
171
+ case "EAST":
172
+ return {
173
+ x: t.x + t.width,
174
+ y: f(
175
+ T(t.y, t.height, s.y, s.height) ?? y + d,
176
+ t.y,
177
+ t.height
178
+ )
179
+ };
180
+ case "SOUTH":
181
+ return {
182
+ x: f(
183
+ T(t.x, t.width, s.x, s.width) ?? h + d,
184
+ t.x,
185
+ t.width
186
+ ),
187
+ y: t.y + t.height
188
+ };
189
+ case "WEST":
190
+ return {
191
+ x: t.x,
192
+ y: f(
193
+ T(t.y, t.height, s.y, s.height) ?? y + d,
194
+ t.y,
195
+ t.height
196
+ )
197
+ };
198
+ }
199
+ }
200
+ export {
201
+ F as routeGraphGeometry
202
+ };
@@ -52,8 +52,10 @@ export interface GraphLayoutOptions {
52
52
  positions?: readonly (GraphPoint & {
53
53
  nodeId: string;
54
54
  })[];
55
- /** Fixed (default) rejects impossible geometry. Preferred retains clear positions and separates colliding siblings, resizing groups around their content before routing. */
56
- positionMode?: 'fixed' | 'preferred';
55
+ /** Root-level ranks. Unassigned roots are placed deterministically near their closest ranked neighbors. */
56
+ layers?: readonly (readonly string[])[];
57
+ /** Fixed (default) rejects impossible geometry. Preferred retains positions; compact uses them only as stable ordering hints. */
58
+ positionMode?: 'fixed' | 'preferred' | 'compact';
57
59
  direction?: 'RIGHT' | 'DOWN' | 'LEFT' | 'UP';
58
60
  spacing?: number;
59
61
  groupPadding?: {
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.