@pibbl/core 0.0.3-alpha.85.1 → 0.0.3-alpha.90.1
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/features/viz/index.d.ts +13 -0
- package/dist/features/viz/index.js +57 -0
- package/dist/features/viz/index.js.map +2 -2
- package/dist/features/viz/lib/graph/bipartite.d.ts +14 -0
- package/dist/features/viz/lib/graph/bipartite.js +250 -0
- package/dist/features/viz/lib/graph/bipartite.js.map +7 -0
- package/dist/features/viz/lib/graph/chord.d.ts +44 -0
- package/dist/features/viz/lib/graph/chord.js +348 -0
- package/dist/features/viz/lib/graph/chord.js.map +7 -0
- package/dist/features/viz/lib/graph/dependency.d.ts +26 -0
- package/dist/features/viz/lib/graph/dependency.js +141 -0
- package/dist/features/viz/lib/graph/dependency.js.map +7 -0
- package/dist/features/viz/lib/graph/force.d.ts +28 -0
- package/dist/features/viz/lib/graph/force.js +580 -0
- package/dist/features/viz/lib/graph/force.js.map +7 -0
- package/dist/features/viz/lib/graph/hierarchy.d.ts +21 -0
- package/dist/features/viz/lib/graph/hierarchy.js +112 -0
- package/dist/features/viz/lib/graph/hierarchy.js.map +7 -0
- package/dist/features/viz/lib/graph/icicle.d.ts +16 -0
- package/dist/features/viz/lib/graph/icicle.js +153 -0
- package/dist/features/viz/lib/graph/icicle.js.map +7 -0
- package/dist/features/viz/lib/graph/matrix.d.ts +30 -0
- package/dist/features/viz/lib/graph/matrix.js +243 -0
- package/dist/features/viz/lib/graph/matrix.js.map +7 -0
- package/dist/features/viz/lib/graph/neighborhood.d.ts +11 -0
- package/dist/features/viz/lib/graph/neighborhood.js +281 -0
- package/dist/features/viz/lib/graph/neighborhood.js.map +7 -0
- package/dist/features/viz/lib/graph/routes.d.ts +35 -0
- package/dist/features/viz/lib/graph/routes.js +102 -0
- package/dist/features/viz/lib/graph/routes.js.map +7 -0
- package/dist/features/viz/lib/graph/sankey.d.ts +44 -0
- package/dist/features/viz/lib/graph/sankey.js +341 -0
- package/dist/features/viz/lib/graph/sankey.js.map +7 -0
- package/dist/features/viz/lib/graph/shared.d.ts +59 -0
- package/dist/features/viz/lib/graph/shared.js +296 -0
- package/dist/features/viz/lib/graph/shared.js.map +7 -0
- package/dist/features/viz/lib/graph/tree.d.ts +11 -0
- package/dist/features/viz/lib/graph/tree.js +232 -0
- package/dist/features/viz/lib/graph/tree.js.map +7 -0
- package/dist/features/viz/lib/graph/treemap.d.ts +20 -0
- package/dist/features/viz/lib/graph/treemap.js +227 -0
- package/dist/features/viz/lib/graph/treemap.js.map +7 -0
- package/dist/features/viz/lib/graph/types.d.ts +1097 -0
- package/dist/filters/backdrop-contrast-gpu.d.ts +5 -0
- package/dist/filters/backdrop-contrast-gpu.js +33 -0
- package/dist/filters/backdrop-contrast-gpu.js.map +7 -0
- package/dist/filters/backdrop-contrast.d.ts +21 -0
- package/dist/filters/backdrop-contrast.js +61 -0
- package/dist/filters/backdrop-contrast.js.map +7 -0
- package/dist/filters/filter-executor.d.ts +11 -4
- package/dist/filters/filter-executor.js +104 -49
- package/dist/filters/filter-executor.js.map +2 -2
- package/dist/filters/render-backdrop-contrast-boundary.d.ts +31 -0
- package/dist/filters/render-backdrop-contrast-boundary.js +116 -0
- package/dist/filters/render-backdrop-contrast-boundary.js.map +7 -0
- package/dist/filters.d.ts +9 -7
- package/dist/filters.js +2 -0
- package/dist/filters.js.map +2 -2
- package/package.json +2 -2
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
import { jsx } from "@pibbl/core/jsx-runtime";
|
|
2
|
+
import {
|
|
3
|
+
Group,
|
|
4
|
+
computed,
|
|
5
|
+
drive,
|
|
6
|
+
resolveSignalValue,
|
|
7
|
+
signal,
|
|
8
|
+
stepper,
|
|
9
|
+
useConst,
|
|
10
|
+
usePlayback,
|
|
11
|
+
useReaction,
|
|
12
|
+
untracked
|
|
13
|
+
} from "@pibbl/core";
|
|
14
|
+
import { graphRecords, nodeSize } from "./dependency.js";
|
|
15
|
+
import {
|
|
16
|
+
graphNodeGeometry,
|
|
17
|
+
readAccessor,
|
|
18
|
+
validateBounds,
|
|
19
|
+
useGraphFrame,
|
|
20
|
+
GraphView
|
|
21
|
+
} from "./shared.js";
|
|
22
|
+
import { straightGraphRoute, routePath } from "./routes.js";
|
|
23
|
+
function configuration(graph, options) {
|
|
24
|
+
const bounds = validateBounds(options.bounds), records = graphRecords(graph, options);
|
|
25
|
+
const settings = {
|
|
26
|
+
seed: options.simulation?.seed ?? 1,
|
|
27
|
+
linkDistance: options.simulation?.linkDistance ?? 90,
|
|
28
|
+
nodeGap: options.simulation?.nodeGap ?? 8,
|
|
29
|
+
maxIterations: options.simulation?.maxIterations ?? 300
|
|
30
|
+
};
|
|
31
|
+
if (!Number.isSafeInteger(settings.seed) || !Number.isSafeInteger(settings.maxIterations) || settings.maxIterations < 0)
|
|
32
|
+
throw new RangeError(
|
|
33
|
+
"Force seed must be a safe integer; maxIterations must be a nonnegative safe integer."
|
|
34
|
+
);
|
|
35
|
+
if (!Number.isFinite(settings.linkDistance) || settings.linkDistance <= 0 || !Number.isFinite(settings.nodeGap) || settings.nodeGap < 0)
|
|
36
|
+
throw new RangeError(
|
|
37
|
+
"Force distances must be finite; linkDistance positive and nodeGap nonnegative."
|
|
38
|
+
);
|
|
39
|
+
const nodes = [...records.nodes].map(([key, datum]) => ({
|
|
40
|
+
key,
|
|
41
|
+
datum,
|
|
42
|
+
...nodeSize(datum, options.nodeSize, { width: 40, height: 40 }),
|
|
43
|
+
label: options.label ? readAccessor(datum, options.label) : String(key),
|
|
44
|
+
detail: options.detail ? readAccessor(datum, options.detail) : void 0
|
|
45
|
+
}));
|
|
46
|
+
if (bounds.width > 0 && bounds.height > 0 && nodes.some((n) => n.width > bounds.width || n.height > bounds.height))
|
|
47
|
+
throw new RangeError("Force node exceeds layout bounds.");
|
|
48
|
+
return {
|
|
49
|
+
bounds,
|
|
50
|
+
settings,
|
|
51
|
+
nodes,
|
|
52
|
+
edges: records.edges,
|
|
53
|
+
directed: options.directed ?? true
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function createForceSimulation(graph, options) {
|
|
57
|
+
let config = configuration(graph, options), iterations = 0, settled = false, particles = [], pins = /* @__PURE__ */ new Map();
|
|
58
|
+
let stableSteps = 0;
|
|
59
|
+
const seedParticles = () => {
|
|
60
|
+
let seed = config.settings.seed >>> 0;
|
|
61
|
+
const random = () => {
|
|
62
|
+
seed = Math.imul(seed, 1664525) + 1013904223 >>> 0;
|
|
63
|
+
return seed / 4294967296;
|
|
64
|
+
};
|
|
65
|
+
return config.nodes.map((node) => ({
|
|
66
|
+
...node,
|
|
67
|
+
x: config.bounds.x + node.width / 2 + random() * Math.max(0, config.bounds.width - node.width),
|
|
68
|
+
y: config.bounds.y + node.height / 2 + random() * Math.max(0, config.bounds.height - node.height),
|
|
69
|
+
vx: 0,
|
|
70
|
+
vy: 0
|
|
71
|
+
}));
|
|
72
|
+
};
|
|
73
|
+
particles = seedParticles();
|
|
74
|
+
const read = () => {
|
|
75
|
+
const { bounds } = config;
|
|
76
|
+
if (!bounds.width || !bounds.height)
|
|
77
|
+
return { bounds, nodes: [], edges: [], iterations, settled };
|
|
78
|
+
const nodes = particles.map((p) => {
|
|
79
|
+
const box = {
|
|
80
|
+
x: p.x - p.width / 2,
|
|
81
|
+
y: p.y - p.height / 2,
|
|
82
|
+
width: p.width,
|
|
83
|
+
height: p.height
|
|
84
|
+
};
|
|
85
|
+
const node = graphNodeGeometry(p.datum, p.key, box, p.label, p.detail);
|
|
86
|
+
return {
|
|
87
|
+
...node,
|
|
88
|
+
label: {
|
|
89
|
+
text: p.label,
|
|
90
|
+
bounds: {
|
|
91
|
+
x: p.x - 80,
|
|
92
|
+
y: p.y + p.height / 2 + 6,
|
|
93
|
+
width: 160,
|
|
94
|
+
height: 18
|
|
95
|
+
},
|
|
96
|
+
rotationDegrees: 0
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
const byKey = new Map(particles.map((p) => [p.key, p]));
|
|
101
|
+
const edges = config.edges.map((edge) => {
|
|
102
|
+
const a = byKey.get(edge.sourceKey), b = byKey.get(edge.targetKey);
|
|
103
|
+
const dx = b.x - a.x, dy = b.y - a.y;
|
|
104
|
+
const boundary = (p, x, y) => {
|
|
105
|
+
const t = Math.min(
|
|
106
|
+
x === 0 ? Infinity : p.width / 2 / Math.abs(x),
|
|
107
|
+
y === 0 ? Infinity : p.height / 2 / Math.abs(y)
|
|
108
|
+
);
|
|
109
|
+
return {
|
|
110
|
+
x: p.x + x * (Number.isFinite(t) ? t : 0),
|
|
111
|
+
y: p.y + y * (Number.isFinite(t) ? t : 0)
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
const route = straightGraphRoute(
|
|
115
|
+
{
|
|
116
|
+
sourceAnchor: boundary(a, dx, dy),
|
|
117
|
+
targetAnchor: boundary(b, -dx, -dy)
|
|
118
|
+
},
|
|
119
|
+
{ arrowLength: config.directed ? 6 : 0 }
|
|
120
|
+
);
|
|
121
|
+
return {
|
|
122
|
+
...edge,
|
|
123
|
+
route,
|
|
124
|
+
path: forcePath(route.segments),
|
|
125
|
+
arrowPath: route.arrowSegments ? routePath(route.arrowSegments) : null
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
return { bounds, nodes, edges, iterations, settled };
|
|
129
|
+
};
|
|
130
|
+
return {
|
|
131
|
+
read,
|
|
132
|
+
step({ iterations: count }) {
|
|
133
|
+
if (!Number.isSafeInteger(count) || count < 0)
|
|
134
|
+
throw new RangeError(
|
|
135
|
+
"Force step iterations must be a nonnegative safe integer."
|
|
136
|
+
);
|
|
137
|
+
if (!config.bounds.width || !config.bounds.height) return read();
|
|
138
|
+
for (let n = 0; n < count && iterations < config.settings.maxIterations && !settled; n++, iterations++) {
|
|
139
|
+
const forces = particles.map((p) => ({
|
|
140
|
+
x: (config.bounds.x + config.bounds.width / 2 - p.x) * 2e-3,
|
|
141
|
+
y: (config.bounds.y + config.bounds.height / 2 - p.y) * 2e-3
|
|
142
|
+
}));
|
|
143
|
+
for (let i = 0; i < particles.length; i++)
|
|
144
|
+
for (let j = i + 1; j < particles.length; j++) {
|
|
145
|
+
const a = particles[i], b = particles[j];
|
|
146
|
+
let dx = b.x - a.x, dy = b.y - a.y;
|
|
147
|
+
if (Math.abs(dx) + Math.abs(dy) < 0.01) {
|
|
148
|
+
dx = 0.1;
|
|
149
|
+
dy = 0.1;
|
|
150
|
+
}
|
|
151
|
+
const distance = Math.hypot(dx, dy), repulsion = 4500 / Math.max(25, distance * distance);
|
|
152
|
+
const overlapX = (a.width + b.width) / 2 + config.settings.nodeGap - Math.abs(dx), overlapY = (a.height + b.height) / 2 + config.settings.nodeGap - Math.abs(dy);
|
|
153
|
+
let fx = dx / distance * repulsion, fy = dy / distance * repulsion;
|
|
154
|
+
if (overlapX > 0 && overlapY > 0) {
|
|
155
|
+
if (overlapX < overlapY)
|
|
156
|
+
fx += Math.sign(dx || 1) * overlapX * 0.12;
|
|
157
|
+
else fy += Math.sign(dy || 1) * overlapY * 0.12;
|
|
158
|
+
}
|
|
159
|
+
forces[i].x -= fx;
|
|
160
|
+
forces[i].y -= fy;
|
|
161
|
+
forces[j].x += fx;
|
|
162
|
+
forces[j].y += fy;
|
|
163
|
+
}
|
|
164
|
+
const indices = new Map(particles.map((p, i) => [p.key, i]));
|
|
165
|
+
for (const edge of config.edges) {
|
|
166
|
+
const i = indices.get(edge.sourceKey), j = indices.get(edge.targetKey), a = particles[i], b = particles[j];
|
|
167
|
+
const dx = b.x - a.x, dy = b.y - a.y, length = Math.hypot(dx, dy) || 1, pull = (length - config.settings.linkDistance) * 0.025;
|
|
168
|
+
const x = dx / length * pull, y = dy / length * pull;
|
|
169
|
+
forces[i].x += x;
|
|
170
|
+
forces[i].y += y;
|
|
171
|
+
forces[j].x -= x;
|
|
172
|
+
forces[j].y -= y;
|
|
173
|
+
}
|
|
174
|
+
let movement = 0;
|
|
175
|
+
particles = particles.map((p, i) => {
|
|
176
|
+
const pin = pins.get(p.key);
|
|
177
|
+
if (pin) return { ...p, ...pin, vx: 0, vy: 0 };
|
|
178
|
+
const vx = Math.max(-8, Math.min(8, (p.vx + forces[i].x) * 0.78)), vy = Math.max(-8, Math.min(8, (p.vy + forces[i].y) * 0.78));
|
|
179
|
+
movement = Math.max(movement, Math.abs(vx) + Math.abs(vy));
|
|
180
|
+
return {
|
|
181
|
+
...p,
|
|
182
|
+
vx,
|
|
183
|
+
vy,
|
|
184
|
+
x: Math.max(
|
|
185
|
+
config.bounds.x + p.width / 2,
|
|
186
|
+
Math.min(
|
|
187
|
+
config.bounds.x + config.bounds.width - p.width / 2,
|
|
188
|
+
p.x + vx
|
|
189
|
+
)
|
|
190
|
+
),
|
|
191
|
+
y: Math.max(
|
|
192
|
+
config.bounds.y + p.height / 2,
|
|
193
|
+
Math.min(
|
|
194
|
+
config.bounds.y + config.bounds.height - p.height / 2,
|
|
195
|
+
p.y + vy
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
};
|
|
199
|
+
});
|
|
200
|
+
stableSteps = movement < 0.02 ? stableSteps + 1 : 0;
|
|
201
|
+
settled = stableSteps >= 8;
|
|
202
|
+
}
|
|
203
|
+
return read();
|
|
204
|
+
},
|
|
205
|
+
update(nextGraph, nextOptions) {
|
|
206
|
+
const next = configuration(nextGraph, nextOptions);
|
|
207
|
+
const old = new Map(particles.map((p) => [p.key, p]));
|
|
208
|
+
config = next;
|
|
209
|
+
particles = seedParticles().map((p) => {
|
|
210
|
+
const previous = old.get(p.key);
|
|
211
|
+
return previous ? {
|
|
212
|
+
...p,
|
|
213
|
+
x: Math.max(
|
|
214
|
+
config.bounds.x + p.width / 2,
|
|
215
|
+
Math.min(
|
|
216
|
+
config.bounds.x + config.bounds.width - p.width / 2,
|
|
217
|
+
previous.x
|
|
218
|
+
)
|
|
219
|
+
),
|
|
220
|
+
y: Math.max(
|
|
221
|
+
config.bounds.y + p.height / 2,
|
|
222
|
+
Math.min(
|
|
223
|
+
config.bounds.y + config.bounds.height - p.height / 2,
|
|
224
|
+
previous.y
|
|
225
|
+
)
|
|
226
|
+
),
|
|
227
|
+
vx: previous.vx,
|
|
228
|
+
vy: previous.vy
|
|
229
|
+
} : p;
|
|
230
|
+
});
|
|
231
|
+
pins = new Map(
|
|
232
|
+
[...pins].filter(
|
|
233
|
+
([key]) => old.has(key) && config.nodes.some((n) => n.key === key)
|
|
234
|
+
)
|
|
235
|
+
);
|
|
236
|
+
iterations = 0;
|
|
237
|
+
stableSteps = 0;
|
|
238
|
+
settled = false;
|
|
239
|
+
},
|
|
240
|
+
restart() {
|
|
241
|
+
iterations = 0;
|
|
242
|
+
stableSteps = 0;
|
|
243
|
+
settled = false;
|
|
244
|
+
},
|
|
245
|
+
reset() {
|
|
246
|
+
pins.clear();
|
|
247
|
+
particles = seedParticles();
|
|
248
|
+
iterations = 0;
|
|
249
|
+
stableSteps = 0;
|
|
250
|
+
settled = false;
|
|
251
|
+
},
|
|
252
|
+
pin(key, position) {
|
|
253
|
+
if (!particles.some((p) => p.key === key))
|
|
254
|
+
throw new Error(`Unknown force node ${key}.`);
|
|
255
|
+
if (!Number.isFinite(position.x) || !Number.isFinite(position.y))
|
|
256
|
+
throw new RangeError("Pin coordinates must be finite.");
|
|
257
|
+
pins.set(key, { ...position });
|
|
258
|
+
particles = particles.map(
|
|
259
|
+
(p) => p.key === key ? { ...p, ...position, vx: 0, vy: 0 } : p
|
|
260
|
+
);
|
|
261
|
+
settled = false;
|
|
262
|
+
stableSteps = 0;
|
|
263
|
+
},
|
|
264
|
+
release(key) {
|
|
265
|
+
if (!particles.some((p) => p.key === key))
|
|
266
|
+
throw new Error(`Unknown force node ${key}.`);
|
|
267
|
+
pins.delete(key);
|
|
268
|
+
settled = false;
|
|
269
|
+
stableSteps = 0;
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
function layoutForceNetwork(graph, options) {
|
|
274
|
+
const session = createForceSimulation(graph, options);
|
|
275
|
+
return session.step({ iterations: options.simulation?.maxIterations ?? 300 });
|
|
276
|
+
}
|
|
277
|
+
function interpolateForceLayout(previous, current, amount) {
|
|
278
|
+
if (previous === current) return current;
|
|
279
|
+
if (amount === 0)
|
|
280
|
+
return { ...current, nodes: previous.nodes, edges: previous.edges };
|
|
281
|
+
const numbers = (a, b) => {
|
|
282
|
+
const result = { ...b };
|
|
283
|
+
for (const key in b) {
|
|
284
|
+
const before = a[key], after = b[key];
|
|
285
|
+
if (typeof before === "number" && typeof after === "number")
|
|
286
|
+
result[key] = before + (after - before) * amount;
|
|
287
|
+
}
|
|
288
|
+
return result;
|
|
289
|
+
};
|
|
290
|
+
const rotation = (a, b) => a + (b - a) * amount;
|
|
291
|
+
const oldNodes = new Map(previous.nodes.map((node) => [node.key, node]));
|
|
292
|
+
const oldEdges = new Map(previous.edges.map((edge) => [edge.key, edge]));
|
|
293
|
+
return {
|
|
294
|
+
...current,
|
|
295
|
+
nodes: current.nodes.map((node) => {
|
|
296
|
+
const old = oldNodes.get(node.key);
|
|
297
|
+
if (!old) return node;
|
|
298
|
+
return {
|
|
299
|
+
...node,
|
|
300
|
+
bounds: numbers(old.bounds, node.bounds),
|
|
301
|
+
label: {
|
|
302
|
+
...node.label,
|
|
303
|
+
bounds: numbers(old.label.bounds, node.label.bounds),
|
|
304
|
+
rotationDegrees: rotation(
|
|
305
|
+
old.label.rotationDegrees,
|
|
306
|
+
node.label.rotationDegrees
|
|
307
|
+
)
|
|
308
|
+
},
|
|
309
|
+
detail: old.detail && node.detail ? {
|
|
310
|
+
...node.detail,
|
|
311
|
+
bounds: numbers(old.detail.bounds, node.detail.bounds),
|
|
312
|
+
rotationDegrees: rotation(
|
|
313
|
+
old.detail.rotationDegrees,
|
|
314
|
+
node.detail.rotationDegrees
|
|
315
|
+
)
|
|
316
|
+
} : node.detail
|
|
317
|
+
};
|
|
318
|
+
}),
|
|
319
|
+
edges: current.edges.map((edge) => {
|
|
320
|
+
const old = oldEdges.get(edge.key);
|
|
321
|
+
if (!old) return edge;
|
|
322
|
+
const segments = (a, b) => b.map(
|
|
323
|
+
(segment, index) => a[index]?.type === segment.type ? numbers(a[index], segment) : segment
|
|
324
|
+
);
|
|
325
|
+
const route = {
|
|
326
|
+
sourceAnchor: numbers(old.route.sourceAnchor, edge.route.sourceAnchor),
|
|
327
|
+
targetAnchor: numbers(old.route.targetAnchor, edge.route.targetAnchor),
|
|
328
|
+
segments: segments(old.route.segments, edge.route.segments),
|
|
329
|
+
arrowSegments: old.route.arrowSegments && edge.route.arrowSegments ? segments(old.route.arrowSegments, edge.route.arrowSegments) : edge.route.arrowSegments
|
|
330
|
+
};
|
|
331
|
+
return {
|
|
332
|
+
...edge,
|
|
333
|
+
route,
|
|
334
|
+
path: forcePath(route.segments),
|
|
335
|
+
arrowPath: route.arrowSegments ? forcePath(route.arrowSegments) : null
|
|
336
|
+
};
|
|
337
|
+
})
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function forcePath(segments) {
|
|
341
|
+
if (segments.length === 2 && segments[0].type === "move" && segments[1].type === "line")
|
|
342
|
+
return `M ${segments[0].x} ${segments[0].y} L ${segments[1].x} ${segments[1].y}`;
|
|
343
|
+
return routePath(segments);
|
|
344
|
+
}
|
|
345
|
+
function useForceNetwork(graph, options) {
|
|
346
|
+
const input = resolveSignalValue(graph);
|
|
347
|
+
let inputError = null;
|
|
348
|
+
let prepared;
|
|
349
|
+
try {
|
|
350
|
+
prepared = configuration(input, options);
|
|
351
|
+
} catch (error) {
|
|
352
|
+
inputError = error instanceof Error ? error : new Error(String(error));
|
|
353
|
+
prepared = configuration(
|
|
354
|
+
{ nodes: [], edges: [] },
|
|
355
|
+
{
|
|
356
|
+
...options,
|
|
357
|
+
simulation: {},
|
|
358
|
+
bounds: { x: 0, y: 0, width: 0, height: 0 }
|
|
359
|
+
}
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
const nodeMetadata = new Map(
|
|
363
|
+
prepared.nodes.map((node) => [node.datum, node])
|
|
364
|
+
);
|
|
365
|
+
const edgeMetadata = new Map(
|
|
366
|
+
prepared.edges.map((edge) => [edge.datum, edge])
|
|
367
|
+
);
|
|
368
|
+
const snapshotOptions = {
|
|
369
|
+
bounds: { ...prepared.bounds },
|
|
370
|
+
simulation: { ...prepared.settings },
|
|
371
|
+
directed: prepared.directed,
|
|
372
|
+
nodeKey: (node) => nodeMetadata.get(node).key,
|
|
373
|
+
edgeKey: (edge) => edgeMetadata.get(edge).key,
|
|
374
|
+
source: (edge) => edgeMetadata.get(edge).sourceKey,
|
|
375
|
+
target: (edge) => edgeMetadata.get(edge).targetKey,
|
|
376
|
+
nodeSize: (node) => nodeMetadata.get(node),
|
|
377
|
+
label: (node) => nodeMetadata.get(node).label,
|
|
378
|
+
detail: options.detail ? (node) => nodeMetadata.get(node).detail : void 0
|
|
379
|
+
};
|
|
380
|
+
const snapshotGraph = {
|
|
381
|
+
nodes: inputError ? [] : [...input.nodes],
|
|
382
|
+
edges: inputError ? [] : [...input.edges]
|
|
383
|
+
};
|
|
384
|
+
const signature = JSON.stringify([
|
|
385
|
+
prepared.bounds,
|
|
386
|
+
prepared.settings,
|
|
387
|
+
prepared.directed,
|
|
388
|
+
prepared.nodes.map(({ datum: _datum, ...metadata }) => metadata),
|
|
389
|
+
prepared.edges.map(({ datum: _datum, ...metadata }) => metadata)
|
|
390
|
+
]);
|
|
391
|
+
const owner = useConst(() => {
|
|
392
|
+
const factory = options.createSimulation ?? createForceSimulation;
|
|
393
|
+
const session = factory(snapshotGraph, snapshotOptions);
|
|
394
|
+
const output = signal({
|
|
395
|
+
layout: session.read(),
|
|
396
|
+
status: options.initialPaused ? "paused" : "running",
|
|
397
|
+
error: null
|
|
398
|
+
});
|
|
399
|
+
return {
|
|
400
|
+
factory,
|
|
401
|
+
session,
|
|
402
|
+
previous: output.get().layout,
|
|
403
|
+
current: output.get(),
|
|
404
|
+
phase: 0,
|
|
405
|
+
output,
|
|
406
|
+
disposed: false,
|
|
407
|
+
pending: [],
|
|
408
|
+
paused: options.initialPaused ?? false,
|
|
409
|
+
signature,
|
|
410
|
+
graph: snapshotGraph,
|
|
411
|
+
options: snapshotOptions
|
|
412
|
+
};
|
|
413
|
+
});
|
|
414
|
+
if (options.createSimulation !== void 0 && options.createSimulation !== owner.factory)
|
|
415
|
+
throw new Error(
|
|
416
|
+
"Force createSimulation is fixed for a mounted hook; remount to replace it."
|
|
417
|
+
);
|
|
418
|
+
const advance = (integrate) => {
|
|
419
|
+
try {
|
|
420
|
+
const pending = owner.pending.splice(0);
|
|
421
|
+
if (!pending.length && owner.current.status === "failed")
|
|
422
|
+
return owner.current;
|
|
423
|
+
for (const command of pending) command();
|
|
424
|
+
if (pending.length) {
|
|
425
|
+
owner.current = { ...owner.current, layout: owner.session.read() };
|
|
426
|
+
owner.previous = owner.current.layout;
|
|
427
|
+
}
|
|
428
|
+
if (integrate && !owner.paused) {
|
|
429
|
+
owner.previous = owner.current.layout;
|
|
430
|
+
owner.current = {
|
|
431
|
+
...owner.current,
|
|
432
|
+
layout: owner.session.step({ iterations: 1 })
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
const layout = owner.current.layout;
|
|
436
|
+
const status = owner.paused || !layout.bounds.width || !layout.bounds.height ? "paused" : layout.settled ? "settled" : layout.iterations >= (owner.options.simulation?.maxIterations ?? 300) ? "exhausted" : "running";
|
|
437
|
+
owner.current = { layout, status, error: null };
|
|
438
|
+
} catch (error) {
|
|
439
|
+
owner.current = {
|
|
440
|
+
layout: owner.output.get().layout,
|
|
441
|
+
status: "failed",
|
|
442
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
return owner.current;
|
|
446
|
+
};
|
|
447
|
+
const program = useConst(
|
|
448
|
+
() => drive(
|
|
449
|
+
owner.output,
|
|
450
|
+
stepper({
|
|
451
|
+
// Twelve presentation subdivisions divide common 60/120/144/240 Hz displays.
|
|
452
|
+
// This is scheduler sampling, not another animation loop or 720 solver ticks.
|
|
453
|
+
stepMilliseconds: 1e3 / 720,
|
|
454
|
+
maxElapsedMilliseconds: 1e3 / 30,
|
|
455
|
+
initial: () => {
|
|
456
|
+
owner.phase = 0;
|
|
457
|
+
return advance(false);
|
|
458
|
+
},
|
|
459
|
+
step: () => {
|
|
460
|
+
owner.phase = (owner.phase + 1) % 12;
|
|
461
|
+
return owner.phase === 0 || owner.pending.length ? advance(owner.phase === 0) : owner.current;
|
|
462
|
+
},
|
|
463
|
+
read: () => {
|
|
464
|
+
const frame = owner.pending.length ? advance(false) : owner.current;
|
|
465
|
+
return frame.status === "running" ? {
|
|
466
|
+
...frame,
|
|
467
|
+
layout: interpolateForceLayout(
|
|
468
|
+
owner.previous,
|
|
469
|
+
frame.layout,
|
|
470
|
+
owner.phase / 12
|
|
471
|
+
)
|
|
472
|
+
} : frame;
|
|
473
|
+
},
|
|
474
|
+
done: (state) => state.status !== "running"
|
|
475
|
+
})
|
|
476
|
+
)
|
|
477
|
+
);
|
|
478
|
+
const playback = usePlayback(program, { autoplay: !options.initialPaused });
|
|
479
|
+
const queue = (command) => {
|
|
480
|
+
if (owner.disposed) return;
|
|
481
|
+
owner.pending.push(command);
|
|
482
|
+
const status = playback.status.get();
|
|
483
|
+
if (status !== "running" && status !== "scheduled")
|
|
484
|
+
playback.play({ conflict: "replace" });
|
|
485
|
+
};
|
|
486
|
+
useReaction(() => {
|
|
487
|
+
if (inputError) {
|
|
488
|
+
queue(() => {
|
|
489
|
+
throw inputError;
|
|
490
|
+
});
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
if (untracked(() => owner.output.get().status) === "failed" || owner.signature !== signature || owner.graph.nodes.some(
|
|
494
|
+
(datum, index) => datum !== snapshotGraph.nodes[index]
|
|
495
|
+
) || owner.graph.edges.some(
|
|
496
|
+
(datum, index) => datum !== snapshotGraph.edges[index]
|
|
497
|
+
)) {
|
|
498
|
+
queue(() => {
|
|
499
|
+
owner.session.update(snapshotGraph, snapshotOptions);
|
|
500
|
+
owner.graph = snapshotGraph;
|
|
501
|
+
owner.options = snapshotOptions;
|
|
502
|
+
owner.signature = signature;
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
}, [signature, inputError?.message, ...input.nodes, ...input.edges]);
|
|
506
|
+
useReaction(
|
|
507
|
+
() => () => {
|
|
508
|
+
owner.disposed = true;
|
|
509
|
+
owner.pending.length = 0;
|
|
510
|
+
},
|
|
511
|
+
[]
|
|
512
|
+
);
|
|
513
|
+
return useConst(() => ({
|
|
514
|
+
layout: computed(() => owner.output.get().layout),
|
|
515
|
+
status: computed(() => owner.output.get().status),
|
|
516
|
+
error: computed(() => owner.output.get().error),
|
|
517
|
+
pause: () => queue(() => {
|
|
518
|
+
owner.paused = true;
|
|
519
|
+
}),
|
|
520
|
+
resume: () => queue(() => {
|
|
521
|
+
owner.paused = false;
|
|
522
|
+
}),
|
|
523
|
+
restart: () => queue(() => {
|
|
524
|
+
owner.session.restart();
|
|
525
|
+
owner.paused = false;
|
|
526
|
+
}),
|
|
527
|
+
reset: () => queue(() => {
|
|
528
|
+
owner.session.reset();
|
|
529
|
+
owner.paused = false;
|
|
530
|
+
}),
|
|
531
|
+
pin: (key, point) => queue(() => {
|
|
532
|
+
owner.session.pin(key, point);
|
|
533
|
+
owner.session.restart();
|
|
534
|
+
}),
|
|
535
|
+
release: (key) => queue(() => {
|
|
536
|
+
owner.session.release(key);
|
|
537
|
+
owner.session.restart();
|
|
538
|
+
})
|
|
539
|
+
}));
|
|
540
|
+
}
|
|
541
|
+
function ForceNetwork(props) {
|
|
542
|
+
const frame = useGraphFrame(props.style);
|
|
543
|
+
const paused = resolveSignalValue(props.paused) ?? false;
|
|
544
|
+
const network = useForceNetwork(props.graph, {
|
|
545
|
+
...props,
|
|
546
|
+
bounds: frame.bounds,
|
|
547
|
+
initialPaused: paused
|
|
548
|
+
});
|
|
549
|
+
useReaction(() => {
|
|
550
|
+
if (paused) network.pause();
|
|
551
|
+
else network.resume();
|
|
552
|
+
}, [paused]);
|
|
553
|
+
return /* @__PURE__ */ jsx(Group, { style: frame.groupStyle, children: /* @__PURE__ */ jsx(
|
|
554
|
+
GraphView,
|
|
555
|
+
{
|
|
556
|
+
...props,
|
|
557
|
+
layout: network.layout,
|
|
558
|
+
style: void 0,
|
|
559
|
+
labelStyle: (node) => ({
|
|
560
|
+
textAlign: "center",
|
|
561
|
+
...resolveSignalValue(
|
|
562
|
+
typeof props.labelStyle === "function" ? props.labelStyle(node) : props.labelStyle
|
|
563
|
+
)
|
|
564
|
+
}),
|
|
565
|
+
nodeStyle: (node) => ({
|
|
566
|
+
cornerRadius: 100,
|
|
567
|
+
...resolveSignalValue(
|
|
568
|
+
typeof props.nodeStyle === "function" ? props.nodeStyle(node) : props.nodeStyle
|
|
569
|
+
)
|
|
570
|
+
})
|
|
571
|
+
}
|
|
572
|
+
) });
|
|
573
|
+
}
|
|
574
|
+
export {
|
|
575
|
+
ForceNetwork,
|
|
576
|
+
createForceSimulation,
|
|
577
|
+
layoutForceNetwork,
|
|
578
|
+
useForceNetwork
|
|
579
|
+
};
|
|
580
|
+
//# sourceMappingURL=force.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/features/viz/lib/graph/force.tsx"],
|
|
4
|
+
"sourcesContent": ["import type { PibblNode } from \"@pibbl/core\";\nimport {\n Group,\n computed,\n drive,\n resolveSignalValue,\n signal,\n stepper,\n useConst,\n usePlayback,\n useReaction,\n untracked,\n} from \"@pibbl/core\";\nimport type {\n GraphData,\n ForceOptions,\n ForceLayout,\n ForceSimulation,\n ForceNetworkController,\n ForceHookOptions,\n ForceNetworkProps,\n Point,\n VizKey,\n} from \"./types.js\";\nimport { graphRecords, nodeSize } from \"./dependency.js\";\nimport {\n graphNodeGeometry,\n readAccessor,\n validateBounds,\n useGraphFrame,\n GraphView,\n} from \"./shared.js\";\nimport { straightGraphRoute, routePath } from \"./routes.js\";\ntype Particle<N> = {\n key: VizKey;\n datum: N;\n x: number;\n y: number;\n vx: number;\n vy: number;\n width: number;\n height: number;\n label: string;\n detail?: string;\n};\nfunction configuration<N, E>(\n graph: GraphData<N, E>,\n options: ForceOptions<N, E>,\n) {\n const bounds = validateBounds(options.bounds),\n records = graphRecords(graph, options);\n const settings = {\n seed: options.simulation?.seed ?? 1,\n linkDistance: options.simulation?.linkDistance ?? 90,\n nodeGap: options.simulation?.nodeGap ?? 8,\n maxIterations: options.simulation?.maxIterations ?? 300,\n };\n if (\n !Number.isSafeInteger(settings.seed) ||\n !Number.isSafeInteger(settings.maxIterations) ||\n settings.maxIterations < 0\n )\n throw new RangeError(\n \"Force seed must be a safe integer; maxIterations must be a nonnegative safe integer.\",\n );\n if (\n !Number.isFinite(settings.linkDistance) ||\n settings.linkDistance <= 0 ||\n !Number.isFinite(settings.nodeGap) ||\n settings.nodeGap < 0\n )\n throw new RangeError(\n \"Force distances must be finite; linkDistance positive and nodeGap nonnegative.\",\n );\n const nodes = [...records.nodes].map(([key, datum]) => ({\n key,\n datum,\n ...nodeSize(datum, options.nodeSize, { width: 40, height: 40 }),\n label: options.label ? readAccessor(datum, options.label) : String(key),\n detail: options.detail ? readAccessor(datum, options.detail) : undefined,\n }));\n if (\n bounds.width > 0 &&\n bounds.height > 0 &&\n nodes.some((n) => n.width > bounds.width || n.height > bounds.height)\n )\n throw new RangeError(\"Force node exceeds layout bounds.\");\n return {\n bounds,\n settings,\n nodes,\n edges: records.edges,\n directed: options.directed ?? true,\n };\n}\n/** Create a deterministic, manually stepped numeric solver without resources or scheduling.\n * Uses inverse-square repulsion, Hooke link relaxation, damping, box collisions and bounded iterations.\n * @param graph - Original records. See {@link GraphData}.\n * @param options - Accessors, bounds and seed. See {@link ForceOptions}.\n * @returns Numeric session whose snapshots can be rendered or advanced by any public driver. See {@link ForceSimulation}.\n */\nexport function createForceSimulation<N, E>(\n graph: GraphData<N, E>,\n options: ForceOptions<N, E>,\n): ForceSimulation<N, E> {\n let config = configuration(graph, options),\n iterations = 0,\n settled = false,\n particles: Particle<N>[] = [],\n pins = new Map<VizKey, Point>();\n let stableSteps = 0;\n const seedParticles = () => {\n let seed = config.settings.seed >>> 0;\n const random = () => {\n seed = (Math.imul(seed, 1664525) + 1013904223) >>> 0;\n return seed / 4294967296;\n };\n return config.nodes.map((node) => ({\n ...node,\n x:\n config.bounds.x +\n node.width / 2 +\n random() * Math.max(0, config.bounds.width - node.width),\n y:\n config.bounds.y +\n node.height / 2 +\n random() * Math.max(0, config.bounds.height - node.height),\n vx: 0,\n vy: 0,\n }));\n };\n particles = seedParticles();\n const read = (): ForceLayout<N, E> => {\n const { bounds } = config;\n if (!bounds.width || !bounds.height)\n return { bounds, nodes: [], edges: [], iterations, settled };\n const nodes = particles.map((p) => {\n const box = {\n x: p.x - p.width / 2,\n y: p.y - p.height / 2,\n width: p.width,\n height: p.height,\n };\n const node = graphNodeGeometry(p.datum, p.key, box, p.label, p.detail);\n return {\n ...node,\n label: {\n text: p.label,\n bounds: {\n x: p.x - 80,\n y: p.y + p.height / 2 + 6,\n width: 160,\n height: 18,\n },\n rotationDegrees: 0,\n },\n };\n });\n const byKey = new Map(particles.map((p) => [p.key, p]));\n const edges = config.edges.map((edge) => {\n const a = byKey.get(edge.sourceKey)!,\n b = byKey.get(edge.targetKey)!;\n const dx = b.x - a.x,\n dy = b.y - a.y;\n const boundary = (p: Particle<N>, x: number, y: number) => {\n const t = Math.min(\n x === 0 ? Infinity : p.width / 2 / Math.abs(x),\n y === 0 ? Infinity : p.height / 2 / Math.abs(y),\n );\n return {\n x: p.x + x * (Number.isFinite(t) ? t : 0),\n y: p.y + y * (Number.isFinite(t) ? t : 0),\n };\n };\n const route = straightGraphRoute(\n {\n sourceAnchor: boundary(a, dx, dy),\n targetAnchor: boundary(b, -dx, -dy),\n },\n { arrowLength: config.directed ? 6 : 0 },\n );\n return {\n ...edge,\n route,\n path: forcePath(route.segments),\n arrowPath: route.arrowSegments ? routePath(route.arrowSegments) : null,\n };\n });\n return { bounds, nodes, edges, iterations, settled };\n };\n return {\n read,\n step({ iterations: count }) {\n if (!Number.isSafeInteger(count) || count < 0)\n throw new RangeError(\n \"Force step iterations must be a nonnegative safe integer.\",\n );\n if (!config.bounds.width || !config.bounds.height) return read();\n for (\n let n = 0;\n n < count && iterations < config.settings.maxIterations && !settled;\n n++, iterations++\n ) {\n const forces = particles.map((p) => ({\n x: (config.bounds.x + config.bounds.width / 2 - p.x) * 0.002,\n y: (config.bounds.y + config.bounds.height / 2 - p.y) * 0.002,\n }));\n for (let i = 0; i < particles.length; i++)\n for (let j = i + 1; j < particles.length; j++) {\n const a = particles[i],\n b = particles[j];\n let dx = b.x - a.x,\n dy = b.y - a.y;\n if (Math.abs(dx) + Math.abs(dy) < 0.01) {\n dx = 0.1;\n dy = 0.1;\n }\n const distance = Math.hypot(dx, dy),\n repulsion = 4500 / Math.max(25, distance * distance);\n const overlapX =\n (a.width + b.width) / 2 +\n config.settings.nodeGap -\n Math.abs(dx),\n overlapY =\n (a.height + b.height) / 2 +\n config.settings.nodeGap -\n Math.abs(dy);\n let fx = (dx / distance) * repulsion,\n fy = (dy / distance) * repulsion;\n if (overlapX > 0 && overlapY > 0) {\n if (overlapX < overlapY)\n fx += Math.sign(dx || 1) * overlapX * 0.12;\n else fy += Math.sign(dy || 1) * overlapY * 0.12;\n }\n forces[i].x -= fx;\n forces[i].y -= fy;\n forces[j].x += fx;\n forces[j].y += fy;\n }\n const indices = new Map(particles.map((p, i) => [p.key, i]));\n for (const edge of config.edges) {\n const i = indices.get(edge.sourceKey)!,\n j = indices.get(edge.targetKey)!,\n a = particles[i],\n b = particles[j];\n const dx = b.x - a.x,\n dy = b.y - a.y,\n length = Math.hypot(dx, dy) || 1,\n pull = (length - config.settings.linkDistance) * 0.025;\n const x = (dx / length) * pull,\n y = (dy / length) * pull;\n forces[i].x += x;\n forces[i].y += y;\n forces[j].x -= x;\n forces[j].y -= y;\n }\n let movement = 0;\n particles = particles.map((p, i) => {\n const pin = pins.get(p.key);\n if (pin) return { ...p, ...pin, vx: 0, vy: 0 };\n const vx = Math.max(-8, Math.min(8, (p.vx + forces[i].x) * 0.78)),\n vy = Math.max(-8, Math.min(8, (p.vy + forces[i].y) * 0.78));\n movement = Math.max(movement, Math.abs(vx) + Math.abs(vy));\n return {\n ...p,\n vx,\n vy,\n x: Math.max(\n config.bounds.x + p.width / 2,\n Math.min(\n config.bounds.x + config.bounds.width - p.width / 2,\n p.x + vx,\n ),\n ),\n y: Math.max(\n config.bounds.y + p.height / 2,\n Math.min(\n config.bounds.y + config.bounds.height - p.height / 2,\n p.y + vy,\n ),\n ),\n };\n });\n stableSteps = movement < 0.02 ? stableSteps + 1 : 0;\n settled = stableSteps >= 8;\n }\n return read();\n },\n update(nextGraph, nextOptions) {\n const next = configuration(nextGraph, nextOptions); // Validate before changing owned state.\n const old = new Map(particles.map((p) => [p.key, p]));\n config = next;\n particles = seedParticles().map((p) => {\n const previous = old.get(p.key);\n return previous\n ? {\n ...p,\n x: Math.max(\n config.bounds.x + p.width / 2,\n Math.min(\n config.bounds.x + config.bounds.width - p.width / 2,\n previous.x,\n ),\n ),\n y: Math.max(\n config.bounds.y + p.height / 2,\n Math.min(\n config.bounds.y + config.bounds.height - p.height / 2,\n previous.y,\n ),\n ),\n vx: previous.vx,\n vy: previous.vy,\n }\n : p;\n });\n pins = new Map(\n [...pins].filter(\n ([key]) => old.has(key) && config.nodes.some((n) => n.key === key),\n ),\n );\n iterations = 0;\n stableSteps = 0;\n settled = false;\n },\n restart() {\n iterations = 0;\n stableSteps = 0;\n settled = false;\n },\n reset() {\n pins.clear();\n particles = seedParticles();\n iterations = 0;\n stableSteps = 0;\n settled = false;\n },\n pin(key, position) {\n if (!particles.some((p) => p.key === key))\n throw new Error(`Unknown force node ${key}.`);\n if (!Number.isFinite(position.x) || !Number.isFinite(position.y))\n throw new RangeError(\"Pin coordinates must be finite.\");\n pins.set(key, { ...position });\n particles = particles.map((p) =>\n p.key === key ? { ...p, ...position, vx: 0, vy: 0 } : p,\n );\n settled = false;\n stableSteps = 0;\n },\n release(key) {\n if (!particles.some((p) => p.key === key))\n throw new Error(`Unknown force node ${key}.`);\n pins.delete(key);\n settled = false;\n stableSteps = 0;\n },\n };\n}\n/**\n * Solve a seeded force layout synchronously, bounded by maxIterations. No timers or resources are allocated.\n * @param graph - Original node and edge records. See {@link GraphData}.\n * @param options - Accessors, finite bounds and numeric settings. See {@link ForceOptions}.\n * @returns A bounded result which may remain unsettled on exhaustion. See {@link ForceLayout}.\n */\nexport function layoutForceNetwork<N, E>(\n graph: GraphData<N, E>,\n options: ForceOptions<N, E>,\n): ForceLayout<N, E> {\n const session = createForceSimulation(graph, options);\n return session.step({ iterations: options.simulation?.maxIterations ?? 300 });\n}\n\n// Interpolate immutable presentation geometry between fixed-rate solver snapshots.\n// The numeric solver stays deterministic while 120/144 Hz displays get fresh poses.\nfunction interpolateForceLayout<N, E>(\n previous: ForceLayout<N, E>,\n current: ForceLayout<N, E>,\n amount: number,\n): ForceLayout<N, E> {\n if (previous === current) return current;\n if (amount === 0)\n return { ...current, nodes: previous.nodes, edges: previous.edges };\n const numbers = <T extends object>(a: T, b: T): T => {\n const result = { ...b };\n for (const key in b) {\n const before = a[key],\n after = b[key];\n if (typeof before === \"number\" && typeof after === \"number\")\n result[key] = (before + (after - before) * amount) as T[typeof key];\n }\n return result;\n };\n const rotation = (a: number, b: number) => a + (b - a) * amount;\n const oldNodes = new Map(previous.nodes.map((node) => [node.key, node]));\n const oldEdges = new Map(previous.edges.map((edge) => [edge.key, edge]));\n return {\n ...current,\n nodes: current.nodes.map((node) => {\n const old = oldNodes.get(node.key);\n if (!old) return node;\n return {\n ...node,\n bounds: numbers(old.bounds, node.bounds),\n label: {\n ...node.label,\n bounds: numbers(old.label.bounds, node.label.bounds),\n rotationDegrees: rotation(\n old.label.rotationDegrees,\n node.label.rotationDegrees,\n ),\n },\n detail:\n old.detail && node.detail\n ? {\n ...node.detail,\n bounds: numbers(old.detail.bounds, node.detail.bounds),\n rotationDegrees: rotation(\n old.detail.rotationDegrees,\n node.detail.rotationDegrees,\n ),\n }\n : node.detail,\n };\n }),\n edges: current.edges.map((edge) => {\n const old = oldEdges.get(edge.key);\n if (!old) return edge;\n const segments = (\n a: typeof edge.route.segments,\n b: typeof edge.route.segments,\n ) =>\n b.map((segment, index) =>\n a[index]?.type === segment.type\n ? numbers(a[index], segment)\n : segment,\n );\n const route = {\n sourceAnchor: numbers(old.route.sourceAnchor, edge.route.sourceAnchor),\n targetAnchor: numbers(old.route.targetAnchor, edge.route.targetAnchor),\n segments: segments(old.route.segments, edge.route.segments),\n arrowSegments:\n old.route.arrowSegments && edge.route.arrowSegments\n ? segments(old.route.arrowSegments, edge.route.arrowSegments)\n : edge.route.arrowSegments,\n };\n return {\n ...edge,\n route,\n path: forcePath(route.segments),\n arrowPath: route.arrowSegments ? forcePath(route.arrowSegments) : null,\n };\n }),\n };\n}\nfunction forcePath(segments: Parameters<typeof routePath>[0]): string {\n if (\n segments.length === 2 &&\n segments[0].type === \"move\" &&\n segments[1].type === \"line\"\n )\n return `M ${segments[0].x} ${segments[0].y} L ${segments[1].x} ${segments[1].y}`;\n return routePath(segments);\n}\n\n/** Own a force session through public stepper, drive, usePlayback and signals.\n * @param graph - Graph input or signal; accessors are snapshotted during component evaluation. See {@link GraphData}.\n * @param options - Geometry and optional resource-free numeric solver factory. See {@link ForceHookOptions}.\n * @returns Readonly snapshots and commands; playback is released on unmount. See {@link ForceNetworkController}.\n */\nexport function useForceNetwork<N, E>(\n graph: import(\"@pibbl/core\").SignalValue<GraphData<N, E>>,\n options: ForceHookOptions<N, E>,\n): ForceNetworkController<N, E> {\n const input = resolveSignalValue(graph);\n // Capture all application callbacks now, outside Advance. The numeric session sees plain admitted values.\n let inputError: Error | null = null;\n let prepared: ReturnType<typeof configuration<N, E>>;\n try {\n prepared = configuration(input, options);\n } catch (error) {\n inputError = error instanceof Error ? error : new Error(String(error));\n prepared = configuration(\n { nodes: [], edges: [] },\n {\n ...options,\n simulation: {},\n bounds: { x: 0, y: 0, width: 0, height: 0 },\n },\n );\n }\n const nodeMetadata = new Map(\n prepared.nodes.map((node) => [node.datum, node]),\n );\n const edgeMetadata = new Map(\n prepared.edges.map((edge) => [edge.datum, edge]),\n );\n const snapshotOptions: ForceOptions<N, E> = {\n bounds: { ...prepared.bounds },\n simulation: { ...prepared.settings },\n directed: prepared.directed,\n nodeKey: (node) => nodeMetadata.get(node)!.key,\n edgeKey: (edge) => edgeMetadata.get(edge)!.key,\n source: (edge) => edgeMetadata.get(edge)!.sourceKey,\n target: (edge) => edgeMetadata.get(edge)!.targetKey,\n nodeSize: (node) => nodeMetadata.get(node)!,\n label: (node) => nodeMetadata.get(node)!.label,\n detail: options.detail\n ? (node) => nodeMetadata.get(node)!.detail!\n : undefined,\n };\n const snapshotGraph = {\n nodes: inputError ? [] : [...input.nodes],\n edges: inputError ? [] : [...input.edges],\n };\n const signature = JSON.stringify([\n prepared.bounds,\n prepared.settings,\n prepared.directed,\n prepared.nodes.map(({ datum: _datum, ...metadata }) => metadata),\n prepared.edges.map(({ datum: _datum, ...metadata }) => metadata),\n ]);\n type Status = \"running\" | \"paused\" | \"settled\" | \"exhausted\" | \"failed\";\n type Frame = {\n layout: ForceLayout<N, E>;\n status: Status;\n error: Error | null;\n };\n const owner = useConst(() => {\n const factory = options.createSimulation ?? createForceSimulation;\n const session = factory(snapshotGraph, snapshotOptions);\n const output = signal<Frame>({\n layout: session.read(),\n status: options.initialPaused ? \"paused\" : \"running\",\n error: null,\n });\n return {\n factory,\n session,\n previous: output.get().layout,\n current: output.get(),\n phase: 0,\n output,\n disposed: false,\n pending: [] as (() => void)[],\n paused: options.initialPaused ?? false,\n signature,\n graph: snapshotGraph,\n options: snapshotOptions,\n };\n });\n if (\n options.createSimulation !== undefined &&\n options.createSimulation !== owner.factory\n )\n throw new Error(\n \"Force createSimulation is fixed for a mounted hook; remount to replace it.\",\n );\n const advance = (integrate: boolean): Frame => {\n try {\n const pending = owner.pending.splice(0);\n if (!pending.length && owner.current.status === \"failed\")\n return owner.current;\n for (const command of pending) command();\n if (pending.length) {\n owner.current = { ...owner.current, layout: owner.session.read() };\n owner.previous = owner.current.layout;\n }\n if (integrate && !owner.paused) {\n owner.previous = owner.current.layout;\n owner.current = {\n ...owner.current,\n layout: owner.session.step({ iterations: 1 }),\n };\n }\n const layout = owner.current.layout;\n const status: Status =\n owner.paused || !layout.bounds.width || !layout.bounds.height\n ? \"paused\"\n : layout.settled\n ? \"settled\"\n : layout.iterations >=\n (owner.options.simulation?.maxIterations ?? 300)\n ? \"exhausted\"\n : \"running\";\n owner.current = { layout, status, error: null };\n } catch (error) {\n owner.current = {\n layout: owner.output.get().layout,\n status: \"failed\",\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n return owner.current;\n };\n const program = useConst(() =>\n drive(\n owner.output,\n stepper<Frame, Frame>({\n // Twelve presentation subdivisions divide common 60/120/144/240 Hz displays.\n // This is scheduler sampling, not another animation loop or 720 solver ticks.\n stepMilliseconds: 1000 / 720,\n maxElapsedMilliseconds: 1000 / 30,\n initial: () => {\n owner.phase = 0;\n return advance(false);\n },\n step: () => {\n owner.phase = (owner.phase + 1) % 12;\n return owner.phase === 0 || owner.pending.length\n ? advance(owner.phase === 0)\n : owner.current;\n },\n read: () => {\n const frame = owner.pending.length ? advance(false) : owner.current;\n return frame.status === \"running\"\n ? {\n ...frame,\n layout: interpolateForceLayout(\n owner.previous,\n frame.layout,\n owner.phase / 12,\n ),\n }\n : frame;\n },\n done: (state) => state.status !== \"running\",\n }),\n ),\n );\n const playback = usePlayback(program, { autoplay: !options.initialPaused });\n const queue = (command: () => void) => {\n if (owner.disposed) return;\n owner.pending.push(command);\n const status = playback.status.get();\n if (status !== \"running\" && status !== \"scheduled\")\n playback.play({ conflict: \"replace\" });\n };\n useReaction(() => {\n if (inputError) {\n queue(() => {\n throw inputError;\n });\n return;\n }\n if (\n untracked(() => owner.output.get().status) === \"failed\" ||\n owner.signature !== signature ||\n owner.graph.nodes.some(\n (datum, index) => datum !== snapshotGraph.nodes[index],\n ) ||\n owner.graph.edges.some(\n (datum, index) => datum !== snapshotGraph.edges[index],\n )\n ) {\n queue(() => {\n owner.session.update(snapshotGraph, snapshotOptions);\n owner.graph = snapshotGraph;\n owner.options = snapshotOptions;\n owner.signature = signature;\n });\n }\n }, [signature, inputError?.message, ...input.nodes, ...input.edges]);\n useReaction(\n () => () => {\n owner.disposed = true;\n owner.pending.length = 0;\n },\n [],\n );\n return useConst(() => ({\n layout: computed(() => owner.output.get().layout),\n status: computed(() => owner.output.get().status),\n error: computed(() => owner.output.get().error),\n pause: () =>\n queue(() => {\n owner.paused = true;\n }),\n resume: () =>\n queue(() => {\n owner.paused = false;\n }),\n restart: () =>\n queue(() => {\n owner.session.restart();\n owner.paused = false;\n }),\n reset: () =>\n queue(() => {\n owner.session.reset();\n owner.paused = false;\n }),\n pin: (key: VizKey, point: Point) =>\n queue(() => {\n owner.session.pin(key, point);\n owner.session.restart();\n }),\n release: (key: VizKey) =>\n queue(() => {\n owner.session.release(key);\n owner.session.restart();\n }),\n }));\n}\n/**\n * Own and render a live force network through the public hook and GraphView; unmount releases playback.\n * @param props - Graph, definite frame, optional solver factory, controlled pause and presentation. See {@link ForceNetworkProps}.\n * @returns A public-hook and public-marks composition. See {@link useForceNetwork}.\n */\nexport function ForceNetwork<N, E>(props: ForceNetworkProps<N, E>): PibblNode {\n const frame = useGraphFrame(props.style);\n const paused = resolveSignalValue(props.paused) ?? false;\n const network = useForceNetwork(props.graph, {\n ...props,\n bounds: frame.bounds,\n initialPaused: paused,\n });\n useReaction(() => {\n if (paused) network.pause();\n else network.resume();\n }, [paused]);\n return (\n <Group style={frame.groupStyle}>\n <GraphView\n {...props}\n layout={network.layout}\n style={undefined}\n labelStyle={(node) => ({\n textAlign: \"center\",\n ...resolveSignalValue(\n typeof props.labelStyle === \"function\"\n ? props.labelStyle(node)\n : props.labelStyle,\n ),\n })}\n nodeStyle={(node) => ({\n cornerRadius: 100,\n ...resolveSignalValue(\n typeof props.nodeStyle === \"function\"\n ? props.nodeStyle(node)\n : props.nodeStyle,\n ),\n })}\n />\n </Group>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|