@deck.gl-community/graph-layers 9.0.0

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 (210) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +7 -0
  3. package/dist/core/base-layout.d.ts +71 -0
  4. package/dist/core/base-layout.js +133 -0
  5. package/dist/core/cache.d.ts +14 -0
  6. package/dist/core/cache.js +26 -0
  7. package/dist/core/constants.d.ts +101 -0
  8. package/dist/core/constants.js +48 -0
  9. package/dist/core/edge.d.ts +86 -0
  10. package/dist/core/edge.js +121 -0
  11. package/dist/core/graph-engine.d.ts +54 -0
  12. package/dist/core/graph-engine.js +128 -0
  13. package/dist/core/graph.d.ts +155 -0
  14. package/dist/core/graph.js +301 -0
  15. package/dist/core/interaction-manager.d.ts +40 -0
  16. package/dist/core/interaction-manager.js +169 -0
  17. package/dist/core/node.d.ts +103 -0
  18. package/dist/core/node.js +177 -0
  19. package/dist/index.cjs +3540 -0
  20. package/dist/index.cjs.map +7 -0
  21. package/dist/index.d.ts +19 -0
  22. package/dist/index.js +28 -0
  23. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-fragment.glsl.d.ts +1 -0
  24. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-fragment.glsl.js +49 -0
  25. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex-tf.glsl.d.ts +1 -0
  26. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex-tf.glsl.js +14 -0
  27. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex.glsl.d.ts +1 -0
  28. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex.glsl.js +73 -0
  29. package/dist/layers/common-layers/flow-path-layer/flow-path-layer.d.ts +20 -0
  30. package/dist/layers/common-layers/flow-path-layer/flow-path-layer.js +133 -0
  31. package/dist/layers/common-layers/marker-layer/atlas-data-url.d.ts +3 -0
  32. package/dist/layers/common-layers/marker-layer/atlas-data-url.js +8 -0
  33. package/dist/layers/common-layers/marker-layer/marker-layer.d.ts +13 -0
  34. package/dist/layers/common-layers/marker-layer/marker-layer.js +29 -0
  35. package/dist/layers/common-layers/marker-layer/marker-list.d.ts +62 -0
  36. package/dist/layers/common-layers/marker-layer/marker-list.js +67 -0
  37. package/dist/layers/common-layers/marker-layer/marker-mapping.d.ts +422 -0
  38. package/dist/layers/common-layers/marker-layer/marker-mapping.js +427 -0
  39. package/dist/layers/common-layers/spline-layer/spline-layer.d.ts +24 -0
  40. package/dist/layers/common-layers/spline-layer/spline-layer.js +68 -0
  41. package/dist/layers/common-layers/zoomable-text-layer/zoomable-text-layer.d.ts +16 -0
  42. package/dist/layers/common-layers/zoomable-text-layer/zoomable-text-layer.js +65 -0
  43. package/dist/layers/edge-layer.d.ts +25 -0
  44. package/dist/layers/edge-layer.js +75 -0
  45. package/dist/layers/edge-layers/curved-edge-layer.d.ts +6 -0
  46. package/dist/layers/edge-layers/curved-edge-layer.js +69 -0
  47. package/dist/layers/edge-layers/edge-label-layer.d.ts +6 -0
  48. package/dist/layers/edge-layers/edge-label-layer.js +42 -0
  49. package/dist/layers/edge-layers/flow-layer.d.ts +6 -0
  50. package/dist/layers/edge-layers/flow-layer.js +28 -0
  51. package/dist/layers/edge-layers/path-edge-layer.d.ts +6 -0
  52. package/dist/layers/edge-layers/path-edge-layer.js +27 -0
  53. package/dist/layers/edge-layers/straight-line-edge-layer.d.ts +6 -0
  54. package/dist/layers/edge-layers/straight-line-edge-layer.js +26 -0
  55. package/dist/layers/graph-layer.d.ts +32 -0
  56. package/dist/layers/graph-layer.js +193 -0
  57. package/dist/layers/node-layers/circle-layer.d.ts +6 -0
  58. package/dist/layers/node-layers/circle-layer.js +23 -0
  59. package/dist/layers/node-layers/image-layer.d.ts +6 -0
  60. package/dist/layers/node-layers/image-layer.js +23 -0
  61. package/dist/layers/node-layers/label-layer.d.ts +6 -0
  62. package/dist/layers/node-layers/label-layer.js +23 -0
  63. package/dist/layers/node-layers/path-rounded-rectange-layer.d.ts +6 -0
  64. package/dist/layers/node-layers/path-rounded-rectange-layer.js +46 -0
  65. package/dist/layers/node-layers/rectangle-layer.d.ts +6 -0
  66. package/dist/layers/node-layers/rectangle-layer.js +49 -0
  67. package/dist/layers/node-layers/rounded-rectangle-layer-fragment.d.ts +1 -0
  68. package/dist/layers/node-layers/rounded-rectangle-layer-fragment.js +30 -0
  69. package/dist/layers/node-layers/rounded-rectangle-layer.d.ts +8 -0
  70. package/dist/layers/node-layers/rounded-rectangle-layer.js +28 -0
  71. package/dist/layers/node-layers/zoomable-marker-layer.d.ts +10 -0
  72. package/dist/layers/node-layers/zoomable-marker-layer.js +40 -0
  73. package/dist/layouts/d3-force/d3-force-layout.d.ts +24 -0
  74. package/dist/layouts/d3-force/d3-force-layout.js +116 -0
  75. package/dist/layouts/d3-force/worker.d.ts +0 -0
  76. package/dist/layouts/d3-force/worker.js +46 -0
  77. package/dist/layouts/gpu-force/gpu-force-layout.d.ts +30 -0
  78. package/dist/layouts/gpu-force/gpu-force-layout.js +232 -0
  79. package/dist/layouts/gpu-force/worker.d.ts +0 -0
  80. package/dist/layouts/gpu-force/worker.js +116 -0
  81. package/dist/layouts/simple-layout/simple-layout.d.ts +22 -0
  82. package/dist/layouts/simple-layout/simple-layout.js +64 -0
  83. package/dist/loaders/edge-parsers.d.ts +6 -0
  84. package/dist/loaders/edge-parsers.js +17 -0
  85. package/dist/loaders/json-loader.d.ts +7 -0
  86. package/dist/loaders/json-loader.js +16 -0
  87. package/dist/loaders/node-parsers.d.ts +3 -0
  88. package/dist/loaders/node-parsers.js +11 -0
  89. package/dist/style/style-property.d.ts +14 -0
  90. package/dist/style/style-property.js +195 -0
  91. package/dist/style/style-sheet.d.ts +10 -0
  92. package/dist/style/style-sheet.js +252 -0
  93. package/dist/utils/create-graph.d.ts +8 -0
  94. package/dist/utils/create-graph.js +33 -0
  95. package/dist/utils/layer-utils.d.ts +1 -0
  96. package/dist/utils/layer-utils.js +20 -0
  97. package/dist/utils/log.d.ts +2 -0
  98. package/dist/utils/log.js +6 -0
  99. package/dist/utils/polygon-calculations.d.ts +1 -0
  100. package/dist/utils/polygon-calculations.js +102 -0
  101. package/package.json +55 -0
  102. package/src/core/base-layout.ts +154 -0
  103. package/src/core/cache.ts +31 -0
  104. package/src/core/constants.ts +58 -0
  105. package/src/core/edge.ts +145 -0
  106. package/src/core/graph-engine.ts +170 -0
  107. package/src/core/graph.ts +342 -0
  108. package/src/core/interaction-manager.ts +225 -0
  109. package/src/core/node.ts +205 -0
  110. package/src/index.ts +42 -0
  111. package/src/layers/common-layers/flow-path-layer/flow-path-layer-fragment.glsl.ts +50 -0
  112. package/src/layers/common-layers/flow-path-layer/flow-path-layer-vertex-tf.glsl.ts +15 -0
  113. package/src/layers/common-layers/flow-path-layer/flow-path-layer-vertex.glsl.ts +74 -0
  114. package/src/layers/common-layers/flow-path-layer/flow-path-layer.ts +154 -0
  115. package/src/layers/common-layers/marker-layer/atlas-data-url.ts +10 -0
  116. package/src/layers/common-layers/marker-layer/marker-atlas.png +0 -0
  117. package/src/layers/common-layers/marker-layer/marker-layer.ts +36 -0
  118. package/src/layers/common-layers/marker-layer/marker-list.ts +68 -0
  119. package/src/layers/common-layers/marker-layer/marker-mapping.ts +428 -0
  120. package/src/layers/common-layers/marker-layer/markers/bell-filled.png +0 -0
  121. package/src/layers/common-layers/marker-layer/markers/bell.png +0 -0
  122. package/src/layers/common-layers/marker-layer/markers/bookmark-filled.png +0 -0
  123. package/src/layers/common-layers/marker-layer/markers/bookmark.png +0 -0
  124. package/src/layers/common-layers/marker-layer/markers/cd-filled.png +0 -0
  125. package/src/layers/common-layers/marker-layer/markers/cd.png +0 -0
  126. package/src/layers/common-layers/marker-layer/markers/checkmark.png +0 -0
  127. package/src/layers/common-layers/marker-layer/markers/circle-check-filled.png +0 -0
  128. package/src/layers/common-layers/marker-layer/markers/circle-check.png +0 -0
  129. package/src/layers/common-layers/marker-layer/markers/circle-filled.png +0 -0
  130. package/src/layers/common-layers/marker-layer/markers/circle-i-filled.png +0 -0
  131. package/src/layers/common-layers/marker-layer/markers/circle-i.png +0 -0
  132. package/src/layers/common-layers/marker-layer/markers/circle-minus-filled.png +0 -0
  133. package/src/layers/common-layers/marker-layer/markers/circle-minus.png +0 -0
  134. package/src/layers/common-layers/marker-layer/markers/circle-plus-filled.png +0 -0
  135. package/src/layers/common-layers/marker-layer/markers/circle-plus.png +0 -0
  136. package/src/layers/common-layers/marker-layer/markers/circle-questionmark-filled.png +0 -0
  137. package/src/layers/common-layers/marker-layer/markers/circle-questionmark.png +0 -0
  138. package/src/layers/common-layers/marker-layer/markers/circle-slash-filled.png +0 -0
  139. package/src/layers/common-layers/marker-layer/markers/circle-slash.png +0 -0
  140. package/src/layers/common-layers/marker-layer/markers/circle-x-filled.png +0 -0
  141. package/src/layers/common-layers/marker-layer/markers/circle-x.png +0 -0
  142. package/src/layers/common-layers/marker-layer/markers/circle.png +0 -0
  143. package/src/layers/common-layers/marker-layer/markers/diamond-filled.png +0 -0
  144. package/src/layers/common-layers/marker-layer/markers/diamond.png +0 -0
  145. package/src/layers/common-layers/marker-layer/markers/flag-filled.png +0 -0
  146. package/src/layers/common-layers/marker-layer/markers/flag.png +0 -0
  147. package/src/layers/common-layers/marker-layer/markers/gear.png +0 -0
  148. package/src/layers/common-layers/marker-layer/markers/heart-filled.png +0 -0
  149. package/src/layers/common-layers/marker-layer/markers/heart.png +0 -0
  150. package/src/layers/common-layers/marker-layer/markers/location-marker-filled.png +0 -0
  151. package/src/layers/common-layers/marker-layer/markers/location-marker.png +0 -0
  152. package/src/layers/common-layers/marker-layer/markers/octagonal-star-filled.png +0 -0
  153. package/src/layers/common-layers/marker-layer/markers/octagonal-star.png +0 -0
  154. package/src/layers/common-layers/marker-layer/markers/person-filled.png +0 -0
  155. package/src/layers/common-layers/marker-layer/markers/person.png +0 -0
  156. package/src/layers/common-layers/marker-layer/markers/pin-filled.png +0 -0
  157. package/src/layers/common-layers/marker-layer/markers/pin.png +0 -0
  158. package/src/layers/common-layers/marker-layer/markers/plus-small.png +0 -0
  159. package/src/layers/common-layers/marker-layer/markers/plus.png +0 -0
  160. package/src/layers/common-layers/marker-layer/markers/rectangle-filled.png +0 -0
  161. package/src/layers/common-layers/marker-layer/markers/rectangle.png +0 -0
  162. package/src/layers/common-layers/marker-layer/markers/star-filled.png +0 -0
  163. package/src/layers/common-layers/marker-layer/markers/star.png +0 -0
  164. package/src/layers/common-layers/marker-layer/markers/tag-filled.png +0 -0
  165. package/src/layers/common-layers/marker-layer/markers/tag.png +0 -0
  166. package/src/layers/common-layers/marker-layer/markers/thumb-down-filled.png +0 -0
  167. package/src/layers/common-layers/marker-layer/markers/thumb-down.png +0 -0
  168. package/src/layers/common-layers/marker-layer/markers/thumb-up.png +0 -0
  169. package/src/layers/common-layers/marker-layer/markers/thumb_up-filled.png +0 -0
  170. package/src/layers/common-layers/marker-layer/markers/triangle-down-filled.png +0 -0
  171. package/src/layers/common-layers/marker-layer/markers/triangle-down.png +0 -0
  172. package/src/layers/common-layers/marker-layer/markers/triangle-left-filled.png +0 -0
  173. package/src/layers/common-layers/marker-layer/markers/triangle-left.png +0 -0
  174. package/src/layers/common-layers/marker-layer/markers/triangle-right-filled.png +0 -0
  175. package/src/layers/common-layers/marker-layer/markers/triangle-right.png +0 -0
  176. package/src/layers/common-layers/marker-layer/markers/triangle-up-filled.png +0 -0
  177. package/src/layers/common-layers/marker-layer/markers/triangle-up.png +0 -0
  178. package/src/layers/common-layers/marker-layer/markers/x-small.png +0 -0
  179. package/src/layers/common-layers/marker-layer/markers/x.png +0 -0
  180. package/src/layers/common-layers/spline-layer/spline-layer.ts +83 -0
  181. package/src/layers/common-layers/zoomable-text-layer/zoomable-text-layer.ts +90 -0
  182. package/src/layers/edge-layer.ts +88 -0
  183. package/src/layers/edge-layers/curved-edge-layer.ts +88 -0
  184. package/src/layers/edge-layers/edge-label-layer.ts +48 -0
  185. package/src/layers/edge-layers/flow-layer.ts +34 -0
  186. package/src/layers/edge-layers/path-edge-layer.ts +39 -0
  187. package/src/layers/edge-layers/straight-line-edge-layer.ts +38 -0
  188. package/src/layers/graph-layer.ts +225 -0
  189. package/src/layers/node-layers/circle-layer.ts +29 -0
  190. package/src/layers/node-layers/image-layer.ts +29 -0
  191. package/src/layers/node-layers/label-layer.ts +29 -0
  192. package/src/layers/node-layers/path-rounded-rectange-layer.ts +56 -0
  193. package/src/layers/node-layers/rectangle-layer.ts +58 -0
  194. package/src/layers/node-layers/rounded-rectangle-layer-fragment.ts +31 -0
  195. package/src/layers/node-layers/rounded-rectangle-layer.ts +32 -0
  196. package/src/layers/node-layers/zoomable-marker-layer.ts +49 -0
  197. package/src/layouts/d3-force/d3-force-layout.ts +145 -0
  198. package/src/layouts/d3-force/worker.ts +61 -0
  199. package/src/layouts/gpu-force/gpu-force-layout.ts +249 -0
  200. package/src/layouts/gpu-force/worker.ts +137 -0
  201. package/src/layouts/simple-layout/simple-layout.ts +87 -0
  202. package/src/loaders/edge-parsers.ts +21 -0
  203. package/src/loaders/json-loader.ts +19 -0
  204. package/src/loaders/node-parsers.ts +13 -0
  205. package/src/style/style-property.ts +229 -0
  206. package/src/style/style-sheet.ts +277 -0
  207. package/src/utils/create-graph.ts +38 -0
  208. package/src/utils/layer-utils.ts +23 -0
  209. package/src/utils/log.ts +9 -0
  210. package/src/utils/polygon-calculations.ts +154 -0
@@ -0,0 +1,249 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {BaseLayout} from '../../core/base-layout';
6
+
7
+ import {EDGE_TYPE} from '../../core/constants';
8
+
9
+ const defaultOptions = {
10
+ alpha: 0.3,
11
+ resumeAlpha: 0.1,
12
+ nBodyStrength: -900,
13
+ nBodyDistanceMin: 100,
14
+ nBodyDistanceMax: 400,
15
+ getCollisionRadius: 0
16
+ };
17
+
18
+ // TODO: this layout should be updated with the organizational and logic improvements made in d3-force
19
+ export class GPUForceLayout extends BaseLayout {
20
+ protected readonly _name: string = 'GPU';
21
+ private _d3Graph: any;
22
+ private _nodeMap: any;
23
+ private _edgeMap: any;
24
+ private _graph: any;
25
+ private _worker: Worker;
26
+ private _callbacks: any;
27
+ constructor(options) {
28
+ super(options);
29
+ this._name = 'GPU';
30
+ this._options = {
31
+ ...defaultOptions,
32
+ ...options
33
+ };
34
+ // store graph and prepare internal data
35
+ this._d3Graph = {nodes: [], edges: []};
36
+ this._nodeMap = {};
37
+ this._edgeMap = {};
38
+ }
39
+
40
+ initializeGraph(graph) {
41
+ this._graph = graph;
42
+ this._nodeMap = {};
43
+ this._edgeMap = {};
44
+ // nodes
45
+ const d3Nodes = graph.getNodes().map((node) => {
46
+ const id = node.id;
47
+ const locked = node.getPropertyValue('locked') || false;
48
+ const x = node.getPropertyValue('x') || 0;
49
+ const y = node.getPropertyValue('y') || 0;
50
+ const collisionRadius = node.getPropertyValue('collisionRadius') || 0;
51
+ const d3Node = {
52
+ id,
53
+ x,
54
+ y,
55
+ fx: locked ? x : null,
56
+ fy: locked ? y : null,
57
+ collisionRadius,
58
+ locked
59
+ };
60
+ this._nodeMap[node.id] = d3Node;
61
+ return d3Node;
62
+ });
63
+ // edges
64
+ const d3Edges = graph.getEdges().map((edge) => {
65
+ const d3Edge = {
66
+ id: edge.id,
67
+ source: this._nodeMap[edge.getSourceNodeId()],
68
+ target: this._nodeMap[edge.getTargetNodeId()]
69
+ };
70
+ this._edgeMap[edge.id] = d3Edge;
71
+ return d3Edge;
72
+ });
73
+ this._d3Graph = {
74
+ nodes: d3Nodes,
75
+ edges: d3Edges
76
+ };
77
+ }
78
+
79
+ start() {
80
+ this._engageWorker();
81
+ }
82
+
83
+ update() {
84
+ this._engageWorker();
85
+ }
86
+
87
+ _engageWorker() {
88
+ // prevent multiple start
89
+ if (this._worker) {
90
+ this._worker.terminate();
91
+ }
92
+
93
+ this._worker = new Worker(new URL('./worker.js', import.meta.url).href);
94
+ const {alpha, nBodyStrength, nBodyDistanceMin, nBodyDistanceMax, getCollisionRadius} = this
95
+ ._options as any;
96
+ this._worker.postMessage({
97
+ nodes: this._d3Graph.nodes,
98
+ edges: this._d3Graph.edges,
99
+ options: {
100
+ alpha,
101
+ nBodyStrength,
102
+ nBodyDistanceMin,
103
+ nBodyDistanceMax,
104
+ getCollisionRadius
105
+ }
106
+ });
107
+ this._worker.onmessage = (event) => {
108
+ switch (event.data.type) {
109
+ case 'tick':
110
+ this.ticked(event.data);
111
+ break;
112
+ case 'end':
113
+ this.ended(event.data);
114
+ break;
115
+ default:
116
+ break;
117
+ }
118
+ };
119
+ }
120
+ ticked(data) {}
121
+ ended(data) {
122
+ const {nodes, edges} = data;
123
+ this.updateD3Graph({nodes, edges});
124
+ this._onLayoutChange();
125
+ this._onLayoutDone();
126
+ }
127
+ resume() {
128
+ throw new Error('Resume unavailable');
129
+ }
130
+ stop() {
131
+ this._worker.terminate();
132
+ }
133
+
134
+ // for steaming new data on the same graph
135
+ updateGraph(graph) {
136
+ if (this._graph.getGraphName() !== graph.getGraphName()) {
137
+ // reset the maps
138
+ this._nodeMap = {};
139
+ this._edgeMap = {};
140
+ }
141
+ this._graph = graph;
142
+ // update internal layout data
143
+ // nodes
144
+ const newNodeMap = {};
145
+ const newD3Nodes = graph.getNodes().map((node) => {
146
+ const id = node.id;
147
+ const locked = node.getPropertyValue('locked') || false;
148
+ const x = node.getPropertyValue('x') || 0;
149
+ const y = node.getPropertyValue('y') || 0;
150
+ const fx = locked ? x : null;
151
+ const fy = locked ? y : null;
152
+ const collisionRadius = node.getPropertyValue('collisionRadius') || 0;
153
+
154
+ const oldD3Node = this._nodeMap[node.id];
155
+ const newD3Node = oldD3Node ? oldD3Node : {id, x, y, fx, fy, collisionRadius};
156
+ newNodeMap[node.id] = newD3Node;
157
+ return newD3Node;
158
+ });
159
+ this._nodeMap = newNodeMap;
160
+ this._d3Graph.nodes = newD3Nodes;
161
+ // edges
162
+ const newEdgeMap = {};
163
+ const newD3Edges = graph.getEdges().map((edge) => {
164
+ const oldD3Edge = this._edgeMap[edge.id];
165
+ const newD3Edge = oldD3Edge || {
166
+ id: edge.id,
167
+ source: newNodeMap[edge.getSourceNodeId()],
168
+ target: newNodeMap[edge.getTargetNodeId()]
169
+ };
170
+ newEdgeMap[edge.id] = newD3Edge;
171
+ return newD3Edge;
172
+ });
173
+ this._edgeMap = newEdgeMap;
174
+ this._d3Graph.edges = newD3Edges;
175
+ }
176
+
177
+ updateD3Graph(graph) {
178
+ const existingNodes = this._graph.getNodes();
179
+ // update internal layout data
180
+ // nodes
181
+ const newNodeMap = {};
182
+ const newD3Nodes = graph.nodes.map((node) => {
183
+ // Update existing _graph with the new values
184
+ const existingNode = existingNodes.find((n) => n.getId() === node.id);
185
+ existingNode.setDataProperty('locked', node.locked);
186
+ existingNode.setDataProperty('x', node.x);
187
+ existingNode.setDataProperty('y', node.y);
188
+ existingNode.setDataProperty('collisionRadius', node.collisionRadius);
189
+
190
+ newNodeMap[node.id] = node;
191
+ return node;
192
+ });
193
+ this._nodeMap = newNodeMap;
194
+ this._d3Graph.nodes = newD3Nodes;
195
+ // edges
196
+ const newEdgeMap = {};
197
+ const newD3Edges = graph.edges.map((edge) => {
198
+ newEdgeMap[edge.id] = edge;
199
+ return edge;
200
+ });
201
+ this._graph.triggerUpdate();
202
+ this._edgeMap = newEdgeMap;
203
+ this._d3Graph.edges = newD3Edges;
204
+ }
205
+
206
+ getNodePosition = (node): [number, number] => {
207
+ const d3Node = this._nodeMap[node.id];
208
+ if (d3Node) {
209
+ return [d3Node.x, d3Node.y];
210
+ }
211
+ return [0, 0];
212
+ };
213
+
214
+ getEdgePosition = (edge) => {
215
+ const d3Edge = this._edgeMap[edge.id];
216
+ const sourcePosition = d3Edge && d3Edge.source;
217
+ const targetPosition = d3Edge && d3Edge.target;
218
+ if (d3Edge && sourcePosition && targetPosition) {
219
+ return {
220
+ type: EDGE_TYPE.LINE,
221
+ sourcePosition: [sourcePosition.x, sourcePosition.y],
222
+ targetPosition: [targetPosition.x, targetPosition.y],
223
+ controlPoints: []
224
+ };
225
+ }
226
+ return {
227
+ type: EDGE_TYPE.LINE,
228
+ sourcePosition: [0, 0],
229
+ targetPosition: [0, 0],
230
+ controlPoints: []
231
+ };
232
+ };
233
+
234
+ lockNodePosition = (node, x, y) => {
235
+ const d3Node = this._nodeMap[node.id];
236
+ d3Node.x = x;
237
+ d3Node.y = y;
238
+ d3Node.fx = x;
239
+ d3Node.fy = y;
240
+ this._callbacks.onLayoutChange();
241
+ this._callbacks.onLayoutDone();
242
+ };
243
+
244
+ unlockNodePosition = (node) => {
245
+ const d3Node = this._nodeMap[node.id];
246
+ d3Node.fx = null;
247
+ d3Node.fy = null;
248
+ };
249
+ }
@@ -0,0 +1,137 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ /* global importScripts GPU*/
6
+
7
+ importScripts('https://cdn.jsdelivr.net/npm/gpu.js@latest/dist/gpu-browser.js');
8
+
9
+ onmessage = function (event) {
10
+ const {nodes: sourceNodes, edges: sourceEdges} = event.data;
11
+ const {nBodyStrength, nBodyDistanceMin, nBodyDistanceMax, getCollisionRadius} =
12
+ event.data.options;
13
+ // FIXME remove cpu mode
14
+ // @ts-expect-error TODO
15
+ const gpu = new GPU.GPU({
16
+ mode: 'cpu'
17
+ });
18
+ function getDistance(node1, node2) {
19
+ const dx = node1[1] - node2[1];
20
+ const dy = node1[2] - node2[2];
21
+ return Math.sqrt(dx * dx + dy * dy);
22
+ }
23
+ function isCollision(node1, node2, radius) {
24
+ return getDistance(node1, node2) < radius;
25
+ }
26
+
27
+ function forceCollide(nodes, currentNode, nodesSize, radius) {
28
+ let collisons = true;
29
+ while (collisons) {
30
+ collisons = false;
31
+ for (let i = 0; i < nodesSize; i++) {
32
+ while (nodes[i][0] !== currentNode[0] && isCollision(currentNode, nodes[i], radius)) {
33
+ collisons = true;
34
+ const xMove = currentNode[1] + Math.random() - 0.5;
35
+ currentNode[1] = currentNode[1] + xMove;
36
+ const yMove = currentNode[2] + Math.random() - 0.5;
37
+ currentNode[2] = currentNode[2] + yMove;
38
+ }
39
+ }
40
+ }
41
+ return [currentNode[1], currentNode[2]];
42
+ }
43
+ // FIXME correct lint errors
44
+ // eslint-disable-next-line max-params
45
+ function forceLink(nodes, edges, currentNode, nodesSize, edgesSize, radius) {
46
+ let x1 = currentNode[1];
47
+ let y1 = currentNode[2];
48
+ for (let i = 0; i < edgesSize; i++) {
49
+ const edge = edges[i];
50
+ if (edge[0] === currentNode[0] || edge[1] === currentNode[0]) {
51
+ const otherNodeId = edge[0] === currentNode[0] ? edge[1] : edge[0];
52
+ // FIXME: deal with the fact that GPUjs doesn't like array.find or undefined
53
+ for (let j = 0; j < nodesSize; j++) {
54
+ // eslint-disable-next-line max-depth
55
+ if (nodes[i][0] === otherNodeId) {
56
+ const otherNode = nodes[j];
57
+ const x2 = otherNode[1];
58
+ const y2 = otherNode[2];
59
+ const dx = x1 - x2;
60
+ const dy = y1 - y2;
61
+ const distance = Math.sqrt(dx * dx + dy * dy);
62
+ const force = 1;
63
+ // eslint-disable-next-line max-depth
64
+ if (distance > radius + force) {
65
+ x1 = dx > 0 ? x1 - force / 2 : x1 + force / 2;
66
+ y1 = dy > 0 ? y1 - force / 2 : y1 + force / 2;
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }
72
+ return [x1, y1];
73
+ }
74
+
75
+ gpu.addFunction(forceCollide);
76
+ gpu.addFunction(forceLink);
77
+ gpu.addFunction(isCollision);
78
+ gpu.addFunction(getDistance);
79
+ const kernel = gpu.createKernel(
80
+ function (kernelNodes, kernelEdges) {
81
+ const currentNode = kernelNodes[this.thread.x];
82
+ forceCollide(
83
+ kernelNodes,
84
+ currentNode,
85
+ this.constants.nodesSize,
86
+ this.constants.collisionRadius
87
+ );
88
+ const forceLinkResult = forceLink(
89
+ kernelNodes,
90
+ kernelEdges,
91
+ currentNode,
92
+ this.constants.nodesSize,
93
+ this.constants.edgesSize,
94
+ this.constants.collisionRadius
95
+ );
96
+ currentNode[1] = forceLinkResult[0];
97
+ currentNode[2] = forceLinkResult[1];
98
+ return [currentNode[1], currentNode[2]];
99
+ },
100
+ {
101
+ constants: {
102
+ nodesSize: sourceNodes.length,
103
+ edgesSize: sourceEdges.length,
104
+ collisionRadius: getCollisionRadius,
105
+ nBodyStrength,
106
+ nBodyDistanceMin,
107
+ nBodyDistanceMax
108
+ },
109
+ output: [sourceNodes.length]
110
+ }
111
+ );
112
+ const tempNodes = sourceNodes.map((node) => [node.id, node.x, node.y, node.locked ? 1 : 0]);
113
+ const tempEdges = sourceEdges.map((edge) => [edge.source.id, edge.target.id]);
114
+ kernel(tempNodes, tempEdges);
115
+ const newNodes = sourceNodes.map((node, index) => {
116
+ const updatedNode = tempNodes.find((n) => n[0] === node.id);
117
+ return {
118
+ ...node,
119
+ x: updatedNode[1],
120
+ y: updatedNode[2]
121
+ };
122
+ });
123
+ const newEdges = sourceEdges.map((edge) => {
124
+ return {
125
+ ...edge,
126
+ source: newNodes.find((node) => node.id === edge.source.id),
127
+ target: newNodes.find((node) => node.id === edge.target.id)
128
+ };
129
+ });
130
+ postMessage({
131
+ type: 'end',
132
+ nodes: newNodes,
133
+ edges: newEdges
134
+ });
135
+ // FIXME cleanup per gpu documentation
136
+ this.self.close();
137
+ };
@@ -0,0 +1,87 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
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]
19
+ };
20
+
21
+ export class SimpleLayout extends BaseLayout {
22
+ protected readonly _name = 'SimpleLayout';
23
+ protected _graph: Graph | null = null;
24
+ protected _nodeMap: Record<string, Node> = {};
25
+ protected _nodePositionMap: Record<string, AccessorVec2> = {};
26
+
27
+ constructor(options = {}) {
28
+ super({...defaultOptions, ...options});
29
+ }
30
+
31
+ initializeGraph(graph: Graph): void {
32
+ this.updateGraph(graph);
33
+ }
34
+
35
+ _notifyLayoutComplete(): void {
36
+ this._onLayoutStart();
37
+ this._onLayoutChange();
38
+ this._onLayoutDone();
39
+ }
40
+
41
+ start(): void {
42
+ this._notifyLayoutComplete();
43
+ }
44
+
45
+ update(): void {
46
+ this._notifyLayoutComplete();
47
+ }
48
+
49
+ resume(): void {
50
+ this._notifyLayoutComplete();
51
+ }
52
+
53
+ updateGraph(graph: Graph): void {
54
+ this._graph = graph;
55
+ this._nodeMap = graph.getNodes().reduce((res, node) => {
56
+ res[node.getId()] = node;
57
+ return res;
58
+ }, {});
59
+ this._nodePositionMap = graph.getNodes().reduce((res, node) => {
60
+ res[node.getId()] = (this._options as any).nodePositionAccessor(node);
61
+ return res;
62
+ }, {});
63
+ }
64
+
65
+ setNodePositionAccessor = (accessor) => {
66
+ (this._options as any).nodePositionAccessor = accessor;
67
+ };
68
+
69
+ getNodePosition = (node) => this._nodePositionMap[node.getId()] as any;
70
+
71
+ getEdgePosition = (edge) => {
72
+ const sourcePos = this._nodePositionMap[edge.getSourceNodeId()];
73
+ const targetPos = this._nodePositionMap[edge.getTargetNodeId()];
74
+ return {
75
+ type: EDGE_TYPE.LINE,
76
+ sourcePosition: sourcePos,
77
+ targetPosition: targetPos,
78
+ controlPoints: []
79
+ } as any;
80
+ };
81
+
82
+ lockNodePosition = (node, x, y) => {
83
+ this._nodePositionMap[node.getId()] = [x, y] as any;
84
+ this._onLayoutChange();
85
+ this._onLayoutDone();
86
+ };
87
+ }
@@ -0,0 +1,21 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {log} from '../utils/log';
6
+
7
+ export function basicEdgeParser(edge) {
8
+ const {id, directed, sourceId, targetId} = edge;
9
+
10
+ if (sourceId === undefined || targetId === undefined) {
11
+ log.error('Invalid edge: sourceId or targetId is missing.')();
12
+ return null;
13
+ }
14
+
15
+ return {
16
+ id,
17
+ directed: directed || false,
18
+ sourceId,
19
+ targetId
20
+ };
21
+ }
@@ -0,0 +1,19 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {createGraph} from '../utils/create-graph';
6
+ import {basicNodeParser} from './node-parsers';
7
+ import {basicEdgeParser} from './edge-parsers';
8
+ import {log} from '../utils/log';
9
+
10
+ export const JSONLoader = ({json, nodeParser = basicNodeParser, edgeParser = basicEdgeParser}) => {
11
+ const {name = 'default', nodes, edges} = json;
12
+ if (!nodes) {
13
+ log.error('Invalid graph: nodes is missing.')();
14
+ return null;
15
+ }
16
+
17
+ const graph = createGraph({name, nodes, edges, nodeParser, edgeParser});
18
+ return graph;
19
+ };
@@ -0,0 +1,13 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {log} from '../utils/log';
6
+
7
+ export function basicNodeParser(node) {
8
+ if (node.id === undefined) {
9
+ log.error('Invalid node: id is missing.')();
10
+ return null;
11
+ }
12
+ return {id: node.id};
13
+ }