@statelyai/layout 0.0.1 → 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 (42) hide show
  1. package/README.md +1 -3
  2. package/dist/elkjs/index.mjs +10 -7
  3. package/dist/{index-D2RodsZY.d.mts → index-8xYkohbz.d.mts} +2 -0
  4. package/dist/index.d.mts +1 -1
  5. package/dist/index.mjs +2 -2
  6. package/dist/layered/index.d.mts +1 -1
  7. package/dist/layered/index.mjs +1 -1
  8. package/dist/{layered-Dd868WZY.mjs → layered-QwJn2gb2.mjs} +399 -53
  9. package/dist/{spore-fTgSoRLP.mjs → spore-D15xIQKj.mjs} +1 -1
  10. package/package.json +16 -6
  11. package/src/box.ts +135 -0
  12. package/src/elkjs/index.ts +1825 -0
  13. package/src/elkjs/types.ts +103 -0
  14. package/src/errors.ts +16 -0
  15. package/src/fixed.ts +80 -0
  16. package/src/index.ts +92 -0
  17. package/src/java-random.ts +46 -0
  18. package/src/layered/bk-node-placement.ts +715 -0
  19. package/src/layered/elk-enum-values.ts +171 -0
  20. package/src/layered/elk-options.generated.ts +315 -0
  21. package/src/layered/elk-options.ts +98 -0
  22. package/src/layered/flexible-ports.ts +11 -0
  23. package/src/layered/high-degree.ts +127 -0
  24. package/src/layered/index.ts +2138 -0
  25. package/src/layered/layer-unzipping.ts +217 -0
  26. package/src/layered/linear-segments-node-placement.ts +447 -0
  27. package/src/layered/long-edges.ts +405 -0
  28. package/src/layered/min-width.ts +159 -0
  29. package/src/layered/multi-edge-wrapping.ts +460 -0
  30. package/src/layered/network-simplex-node-placement.ts +500 -0
  31. package/src/layered/network-simplex.ts +346 -0
  32. package/src/layered/node-promotion.ts +197 -0
  33. package/src/layered/spacing.ts +37 -0
  34. package/src/layered/spline-bezier.ts +102 -0
  35. package/src/layered/strategies.ts +5343 -0
  36. package/src/layered/stretch-width.ts +136 -0
  37. package/src/layered/types.ts +111 -0
  38. package/src/layout.ts +202 -0
  39. package/src/packing.ts +74 -0
  40. package/src/random.ts +142 -0
  41. package/src/spore.ts +103 -0
  42. package/src/types.ts +84 -0
@@ -1,4 +1,4 @@
1
- import { F as placePorts, O as getPolylineMidpoint, z as JavaRandom } from "./layered-Dd868WZY.mjs";
1
+ import { F as placePorts, O as getPolylineMidpoint, z as JavaRandom } from "./layered-QwJn2gb2.mjs";
2
2
  import { getNodeSize } from "@statelyai/graph/layout";
3
3
 
4
4
  //#region src/fixed.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statelyai/layout",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Extensible, graph-native layout algorithms for @statelyai/graph",
5
5
  "license": "EPL-2.0 OR GPL-3.0-or-later",
6
6
  "repository": {
@@ -9,6 +9,7 @@
9
9
  },
10
10
  "files": [
11
11
  "dist",
12
+ "src",
12
13
  "LICENSE.md",
13
14
  "NOTICE.md"
14
15
  ],
@@ -16,11 +17,20 @@
16
17
  "sideEffects": false,
17
18
  "main": "./dist/index.mjs",
18
19
  "module": "./dist/index.mjs",
19
- "types": "./dist/index.d.mts",
20
+ "types": "./src/index.ts",
20
21
  "exports": {
21
- ".": "./dist/index.mjs",
22
- "./elkjs": "./dist/elkjs/index.mjs",
23
- "./layered": "./dist/layered/index.mjs",
22
+ ".": {
23
+ "types": "./src/index.ts",
24
+ "default": "./dist/index.mjs"
25
+ },
26
+ "./elkjs": {
27
+ "types": "./src/elkjs/index.ts",
28
+ "default": "./dist/elkjs/index.mjs"
29
+ },
30
+ "./layered": {
31
+ "types": "./src/layered/index.ts",
32
+ "default": "./dist/layered/index.mjs"
33
+ },
24
34
  "./package.json": "./package.json"
25
35
  },
26
36
  "publishConfig": {
@@ -58,7 +68,7 @@
58
68
  "@statelyai/graph": "^2.1.0"
59
69
  },
60
70
  "scripts": {
61
- "build": "tsdown",
71
+ "build": "tsdown --config tsdown.config.mjs",
62
72
  "bench": "vitest bench --run",
63
73
  "demo": "portless --name layout vite --config demo/vite.config.ts",
64
74
  "demo:build": "vite build --config demo/vite.config.ts",
package/src/box.ts ADDED
@@ -0,0 +1,135 @@
1
+ /*******************************************************************************
2
+ * Copyright (c) 2009, 2020 Kiel University and others.
3
+ *
4
+ * Translated from ELK v0.11.0 BoxLayoutProvider.java SIMPLE mode.
5
+ * Source commit: 54123e884b1ae743b453260f713b20c9bf5787f2
6
+ * SPDX-License-Identifier: EPL-2.0
7
+ *******************************************************************************/
8
+ import type { Graph, GraphNode, VisualGraph, VisualNode } from "@statelyai/graph";
9
+ import { getNodeSize, type LayoutOptions } from "@statelyai/graph/layout";
10
+ import { getFixedLayout } from "./fixed";
11
+ import type { LayoutPadding } from "./layered";
12
+ import type { LayoutAlgorithm } from "./types";
13
+
14
+ export interface BoxLayoutOptions extends Pick<LayoutOptions, "direction" | "measure"> {
15
+ spacing?: number;
16
+ padding?: number | Partial<LayoutPadding>;
17
+ aspectRatio?: number;
18
+ interactive?: boolean;
19
+ expandNodes?: boolean;
20
+ priority?: (node: GraphNode) => number | undefined;
21
+ }
22
+
23
+ function getPadding(value: BoxLayoutOptions["padding"]): LayoutPadding {
24
+ if (typeof value === "number") {
25
+ return { top: value, right: value, bottom: value, left: value };
26
+ }
27
+ return {
28
+ top: value?.top ?? 15,
29
+ right: value?.right ?? 15,
30
+ bottom: value?.bottom ?? 15,
31
+ left: value?.left ?? 15,
32
+ };
33
+ }
34
+
35
+ function standardDeviation(values: readonly number[], mean: number): number {
36
+ if (values.length < 2) return 0;
37
+ const variance = values.reduce((sum, value) => sum + (value - mean) ** 2, 0);
38
+ return Math.sqrt(variance / (values.length - 1));
39
+ }
40
+
41
+ /** ELK Box SIMPLE packing translated onto `@statelyai/graph`. */
42
+ export function getBoxLayout<N, E, G, P>(
43
+ graph: Graph<N, E, G, P> | VisualGraph<N, E, G, P>,
44
+ options: BoxLayoutOptions = {},
45
+ ): VisualGraph<N, E, G, P> {
46
+ const spacing = Math.fround(options.spacing ?? 15);
47
+ const padding = getPadding(options.padding);
48
+ const aspectRatio = (options.aspectRatio ?? 1.3) > 0 ? (options.aspectRatio ?? 1.3) : 1.3;
49
+ const sizes = new Map(graph.nodes.map((node) => [node.id, getNodeSize(node, options)]));
50
+ const sortedNodes = [...graph.nodes].sort((first, second) => {
51
+ const priorityDifference = (options.priority?.(second) ?? 0) - (options.priority?.(first) ?? 0);
52
+ if (priorityDifference !== 0) return priorityDifference;
53
+ if (options.interactive) {
54
+ const yDifference = (first.y ?? 0) - (second.y ?? 0);
55
+ if (yDifference !== 0) return yDifference;
56
+ const xDifference = (first.x ?? 0) - (second.x ?? 0);
57
+ if (xDifference !== 0) return xDifference;
58
+ }
59
+ const firstSize = sizes.get(first.id) ?? { width: 0, height: 0 };
60
+ const secondSize = sizes.get(second.id) ?? { width: 0, height: 0 };
61
+ return firstSize.width * firstSize.height - secondSize.width * secondSize.height;
62
+ });
63
+
64
+ const areas = sortedNodes.map((node) => {
65
+ const size = sizes.get(node.id) ?? { width: 0, height: 0 };
66
+ return size.width * size.height;
67
+ });
68
+ let totalArea = areas.reduce((sum, area) => sum + area, 0);
69
+ const mean = areas.length === 0 ? 0 : totalArea / areas.length;
70
+ totalArea += areas.length * standardDeviation(areas, mean);
71
+ totalArea += Math.sqrt(totalArea) * (padding.bottom + padding.top);
72
+ totalArea += Math.sqrt(totalArea) * padding.right;
73
+ const widestNode = Math.max(0, ...sortedNodes.map((node) => sizes.get(node.id)?.width ?? 0));
74
+ const maximumRowWidth = Math.max(widestNode, Math.sqrt(totalArea * aspectRatio)) + padding.left;
75
+
76
+ let x = padding.left;
77
+ let y = padding.top;
78
+ let rowHeight = 0;
79
+ let rowStart = 0;
80
+ const rows: Array<{ start: number; end: number; height: number }> = [];
81
+ const nodes: VisualNode<N, P>[] = [];
82
+ for (const node of sortedNodes) {
83
+ const size = sizes.get(node.id) ?? { width: 0, height: 0 };
84
+ if (x + size.width > maximumRowWidth) {
85
+ rows.push({ start: rowStart, end: nodes.length, height: rowHeight });
86
+ rowStart = nodes.length;
87
+ x = padding.left;
88
+ y += rowHeight + spacing;
89
+ rowHeight = 0;
90
+ }
91
+ nodes.push({ ...node, x, y, ...size } as VisualNode<N, P>);
92
+ x += size.width + spacing;
93
+ rowHeight = Math.max(rowHeight, size.height);
94
+ }
95
+ rows.push({ start: rowStart, end: nodes.length, height: rowHeight });
96
+
97
+ if (options.expandNodes) {
98
+ const broadestRow = Math.max(
99
+ padding.left + padding.right,
100
+ ...nodes.map((node) => node.x + node.width + padding.right),
101
+ );
102
+ for (const row of rows) {
103
+ for (let index = row.start; index < row.end; index++) {
104
+ const node = nodes[index];
105
+ if (!node) continue;
106
+ node.height = row.height;
107
+ if (index === row.end - 1) node.width = broadestRow - node.x - padding.right;
108
+ }
109
+ }
110
+ }
111
+
112
+ const placedById = new Map(nodes.map((node) => [node.id, node]));
113
+ return getFixedLayout(
114
+ {
115
+ ...graph,
116
+ nodes: graph.nodes.map((node) => placedById.get(node.id) ?? node) as VisualNode<N, P>[],
117
+ },
118
+ { direction: options.direction ?? graph.direction },
119
+ );
120
+ }
121
+
122
+ export const boxAlgorithm: LayoutAlgorithm<BoxLayoutOptions> = {
123
+ id: "box",
124
+ capabilities: {
125
+ full: true,
126
+ incremental: false,
127
+ partial: false,
128
+ routeOnly: false,
129
+ hierarchy: false,
130
+ ports: true,
131
+ },
132
+ layout(graph, options) {
133
+ return getBoxLayout(graph, options ?? {});
134
+ },
135
+ };