@statelyai/layout 0.0.0 → 0.0.2

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 (46) hide show
  1. package/NOTICE.md +9 -1
  2. package/README.md +50 -25
  3. package/dist/elkjs/index.d.mts +3 -0
  4. package/dist/elkjs/index.mjs +904 -97
  5. package/dist/index-8xYkohbz.d.mts +1212 -0
  6. package/dist/index.d.mts +2 -2
  7. package/dist/index.mjs +3 -3
  8. package/dist/layered/index.d.mts +2 -2
  9. package/dist/layered/index.mjs +2 -2
  10. package/dist/layered-QwJn2gb2.mjs +8978 -0
  11. package/dist/{spore-cihb_Aht.mjs → spore-D15xIQKj.mjs} +1 -31
  12. package/package.json +59 -26
  13. package/src/box.ts +135 -0
  14. package/src/elkjs/index.ts +1825 -0
  15. package/src/elkjs/types.ts +103 -0
  16. package/src/errors.ts +16 -0
  17. package/src/fixed.ts +80 -0
  18. package/src/index.ts +92 -0
  19. package/src/java-random.ts +46 -0
  20. package/src/layered/bk-node-placement.ts +715 -0
  21. package/src/layered/elk-enum-values.ts +171 -0
  22. package/src/layered/elk-options.generated.ts +315 -0
  23. package/src/layered/elk-options.ts +98 -0
  24. package/src/layered/flexible-ports.ts +11 -0
  25. package/src/layered/high-degree.ts +127 -0
  26. package/src/layered/index.ts +2138 -0
  27. package/src/layered/layer-unzipping.ts +217 -0
  28. package/src/layered/linear-segments-node-placement.ts +447 -0
  29. package/src/layered/long-edges.ts +405 -0
  30. package/src/layered/min-width.ts +159 -0
  31. package/src/layered/multi-edge-wrapping.ts +460 -0
  32. package/src/layered/network-simplex-node-placement.ts +500 -0
  33. package/src/layered/network-simplex.ts +346 -0
  34. package/src/layered/node-promotion.ts +197 -0
  35. package/src/layered/spacing.ts +37 -0
  36. package/src/layered/spline-bezier.ts +102 -0
  37. package/src/layered/strategies.ts +5343 -0
  38. package/src/layered/stretch-width.ts +136 -0
  39. package/src/layered/types.ts +111 -0
  40. package/src/layout.ts +202 -0
  41. package/src/packing.ts +74 -0
  42. package/src/random.ts +142 -0
  43. package/src/spore.ts +103 -0
  44. package/src/types.ts +84 -0
  45. package/dist/index-v0P1Ake8.d.mts +0 -149
  46. package/dist/layered-ByNCZQgJ.mjs +0 -439
package/src/spore.ts ADDED
@@ -0,0 +1,103 @@
1
+ import type { Graph, VisualGraph, VisualNode } from "@statelyai/graph";
2
+ import { getNodeSize, type LayoutOptions } from "@statelyai/graph/layout";
3
+ import { getFixedLayout } from "./fixed";
4
+ import type { LayoutPadding } from "./layered";
5
+ import type { LayoutAlgorithm } from "./types";
6
+
7
+ export interface SporeLayoutOptions extends Pick<LayoutOptions, "direction" | "measure"> {
8
+ spacing?: number;
9
+ padding?: number | Partial<LayoutPadding>;
10
+ }
11
+
12
+ function getPadding(value: SporeLayoutOptions["padding"]): LayoutPadding {
13
+ if (typeof value === "number") {
14
+ return { top: value, right: value, bottom: value, left: value };
15
+ }
16
+ return {
17
+ top: value?.top ?? 0,
18
+ right: value?.right ?? 0,
19
+ bottom: value?.bottom ?? 0,
20
+ left: value?.left ?? 0,
21
+ };
22
+ }
23
+
24
+ function getSporeLayout<N, E, G, P>(
25
+ graph: Graph<N, E, G, P> | VisualGraph<N, E, G, P>,
26
+ options: SporeLayoutOptions,
27
+ compact: boolean,
28
+ ): VisualGraph<N, E, G, P> {
29
+ const spacing = options.spacing ?? 20;
30
+ const padding = getPadding(options.padding);
31
+ const nodes: VisualNode<N, P>[] = [];
32
+
33
+ graph.nodes.forEach((node, index) => {
34
+ const size = getNodeSize(node, options);
35
+ const previous = graph.nodes[index - 1];
36
+ const placedPrevious = nodes[index - 1];
37
+ if (!previous || !placedPrevious) {
38
+ nodes.push({
39
+ ...node,
40
+ x: padding.left,
41
+ y: padding.top,
42
+ ...size,
43
+ } as VisualNode<N, P>);
44
+ return;
45
+ }
46
+ const deltaX = (node.x ?? 0) - (previous.x ?? 0);
47
+ const deltaY = (node.y ?? 0) - (previous.y ?? 0);
48
+ const requiredX = placedPrevious.width + spacing;
49
+ const requiredY = placedPrevious.height + spacing;
50
+ const distance = (delta: number, required: number): number => {
51
+ if (delta === 0) return 0;
52
+ const magnitude = compact ? required : Math.max(Math.abs(delta), required);
53
+ return Math.sign(delta) * magnitude;
54
+ };
55
+ nodes.push({
56
+ ...node,
57
+ x: placedPrevious.x + distance(deltaX, requiredX),
58
+ y: placedPrevious.y + distance(deltaY, requiredY),
59
+ ...size,
60
+ } as VisualNode<N, P>);
61
+ });
62
+
63
+ return getFixedLayout({ ...graph, nodes }, { direction: options.direction ?? graph.direction });
64
+ }
65
+
66
+ /** Compact an existing layout while preserving its relative directions. */
67
+ export function getSporeCompactionLayout<N, E, G, P>(
68
+ graph: Graph<N, E, G, P> | VisualGraph<N, E, G, P>,
69
+ options: SporeLayoutOptions = {},
70
+ ): VisualGraph<N, E, G, P> {
71
+ return getSporeLayout(graph, options, true);
72
+ }
73
+
74
+ /** Remove overlap while preserving existing distances that already fit. */
75
+ export function getSporeOverlapRemovalLayout<N, E, G, P>(
76
+ graph: Graph<N, E, G, P> | VisualGraph<N, E, G, P>,
77
+ options: SporeLayoutOptions = {},
78
+ ): VisualGraph<N, E, G, P> {
79
+ return getSporeLayout(graph, options, false);
80
+ }
81
+
82
+ function algorithm(
83
+ id: "sporeCompaction" | "sporeOverlap",
84
+ compact: boolean,
85
+ ): LayoutAlgorithm<SporeLayoutOptions> {
86
+ return {
87
+ id,
88
+ capabilities: {
89
+ full: true,
90
+ incremental: false,
91
+ partial: false,
92
+ routeOnly: false,
93
+ hierarchy: false,
94
+ ports: true,
95
+ },
96
+ layout(graph, options) {
97
+ return getSporeLayout(graph, options ?? {}, compact);
98
+ },
99
+ };
100
+ }
101
+
102
+ export const sporeCompactionAlgorithm = algorithm("sporeCompaction", true);
103
+ export const sporeOverlapRemovalAlgorithm = algorithm("sporeOverlap", false);
package/src/types.ts ADDED
@@ -0,0 +1,84 @@
1
+ import type { Graph, GraphPatch, VisualGraph } from "@statelyai/graph";
2
+
3
+ export type AnyGraph = Graph<unknown, unknown, unknown, unknown>;
4
+
5
+ export type LayoutDirection = "up" | "down" | "left" | "right";
6
+
7
+ export type LayoutScope =
8
+ | { mode: "full" }
9
+ | {
10
+ mode: "incremental";
11
+ previous: VisualGraph;
12
+ }
13
+ | {
14
+ mode: "partial";
15
+ previous: VisualGraph;
16
+ nodeIds: readonly string[];
17
+ }
18
+ | {
19
+ mode: "route-only";
20
+ previous: VisualGraph;
21
+ edgeIds?: readonly string[];
22
+ };
23
+
24
+ export interface LayoutDiagnostic {
25
+ severity: "info" | "warning" | "error";
26
+ code: string;
27
+ message: string;
28
+ entityIds?: readonly string[];
29
+ phase?: string;
30
+ }
31
+
32
+ export interface LayoutPhaseMetrics {
33
+ id: string;
34
+ durationMs: number;
35
+ }
36
+
37
+ export interface LayoutMetrics {
38
+ durationMs: number;
39
+ nodeCount: number;
40
+ edgeCount: number;
41
+ phases: readonly LayoutPhaseMetrics[];
42
+ }
43
+
44
+ export interface LayoutCapabilities {
45
+ full: boolean;
46
+ incremental: boolean;
47
+ partial: boolean;
48
+ routeOnly: boolean;
49
+ hierarchy: boolean;
50
+ ports: boolean;
51
+ }
52
+
53
+ export interface LayoutAlgorithm<Options = unknown> {
54
+ readonly id: string;
55
+ readonly capabilities: LayoutCapabilities;
56
+ layout<N, E, G, P>(
57
+ graph: Graph<N, E, G, P> | VisualGraph<N, E, G, P>,
58
+ options: Options,
59
+ context: LayoutExecutionContext,
60
+ ): VisualGraph<N, E, G, P> | Promise<VisualGraph<N, E, G, P>>;
61
+ }
62
+
63
+ export interface LayoutExecutionContext {
64
+ readonly scope: LayoutScope;
65
+ readonly signal?: AbortSignal;
66
+ readonly diagnostics: LayoutDiagnostic[];
67
+ measurePhase<T>(id: string, run: () => T): T;
68
+ throwIfAborted(): void;
69
+ }
70
+
71
+ export interface LayoutRequest<N = unknown, E = unknown, G = unknown, P = unknown, O = unknown> {
72
+ graph: Graph<N, E, G, P> | VisualGraph<N, E, G, P>;
73
+ algorithm?: string | LayoutAlgorithm<O>;
74
+ options?: O;
75
+ scope?: LayoutScope;
76
+ signal?: AbortSignal;
77
+ }
78
+
79
+ export interface LayoutResult<N = unknown, E = unknown, G = unknown, P = unknown> {
80
+ graph: VisualGraph<N, E, G, P>;
81
+ patches: readonly GraphPatch<N, E>[];
82
+ diagnostics: readonly LayoutDiagnostic[];
83
+ metrics: LayoutMetrics;
84
+ }
@@ -1,149 +0,0 @@
1
- import { LayoutConstraints } from "@statelyai/graph/layout";
2
- import { EntityRect, Graph, GraphNode, GraphPatch, Point, VisualGraph } from "@statelyai/graph";
3
-
4
- //#region src/types.d.ts
5
- type AnyGraph = Graph<unknown, unknown, unknown, unknown>;
6
- type LayoutDirection = "up" | "down" | "left" | "right";
7
- type LayoutScope = {
8
- mode: "full";
9
- } | {
10
- mode: "incremental";
11
- previous: VisualGraph;
12
- } | {
13
- mode: "partial";
14
- previous: VisualGraph;
15
- nodeIds: readonly string[];
16
- } | {
17
- mode: "route-only";
18
- previous: VisualGraph;
19
- edgeIds?: readonly string[];
20
- };
21
- interface LayoutDiagnostic {
22
- severity: "info" | "warning" | "error";
23
- code: string;
24
- message: string;
25
- entityIds?: readonly string[];
26
- phase?: string;
27
- }
28
- interface LayoutPhaseMetrics {
29
- id: string;
30
- durationMs: number;
31
- }
32
- interface LayoutMetrics {
33
- durationMs: number;
34
- nodeCount: number;
35
- edgeCount: number;
36
- phases: readonly LayoutPhaseMetrics[];
37
- }
38
- interface LayoutCapabilities {
39
- full: boolean;
40
- incremental: boolean;
41
- partial: boolean;
42
- routeOnly: boolean;
43
- hierarchy: boolean;
44
- ports: boolean;
45
- }
46
- interface LayoutAlgorithm<Options = unknown> {
47
- readonly id: string;
48
- readonly capabilities: LayoutCapabilities;
49
- layout<N, E, G, P>(graph: Graph<N, E, G, P> | VisualGraph<N, E, G, P>, options: Options, context: LayoutExecutionContext): VisualGraph<N, E, G, P> | Promise<VisualGraph<N, E, G, P>>;
50
- }
51
- interface LayoutExecutionContext {
52
- readonly scope: LayoutScope;
53
- readonly signal?: AbortSignal;
54
- readonly diagnostics: LayoutDiagnostic[];
55
- measurePhase<T>(id: string, run: () => T): T;
56
- throwIfAborted(): void;
57
- }
58
- interface LayoutRequest<N = unknown, E = unknown, G = unknown, P = unknown, O = unknown> {
59
- graph: Graph<N, E, G, P> | VisualGraph<N, E, G, P>;
60
- algorithm?: string | LayoutAlgorithm<O>;
61
- options?: O;
62
- scope?: LayoutScope;
63
- signal?: AbortSignal;
64
- }
65
- interface LayoutResult<N = unknown, E = unknown, G = unknown, P = unknown> {
66
- graph: VisualGraph<N, E, G, P>;
67
- patches: readonly GraphPatch<N, E>[];
68
- diagnostics: readonly LayoutDiagnostic[];
69
- metrics: LayoutMetrics;
70
- }
71
- //#endregion
72
- //#region src/layered/types.d.ts
73
- interface NodeSize {
74
- width: number;
75
- height: number;
76
- }
77
- interface LayeredSpacing {
78
- node: number;
79
- layer: number;
80
- }
81
- interface LayoutPadding {
82
- top: number;
83
- right: number;
84
- bottom: number;
85
- left: number;
86
- }
87
- interface LayeredPhaseInput {
88
- graph: Graph<unknown, unknown, unknown, unknown>;
89
- sizes: ReadonlyMap<string, NodeSize>;
90
- direction: LayoutDirection;
91
- spacing: LayeredSpacing;
92
- padding: LayoutPadding;
93
- constrainedLayerByNodeId: ReadonlyMap<string, number>;
94
- }
95
- interface AcyclicOrientation {
96
- reversedEdgeIds: ReadonlySet<string>;
97
- }
98
- interface LayerAssignment {
99
- layerByNodeId: ReadonlyMap<string, number>;
100
- }
101
- interface LayerOrder {
102
- layers: readonly (readonly string[])[];
103
- }
104
- interface NodePlacement {
105
- rectByNodeId: ReadonlyMap<string, EntityRect>;
106
- }
107
- interface EdgeRoutes {
108
- pointsByEdgeId: ReadonlyMap<string, readonly Point[]>;
109
- }
110
- type CycleBreaker = (input: LayeredPhaseInput) => AcyclicOrientation;
111
- type LayerAssigner = (input: LayeredPhaseInput, orientation: AcyclicOrientation) => LayerAssignment;
112
- type CrossingMinimizer = (input: LayeredPhaseInput, orientation: AcyclicOrientation, assignment: LayerAssignment) => LayerOrder;
113
- type NodePlacer = (input: LayeredPhaseInput, order: LayerOrder) => NodePlacement;
114
- type EdgeRouter = (input: LayeredPhaseInput, orientation: AcyclicOrientation, placement: NodePlacement) => EdgeRoutes;
115
- interface LayeredStrategies {
116
- breakCycles?: CycleBreaker;
117
- assignLayers?: LayerAssigner;
118
- minimizeCrossings?: CrossingMinimizer;
119
- placeNodes?: NodePlacer;
120
- routeEdges?: EdgeRouter;
121
- }
122
- interface LayeredLayoutOptions {
123
- direction?: LayoutDirection;
124
- spacing?: Partial<LayeredSpacing>;
125
- padding?: number | Partial<LayoutPadding>;
126
- constraints?: LayoutConstraints;
127
- measure?: (node: GraphNode) => NodeSize;
128
- crossingSweeps?: number;
129
- strategies?: LayeredStrategies;
130
- }
131
- //#endregion
132
- //#region src/layered/strategies.d.ts
133
- declare const breakCyclesWithDepthFirstSearch: CycleBreaker;
134
- declare const assignLayersByLongestPath: LayerAssigner;
135
- declare function minimizeCrossingsWithBarycenter(sweeps?: number): CrossingMinimizer;
136
- declare const placeNodesInLayers: NodePlacer;
137
- declare const routeEdgesOrthogonally: EdgeRouter;
138
- //#endregion
139
- //#region src/layered/index.d.ts
140
- /**
141
- * Deterministic native layered layout for an `@statelyai/graph` graph.
142
- *
143
- * This initial vertical slice supports flat graphs, cycles, ports, self-loops,
144
- * four directions, custom phase strategies, and orthogonal routes.
145
- */
146
- declare function getLayeredLayout<N, E, G, P>(graph: Graph<N, E, G, P> | VisualGraph<N, E, G, P>, options?: LayeredLayoutOptions): VisualGraph<N, E, G, P>;
147
- declare const layeredAlgorithm: LayoutAlgorithm<LayeredLayoutOptions>;
148
- //#endregion
149
- export { LayoutMetrics as A, NodeSize as C, LayoutDiagnostic as D, LayoutCapabilities as E, LayoutRequest as M, LayoutResult as N, LayoutDirection as O, LayoutScope as P, NodePlacer as S, LayoutAlgorithm as T, LayeredPhaseInput as _, minimizeCrossingsWithBarycenter as a, LayoutPadding as b, AcyclicOrientation as c, EdgeRouter as d, EdgeRoutes as f, LayeredLayoutOptions as g, LayerOrder as h, breakCyclesWithDepthFirstSearch as i, LayoutPhaseMetrics as j, LayoutExecutionContext as k, CrossingMinimizer as l, LayerAssignment as m, layeredAlgorithm as n, placeNodesInLayers as o, LayerAssigner as p, assignLayersByLongestPath as r, routeEdgesOrthogonally as s, getLayeredLayout as t, CycleBreaker as u, LayeredSpacing as v, AnyGraph as w, NodePlacement as x, LayeredStrategies as y };