@deck.gl-community/graph-layers 9.0.2 → 9.1.0-beta.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.
Files changed (118) hide show
  1. package/LICENSE +1 -1
  2. package/dist/core/graph-engine.d.ts +16 -7
  3. package/dist/core/graph-engine.d.ts.map +1 -1
  4. package/dist/core/graph-engine.js +13 -4
  5. package/dist/core/graph-layout.d.ts +69 -0
  6. package/dist/core/graph-layout.d.ts.map +1 -0
  7. package/dist/core/{base-layout.js → graph-layout.js} +63 -80
  8. package/dist/core/interaction-manager.d.ts +1 -1
  9. package/dist/core/interaction-manager.d.ts.map +1 -1
  10. package/dist/{core → graph}/edge.d.ts +18 -17
  11. package/dist/graph/edge.d.ts.map +1 -0
  12. package/dist/{core → graph}/edge.js +12 -15
  13. package/dist/{core → graph}/graph.d.ts +34 -31
  14. package/dist/graph/graph.d.ts.map +1 -0
  15. package/dist/{core → graph}/graph.js +43 -36
  16. package/dist/{core → graph}/node.d.ts +20 -20
  17. package/dist/graph/node.d.ts.map +1 -0
  18. package/dist/{core → graph}/node.js +16 -18
  19. package/dist/index.cjs +1181 -434
  20. package/dist/index.cjs.map +4 -4
  21. package/dist/index.d.ts +16 -14
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +19 -18
  24. package/dist/layers/graph-layer.d.ts +45 -5
  25. package/dist/layers/graph-layer.d.ts.map +1 -1
  26. package/dist/layers/graph-layer.js +80 -38
  27. package/dist/layers/node-layers/{path-rounded-rectange-layer.d.ts → path-rounded-rectangle-layer.d.ts} +1 -1
  28. package/dist/layers/node-layers/path-rounded-rectangle-layer.d.ts.map +1 -0
  29. package/dist/layers/node-layers/rounded-rectangle-layer-fragment.d.ts +1 -1
  30. package/dist/layers/node-layers/rounded-rectangle-layer-fragment.d.ts.map +1 -1
  31. package/dist/layers/node-layers/rounded-rectangle-layer-fragment.js +1 -3
  32. package/dist/layers/node-layers/rounded-rectangle-layer.d.ts +12 -3
  33. package/dist/layers/node-layers/rounded-rectangle-layer.d.ts.map +1 -1
  34. package/dist/layers/node-layers/rounded-rectangle-layer.js +25 -11
  35. package/dist/layouts/d3-force/d3-force-layout.d.ts +12 -3
  36. package/dist/layouts/d3-force/d3-force-layout.d.ts.map +1 -1
  37. package/dist/layouts/d3-force/d3-force-layout.js +11 -11
  38. package/dist/layouts/d3-force/worker.d.ts.map +1 -1
  39. package/dist/layouts/experimental/force-multi-graph-layout.d.ts +43 -0
  40. package/dist/layouts/experimental/force-multi-graph-layout.d.ts.map +1 -0
  41. package/dist/layouts/experimental/force-multi-graph-layout.js +226 -0
  42. package/dist/layouts/experimental/hive-plot-layout.d.ts +34 -0
  43. package/dist/layouts/experimental/hive-plot-layout.d.ts.map +1 -0
  44. package/dist/layouts/experimental/hive-plot-layout.js +142 -0
  45. package/dist/layouts/experimental/radial-layout.d.ts +28 -0
  46. package/dist/layouts/experimental/radial-layout.d.ts.map +1 -0
  47. package/dist/layouts/experimental/radial-layout.js +164 -0
  48. package/dist/layouts/gpu-force/gpu-force-layout.d.ts +15 -3
  49. package/dist/layouts/gpu-force/gpu-force-layout.d.ts.map +1 -1
  50. package/dist/layouts/gpu-force/gpu-force-layout.js +20 -18
  51. package/dist/layouts/gpu-force/worker.d.ts.map +1 -1
  52. package/dist/layouts/simple-layout.d.ts +42 -0
  53. package/dist/layouts/simple-layout.d.ts.map +1 -0
  54. package/dist/layouts/{simple-layout/simple-layout.js → simple-layout.js} +8 -7
  55. package/dist/loaders/create-graph.d.ts +13 -0
  56. package/dist/loaders/create-graph.d.ts.map +1 -0
  57. package/dist/{utils → loaders}/create-graph.js +9 -4
  58. package/dist/loaders/edge-parsers.d.ts +2 -6
  59. package/dist/loaders/edge-parsers.d.ts.map +1 -1
  60. package/dist/loaders/json-loader.js +1 -1
  61. package/dist/loaders/node-parsers.d.ts +2 -3
  62. package/dist/loaders/node-parsers.d.ts.map +1 -1
  63. package/dist/loaders/simple-json-graph-loader.d.ts +12 -0
  64. package/dist/loaders/simple-json-graph-loader.d.ts.map +1 -0
  65. package/dist/loaders/simple-json-graph-loader.js +20 -0
  66. package/dist/loaders/table-graph-loader.d.ts +17 -0
  67. package/dist/loaders/table-graph-loader.d.ts.map +1 -0
  68. package/dist/loaders/table-graph-loader.js +91 -0
  69. package/dist/utils/log.d.ts +1 -1
  70. package/dist/utils/log.d.ts.map +1 -1
  71. package/dist/utils/log.js +3 -3
  72. package/dist/widgets/long-press-button.d.ts +13 -0
  73. package/dist/widgets/long-press-button.d.ts.map +1 -0
  74. package/dist/widgets/long-press-button.js +31 -0
  75. package/dist/widgets/view-control-widget.d.ts +78 -0
  76. package/dist/widgets/view-control-widget.d.ts.map +1 -0
  77. package/dist/widgets/view-control-widget.js +194 -0
  78. package/package.json +8 -6
  79. package/src/core/graph-engine.ts +30 -10
  80. package/src/core/graph-layout.ts +146 -0
  81. package/src/core/interaction-manager.ts +2 -2
  82. package/src/{core → graph}/edge.ts +19 -17
  83. package/src/{core → graph}/graph.ts +51 -36
  84. package/src/{core → graph}/node.ts +21 -20
  85. package/src/index.ts +28 -28
  86. package/src/layers/graph-layer.ts +133 -46
  87. package/src/layers/node-layers/rounded-rectangle-layer-fragment.ts +1 -3
  88. package/src/layers/node-layers/rounded-rectangle-layer.ts +34 -10
  89. package/src/layouts/d3-force/d3-force-layout.ts +21 -11
  90. package/src/layouts/experimental/force-multi-graph-layout.ts +268 -0
  91. package/src/layouts/experimental/hive-plot-layout.ts +182 -0
  92. package/src/layouts/experimental/radial-layout.ts +210 -0
  93. package/src/layouts/gpu-force/gpu-force-layout.ts +32 -17
  94. package/src/layouts/{simple-layout/simple-layout.ts → simple-layout.ts} +34 -19
  95. package/src/{utils → loaders}/create-graph.ts +9 -4
  96. package/src/loaders/edge-parsers.ts +2 -1
  97. package/src/loaders/json-loader.ts +1 -1
  98. package/src/loaders/node-parsers.ts +2 -1
  99. package/src/loaders/simple-json-graph-loader.ts +28 -0
  100. package/src/loaders/table-graph-loader.ts +124 -0
  101. package/src/utils/log.ts +3 -3
  102. package/src/widgets/long-press-button.tsx +50 -0
  103. package/src/widgets/view-control-widget.tsx +337 -0
  104. package/dist/core/base-layout.d.ts +0 -72
  105. package/dist/core/base-layout.d.ts.map +0 -1
  106. package/dist/core/edge.d.ts.map +0 -1
  107. package/dist/core/graph.d.ts.map +0 -1
  108. package/dist/core/node.d.ts.map +0 -1
  109. package/dist/layers/node-layers/path-rounded-rectange-layer.d.ts.map +0 -1
  110. package/dist/layouts/simple-layout/simple-layout.d.ts +0 -23
  111. package/dist/layouts/simple-layout/simple-layout.d.ts.map +0 -1
  112. package/dist/utils/create-graph.d.ts +0 -9
  113. package/dist/utils/create-graph.d.ts.map +0 -1
  114. package/src/core/base-layout.ts +0 -154
  115. /package/dist/layers/node-layers/{path-rounded-rectange-layer.js → path-rounded-rectangle-layer.js} +0 -0
  116. /package/src/layers/node-layers/{path-rounded-rectange-layer.ts → path-rounded-rectangle-layer.ts} +0 -0
  117. /package/src/layouts/d3-force/{worker.ts → worker.js} +0 -0
  118. /package/src/layouts/gpu-force/{worker.ts → worker.js} +0 -0
@@ -0,0 +1,182 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {GraphLayout, GraphLayoutOptions} from '../../core/graph-layout';
6
+ import {Node} from '../../graph/node';
7
+ import {EDGE_TYPE} from '../../core/constants';
8
+ import {Graph} from '../../graph/graph';
9
+
10
+ export type HivePlotLayoutOptions = GraphLayoutOptions & {
11
+ innerRadius?: number;
12
+ outerRadius?: number;
13
+ getNodeAxis?: (node: Node) => any;
14
+ };
15
+
16
+ export class HivePlotLayout extends GraphLayout<HivePlotLayoutOptions> {
17
+ static defaultOptions = {
18
+ innerRadius: 100,
19
+ outerRadius: 500,
20
+ getNodeAxis: (node: Node) => node.getPropertyValue('group')
21
+ } as const satisfies Readonly<Required<HivePlotLayoutOptions>>;
22
+
23
+ _name = 'HivePlot';
24
+ _graph: Graph;
25
+ _totalAxis: number;
26
+ _axis: Record<string, any>;
27
+ _nodeMap = {};
28
+ _nodePositionMap = {};
29
+
30
+ constructor(options: HivePlotLayoutOptions = {}) {
31
+ super(options);
32
+ this._options = {
33
+ ...HivePlotLayout.defaultOptions,
34
+ ...options
35
+ };
36
+ }
37
+
38
+ initializeGraph(graph: Graph) {
39
+ this.updateGraph(graph);
40
+ }
41
+
42
+ updateGraph(graph) {
43
+ const {getNodeAxis, innerRadius, outerRadius} = this._options;
44
+ this._graph = graph;
45
+ this._nodeMap = graph.getNodes().reduce((res, node) => {
46
+ res[node.getId()] = node;
47
+ return res;
48
+ }, {});
49
+
50
+ // bucket nodes into few axis
51
+
52
+ this._axis = graph.getNodes().reduce((res, node) => {
53
+ const axis = getNodeAxis(node);
54
+ if (!res[axis]) {
55
+ res[axis] = [];
56
+ }
57
+ res[axis].push(node);
58
+ return res;
59
+ }, {});
60
+
61
+ // sort nodes along the same axis by degree
62
+ this._axis = Object.keys(this._axis).reduce((res, axis) => {
63
+ const bucketedNodes = this._axis[axis];
64
+ const sortedNodes = bucketedNodes.sort((a, b) => {
65
+ if (a.getDegree() > b.getDegree()) {
66
+ return 1;
67
+ }
68
+ if (a.getDegree() === b.getDegree()) {
69
+ return 0;
70
+ }
71
+ return -1;
72
+ });
73
+ res[axis] = sortedNodes;
74
+ return res;
75
+ }, {});
76
+ this._totalAxis = Object.keys(this._axis).length;
77
+ const center = [0, 0];
78
+ const angleInterval = 360 / Object.keys(this._axis).length;
79
+
80
+ // calculate positions
81
+ this._nodePositionMap = Object.keys(this._axis).reduce((res, axis, axisIdx) => {
82
+ const axisAngle = angleInterval * axisIdx;
83
+ const bucketedNodes = this._axis[axis];
84
+ const interval = (outerRadius - innerRadius) / bucketedNodes.length;
85
+
86
+ bucketedNodes.forEach((node, idx) => {
87
+ const radius = innerRadius + idx * interval;
88
+ const x = Math.cos((axisAngle / 180) * Math.PI) * radius + center[0];
89
+ const y = Math.sin((axisAngle / 180) * Math.PI) * radius + center[1];
90
+ res[node.getId()] = [x, y];
91
+ });
92
+ return res;
93
+ }, {});
94
+ }
95
+
96
+ start() {
97
+ this._onLayoutChange();
98
+ this._onLayoutDone();
99
+ }
100
+
101
+ getNodePosition = (node) => this._nodePositionMap[node.getId()];
102
+
103
+ getEdgePosition = (edge) => {
104
+ const {getNodeAxis} = this._options;
105
+ const sourceNodeId = edge.getSourceNodeId();
106
+ const targetNodeId = edge.getTargetNodeId();
107
+
108
+ const sourcePosition = this._nodePositionMap[sourceNodeId];
109
+ const targetPosition = this._nodePositionMap[targetNodeId];
110
+
111
+ const sourceNode = this._nodeMap[sourceNodeId];
112
+ const targetNode = this._nodeMap[targetNodeId];
113
+
114
+ const sourceNodeAxis = getNodeAxis(sourceNode);
115
+ const targetNodeAxis = getNodeAxis(targetNode);
116
+
117
+ if (sourceNodeAxis === targetNodeAxis) {
118
+ return {
119
+ type: EDGE_TYPE.LINE,
120
+ sourcePosition,
121
+ targetPosition,
122
+ controlPoints: []
123
+ };
124
+ }
125
+
126
+ const controlPoint = computeControlPoint({
127
+ sourcePosition,
128
+ sourceNodeAxis,
129
+ targetPosition,
130
+ targetNodeAxis,
131
+ totalAxis: this._totalAxis
132
+ });
133
+
134
+ return {
135
+ type: EDGE_TYPE.SPLINE_CURVE,
136
+ sourcePosition,
137
+ targetPosition,
138
+ controlPoints: [controlPoint]
139
+ };
140
+ };
141
+
142
+ lockNodePosition = (node, x, y) => {
143
+ this._nodePositionMap[node.id] = [x, y];
144
+ this._onLayoutChange();
145
+ this._onLayoutDone();
146
+ };
147
+ }
148
+
149
+ function computeControlPoint({
150
+ sourcePosition,
151
+ sourceNodeAxis,
152
+ targetPosition,
153
+ targetNodeAxis,
154
+ totalAxis
155
+ }): [number, number] {
156
+ const halfAxis = (totalAxis - 1) / 2;
157
+ // check whether the source/target are at the same side.
158
+ const sameSide =
159
+ (sourceNodeAxis <= halfAxis && targetNodeAxis <= halfAxis) ||
160
+ (sourceNodeAxis > halfAxis && targetNodeAxis > halfAxis);
161
+ // curve direction
162
+ const direction = sameSide && sourceNodeAxis <= halfAxis && targetNodeAxis <= halfAxis ? 1 : -1;
163
+
164
+ // flip the source/target to follow the clockwise diretion
165
+ const source = sourceNodeAxis < targetNodeAxis && sameSide ? sourcePosition : targetPosition;
166
+ const target = sourceNodeAxis < targetNodeAxis && sameSide ? targetPosition : sourcePosition;
167
+
168
+ // calculate offset
169
+ const distance = Math.hypot(source[0] - target[0], source[1] - target[1]);
170
+ const offset = distance * 0.2;
171
+
172
+ const midPoint = [(source[0] + target[0]) / 2, (source[1] + target[1]) / 2];
173
+ const dx = target[0] - source[0];
174
+ const dy = target[1] - source[1];
175
+ const normal = [dy, -dx];
176
+ const length = Math.hypot(dy, -dx);
177
+ const normalized = [normal[0] / length, normal[1] / length];
178
+ return [
179
+ midPoint[0] + normalized[0] * offset * direction,
180
+ midPoint[1] + normalized[1] * offset * direction
181
+ ];
182
+ }
@@ -0,0 +1,210 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {GraphLayout, GraphLayoutOptions} from '../../core/graph-layout';
6
+ import {Node} from '../../graph/node';
7
+ import {EDGE_TYPE} from '../../core/constants';
8
+ import {Graph} from '../../graph/graph';
9
+
10
+ export type RadialLayoutOptions = GraphLayoutOptions & {
11
+ radius?: number;
12
+ tree?: any;
13
+ };
14
+
15
+ const traverseTree = (nodeId, nodeMap) => {
16
+ const node = nodeMap[nodeId];
17
+ if (node.isLeaf) {
18
+ return node;
19
+ }
20
+ return {
21
+ ...node,
22
+ children: node.children.map((nid) => traverseTree(nid, nodeMap))
23
+ };
24
+ };
25
+
26
+ const getLeafNodeCount = (node, count) => {
27
+ if (!node.children || node.children.length === 0) {
28
+ return count + 1;
29
+ }
30
+ const sum = node.children.reduce((res, c) => {
31
+ return res + getLeafNodeCount(c, 0);
32
+ }, 0);
33
+ return count + sum;
34
+ };
35
+
36
+ const getTreeDepth = (node, depth = 0) => {
37
+ if (node.isLeaf) {
38
+ return depth;
39
+ }
40
+ return getTreeDepth(node.children[0], depth + 1);
41
+ };
42
+
43
+ const getPath = (node, targetId, path) => {
44
+ if (node.id === targetId) {
45
+ path.push(node.id);
46
+ return true;
47
+ }
48
+ const inChildren = node.children && node.children.some((c) => getPath(c, targetId, path));
49
+ if (inChildren) {
50
+ path.push(node.id);
51
+ return true;
52
+ }
53
+ return false;
54
+ };
55
+
56
+ export class RadialLayout extends GraphLayout<RadialLayoutOptions> {
57
+ static defaultOptions = {
58
+ radius: 500
59
+ };
60
+
61
+ _name = 'RadialLayout';
62
+ _graph: Graph = null;
63
+ // custom layout data structure
64
+ _hierarchicalPoints = {};
65
+ nestedTree;
66
+
67
+ constructor(options: RadialLayoutOptions = {}) {
68
+ super(options);
69
+ this._options = {
70
+ ...RadialLayout.defaultOptions,
71
+ ...options
72
+ };
73
+ }
74
+
75
+ initializeGraph(graph: Graph): void {
76
+ this.updateGraph(graph);
77
+ }
78
+
79
+ updateGraph(graph: Graph): void {
80
+ this._graph = graph;
81
+ }
82
+
83
+ start(): void {
84
+ const nodeCount = this._graph.getNodes().length;
85
+ if (nodeCount === 0) {
86
+ return;
87
+ }
88
+
89
+ const {tree} = this._options;
90
+
91
+ if (!tree || tree.length === 0) {
92
+ return;
93
+ }
94
+
95
+ const {radius} = this._options;
96
+ const unitAngle = 360 / nodeCount;
97
+
98
+ // hierarchical positions
99
+ const rootNode = tree[0];
100
+
101
+ const nodeMap = tree.reduce((res, node) => {
102
+ res[node.id] = {
103
+ ...node,
104
+ isLeaf: !node.children || node.children.length === 0
105
+ };
106
+ return res;
107
+ }, {});
108
+ // nested structure
109
+ this.nestedTree = traverseTree(rootNode.id, nodeMap);
110
+
111
+ const totalLevels = getTreeDepth(this.nestedTree, 0);
112
+ const distanceBetweenLevels = radius / (totalLevels - 1);
113
+
114
+ const calculatePosition = (node, level, startAngle, positionMap) => {
115
+ const isRoot = node.id === rootNode.id;
116
+
117
+ if (node.children && node.children.length !== 0) {
118
+ const groupSize = getLeafNodeCount(node, 0);
119
+ // center the pos
120
+ positionMap[node.id] = isRoot
121
+ ? [0, 0]
122
+ : rotate(
123
+ 0,
124
+ 0,
125
+ 0,
126
+ distanceBetweenLevels * (level + 1),
127
+ startAngle + unitAngle * (groupSize / 2)
128
+ );
129
+ // calculate children position
130
+ let tempAngle = startAngle;
131
+ node.children.forEach((n) => {
132
+ calculatePosition(n, level + 1, tempAngle, positionMap);
133
+ tempAngle += getLeafNodeCount(n, 0) * unitAngle;
134
+ });
135
+ } else {
136
+ positionMap[node.id] = rotate(
137
+ 0,
138
+ 0,
139
+ 0,
140
+ distanceBetweenLevels * (level + 1),
141
+ startAngle + unitAngle
142
+ );
143
+ }
144
+ };
145
+
146
+ this._hierarchicalPoints = {};
147
+ calculatePosition(this.nestedTree, 0, 0, this._hierarchicalPoints);
148
+ // layout completes: notifiy component to re-render
149
+ this._onLayoutChange();
150
+ this._onLayoutDone();
151
+ }
152
+
153
+ getNodePosition = (node) => {
154
+ return this._hierarchicalPoints[node.id];
155
+ };
156
+
157
+ // spline curve version
158
+ getEdgePosition = (edge) => {
159
+ const sourceNodeId = edge.getSourceNodeId();
160
+ const targetNodeId = edge.getTargetNodeId();
161
+ const sourceNodePos = this._hierarchicalPoints[sourceNodeId];
162
+ const targetNodePos = this._hierarchicalPoints[targetNodeId];
163
+
164
+ const sourcePath = [];
165
+ getPath(this.nestedTree, sourceNodeId, sourcePath);
166
+ const targetPath = [];
167
+ getPath(this.nestedTree, targetNodeId, targetPath);
168
+
169
+ const totalLevels = sourcePath.length;
170
+ let commonAncestorLevel = totalLevels - 1; // root
171
+ for (let i = 0; i < totalLevels; i++) {
172
+ if (sourcePath[i] === targetPath[i]) {
173
+ commonAncestorLevel = i;
174
+ break;
175
+ }
176
+ }
177
+
178
+ const wayPoints = [];
179
+ for (let i = 1; i <= commonAncestorLevel; i++) {
180
+ const nodeId = sourcePath[i];
181
+ wayPoints.push(this._hierarchicalPoints[nodeId]);
182
+ }
183
+ for (let i = commonAncestorLevel - 1; i > 0; i--) {
184
+ const nodeId = targetPath[i];
185
+ wayPoints.push(this._hierarchicalPoints[nodeId]);
186
+ }
187
+
188
+ return {
189
+ type: EDGE_TYPE.SPLINE_CURVE,
190
+ sourcePosition: sourceNodePos,
191
+ targetPosition: targetNodePos,
192
+ controlPoints: wayPoints
193
+ };
194
+ };
195
+
196
+ lockNodePosition = (node, x, y) => {
197
+ this._hierarchicalPoints[node.id] = [x, y];
198
+ this._onLayoutChange();
199
+ this._onLayoutDone();
200
+ };
201
+ }
202
+
203
+ function rotate(cx, cy, x, y, angle) {
204
+ const radians = (Math.PI / 180) * angle;
205
+ const cos = Math.cos(radians);
206
+ const sin = Math.sin(radians);
207
+ const nx = cos * (x - cx) + sin * (y - cy) + cx;
208
+ const ny = cos * (y - cy) - sin * (x - cx) + cy;
209
+ return [nx, ny];
210
+ }
@@ -2,21 +2,32 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {BaseLayout} from '../../core/base-layout';
5
+ import {GraphLayout, GraphLayoutOptions} from '../../core/graph-layout';
6
6
 
7
7
  import {EDGE_TYPE} from '../../core/constants';
8
8
 
9
- const defaultOptions = {
10
- alpha: 0.3,
11
- resumeAlpha: 0.1,
12
- nBodyStrength: -900,
13
- nBodyDistanceMin: 100,
14
- nBodyDistanceMax: 400,
15
- getCollisionRadius: 0
9
+ export type GPUForceLayoutOptions = GraphLayoutOptions & {
10
+ alpha?: number;
11
+ resumeAlpha?: number;
12
+ nBodyStrength?: number;
13
+ nBodyDistanceMin?: number;
14
+ nBodyDistanceMax?: number;
15
+ getCollisionRadius?: number;
16
16
  };
17
17
 
18
- // TODO: this layout should be updated with the organizational and logic improvements made in d3-force
19
- export class GPUForceLayout extends BaseLayout {
18
+ /**
19
+ * @todo this layout should be updated with the organizational and logic improvements made in d3-force
20
+ */
21
+ export class GPUForceLayout extends GraphLayout<GPUForceLayoutOptions> {
22
+ static defaultOptions: Required<GPUForceLayoutOptions> = {
23
+ alpha: 0.3,
24
+ resumeAlpha: 0.1,
25
+ nBodyStrength: -900,
26
+ nBodyDistanceMin: 100,
27
+ nBodyDistanceMax: 400,
28
+ getCollisionRadius: 0
29
+ };
30
+
20
31
  protected readonly _name: string = 'GPU';
21
32
  private _d3Graph: any;
22
33
  private _nodeMap: any;
@@ -24,13 +35,17 @@ export class GPUForceLayout extends BaseLayout {
24
35
  private _graph: any;
25
36
  private _worker: Worker;
26
37
  private _callbacks: any;
27
- constructor(options) {
28
- super(options);
29
- this._name = 'GPU';
30
- this._options = {
31
- ...defaultOptions,
38
+
39
+ constructor(options: GPUForceLayoutOptions = {}) {
40
+ const _options = {
41
+ ...GPUForceLayout.defaultOptions,
32
42
  ...options
33
43
  };
44
+
45
+ super(_options);
46
+
47
+ this._name = 'GPU';
48
+ this._options = _options;
34
49
  // store graph and prepare internal data
35
50
  this._d3Graph = {nodes: [], edges: []};
36
51
  this._nodeMap = {};
@@ -91,8 +106,8 @@ export class GPUForceLayout extends BaseLayout {
91
106
  }
92
107
 
93
108
  this._worker = new Worker(new URL('./worker.js', import.meta.url).href);
94
- const {alpha, nBodyStrength, nBodyDistanceMin, nBodyDistanceMax, getCollisionRadius} = this
95
- ._options as any;
109
+ const {alpha, nBodyStrength, nBodyDistanceMin, nBodyDistanceMax, getCollisionRadius} =
110
+ this._options;
96
111
  this._worker.postMessage({
97
112
  nodes: this._d3Graph.nodes,
98
113
  edges: this._d3Graph.edges,
@@ -2,30 +2,45 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {BaseLayout, BaseLayoutOptions} from '../../core/base-layout';
6
- import {Node} from '../../core/node';
7
- import {EDGE_TYPE} from '../../core/constants';
8
- import {Graph} from '../../core/graph';
9
-
10
- type AccessorVec2 = (node: Node) => [number, number];
11
-
12
- interface SimpleLayoutOptions extends BaseLayoutOptions {
13
- nodePositionAccessor?: AccessorVec2;
14
- }
15
-
16
- const defaultOptions: Required<SimpleLayoutOptions> = {
17
- nodePositionAccessor: (node) =>
18
- [node.getPropertyValue('x'), node.getPropertyValue('y')] as [number, number]
5
+ import {GraphLayout, GraphLayoutOptions} from '../core/graph-layout';
6
+ import {Node} from '../graph/node';
7
+ import {EDGE_TYPE} from '../core/constants';
8
+ import {Graph} from '../graph/graph';
9
+
10
+ export type SimpleLayoutOptions = GraphLayoutOptions & {
11
+ /** The accessor lets the application supply the position ([x, y]) of each node.
12
+ * @example
13
+ ```js
14
+ <GraphGL
15
+ {...otherProps}
16
+ layout={
17
+ new SimpleLayout({
18
+ nodePositionAccessor: node => [
19
+ node.getPropertyValue('x'),
20
+ node.getPropertyValue('y'),
21
+ ]
22
+ })
23
+ }
24
+ />
25
+ ```
26
+ */
27
+ nodePositionAccessor?: (node: Node) => [number, number];
19
28
  };
20
29
 
21
- export class SimpleLayout extends BaseLayout {
30
+ /** A basic layout where the application controls positions of each node */
31
+ export class SimpleLayout extends GraphLayout<SimpleLayoutOptions> {
32
+ static defaultOptions: Required<SimpleLayoutOptions> = {
33
+ nodePositionAccessor: (node) =>
34
+ [node.getPropertyValue('x'), node.getPropertyValue('y')] as [number, number]
35
+ };
36
+
22
37
  protected readonly _name = 'SimpleLayout';
23
38
  protected _graph: Graph | null = null;
24
39
  protected _nodeMap: Record<string, Node> = {};
25
- protected _nodePositionMap: Record<string, AccessorVec2> = {};
40
+ protected _nodePositionMap: Record<string, (node: Node) => [number, number]> = {};
26
41
 
27
- constructor(options = {}) {
28
- super({...defaultOptions, ...options});
42
+ constructor(options: SimpleLayoutOptions = {}) {
43
+ super({...SimpleLayout.defaultOptions, ...options});
29
44
  }
30
45
 
31
46
  initializeGraph(graph: Graph): void {
@@ -57,7 +72,7 @@ export class SimpleLayout extends BaseLayout {
57
72
  return res;
58
73
  }, {});
59
74
  this._nodePositionMap = graph.getNodes().reduce((res, node) => {
60
- res[node.getId()] = (this._options as any).nodePositionAccessor(node);
75
+ res[node.getId()] = this._options.nodePositionAccessor(node);
61
76
  return res;
62
77
  }, {});
63
78
  }
@@ -2,11 +2,16 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {Edge} from '../core/edge';
6
- import {Node} from '../core/node';
7
- import {Graph} from '../core/graph';
5
+ import {Edge} from '../graph/edge';
6
+ import {Node} from '../graph/node';
7
+ import {Graph} from '../graph/graph';
8
8
 
9
- export function createGraph({name, nodes, edges, nodeParser, edgeParser}) {
9
+ /**
10
+ * @deprecated Use `new Graph(name, nodes, edges)`
11
+ * Create a graph from a list of Nodes and edges
12
+ */
13
+ export function createGraph(props: {name; nodes; edges; nodeParser; edgeParser}) {
14
+ const {name, nodes, edges, nodeParser, edgeParser} = props;
10
15
  // create a new empty graph
11
16
  const graph = new Graph();
12
17
 
@@ -2,9 +2,10 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
+ import type {EdgeOptions} from '../graph/edge';
5
6
  import {log} from '../utils/log';
6
7
 
7
- export function basicEdgeParser(edge) {
8
+ export function basicEdgeParser(edge: any): Omit<EdgeOptions, 'data'> {
8
9
  const {id, directed, sourceId, targetId} = edge;
9
10
 
10
11
  if (sourceId === undefined || targetId === undefined) {
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {createGraph} from '../utils/create-graph';
5
+ import {createGraph} from './create-graph';
6
6
  import {basicNodeParser} from './node-parsers';
7
7
  import {basicEdgeParser} from './edge-parsers';
8
8
  import {log} from '../utils/log';
@@ -2,9 +2,10 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
+ import type {NodeOptions} from '../graph/node';
5
6
  import {log} from '../utils/log';
6
7
 
7
- export function basicNodeParser(node) {
8
+ export function basicNodeParser(node: any): Pick<NodeOptions, 'id'> {
8
9
  if (node.id === undefined) {
9
10
  log.error('Invalid node: id is missing.')();
10
11
  return null;
@@ -0,0 +1,28 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {createGraph} from './create-graph';
6
+ import {log} from '../utils/log';
7
+ import {basicNodeParser} from './node-parsers';
8
+ import {basicEdgeParser} from './edge-parsers';
9
+
10
+ /** @deprecated Use loadSimpleJSONGraph */
11
+ export const JSONLoader = ({json, nodeParser, edgeParser}) =>
12
+ loadSimpleJSONGraph(json, {nodeParser, edgeParser});
13
+
14
+ /** A loader for a simple graph format */
15
+ export function loadSimpleJSONGraph(
16
+ json: Record<string, unknown>,
17
+ options?: {nodeParser; edgeParser}
18
+ ) {
19
+ const {nodeParser = basicNodeParser, edgeParser = basicEdgeParser} = options;
20
+ const {name = 'default', nodes, edges} = json;
21
+ if (!nodes) {
22
+ log.error('Invalid graph: nodes is missing.')();
23
+ return null;
24
+ }
25
+
26
+ const graph = createGraph({name, nodes, edges, nodeParser, edgeParser});
27
+ return graph;
28
+ }