@nodius/layouting 0.1.0 → 0.1.3
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/LICENSE +201 -201
- package/README.md +1092 -122
- package/dist/algorithms/component-packing.d.ts +9 -0
- package/dist/algorithms/component-packing.d.ts.map +1 -0
- package/dist/algorithms/coordinate-assignment.d.ts +7 -0
- package/dist/algorithms/coordinate-assignment.d.ts.map +1 -0
- package/dist/algorithms/crossing-minimization.d.ts +11 -0
- package/dist/algorithms/crossing-minimization.d.ts.map +1 -0
- package/dist/algorithms/cycle-breaking.d.ts +8 -0
- package/dist/algorithms/cycle-breaking.d.ts.map +1 -0
- package/dist/algorithms/edge-routing.d.ts +17 -0
- package/dist/algorithms/edge-routing.d.ts.map +1 -0
- package/dist/algorithms/layer-assignment.d.ts +20 -0
- package/dist/algorithms/layer-assignment.d.ts.map +1 -0
- package/dist/algorithms/value-cluster.d.ts +15 -0
- package/dist/algorithms/value-cluster.d.ts.map +1 -0
- package/dist/algorithms/value-placement.d.ts +25 -0
- package/dist/algorithms/value-placement.d.ts.map +1 -0
- package/dist/debug.d.ts +20 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/graph.d.ts +50 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/incremental.d.ts +33 -0
- package/dist/incremental.d.ts.map +1 -0
- package/dist/index.d.ts +7 -176
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1159 -234
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1156 -233
- package/dist/index.mjs.map +1 -1
- package/dist/layout.d.ts +10 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/proposals.d.ts +44 -0
- package/dist/proposals.d.ts.map +1 -0
- package/dist/types.d.ts +214 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +5 -4
- package/dist/index.d.mts +0 -176
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { HandleInput, LayoutInput, LayoutResult, ResolvedOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Inspect every input node and offer rotation proposals to the application
|
|
4
|
+
* when the node's handle layout doesn't match how the layout engine will end
|
|
5
|
+
* up placing it.
|
|
6
|
+
*
|
|
7
|
+
* The expected handle orientation depends on the node's role:
|
|
8
|
+
*
|
|
9
|
+
* - **Rail nodes** (with at least one control edge): they flow along the
|
|
10
|
+
* global direction. In TB: inputs on top, outputs on bottom.
|
|
11
|
+
* - **Value nodes** (only data edges): they end up as sidecars on the side
|
|
12
|
+
* of their consumer. Their handles must point TOWARD the consumer — i.e.
|
|
13
|
+
* opposite to the consumer's handle. A value attached to a `left` handle
|
|
14
|
+
* of the consumer will sit on the consumer's left flank, so its output
|
|
15
|
+
* needs to face `right`.
|
|
16
|
+
*
|
|
17
|
+
* The application's `onProposal` callback may:
|
|
18
|
+
* - accept by returning the proposed node (or a modified version)
|
|
19
|
+
* - reject by returning `null` / `undefined` / nothing
|
|
20
|
+
*/
|
|
21
|
+
export declare function applyRotationProposals(input: LayoutInput, options: ResolvedOptions): LayoutInput;
|
|
22
|
+
/**
|
|
23
|
+
* Per-handle strategic placement. Unlike `applyRotationProposals` which rotates
|
|
24
|
+
* every handle uniformly, this pass uses the geometry from a preview layout to
|
|
25
|
+
* suggest, for each handle, the side that actually points toward its neighbor.
|
|
26
|
+
*
|
|
27
|
+
* The caller must provide a `preview` layout — typically obtained by running
|
|
28
|
+
* a first layout pass with `onProposal` unset.
|
|
29
|
+
*
|
|
30
|
+
* The application's `onProposal` callback receives a single
|
|
31
|
+
* `RelocateHandlesProposal` per node (with all per-handle moves bundled). It
|
|
32
|
+
* may accept it as-is, modify per-handle, or reject.
|
|
33
|
+
*/
|
|
34
|
+
export declare function applyRelocateProposals(input: LayoutInput, preview: LayoutResult, options: ResolvedOptions): LayoutInput;
|
|
35
|
+
/**
|
|
36
|
+
* Rotate a set of handles by `rot` degrees clockwise. The handles' position
|
|
37
|
+
* along the side (offset) is preserved.
|
|
38
|
+
*
|
|
39
|
+
* Note: width/height of the node are NOT swapped here. The caller is free to
|
|
40
|
+
* swap them when accepting the proposal (most layouts use square-ish nodes,
|
|
41
|
+
* so we don't enforce a dimension swap).
|
|
42
|
+
*/
|
|
43
|
+
export declare function rotateHandles(handles: HandleInput[], rot: 90 | -90 | 180): HandleInput[];
|
|
44
|
+
//# sourceMappingURL=proposals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposals.d.ts","sourceRoot":"","sources":["../src/proposals.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EAGX,WAAW,EACX,YAAY,EAIZ,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,GAAG,WAAW,CAgBhG;AAsLD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,eAAe,GACvB,WAAW,CAcb;AAgGD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,GAAG,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,GAAG,WAAW,EAAE,CAWxF"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/** Position on a node where a handle can be placed */
|
|
2
|
+
export type HandleSide = 'top' | 'right' | 'bottom' | 'left';
|
|
3
|
+
/** Handle type - input receives connections, output sends connections */
|
|
4
|
+
export type HandleType = 'input' | 'output';
|
|
5
|
+
/** Layout direction. 'TB' or 'LR' are the supported strict reading axes. */
|
|
6
|
+
export type LayoutDirection = 'TB' | 'LR' | 'BT' | 'RL';
|
|
7
|
+
/**
|
|
8
|
+
* Edge kind drives the layout weight:
|
|
9
|
+
* - `control`: full strength; defines the execution rail (layer count).
|
|
10
|
+
* - `data`: light weight; values are pulled onto the same layer as their consumer
|
|
11
|
+
* instead of extending the rail.
|
|
12
|
+
*/
|
|
13
|
+
export type EdgeKind = 'control' | 'data';
|
|
14
|
+
/** A 2D point */
|
|
15
|
+
export interface Point {
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
}
|
|
19
|
+
/** Handle definition on a node */
|
|
20
|
+
export interface HandleInput {
|
|
21
|
+
id: string;
|
|
22
|
+
type: HandleType;
|
|
23
|
+
position: HandleSide;
|
|
24
|
+
/** Position along the side (0 = start, 1 = end). Default: 0.5 */
|
|
25
|
+
offset?: number;
|
|
26
|
+
}
|
|
27
|
+
/** Node input definition */
|
|
28
|
+
export interface NodeInput {
|
|
29
|
+
id: string;
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
handles: HandleInput[];
|
|
33
|
+
/** Parent node id for compound (nested) layouts. */
|
|
34
|
+
parentId?: string;
|
|
35
|
+
}
|
|
36
|
+
/** Edge input definition */
|
|
37
|
+
export interface EdgeInput {
|
|
38
|
+
id: string;
|
|
39
|
+
from: string;
|
|
40
|
+
to: string;
|
|
41
|
+
fromHandle: string;
|
|
42
|
+
toHandle: string;
|
|
43
|
+
/** Default: 'control' */
|
|
44
|
+
kind?: EdgeKind;
|
|
45
|
+
/** Explicit weight override. Defaults: 1 (control), 0.25 (data). */
|
|
46
|
+
weight?: number;
|
|
47
|
+
}
|
|
48
|
+
/** Complete layout input */
|
|
49
|
+
export interface LayoutInput {
|
|
50
|
+
nodes: NodeInput[];
|
|
51
|
+
edges: EdgeInput[];
|
|
52
|
+
}
|
|
53
|
+
/** Per-kind default weight overrides. */
|
|
54
|
+
export interface EdgeWeights {
|
|
55
|
+
control?: number;
|
|
56
|
+
data?: number;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A proposal the layout engine emits to the calling application during a pass.
|
|
60
|
+
* The app inspects it and decides whether to accept it, modify it, or reject it
|
|
61
|
+
* by returning either the (possibly tweaked) proposed node or `null`/`undefined`
|
|
62
|
+
* to keep the original.
|
|
63
|
+
*/
|
|
64
|
+
export interface RotateProposal {
|
|
65
|
+
type: 'rotate';
|
|
66
|
+
/** The node being analyzed. */
|
|
67
|
+
nodeId: string;
|
|
68
|
+
/** Same node as provided in the input. */
|
|
69
|
+
current: NodeInput;
|
|
70
|
+
/** The engine's proposed version after rotating handles. */
|
|
71
|
+
proposed: NodeInput;
|
|
72
|
+
/** Rotation in degrees (CW = positive). */
|
|
73
|
+
rotation: 90 | -90 | 180;
|
|
74
|
+
/** Reason this proposal was emitted (handle layout mismatches direction, etc.). */
|
|
75
|
+
reason: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* A per-handle strategic placement proposal. Unlike `RotateProposal` (which
|
|
79
|
+
* moves every handle uniformly), this proposal lifts each handle individually
|
|
80
|
+
* to the side that points toward its actual neighbor — computed from a preview
|
|
81
|
+
* layout pass, so the suggested sides reflect the real geometry.
|
|
82
|
+
*
|
|
83
|
+
* Example: a node with three outputs `out1`, `out2`, `out3` whose neighbors
|
|
84
|
+
* end up below, to the right, and above respectively will receive a proposal
|
|
85
|
+
* moving `out1` to `bottom`, `out2` to `right`, and `out3` to `top` — without
|
|
86
|
+
* touching unused handles.
|
|
87
|
+
*/
|
|
88
|
+
export interface RelocateHandlesProposal {
|
|
89
|
+
type: 'relocate-handles';
|
|
90
|
+
/** The node being analyzed. */
|
|
91
|
+
nodeId: string;
|
|
92
|
+
/** Same node as provided in the input. */
|
|
93
|
+
current: NodeInput;
|
|
94
|
+
/** Node with each affected handle moved to its optimal side. Unused handles are preserved. */
|
|
95
|
+
proposed: NodeInput;
|
|
96
|
+
/**
|
|
97
|
+
* Per-handle changes: { handleId → { from, to } }. Only handles whose side
|
|
98
|
+
* differs from the input are present.
|
|
99
|
+
*/
|
|
100
|
+
changes: Record<string, {
|
|
101
|
+
from: HandleSide;
|
|
102
|
+
to: HandleSide;
|
|
103
|
+
}>;
|
|
104
|
+
/** Reason: which handles benefit from which moves. */
|
|
105
|
+
reason: string;
|
|
106
|
+
}
|
|
107
|
+
export type LayoutProposal = RotateProposal | RelocateHandlesProposal;
|
|
108
|
+
export type ProposalCallback = (proposal: LayoutProposal) => NodeInput | null | undefined | void;
|
|
109
|
+
/**
|
|
110
|
+
* Quality / speed trade-off preset.
|
|
111
|
+
* - 'draft' : ~3× faster than balanced. Skips the transpose pass and uses
|
|
112
|
+
* far fewer iterations. Visually acceptable for previews,
|
|
113
|
+
* large graphs, or interactive scrubbing where the user is
|
|
114
|
+
* about to layout again anyway. Output is NOT bit-compatible
|
|
115
|
+
* with 'balanced'.
|
|
116
|
+
* - 'balanced' : default. Bit-identical to past releases.
|
|
117
|
+
* - 'high' : ~2× slower than balanced. More iterations of barycenter +
|
|
118
|
+
* coordinate optimization. Negligible quality gain on most
|
|
119
|
+
* realistic inputs — use only when the graph is dense.
|
|
120
|
+
*/
|
|
121
|
+
export type LayoutQuality = 'draft' | 'balanced' | 'high';
|
|
122
|
+
/** Layout configuration options */
|
|
123
|
+
export interface LayoutOptions {
|
|
124
|
+
/** Layout direction. Default: 'TB' */
|
|
125
|
+
direction?: LayoutDirection;
|
|
126
|
+
/**
|
|
127
|
+
* Speed / quality trade-off. Default: 'balanced'. Scales iteration counts
|
|
128
|
+
* and toggles optional passes. Explicit numeric overrides
|
|
129
|
+
* (`crossingMinimizationIterations`, `coordinateOptimizationIterations`)
|
|
130
|
+
* take precedence over the preset.
|
|
131
|
+
*/
|
|
132
|
+
quality?: LayoutQuality;
|
|
133
|
+
/** Minimum spacing between nodes in the same layer. Default: 40 */
|
|
134
|
+
nodeSpacing?: number;
|
|
135
|
+
/** Minimum spacing between layers. Default: 60 */
|
|
136
|
+
layerSpacing?: number;
|
|
137
|
+
/** Number of iterations for crossing minimization. Default: 24 */
|
|
138
|
+
crossingMinimizationIterations?: number;
|
|
139
|
+
/** Number of iterations for coordinate optimization. Default: 8 */
|
|
140
|
+
coordinateOptimizationIterations?: number;
|
|
141
|
+
/**
|
|
142
|
+
* Force-skip the per-layer transpose pass in crossing minimization. The
|
|
143
|
+
* preset already disables it for very large graphs; setting this to `true`
|
|
144
|
+
* disables it unconditionally for an additional speedup (lower quality).
|
|
145
|
+
* Default: false.
|
|
146
|
+
*/
|
|
147
|
+
skipTranspose?: boolean;
|
|
148
|
+
/** Margin for edge routing (distance from node before turning). Default: 20 */
|
|
149
|
+
edgeMargin?: number;
|
|
150
|
+
/** Override default per-kind weights. */
|
|
151
|
+
edgeWeights?: EdgeWeights;
|
|
152
|
+
/** When true, disjoint components are packed side-by-side. Default: true */
|
|
153
|
+
packComponents?: boolean;
|
|
154
|
+
/** Padding around compound (parent) bounding boxes. Default: 24 */
|
|
155
|
+
compoundPadding?: number;
|
|
156
|
+
/**
|
|
157
|
+
* Called once per node when the engine thinks a rotation of the node's
|
|
158
|
+
* handles would suit the chosen direction better. Return the (possibly
|
|
159
|
+
* tweaked) proposed node to accept, or `null`/nothing to keep the original.
|
|
160
|
+
*/
|
|
161
|
+
onProposal?: ProposalCallback;
|
|
162
|
+
}
|
|
163
|
+
/** Resolved options with all defaults applied */
|
|
164
|
+
export interface ResolvedOptions {
|
|
165
|
+
direction: LayoutDirection;
|
|
166
|
+
quality: LayoutQuality;
|
|
167
|
+
nodeSpacing: number;
|
|
168
|
+
layerSpacing: number;
|
|
169
|
+
crossingMinimizationIterations: number;
|
|
170
|
+
coordinateOptimizationIterations: number;
|
|
171
|
+
skipTranspose: boolean;
|
|
172
|
+
edgeMargin: number;
|
|
173
|
+
controlWeight: number;
|
|
174
|
+
dataWeight: number;
|
|
175
|
+
packComponents: boolean;
|
|
176
|
+
compoundPadding: number;
|
|
177
|
+
onProposal?: ProposalCallback;
|
|
178
|
+
}
|
|
179
|
+
export declare function resolveOptions(options?: LayoutOptions): ResolvedOptions;
|
|
180
|
+
/** Positioned handle in the output */
|
|
181
|
+
export interface HandleOutput {
|
|
182
|
+
id: string;
|
|
183
|
+
type: HandleType;
|
|
184
|
+
position: HandleSide;
|
|
185
|
+
x: number;
|
|
186
|
+
y: number;
|
|
187
|
+
}
|
|
188
|
+
/** Positioned node in the output */
|
|
189
|
+
export interface NodeOutput {
|
|
190
|
+
id: string;
|
|
191
|
+
x: number;
|
|
192
|
+
y: number;
|
|
193
|
+
width: number;
|
|
194
|
+
height: number;
|
|
195
|
+
handles: HandleOutput[];
|
|
196
|
+
/** Echoed back so consumers can reconstruct the hierarchy. */
|
|
197
|
+
parentId?: string;
|
|
198
|
+
}
|
|
199
|
+
/** Routed edge in the output */
|
|
200
|
+
export interface EdgeOutput {
|
|
201
|
+
id: string;
|
|
202
|
+
from: string;
|
|
203
|
+
to: string;
|
|
204
|
+
fromHandle: string;
|
|
205
|
+
toHandle: string;
|
|
206
|
+
points: Point[];
|
|
207
|
+
kind: EdgeKind;
|
|
208
|
+
}
|
|
209
|
+
/** Complete layout result */
|
|
210
|
+
export interface LayoutResult {
|
|
211
|
+
nodes: NodeOutput[];
|
|
212
|
+
edges: EdgeOutput[];
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nodius/layouting",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Zero-dependency, optimized graph layouting algorithm for node-based technical diagrams with incremental layout support",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
"dist"
|
|
20
20
|
],
|
|
21
21
|
"scripts": {
|
|
22
|
-
"build": "tsup",
|
|
22
|
+
"build": "tsup && tsc --emitDeclarationOnly",
|
|
23
23
|
"dev": "tsup --watch",
|
|
24
|
+
"dev:types": "tsc --emitDeclarationOnly --watch",
|
|
24
25
|
"test": "vitest run",
|
|
25
26
|
"test:watch": "vitest",
|
|
26
27
|
"test:coverage": "vitest run --coverage",
|
|
@@ -42,7 +43,7 @@
|
|
|
42
43
|
"license": "ISC",
|
|
43
44
|
"devDependencies": {
|
|
44
45
|
"tsup": "^8.5.1",
|
|
45
|
-
"typescript": "^
|
|
46
|
-
"vitest": "^4.
|
|
46
|
+
"typescript": "^6.0.3",
|
|
47
|
+
"vitest": "^4.1.6"
|
|
47
48
|
}
|
|
48
49
|
}
|
package/dist/index.d.mts
DELETED
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
/** Position on a node where a handle can be placed */
|
|
2
|
-
type HandleSide = 'top' | 'right' | 'bottom' | 'left';
|
|
3
|
-
/** Handle type - input receives connections, output sends connections */
|
|
4
|
-
type HandleType = 'input' | 'output';
|
|
5
|
-
/** Layout direction */
|
|
6
|
-
type LayoutDirection = 'TB' | 'LR' | 'BT' | 'RL';
|
|
7
|
-
/** A 2D point */
|
|
8
|
-
interface Point {
|
|
9
|
-
x: number;
|
|
10
|
-
y: number;
|
|
11
|
-
}
|
|
12
|
-
/** Handle definition on a node */
|
|
13
|
-
interface HandleInput {
|
|
14
|
-
id: string;
|
|
15
|
-
type: HandleType;
|
|
16
|
-
position: HandleSide;
|
|
17
|
-
/** Position along the side (0 = start, 1 = end). Default: 0.5 */
|
|
18
|
-
offset?: number;
|
|
19
|
-
}
|
|
20
|
-
/** Node input definition */
|
|
21
|
-
interface NodeInput {
|
|
22
|
-
id: string;
|
|
23
|
-
width: number;
|
|
24
|
-
height: number;
|
|
25
|
-
handles: HandleInput[];
|
|
26
|
-
}
|
|
27
|
-
/** Edge input definition */
|
|
28
|
-
interface EdgeInput {
|
|
29
|
-
id: string;
|
|
30
|
-
from: string;
|
|
31
|
-
to: string;
|
|
32
|
-
fromHandle: string;
|
|
33
|
-
toHandle: string;
|
|
34
|
-
}
|
|
35
|
-
/** Complete layout input */
|
|
36
|
-
interface LayoutInput {
|
|
37
|
-
nodes: NodeInput[];
|
|
38
|
-
edges: EdgeInput[];
|
|
39
|
-
}
|
|
40
|
-
/** Layout configuration options */
|
|
41
|
-
interface LayoutOptions {
|
|
42
|
-
/** Layout direction. Default: 'TB' */
|
|
43
|
-
direction?: LayoutDirection;
|
|
44
|
-
/** Minimum spacing between nodes in the same layer. Default: 40 */
|
|
45
|
-
nodeSpacing?: number;
|
|
46
|
-
/** Minimum spacing between layers. Default: 60 */
|
|
47
|
-
layerSpacing?: number;
|
|
48
|
-
/** Number of iterations for crossing minimization. Default: 24 */
|
|
49
|
-
crossingMinimizationIterations?: number;
|
|
50
|
-
/** Number of iterations for coordinate optimization. Default: 8 */
|
|
51
|
-
coordinateOptimizationIterations?: number;
|
|
52
|
-
/** Margin for edge routing (distance from node before turning). Default: 20 */
|
|
53
|
-
edgeMargin?: number;
|
|
54
|
-
}
|
|
55
|
-
/** Positioned handle in the output */
|
|
56
|
-
interface HandleOutput {
|
|
57
|
-
id: string;
|
|
58
|
-
type: HandleType;
|
|
59
|
-
position: HandleSide;
|
|
60
|
-
x: number;
|
|
61
|
-
y: number;
|
|
62
|
-
}
|
|
63
|
-
/** Positioned node in the output */
|
|
64
|
-
interface NodeOutput {
|
|
65
|
-
id: string;
|
|
66
|
-
x: number;
|
|
67
|
-
y: number;
|
|
68
|
-
width: number;
|
|
69
|
-
height: number;
|
|
70
|
-
handles: HandleOutput[];
|
|
71
|
-
}
|
|
72
|
-
/** Routed edge in the output */
|
|
73
|
-
interface EdgeOutput {
|
|
74
|
-
id: string;
|
|
75
|
-
from: string;
|
|
76
|
-
to: string;
|
|
77
|
-
fromHandle: string;
|
|
78
|
-
toHandle: string;
|
|
79
|
-
points: Point[];
|
|
80
|
-
}
|
|
81
|
-
/** Complete layout result */
|
|
82
|
-
interface LayoutResult {
|
|
83
|
-
nodes: NodeOutput[];
|
|
84
|
-
edges: EdgeOutput[];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
interface InternalNode {
|
|
88
|
-
id: string;
|
|
89
|
-
width: number;
|
|
90
|
-
height: number;
|
|
91
|
-
handles: HandleInput[];
|
|
92
|
-
isDummy: boolean;
|
|
93
|
-
layer: number;
|
|
94
|
-
order: number;
|
|
95
|
-
x: number;
|
|
96
|
-
y: number;
|
|
97
|
-
}
|
|
98
|
-
interface InternalEdge {
|
|
99
|
-
id: string;
|
|
100
|
-
from: string;
|
|
101
|
-
to: string;
|
|
102
|
-
fromHandle: string;
|
|
103
|
-
toHandle: string;
|
|
104
|
-
reversed: boolean;
|
|
105
|
-
originalId: string;
|
|
106
|
-
}
|
|
107
|
-
declare class Graph {
|
|
108
|
-
nodes: Map<string, InternalNode>;
|
|
109
|
-
edges: Map<string, InternalEdge>;
|
|
110
|
-
outEdges: Map<string, Set<string>>;
|
|
111
|
-
inEdges: Map<string, Set<string>>;
|
|
112
|
-
addNode(node: InternalNode): void;
|
|
113
|
-
addEdge(edge: InternalEdge): void;
|
|
114
|
-
removeEdge(edgeId: string): void;
|
|
115
|
-
removeNode(nodeId: string): void;
|
|
116
|
-
predecessors(nodeId: string): string[];
|
|
117
|
-
successors(nodeId: string): string[];
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Compute a complete layout for the given graph.
|
|
122
|
-
* This is the main entry point for one-shot layout computation.
|
|
123
|
-
*/
|
|
124
|
-
declare function layout(input: LayoutInput, options?: LayoutOptions): LayoutResult;
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Incremental layout engine.
|
|
128
|
-
* Maintains layout state and supports adding/removing nodes
|
|
129
|
-
* without full recomputation.
|
|
130
|
-
*/
|
|
131
|
-
declare class IncrementalLayout {
|
|
132
|
-
private options;
|
|
133
|
-
private inputNodes;
|
|
134
|
-
private inputEdges;
|
|
135
|
-
private lastResult;
|
|
136
|
-
private nodePositions;
|
|
137
|
-
constructor(options?: LayoutOptions);
|
|
138
|
-
/**
|
|
139
|
-
* Set the full graph and compute a complete layout.
|
|
140
|
-
*/
|
|
141
|
-
setGraph(input: LayoutInput): LayoutResult;
|
|
142
|
-
/**
|
|
143
|
-
* Add nodes and edges incrementally.
|
|
144
|
-
* Attempts to minimize layout changes for existing nodes.
|
|
145
|
-
*/
|
|
146
|
-
addNodes(nodes: NodeInput[], edges?: EdgeInput[]): LayoutResult;
|
|
147
|
-
/**
|
|
148
|
-
* Remove nodes (and their connected edges) from the layout.
|
|
149
|
-
*/
|
|
150
|
-
removeNodes(nodeIds: string[]): LayoutResult;
|
|
151
|
-
/**
|
|
152
|
-
* Add edges between existing nodes.
|
|
153
|
-
*/
|
|
154
|
-
addEdges(edges: EdgeInput[]): LayoutResult;
|
|
155
|
-
/**
|
|
156
|
-
* Remove edges from the layout.
|
|
157
|
-
*/
|
|
158
|
-
removeEdges(edgeIds: string[]): LayoutResult;
|
|
159
|
-
/**
|
|
160
|
-
* Get the current layout result.
|
|
161
|
-
*/
|
|
162
|
-
getResult(): LayoutResult | null;
|
|
163
|
-
private recompute;
|
|
164
|
-
private recomputeIncremental;
|
|
165
|
-
/**
|
|
166
|
-
* Apply stability: blend new positions with old positions for existing nodes.
|
|
167
|
-
* This reduces visual disruption when adding new nodes.
|
|
168
|
-
*/
|
|
169
|
-
private applyStability;
|
|
170
|
-
private cachePositions;
|
|
171
|
-
private buildResult;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
declare function countAllCrossings(graph: Graph, layers: string[][]): number;
|
|
175
|
-
|
|
176
|
-
export { type EdgeInput, type EdgeOutput, type HandleInput, type HandleOutput, type HandleSide, type HandleType, IncrementalLayout, type LayoutDirection, type LayoutInput, type LayoutOptions, type LayoutResult, type NodeInput, type NodeOutput, type Point, countAllCrossings, layout };
|