@nodius/layouting 0.1.0 → 0.1.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.
Files changed (38) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +280 -126
  3. package/dist/algorithms/component-packing.d.ts +9 -0
  4. package/dist/algorithms/component-packing.d.ts.map +1 -0
  5. package/dist/algorithms/coordinate-assignment.d.ts +7 -0
  6. package/dist/algorithms/coordinate-assignment.d.ts.map +1 -0
  7. package/dist/algorithms/crossing-minimization.d.ts +7 -0
  8. package/dist/algorithms/crossing-minimization.d.ts.map +1 -0
  9. package/dist/algorithms/cycle-breaking.d.ts +8 -0
  10. package/dist/algorithms/cycle-breaking.d.ts.map +1 -0
  11. package/dist/algorithms/edge-routing.d.ts +17 -0
  12. package/dist/algorithms/edge-routing.d.ts.map +1 -0
  13. package/dist/algorithms/layer-assignment.d.ts +20 -0
  14. package/dist/algorithms/layer-assignment.d.ts.map +1 -0
  15. package/dist/algorithms/value-cluster.d.ts +15 -0
  16. package/dist/algorithms/value-cluster.d.ts.map +1 -0
  17. package/dist/algorithms/value-placement.d.ts +25 -0
  18. package/dist/algorithms/value-placement.d.ts.map +1 -0
  19. package/dist/debug.d.ts +20 -0
  20. package/dist/debug.d.ts.map +1 -0
  21. package/dist/graph.d.ts +50 -0
  22. package/dist/graph.d.ts.map +1 -0
  23. package/dist/incremental.d.ts +33 -0
  24. package/dist/incremental.d.ts.map +1 -0
  25. package/dist/index.d.ts +7 -176
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +904 -149
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +901 -148
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/layout.d.ts +10 -0
  32. package/dist/layout.d.ts.map +1 -0
  33. package/dist/proposals.d.ts +31 -0
  34. package/dist/proposals.d.ts.map +1 -0
  35. package/dist/types.d.ts +155 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/package.json +5 -4
  38. package/dist/index.d.mts +0 -176
@@ -0,0 +1,25 @@
1
+ import { Graph } from '../graph';
2
+ import { LayoutDirection, ResolvedOptions } from '../types';
3
+ /**
4
+ * Sidecar placement for value nodes.
5
+ *
6
+ * Values (nodes whose every incident edge is a data edge) are NOT laid out
7
+ * alongside the control rail — they are attached as sidecars to the flanks of
8
+ * their dominant consumer once the rail is finalized. This way:
9
+ *
10
+ * - the rail stays perfectly aligned (its layout is computed without values)
11
+ * - values cluster around the node that actually uses them
12
+ * - extra values don't widen/displace the rail
13
+ *
14
+ * In TB direction, sidecars sit at the consumer's vertical center, alternating
15
+ * left/right. In LR direction, they sit at the consumer's horizontal center,
16
+ * alternating top/bottom.
17
+ */
18
+ export declare function placeValueSidecars(graph: Graph, layers: string[][], options: ResolvedOptions): void;
19
+ export declare function isValueLayer(layer: string[], graph: Graph): boolean;
20
+ /** Filter layers to keep only non-value, non-dummy nodes per layer. */
21
+ export declare function railLayers(layers: string[][], graph: Graph): string[][];
22
+ export declare function getDirection(direction: LayoutDirection): {
23
+ isHorizontal: boolean;
24
+ };
25
+ //# sourceMappingURL=value-placement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value-placement.d.ts","sourceRoot":"","sources":["../../src/algorithms/value-placement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE5D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EAAE,EAAE,EAClB,OAAO,EAAE,eAAe,GACvB,IAAI,CAyFN;AA0HD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAMnE;AAED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,EAAE,CAOvE;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,eAAe,GAAG;IAAE,YAAY,EAAE,OAAO,CAAA;CAAE,CAElF"}
@@ -0,0 +1,20 @@
1
+ import { LayoutResult } from './types';
2
+ /**
3
+ * Render a `LayoutResult` to a human-readable text block.
4
+ *
5
+ * Useful when iterating on the algorithm without opening a browser:
6
+ * - a per-layer summary (Y bands in TB, X bands in LR-ish)
7
+ * - per-node hierarchy + bbox
8
+ * - per-edge endpoints and kind
9
+ * - an ASCII grid (optional) sketching the final layout
10
+ */
11
+ export interface PrintLayoutOptions {
12
+ /** Include an ASCII grid sketch (default: true). */
13
+ grid?: boolean;
14
+ /** Grid resolution: characters per coordinate unit (default: auto). */
15
+ gridScale?: number;
16
+ /** Max grid width in characters (default: 80). */
17
+ gridWidth?: number;
18
+ }
19
+ export declare function printLayout(result: LayoutResult, options?: PrintLayoutOptions): string;
20
+ //# sourceMappingURL=debug.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA0B,MAAM,SAAS,CAAC;AAE/D;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB;IACjC,oDAAoD;IACpD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,GAAE,kBAAuB,GAAG,MAAM,CA0F1F"}
@@ -0,0 +1,50 @@
1
+ import { HandleInput, HandleSide, NodeInput, EdgeInput, Point, EdgeKind } from './types';
2
+ export interface InternalNode {
3
+ id: string;
4
+ width: number;
5
+ height: number;
6
+ handles: HandleInput[];
7
+ isDummy: boolean;
8
+ layer: number;
9
+ order: number;
10
+ x: number;
11
+ y: number;
12
+ parentId?: string;
13
+ /** True if this node represents a compound (its size was computed from children). */
14
+ isCompound: boolean;
15
+ /** True when the node has no control edges and only participates in data edges. */
16
+ isValue: boolean;
17
+ }
18
+ export interface InternalEdge {
19
+ id: string;
20
+ from: string;
21
+ to: string;
22
+ fromHandle: string;
23
+ toHandle: string;
24
+ reversed: boolean;
25
+ originalId: string;
26
+ kind: EdgeKind;
27
+ weight: number;
28
+ }
29
+ export declare class Graph {
30
+ nodes: Map<string, InternalNode>;
31
+ edges: Map<string, InternalEdge>;
32
+ outEdges: Map<string, Set<string>>;
33
+ inEdges: Map<string, Set<string>>;
34
+ addNode(node: InternalNode): void;
35
+ addEdge(edge: InternalEdge): void;
36
+ removeEdge(edgeId: string): void;
37
+ removeNode(nodeId: string): void;
38
+ predecessors(nodeId: string): string[];
39
+ successors(nodeId: string): string[];
40
+ }
41
+ export interface BuildGraphContext {
42
+ controlWeight: number;
43
+ dataWeight: number;
44
+ }
45
+ export declare function buildGraph(nodes: NodeInput[], edges: EdgeInput[], ctx?: BuildGraphContext): Graph;
46
+ /** Compute the absolute position of a handle on a positioned node */
47
+ export declare function getHandlePosition(node: InternalNode, handleId: string): Point;
48
+ /** Get the direction vector for exiting/entering a handle */
49
+ export declare function getHandleDirection(side: HandleSide): Point;
50
+ //# sourceMappingURL=graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEzF,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,UAAU,EAAE,OAAO,CAAC;IACpB,mFAAmF;IACnF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,KAAK;IAChB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAa;IAC7C,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAa;IAC7C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAa;IAC/C,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAa;IAE9C,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAMjC,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAQjC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQhC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAUhC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IAYtC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;CAWrC;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,SAAS,EAAE,EAClB,KAAK,EAAE,SAAS,EAAE,EAClB,GAAG,GAAE,iBAA0D,GAC9D,KAAK,CA2DP;AAED,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,CAkB7E;AAED,6DAA6D;AAC7D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,KAAK,CAO1D"}
@@ -0,0 +1,33 @@
1
+ import { LayoutInput, LayoutOptions, LayoutResult, NodeInput, EdgeInput } from './types';
2
+ /**
3
+ * Incremental layout engine.
4
+ * Maintains layout state and supports adding/removing nodes
5
+ * without full recomputation.
6
+ *
7
+ * Compound layouts and value-pulled nodes are handled through the unified
8
+ * `layout()` entry point, so any input change re-uses the same logic.
9
+ */
10
+ export declare class IncrementalLayout {
11
+ private resolvedOptions;
12
+ private options;
13
+ private inputNodes;
14
+ private inputEdges;
15
+ private lastResult;
16
+ private nodePositions;
17
+ constructor(options?: LayoutOptions);
18
+ setGraph(input: LayoutInput): LayoutResult;
19
+ addNodes(nodes: NodeInput[], edges?: EdgeInput[]): LayoutResult;
20
+ removeNodes(nodeIds: string[]): LayoutResult;
21
+ addEdges(edges: EdgeInput[]): LayoutResult;
22
+ removeEdges(edgeIds: string[]): LayoutResult;
23
+ getResult(): LayoutResult | null;
24
+ private recompute;
25
+ private recomputeWithStability;
26
+ /**
27
+ * Blend the freshly computed positions with the previous ones, so existing
28
+ * nodes don't jump too far when a small change happens.
29
+ */
30
+ private applyStability;
31
+ private cachePositions;
32
+ }
33
+ //# sourceMappingURL=incremental.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incremental.d.ts","sourceRoot":"","sources":["../src/incremental.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,aAAa,EACb,YAAY,EACZ,SAAS,EACT,SAAS,EAGV,MAAM,SAAS,CAAC;AAGjB;;;;;;;GAOG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,UAAU,CAAqC;IACvD,OAAO,CAAC,UAAU,CAAqC;IACvD,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,aAAa,CAAoD;gBAE7D,OAAO,CAAC,EAAE,aAAa;IAKnC,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY;IAQ1C,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,GAAG,YAAY;IAM/D,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,YAAY;IAY5C,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,YAAY;IAK1C,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,YAAY;IAK5C,SAAS,IAAI,YAAY,GAAG,IAAI;IAIhC,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,sBAAsB;IAY9B;;;OAGG;IACH,OAAO,CAAC,cAAc;IA2BtB,OAAO,CAAC,cAAc;CAOvB"}
package/dist/index.d.ts CHANGED
@@ -1,176 +1,7 @@
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 };
1
+ export { layout } from './layout';
2
+ export { IncrementalLayout } from './incremental';
3
+ export { countAllCrossings } from './algorithms/crossing-minimization';
4
+ export { printLayout } from './debug';
5
+ export type { HandleSide, HandleType, LayoutDirection, EdgeKind, EdgeWeights, Point, HandleInput, NodeInput, EdgeInput, LayoutInput, LayoutOptions, HandleOutput, NodeOutput, EdgeOutput, LayoutResult, LayoutProposal, RotateProposal, ProposalCallback, } from './types';
6
+ export { rotateHandles } from './proposals';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC,YAAY,EACV,UAAU,EACV,UAAU,EACV,eAAe,EACf,QAAQ,EACR,WAAW,EACX,KAAK,EACL,WAAW,EACX,SAAS,EACT,SAAS,EACT,WAAW,EACX,aAAa,EACb,YAAY,EACZ,UAAU,EACV,UAAU,EACV,YAAY,EACZ,cAAc,EACd,cAAc,EACd,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}