@weasel-js/diagram 1.9.3 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/{chunk-ERT3XWBS.js → chunk-BWQJYEA3.js} +241 -66
- package/dist/chunk-BWQJYEA3.js.map +1 -0
- package/dist/index.d.ts +132 -161
- package/dist/index.js +168 -51
- package/dist/index.js.map +1 -1
- package/dist/layout.d.ts +2 -1
- package/dist/{layout.entry-KHbx5uGC.d.ts → layout.entry-CIdRpG2i.d.ts} +74 -103
- package/dist/layout.js +1 -1
- package/package.json +6 -3
- package/dist/chunk-ERT3XWBS.js.map +0 -1
package/dist/layout.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { j as BodyFloor, k as BodyNodeSpec, B as BodySpec, l as Bounds, m as BuildBodyOptions, C as COMPASS, p as DEFAULT_NODE_GAP, q as DEFAULT_PORTS, r as DEFAULT_RANK_GAP, f as DiagramNode, u as ForceBody, F as ForceOptions, v as ForceRelaxation, i as Graph,
|
|
1
|
+
export { j as BodyFloor, k as BodyNodeSpec, B as BodySpec, l as Bounds, m as BuildBodyOptions, C as COMPASS, p as DEFAULT_NODE_GAP, q as DEFAULT_PORTS, r as DEFAULT_RANK_GAP, f as DiagramNode, u as ForceBody, F as ForceOptions, v as ForceRelaxation, i as Graph, x as GraphEdge, z as GraphNode, H as LayoutAxes, I as LayoutDirection, L as LayoutFn, g as LayoutOptions, h as LayoutResult, M as MeasureRowText, O as Outline, P as Port, c as PortAnchor, e as PortSpec, a as PortsOptions, R as Row, J as RowBox, K as RowNodeData, N as RowPort, Q as RowPortBox, S as RowTextStyle, T as Slot, U as axesFor, V as backEdges, W as bodyOutline, Y as boxForContent, Z as buildBody, $ as canvasMeasure, a0 as contentBox, aw as extent, a5 as force, a6 as forceRelaxation, a7 as forestOf, a8 as graphOrder, ab as layered, ac as layoutBody, ad as layoutRowPorts, ae as measureBody, af as outlinePath, ag as outlinePolyline, ah as packAcross, aj as pinnedSet, ak as portOf, al as portsOf, am as portsOnOutline, ao as ranksOf, ap as rayHit, aq as seededOrder, ar as settle, as as sizeToBody, at as translated, au as tree, av as untilSettled } from './layout.entry-CIdRpG2i.js';
|
|
2
2
|
import '@weasel-js/geom';
|
|
3
3
|
import '@weasel-js/core/math';
|
|
4
|
+
import '@weasel-js/simulation';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as _weasel_js_geom from '@weasel-js/geom';
|
|
2
|
-
import { Path, PoseDescriptor, Vec2
|
|
2
|
+
import { Path, PoseDescriptor, Vec2 } from '@weasel-js/core/math';
|
|
3
|
+
import { SimulationNode, createSimulation } from '@weasel-js/simulation';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* The shapes a built body can wear, as paths in the node's bounds.
|
|
@@ -56,18 +57,15 @@ declare function boxForContent(outline: Outline, content: {
|
|
|
56
57
|
/**
|
|
57
58
|
* Reading the `DiagramNode` trait off a scene node.
|
|
58
59
|
*
|
|
59
|
-
* Two ways to attach it
|
|
60
|
+
* Two ways to attach it:
|
|
60
61
|
*
|
|
61
|
-
* - **On the node.** `data.diagram` holds the trait.
|
|
62
|
-
* what a connect gesture writes when the author drags a new edge.
|
|
62
|
+
* - **On the node.** `data.diagram` holds the trait.
|
|
63
63
|
* - **By kind.** A consumer declares once which data shapes take part, and
|
|
64
|
-
* every matching node gets the trait without being stamped
|
|
65
|
-
*
|
|
66
|
-
* wins — and is the shape to reach for when the participants are a class
|
|
67
|
-
* of node rather than a hand-picked set.
|
|
64
|
+
* every matching node gets the trait without being stamped — a predicate
|
|
65
|
+
* over `data`, first match wins.
|
|
68
66
|
*
|
|
69
67
|
* A reader is a plain function, so a consumer whose data lives somewhere else
|
|
70
|
-
*
|
|
68
|
+
* passes their own.
|
|
71
69
|
*/
|
|
72
70
|
|
|
73
71
|
/** The key on a node's `data` the default reader looks under. */
|
|
@@ -98,17 +96,13 @@ interface DiagramNodeEntry {
|
|
|
98
96
|
* An edge's trait lives under the same key, so `from` and `to` are what tells
|
|
99
97
|
* the two apart. Without that test an edge reads as a participant declaring
|
|
100
98
|
* no ports, and collects the four defaults on the degenerate pose an edge
|
|
101
|
-
* carries
|
|
102
|
-
*
|
|
103
|
-
* also take a slot in every layout. */
|
|
99
|
+
* carries. An edge label's `label` trait and an anchored node's `anchor` are
|
|
100
|
+
* excluded the same way. */
|
|
104
101
|
declare const dataKeyReader: DiagramNodeReader;
|
|
105
102
|
/**
|
|
106
103
|
* A reader over declared kinds. A trait on the node's own data still wins, so
|
|
107
|
-
* a single node can opt out of, or override, whatever its kind says.
|
|
108
|
-
*
|
|
109
|
-
* Throws on a duplicate `name`, for the reason `mergeContributions` does: a
|
|
110
|
-
* class of node silently losing its ports is what this registry exists to make
|
|
111
|
-
* loud.
|
|
104
|
+
* a single node can opt out of, or override, whatever its kind says. Throws on
|
|
105
|
+
* a duplicate `name`.
|
|
112
106
|
*/
|
|
113
107
|
declare function createDiagramNodes(entries: readonly DiagramNodeEntry[]): DiagramNodeReader;
|
|
114
108
|
/** The trait `node` carries, through `read` (default: its own `data.diagram`). */
|
|
@@ -119,15 +113,10 @@ declare function isPinned(node: DiagramNodeLike, read?: DiagramNodeReader): bool
|
|
|
119
113
|
/**
|
|
120
114
|
* `Graph` — the adjacency index a layout runs over.
|
|
121
115
|
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
* not on the hot path. Measure before changing that.
|
|
127
|
-
*
|
|
128
|
-
* A node's *identity* is its id and its *size* is its bounds; where it currently
|
|
129
|
-
* sits is here too, because a re-layout that ignores where things already are
|
|
130
|
-
* scrambles a diagram the author has arranged.
|
|
116
|
+
* Built from the scene on demand, used, and thrown away. Rebuilding per layout
|
|
117
|
+
* invocation is deliberate — a maintained index is a cache to invalidate on
|
|
118
|
+
* every add, delete, reparent, and `dependsOn` edit, and layout is not on the
|
|
119
|
+
* hot path.
|
|
131
120
|
*/
|
|
132
121
|
|
|
133
122
|
/** A scene node as the graph reads it. `dependsOn` is what an edge's two
|
|
@@ -149,17 +138,20 @@ interface GraphNode {
|
|
|
149
138
|
bounds: Bounds;
|
|
150
139
|
/** Layout must not move it. */
|
|
151
140
|
pinned: boolean;
|
|
152
|
-
/** The group it belongs to, when it belongs to one. */
|
|
141
|
+
/** The innermost group it belongs to, when it belongs to one. */
|
|
153
142
|
group?: string;
|
|
154
143
|
}
|
|
155
144
|
/** A box drawn around some participants, which a layout keeps together and
|
|
156
145
|
* leaves room for. */
|
|
157
146
|
interface GraphGroup {
|
|
158
147
|
id: string;
|
|
159
|
-
/**
|
|
148
|
+
/** Every participant inside, through any group nested in this one, in
|
|
149
|
+
* source order. */
|
|
160
150
|
members: readonly string[];
|
|
161
|
-
/** Room the box keeps around
|
|
151
|
+
/** Room the box keeps around what it holds, in world units. */
|
|
162
152
|
inset: GroupInset;
|
|
153
|
+
/** The group this one is directly inside. */
|
|
154
|
+
parent?: string;
|
|
163
155
|
}
|
|
164
156
|
/** One connection. `id` is the edge node's own id, so a caller can go back to
|
|
165
157
|
* the scene for its trait. */
|
|
@@ -172,8 +164,7 @@ interface GraphEdge {
|
|
|
172
164
|
* Nodes, edges, and the two adjacency reads a layout needs.
|
|
173
165
|
*
|
|
174
166
|
* Every list is in source order — render order, when the source is a scene —
|
|
175
|
-
* which is what a layout's tiebreaks resolve against.
|
|
176
|
-
* downstream of this, and this is where that starts.
|
|
167
|
+
* which is what a layout's tiebreaks resolve against.
|
|
177
168
|
*/
|
|
178
169
|
interface Graph {
|
|
179
170
|
readonly nodes: readonly GraphNode[];
|
|
@@ -197,11 +188,10 @@ interface BuildGraphOptions<TPose> {
|
|
|
197
188
|
*
|
|
198
189
|
* A node is an edge if it carries the edge trait and names exactly two
|
|
199
190
|
* dependencies; a group if its trait carries `group`, with its dependencies as
|
|
200
|
-
* its members; a participant if the reader hands back any other
|
|
191
|
+
* its members, which may be groups themselves (see `nestGroups`); a participant if the reader hands back any other
|
|
201
192
|
* `DiagramNode`; and otherwise not in the diagram at all. An edge whose
|
|
202
|
-
* endpoints are not both participants or groups is dropped
|
|
203
|
-
*
|
|
204
|
-
* members (see `expandGroupEdges`).
|
|
193
|
+
* endpoints are not both participants or groups is dropped, and an edge to a
|
|
194
|
+
* group ranks against its members (see `expandGroupEdges`).
|
|
205
195
|
*/
|
|
206
196
|
declare function buildGraph<TPose>(source: GraphSource<TPose>, opts?: BuildGraphOptions<TPose>): Graph;
|
|
207
197
|
|
|
@@ -210,24 +200,19 @@ declare function buildGraph<TPose>(source: GraphSource<TPose>, opts?: BuildGraph
|
|
|
210
200
|
*
|
|
211
201
|
* A layout is a pure function of the graph — no scene, no ops, no history. It
|
|
212
202
|
* hands back the new top-left for every node that **moves**, and a node already
|
|
213
|
-
* standing where the layout wants it is
|
|
214
|
-
* what makes re-running a layout free rather than destructive, and it is the
|
|
215
|
-
* property the idempotence test asserts.
|
|
203
|
+
* standing where the layout wants it is absent from the answer.
|
|
216
204
|
*
|
|
217
|
-
* Three rules keep re-layout non-destructive
|
|
218
|
-
* than in each algorithm:
|
|
205
|
+
* Three rules keep re-layout non-destructive:
|
|
219
206
|
*
|
|
220
207
|
* - **No RNG anywhere.** Every tiebreak falls back to the graph's own node
|
|
221
|
-
* order
|
|
208
|
+
* order.
|
|
222
209
|
* - **Within-rank order is seeded from where the nodes already are**, read
|
|
223
|
-
* off the cross axis, rather than from crossing-minimization.
|
|
224
|
-
* dragged two boxes into an order gets that order back.
|
|
210
|
+
* off the cross axis, rather than from crossing-minimization.
|
|
225
211
|
* - **A pin set nothing moves.** Pinned nodes are never in the result, and
|
|
226
212
|
* the rest of the layout is translated to sit around them.
|
|
227
213
|
*
|
|
228
|
-
* `layered` and `tree` are idempotent
|
|
229
|
-
*
|
|
230
|
-
* iterative relaxation and makes no such claim — re-running it keeps relaxing.
|
|
214
|
+
* `layered` and `tree` are idempotent; `force` is an iterative relaxation and
|
|
215
|
+
* re-running it keeps relaxing.
|
|
231
216
|
*/
|
|
232
217
|
|
|
233
218
|
/** Which way the ranks stack. `force` ignores it. */
|
|
@@ -284,32 +269,32 @@ interface Slot {
|
|
|
284
269
|
rank: number;
|
|
285
270
|
}
|
|
286
271
|
/**
|
|
287
|
-
* Turn canonical slots into the positions to write
|
|
272
|
+
* Turn canonical slots into the positions to write: map the canonical frame
|
|
273
|
+
* onto the world axes, translate the whole layout so it lands where the graph
|
|
274
|
+
* already is, and drop everything that is pinned or that would not move.
|
|
288
275
|
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
* The translation is what makes the layout non-destructive, and it is chosen so
|
|
294
|
-
* that a second run lands on the same answer. With a pin, it is whatever keeps
|
|
295
|
-
* the first pinned node exactly where it is. Without one, it is whatever puts
|
|
296
|
-
* the layout's own bounding box where the graph's bounding box already starts —
|
|
297
|
-
* which the first run then makes true, so the second run computes the same
|
|
298
|
-
* translation and writes nothing.
|
|
276
|
+
* With a pin, the translation keeps the first pinned node exactly where it is.
|
|
277
|
+
* Without one, it puts the layout's bounding box where the graph's already
|
|
278
|
+
* starts, so a second run computes the same translation and writes nothing.
|
|
299
279
|
*/
|
|
300
280
|
declare function settle(graph: Graph, slots: ReadonlyMap<string, Slot>, opts?: LayoutOptions): LayoutResult;
|
|
281
|
+
/**
|
|
282
|
+
* Run `once` until a pass moves nothing, and answer with where that leaves
|
|
283
|
+
* each node.
|
|
284
|
+
*
|
|
285
|
+
* A layout that keeps groups together can move an outsider out of a group's
|
|
286
|
+
* column, which changes the order the next run would start from. `passes`
|
|
287
|
+
* bounds an arrangement that never comes to rest.
|
|
288
|
+
*/
|
|
289
|
+
declare function untilSettled(once: LayoutFn, graph: Graph, opts?: LayoutOptions, passes?: number): LayoutResult;
|
|
301
290
|
/**
|
|
302
291
|
* {@link settle}'s second half, for a layout that already works in world
|
|
303
|
-
* coordinates
|
|
304
|
-
* than filling slots.
|
|
292
|
+
* coordinates.
|
|
305
293
|
*/
|
|
306
294
|
declare function translated(graph: Graph, placed: ReadonlyMap<string, Vec2>, pinned: ReadonlySet<string>, tolerance?: number): LayoutResult;
|
|
307
295
|
/**
|
|
308
296
|
* Lay a list of nodes out along the cross axis, in the order given, and hand
|
|
309
297
|
* back each one's low corner plus the total span.
|
|
310
|
-
*
|
|
311
|
-
* Shared by `layered`'s ranks and `tree`'s sibling rows, which pack a row the
|
|
312
|
-
* same way and differ only in what decides the order.
|
|
313
298
|
*/
|
|
314
299
|
declare function packAcross(nodes: readonly GraphNode[], axis: 'x' | 'y', gap: number): {
|
|
315
300
|
at: Map<string, number>;
|
|
@@ -331,9 +316,9 @@ declare function graphOrder(graph: Graph): (id: string) => number;
|
|
|
331
316
|
* to its last — including a rank in between that holds none of its members, or
|
|
332
317
|
* an outsider would land inside the box there. Groups keep one cross position
|
|
333
318
|
* across every rank, so two groups' columns never cross and their boxes never
|
|
334
|
-
* overlap. Ungrouped nodes pack around the columns rank by rank
|
|
319
|
+
* overlap. Ungrouped nodes pack around the columns rank by rank.
|
|
335
320
|
*
|
|
336
|
-
*
|
|
321
|
+
* A group may be a member of another: its column then sits inside its parent's.
|
|
337
322
|
*/
|
|
338
323
|
|
|
339
324
|
/** Room a group's box keeps around its members, in world units. */
|
|
@@ -351,23 +336,25 @@ declare const DEFAULT_GROUP_INSET = 12;
|
|
|
351
336
|
* The gap between each rank and the next, widened so a group's box fits: the
|
|
352
337
|
* widest inset of a group ending at rank `i` and of one starting at `i + 1`
|
|
353
338
|
* both come on top of `rankGap`, since those two boxes can face each other
|
|
354
|
-
* across it.
|
|
339
|
+
* across it. A group's inset there includes that of any group nested in it
|
|
340
|
+
* that ends, or starts, at the same rank. `rows` is the nodes of each rank.
|
|
355
341
|
*/
|
|
356
342
|
declare function rankGaps(graph: Graph, rows: readonly (readonly GraphNode[])[], axes: LayoutAxes, rankGap: number): number[];
|
|
357
343
|
/**
|
|
358
344
|
* Cross positions for every node, with each group's members kept in a column
|
|
359
|
-
* of their own
|
|
360
|
-
*
|
|
361
|
-
*
|
|
345
|
+
* of their own, and a nested group in a column inside its parent's.
|
|
346
|
+
* `preferred` is where the layout would put each node's low corner with no
|
|
347
|
+
* groups at all; nodes and columns keep that order and are only ever pushed
|
|
348
|
+
* toward the high end, by as much as it takes to stop overlapping.
|
|
362
349
|
*/
|
|
363
350
|
declare function packClusters(graph: Graph, rows: readonly (readonly GraphNode[])[], preferred: ReadonlyMap<string, number>, axes: LayoutAxes, nodeGap: number): Map<string, number>;
|
|
364
351
|
/**
|
|
365
352
|
* Edges as a layout should rank by: one into a group arrives at its entry
|
|
366
353
|
* members — those no other member points at — and one out of it leaves from its
|
|
367
354
|
* exit members. A group with no such member, a pure cycle, is all entries and
|
|
368
|
-
* all exits. An edge between a group and
|
|
369
|
-
*
|
|
370
|
-
*
|
|
355
|
+
* all exits. An edge between a group and something inside it, a member or a
|
|
356
|
+
* nested group, is that group's internal business and ranks nothing beyond
|
|
357
|
+
* what its member-to-member edges already do.
|
|
371
358
|
*/
|
|
372
359
|
declare function expandGroupEdges(edges: readonly GraphEdge[], groups: readonly GraphGroup[]): GraphEdge[];
|
|
373
360
|
|
|
@@ -452,9 +439,7 @@ type Row =
|
|
|
452
439
|
value: string;
|
|
453
440
|
style?: RowTextStyle;
|
|
454
441
|
}
|
|
455
|
-
/** A row that carries ports on its own left and right edges
|
|
456
|
-
* visual-programming shape, where an operator's inputs line up with the
|
|
457
|
-
* rows they feed. */
|
|
442
|
+
/** A row that carries ports on its own left and right edges. */
|
|
458
443
|
| {
|
|
459
444
|
kind: 'ports';
|
|
460
445
|
left?: readonly RowPort[];
|
|
@@ -550,8 +535,7 @@ declare function canvasMeasure(ctx: {
|
|
|
550
535
|
declare function measureBody(spec: BodySpec, measure?: MeasureRowText): BodyFloor;
|
|
551
536
|
/**
|
|
552
537
|
* The authored size, grown to fit the body. Never shrinks: a row removed
|
|
553
|
-
* leaves the node the size the author last saw it at
|
|
554
|
-
* behavior that survives a resize the author did on purpose.
|
|
538
|
+
* leaves the node the size the author last saw it at.
|
|
555
539
|
*/
|
|
556
540
|
declare function sizeToBody<TPose extends Bounds>(pose: TPose, floor: BodyFloor): TPose;
|
|
557
541
|
/** Where each row sits inside `bounds`, top to bottom. Rows keep their
|
|
@@ -559,8 +543,7 @@ declare function sizeToBody<TPose extends Bounds>(pose: TPose, floor: BodyFloor)
|
|
|
559
543
|
* places the block of them within it. */
|
|
560
544
|
declare function layoutBody(spec: BodySpec, bounds: Bounds, measure?: MeasureRowText): RowBox[];
|
|
561
545
|
/**
|
|
562
|
-
* Where each of a `ports` row's ports goes inside `box
|
|
563
|
-
* `layoutBody` gives one box per row.
|
|
546
|
+
* Where each of a `ports` row's ports goes inside `box`.
|
|
564
547
|
*
|
|
565
548
|
* Both sides are cut into the same number of slots — the longer side's count —
|
|
566
549
|
* so the nth input faces the nth output whichever side has more. A label box
|
|
@@ -576,13 +559,12 @@ declare function layoutRowPorts(row: Extract<Row, {
|
|
|
576
559
|
* left or right edge.
|
|
577
560
|
*
|
|
578
561
|
* Anchors are normalized against `bounds`, so they survive the node being
|
|
579
|
-
* resized
|
|
562
|
+
* resized.
|
|
580
563
|
*
|
|
581
564
|
* **A row port on a side takes that side's compass default with it.** Both sit
|
|
582
565
|
* on the same edge, and a row near the vertical middle puts one exactly on top
|
|
583
566
|
* of `w` or `e` — where the later region wins the hit and the other is
|
|
584
|
-
* grabbable nowhere.
|
|
585
|
-
* that side is for.
|
|
567
|
+
* grabbable nowhere.
|
|
586
568
|
*/
|
|
587
569
|
declare function bodyTrait(spec: BodySpec, bounds: Bounds, measure?: MeasureRowText): DiagramNode;
|
|
588
570
|
/** The outline path for a built body at `bounds` — what paints it, and what a
|
|
@@ -610,8 +592,7 @@ interface BuildBodyOptions<TData, TLayer extends string, TPose extends Bounds> {
|
|
|
610
592
|
/** One row's data, or `null` to leave that row undrawn. */
|
|
611
593
|
row: RowNodeData<TData>;
|
|
612
594
|
/** One row port's label, or `null` to leave it undrawn. Ports with no
|
|
613
|
-
* `label` are never offered. Omit to draw none
|
|
614
|
-
* named only for the width they claim needs nothing here. */
|
|
595
|
+
* `label` are never offered. Omit to draw none. */
|
|
615
596
|
portLabel?: (text: string, box: RowPortBox) => TData | null;
|
|
616
597
|
}
|
|
617
598
|
/**
|
|
@@ -619,13 +600,9 @@ interface BuildBodyOptions<TData, TLayer extends string, TPose extends Bounds> {
|
|
|
619
600
|
* leaf per row that wants drawing.
|
|
620
601
|
*
|
|
621
602
|
* Rows are ordinary scene nodes rather than something this package paints, so
|
|
622
|
-
* the kit's own text painter draws them and text editing, styling and
|
|
623
|
-
* selection work on them unchanged. The
|
|
624
|
-
*
|
|
625
|
-
* is why a label and its ports cannot drift apart.
|
|
626
|
-
*
|
|
627
|
-
* The pose is `sizeToBody(at, measureBody(spec))`: the body measures a floor
|
|
628
|
-
* and the authored size is grown to clear it, never shrunk.
|
|
603
|
+
* the kit's own text painter draws them and text editing, styling, and
|
|
604
|
+
* selection work on them unchanged. The returned pose is `at` grown to fit the
|
|
605
|
+
* body, never shrunk.
|
|
629
606
|
*/
|
|
630
607
|
declare function buildBody<TData, TLayer extends string, TPose extends Bounds>(spec: BodySpec, at: TPose, opts: BuildBodyOptions<TData, TLayer, TPose>): {
|
|
631
608
|
pose: TPose;
|
|
@@ -708,15 +685,10 @@ declare function portOf<TPose>(node: DiagramNodeLike, pose: TPose, portId: strin
|
|
|
708
685
|
* Seeded from where the nodes already are rather than from a fresh random
|
|
709
686
|
* scatter: an author who has arranged half a diagram gets that arrangement
|
|
710
687
|
* relaxed, not replaced. There is no RNG in it at all — two coincident nodes
|
|
711
|
-
* are separated along a golden-angle spiral keyed to their index
|
|
712
|
-
* a random jiggle is for elsewhere.
|
|
688
|
+
* are separated along a golden-angle spiral keyed to their index.
|
|
713
689
|
*
|
|
714
|
-
* The
|
|
715
|
-
*
|
|
716
|
-
* are the naive O(n²) kind — right for the tens-to-hundreds of nodes an
|
|
717
|
-
* edge-per-scene-node diagram is already sized for, wrong for a 10k-node graph,
|
|
718
|
-
* which wants d3-force's Barnes–Hut through `useSimulation` and its own render
|
|
719
|
-
* layer.
|
|
690
|
+
* The forces are the naive O(n²) kind — right for tens to hundreds of nodes,
|
|
691
|
+
* wrong for a 10k-node graph.
|
|
720
692
|
*
|
|
721
693
|
* **This is the one layout that is not idempotent.** A relaxation re-run from
|
|
722
694
|
* its own output keeps relaxing; `direction` means nothing to it. Pins and the
|
|
@@ -739,6 +711,8 @@ interface ForceOptions extends LayoutOptions {
|
|
|
739
711
|
gravity?: number;
|
|
740
712
|
/** Clear space kept between two boxes, in world units. Default 24. */
|
|
741
713
|
padding?: number;
|
|
714
|
+
/** How hard a group draws its members together, 0..1. Default 0.2. */
|
|
715
|
+
groupStrength?: number;
|
|
742
716
|
}
|
|
743
717
|
/** One node as the relaxation sees it: a simulation point centered on the
|
|
744
718
|
* node's box. */
|
|
@@ -751,10 +725,6 @@ interface ForceBody extends SimulationNode {
|
|
|
751
725
|
}
|
|
752
726
|
/**
|
|
753
727
|
* The bodies and the force list, wound up and ready to tick.
|
|
754
|
-
*
|
|
755
|
-
* Shared by the one-shot `force` below and the live relaxation in `live.ts`,
|
|
756
|
-
* which ticks it a frame at a time. Two copies of a force list drift, and the
|
|
757
|
-
* only thing that would say so is the arrangement they produce.
|
|
758
728
|
*/
|
|
759
729
|
interface ForceRelaxation {
|
|
760
730
|
bodies: ForceBody[];
|
|
@@ -786,6 +756,7 @@ declare function ranksOf(graph: Graph, back: ReadonlySet<string>): Map<string, n
|
|
|
786
756
|
* moves nothing — except under `order: 'barycenter'`, which reorders them. */
|
|
787
757
|
declare const layered: LayoutFn;
|
|
788
758
|
|
|
759
|
+
/** A graph read as trees: its roots, each node's children in order, and each node's depth. */
|
|
789
760
|
interface Forest {
|
|
790
761
|
roots: GraphNode[];
|
|
791
762
|
children: Map<string, GraphNode[]>;
|
|
@@ -825,4 +796,4 @@ declare function rayHit(poly: readonly number[], center: {
|
|
|
825
796
|
*/
|
|
826
797
|
declare function portsOnOutline(ports: readonly Port[], outline: Outline, bounds: Bounds): Port[];
|
|
827
798
|
|
|
828
|
-
export {
|
|
799
|
+
export { canvasMeasure as $, type GraphNodeLike as A, type BodySpec as B, COMPASS as C, type DiagramNodeLike as D, type GroupInset as E, type ForceOptions as F, type GraphSource as G, type LayoutAxes as H, type LayoutDirection as I, type RowBox as J, type RowNodeData as K, type LayoutFn as L, type MeasureRowText as M, type RowPort as N, type Outline as O, type Port as P, type RowPortBox as Q, type Row as R, type RowTextStyle as S, type Slot as T, axesFor as U, backEdges as V, bodyOutline as W, bodyTrait as X, boxForContent as Y, buildBody as Z, buildGraph as _, type PortsOptions as a, contentBox as a0, createDiagramNodes as a1, dataKeyReader as a2, diagramNodeOf as a3, expandGroupEdges as a4, force as a5, forceRelaxation as a6, forestOf as a7, graphOrder as a8, insetOf as a9, isPinned as aa, layered as ab, layoutBody as ac, layoutRowPorts as ad, measureBody as ae, outlinePath as af, outlinePolyline as ag, packAcross as ah, packClusters as ai, pinnedSet as aj, portOf as ak, portsOf as al, portsOnOutline as am, rankGaps as an, ranksOf as ao, rayHit as ap, seededOrder as aq, settle as ar, sizeToBody as as, translated as at, tree as au, untilSettled as av, extent as aw, type DiagramNodeReader as b, type PortAnchor as c, type DiagramGroup as d, type PortSpec as e, type DiagramNode as f, type LayoutOptions as g, type LayoutResult as h, type Graph as i, type BodyFloor as j, type BodyNodeSpec as k, type Bounds as l, type BuildBodyOptions as m, type BuildGraphOptions as n, DEFAULT_GROUP_INSET as o, DEFAULT_NODE_GAP as p, DEFAULT_PORTS as q, DEFAULT_RANK_GAP as r, DIAGRAM_TRAIT_KEY as s, type DiagramNodeEntry as t, type ForceBody as u, type ForceRelaxation as v, type Forest as w, type GraphEdge as x, type GraphGroup as y, type GraphNode as z };
|
package/dist/layout.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { COMPASS, DEFAULT_NODE_GAP, DEFAULT_PORTS, DEFAULT_RANK_GAP, axesFor, backEdges, bodyOutline, boxForContent, buildBody, canvasMeasure, contentBox, extent, force, forceRelaxation, forestOf, graphOrder, layered, layoutBody, layoutRowPorts, measureBody, outlinePath, outlinePolyline, packAcross, pinnedSet, portOf, portsOf, portsOnOutline, ranksOf, rayHit, seededOrder, settle, sizeToBody, translated, tree } from './chunk-
|
|
1
|
+
export { COMPASS, DEFAULT_NODE_GAP, DEFAULT_PORTS, DEFAULT_RANK_GAP, axesFor, backEdges, bodyOutline, boxForContent, buildBody, canvasMeasure, contentBox, extent, force, forceRelaxation, forestOf, graphOrder, layered, layoutBody, layoutRowPorts, measureBody, outlinePath, outlinePolyline, packAcross, pinnedSet, portOf, portsOf, portsOnOutline, ranksOf, rayHit, seededOrder, settle, sizeToBody, translated, tree, untilSettled } from './chunk-BWQJYEA3.js';
|
|
2
2
|
//# sourceMappingURL=layout.js.map
|
|
3
3
|
//# sourceMappingURL=layout.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weasel-js/diagram",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Node-link diagramming for weasel: any scene node becomes a diagram participant, with ports on its perimeter and an optional body builder for flowchart-shaped boxes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -21,8 +21,11 @@
|
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
23
|
"react": ">=18",
|
|
24
|
-
"@weasel-js/
|
|
25
|
-
"@weasel-js/
|
|
24
|
+
"@weasel-js/animator": "1.10.0",
|
|
25
|
+
"@weasel-js/core": "1.10.0",
|
|
26
|
+
"@weasel-js/font": "1.10.0",
|
|
27
|
+
"@weasel-js/geom": "1.10.0",
|
|
28
|
+
"@weasel-js/simulation": "1.10.0"
|
|
26
29
|
},
|
|
27
30
|
"author": "orochi235",
|
|
28
31
|
"homepage": "https://orochi235.github.io/weasel/",
|