@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,58 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {MarkerList} from '../layers/common-layers/marker-layer/marker-list';
6
+
7
+ /** All the markers supported by node type MARKER */
8
+ export const MARKER_TYPE = MarkerList;
9
+
10
+ export type ValueOf<T> = T[keyof T];
11
+
12
+ // the interaction state of a node.
13
+ export const NODE_STATE = {
14
+ DEFAULT: 'default',
15
+ HOVER: 'hover',
16
+ DRAGGING: 'dragging',
17
+ SELECTED: 'selected'
18
+ };
19
+
20
+ export const EDGE_STATE = {
21
+ DEFAULT: 'default',
22
+ HOVER: 'hover',
23
+ DRAGGING: 'dragging',
24
+ SELECTED: 'selected'
25
+ };
26
+
27
+ // node visual marker type
28
+ export const NODE_TYPE = {
29
+ CIRCLE: 'CIRCLE',
30
+ RECTANGLE: 'RECTANGLE',
31
+ ROUNDED_RECTANGLE: 'ROUNDED_RECTANGLE',
32
+ PATH_ROUNDED_RECTANGLE: 'PATH_ROUNDED_RECTANGLE',
33
+ ICON: 'ICON',
34
+ LABEL: 'LABEL',
35
+ MARKER: 'MARKER'
36
+ };
37
+
38
+ // edge shape
39
+ export const EDGE_TYPE = {
40
+ SPLINE_CURVE: 'SPLINE_CURVE',
41
+ LINE: 'LINE',
42
+ PATH: 'PATH'
43
+ };
44
+
45
+ // decorators on edges
46
+ export const EDGE_DECORATOR_TYPE = {
47
+ LABEL: 'EDGE_LABEL',
48
+ FLOW: 'FLOW'
49
+ };
50
+
51
+ // the status of the layout
52
+ export const LAYOUT_STATE = {
53
+ INIT: 'INIT',
54
+ START: 'START',
55
+ CALCULATING: 'CALCULATING',
56
+ DONE: 'DONE',
57
+ ERROR: 'ERROR'
58
+ };
@@ -0,0 +1,145 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ // Basic data structure of an edge
6
+ import {EDGE_STATE} from './constants';
7
+ import {Node} from './node';
8
+
9
+ interface EdgeOptions {
10
+ id: string | number;
11
+ sourceId: string | number;
12
+ targetId: string | number;
13
+ directed?: boolean;
14
+ data: Record<string, unknown>;
15
+ }
16
+
17
+ export class Edge {
18
+ /** Unique uuid of the edge. */
19
+ public id: string | number;
20
+ /** ID of the source node. */
21
+ private _sourceId: string | number;
22
+ /** ID of the target node. */
23
+ private _targetId: string | number;
24
+ /** Whether the edge is directed or not. */
25
+ private _directed: boolean;
26
+ /** Origin data reference of the edge. */
27
+ private _data: Record<string, unknown>;
28
+ /** Check the type of the object when picking engine gets it. */
29
+ public readonly isEdge = true;
30
+ /** Nodes at either end of this edge. */
31
+ private readonly _connectedNodes: Record<string, Node> = {};
32
+ /** Edge state. */
33
+ public state = EDGE_STATE.DEFAULT;
34
+
35
+ /**
36
+ * The constructor
37
+ * @param {String|Number} options.id - the unique ID of the edge
38
+ * @param {String|Number} options.sourceId - the ID of the source node
39
+ * @param {String|Number} options.targetId - the ID of the target node
40
+ * @param {Boolean} options.directed - whether the edge is directed or not
41
+ * @param {Record<string, unknown>} options.data - origin data reference
42
+ */
43
+ constructor({id, sourceId, targetId, data, directed = false}: EdgeOptions) {
44
+ this.id = id;
45
+ this._sourceId = sourceId;
46
+ this._targetId = targetId;
47
+ this._directed = directed;
48
+ this._data = data;
49
+ }
50
+
51
+ /**
52
+ * Return the ID of the edge
53
+ * @return {String|Number} - the ID of the edge.
54
+ */
55
+ getId(): string | number {
56
+ return this.id;
57
+ }
58
+
59
+ /**
60
+ * Return whether the edge is directed or not.
61
+ * @return {Boolean} true if the edge is directed.
62
+ */
63
+ isDirected(): boolean {
64
+ return this._directed;
65
+ }
66
+
67
+ /**
68
+ * Get the ID of the source node.
69
+ * @return {String|Number} the ID of the source node.
70
+ */
71
+ getSourceNodeId(): string | number {
72
+ return this._sourceId;
73
+ }
74
+
75
+ /**
76
+ * Get the ID of the target node.
77
+ * @return {String|Number} the ID of the target node.
78
+ */
79
+ getTargetNodeId(): string | number {
80
+ return this._targetId;
81
+ }
82
+
83
+ /**
84
+ * Return of the value of the selected property key.
85
+ * @param {String} key - property key.
86
+ * @return {Any} - the value of the property.
87
+ */
88
+ getPropertyValue(key: string): unknown {
89
+ // try to search the key within this object
90
+ if (this.hasOwnProperty(key)) {
91
+ return this[key];
92
+ }
93
+ // try to search the key in the original data reference
94
+ else if (this._data.hasOwnProperty(key)) {
95
+ return this._data[key];
96
+ }
97
+ // otherwise, not found
98
+ return undefined;
99
+ }
100
+
101
+ /**
102
+ * Set the origin data as a reference.
103
+ * @param {Object} data - the origin data.
104
+ */
105
+ setData(data: Record<string, unknown>): void {
106
+ this._data = data;
107
+ }
108
+
109
+ /**
110
+ * Update a data property.
111
+ * @param {String} key - the key of the property
112
+ * @param {Any} value - the value of the property.
113
+ */
114
+ setDataProperty(key: string, value: unknown): void {
115
+ this._data[key] = value;
116
+ }
117
+
118
+ /**
119
+ * Set edge state
120
+ * @param {String} state - one of EDGE_STATE
121
+ */
122
+ setState(state: string): void {
123
+ this.state = state;
124
+ }
125
+
126
+ /**
127
+ * Get edge state
128
+ * @returns {string} state - one of EDGE_STATE
129
+ */
130
+ getState(): string {
131
+ return this.state;
132
+ }
133
+
134
+ addNode(node: Node): void {
135
+ this._connectedNodes[node.getId()] = node;
136
+ }
137
+
138
+ removeNode(node: Node): void {
139
+ delete this._connectedNodes[node.getId()];
140
+ }
141
+
142
+ getConnectedNodes(): Node[] {
143
+ return Object.values(this._connectedNodes);
144
+ }
145
+ }
@@ -0,0 +1,170 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {BaseLayout} from './base-layout';
6
+ import {Cache} from './cache';
7
+ import {Edge} from './edge';
8
+ import {Graph} from './graph';
9
+
10
+ // Graph engine controls the graph data and layout calculation
11
+ export class GraphEngine extends EventTarget {
12
+ private readonly _graph: Graph;
13
+ private readonly _layout: BaseLayout;
14
+ private readonly _cache = new Cache<'nodes' | 'edges', Node[] | Edge[]>();
15
+ private _layoutDirty = false;
16
+ private _transactionInProgress = false;
17
+
18
+ constructor(graph: Graph, layout: BaseLayout) {
19
+ super();
20
+ this._graph = graph;
21
+ this._layout = layout;
22
+ }
23
+
24
+ /** Getters */
25
+
26
+ getNodes = (): Node[] => {
27
+ this._updateCache('nodes', () =>
28
+ this._graph.getNodes().filter((node) => this.getNodePosition(node))
29
+ );
30
+
31
+ return this._cache.get('nodes') as Node[];
32
+ };
33
+
34
+ getEdges = () => {
35
+ this._updateCache('edges', () =>
36
+ this._graph.getEdges().filter((edge) => this.getEdgePosition(edge))
37
+ );
38
+
39
+ return this._cache.get('edges') as Edge[];
40
+ };
41
+
42
+ getNodePosition = (node) => this._layout.getNodePosition(node);
43
+
44
+ getEdgePosition = (edge) => this._layout.getEdgePosition(edge);
45
+
46
+ getGraphVersion = () => this._graph.version;
47
+
48
+ getLayoutLastUpdate = () => this._layout.version;
49
+
50
+ getLayoutState = () => this._layout.state;
51
+
52
+ /** Operations on the graph */
53
+
54
+ lockNodePosition = (node, x, y) => this._layout.lockNodePosition(node, x, y);
55
+
56
+ unlockNodePosition = (node) => this._layout.unlockNodePosition(node);
57
+
58
+ /**
59
+ * @fires GraphEngine#onLayoutStart
60
+ */
61
+ _onLayoutStart = () => {
62
+ /**
63
+ * @event GraphEngine#onLayoutStart
64
+ * @type {CustomEvent}
65
+ */
66
+ this.dispatchEvent(new CustomEvent('onLayoutStart'));
67
+ };
68
+
69
+ /**
70
+ * @fires GraphEngine#onLayoutChange
71
+ */
72
+ _onLayoutChange = () => {
73
+ /**
74
+ * @event GraphEngine#onLayoutChange
75
+ * @type {CustomEvent}
76
+ */
77
+ this.dispatchEvent(new CustomEvent('onLayoutChange'));
78
+ };
79
+
80
+ /**
81
+ * @fires GraphEngine#onLayoutDone
82
+ */
83
+ _onLayoutDone = () => {
84
+ /**
85
+ * @event GraphEngine#onLayoutDone
86
+ * @type {CustomEvent}
87
+ */
88
+ this.dispatchEvent(new CustomEvent('onLayoutDone'));
89
+ };
90
+
91
+ /**
92
+ * @fires GraphEngine#onLayoutError
93
+ */
94
+ _onLayoutError = () => {
95
+ /**
96
+ * @event GraphEngine#onLayoutError
97
+ * @type {CustomEvent}
98
+ */
99
+ this.dispatchEvent(new CustomEvent('onLayoutError'));
100
+ };
101
+
102
+ _onGraphStructureChanged = (entity) => {
103
+ this._layoutDirty = true;
104
+ this._graphChanged();
105
+ };
106
+
107
+ _onTransactionStart = () => {
108
+ this._transactionInProgress = true;
109
+ };
110
+
111
+ _onTransactionEnd = () => {
112
+ this._transactionInProgress = false;
113
+ this._graphChanged();
114
+ };
115
+
116
+ /** Layout calculations */
117
+
118
+ run = () => {
119
+ // TODO: throw if running on a cleared engine
120
+
121
+ this._graph.addEventListener('transactionStart', this._onTransactionStart);
122
+ this._graph.addEventListener('transactionEnd', this._onTransactionEnd);
123
+ this._graph.addEventListener('onNodeAdded', this._onGraphStructureChanged);
124
+ this._graph.addEventListener('onNodeRemoved', this._onGraphStructureChanged);
125
+ this._graph.addEventListener('onEdgeAdded', this._onGraphStructureChanged);
126
+ this._graph.addEventListener('onEdgeRemoved', this._onGraphStructureChanged);
127
+
128
+ this._layout.addEventListener('onLayoutStart', this._onLayoutStart);
129
+ this._layout.addEventListener('onLayoutChange', this._onLayoutChange);
130
+ this._layout.addEventListener('onLayoutDone', this._onLayoutDone);
131
+ this._layout.addEventListener('onLayoutError', this._onLayoutError);
132
+
133
+ this._layout.initializeGraph(this._graph);
134
+ this._layout.start();
135
+ };
136
+
137
+ clear = () => {
138
+ this._graph.removeEventListener('transactionStart', this._onTransactionStart);
139
+ this._graph.removeEventListener('transactionEnd', this._onTransactionEnd);
140
+ this._graph.removeEventListener('onNodeAdded', this._onGraphStructureChanged);
141
+ this._graph.removeEventListener('onNodeRemoved', this._onGraphStructureChanged);
142
+ this._graph.removeEventListener('onEdgeAdded', this._onGraphStructureChanged);
143
+ this._graph.removeEventListener('onEdgeRemoved', this._onGraphStructureChanged);
144
+
145
+ this._layout.removeEventListener('onLayoutStart', this._onLayoutStart);
146
+ this._layout.removeEventListener('onLayoutChange', this._onLayoutChange);
147
+ this._layout.removeEventListener('onLayoutDone', this._onLayoutDone);
148
+ this._layout.removeEventListener('onLayoutError', this._onLayoutError);
149
+ };
150
+
151
+ resume = () => this._layout.resume();
152
+
153
+ stop = () => this._layout.stop();
154
+
155
+ _graphChanged = () => {
156
+ if (this._layoutDirty && !this._transactionInProgress) {
157
+ this._updateLayout();
158
+ }
159
+ };
160
+
161
+ _updateLayout = () => {
162
+ this._layout.updateGraph(this._graph);
163
+ this._layout.update();
164
+ this._layoutDirty = false;
165
+ };
166
+
167
+ _updateCache(key, updateValue) {
168
+ this._cache.set(key, updateValue, this._graph.version + this._layout.version);
169
+ }
170
+ }
@@ -0,0 +1,342 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {log} from '../utils/log';
6
+ import {Cache} from './cache';
7
+ import {Edge} from './edge';
8
+ import {Node} from './node';
9
+
10
+ // Basic graph data structure
11
+ export class Graph extends EventTarget {
12
+ /** List object of nodes. */
13
+ private _nodeMap: Record<string, Node> = {};
14
+ /** List of object edges. */
15
+ private _edgeMap: Record<string, Edge> = {};
16
+ /**
17
+ * Identifies whether performing dirty check when streaming new data. If
18
+ * the name of the graph is not specified, will fall back to current time stamp.
19
+ */
20
+ private _name: string = Date.now().toString();
21
+ /** Version the graph. A version is a number that is incremented every time the graph is updated. */
22
+ public version = 0;
23
+ /** Cached data: create array data from maps. */
24
+ private _cache = new Cache<'nodes' | 'edges', Node[] | Edge[]>();
25
+
26
+ /**
27
+ * The constructor of the Graph class.
28
+ * @param {Object} graph - copy the graph if this exists.
29
+ */
30
+ constructor(graph: Graph | null = null) {
31
+ super();
32
+
33
+ // copy the graph if it exists in the parameter
34
+ if (graph) {
35
+ // start copying the graph
36
+ this._nodeMap = graph._nodeMap;
37
+ this._edgeMap = graph._edgeMap;
38
+ this._name = graph && graph._name;
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Set graph name
44
+ * @param {string} name
45
+ */
46
+ setGraphName(name: string): void {
47
+ this._name = name;
48
+ }
49
+
50
+ /** Get the name of the graph. Default value is the time stamp when creating this graph.
51
+ * @return {string} graph name.
52
+ */
53
+ getGraphName(): string {
54
+ return this._name.toString();
55
+ }
56
+
57
+ /**
58
+ * Perform a batch of operations defined by cb before indicating graph is updated
59
+ * @param {function} cb - a callback fuction containing the operations to perform
60
+ */
61
+ transaction<T>(cb: (...args: unknown[]) => T): T {
62
+ try {
63
+ this.dispatchEvent(new CustomEvent('transactionStart'));
64
+ return cb();
65
+ } finally {
66
+ this.dispatchEvent(new CustomEvent('transactionEnd'));
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Add a new node to the graph.
72
+ * @param {Node} node - expect a Node object to be added to the graph.
73
+ */
74
+ addNode(node: Node): void {
75
+ // add it to the list and map
76
+ this._nodeMap[node.getId()] = node;
77
+ // update last update time stamp
78
+ this._bumpVersion();
79
+ this.dispatchEvent(new CustomEvent('onNodeAdded', {node} as any));
80
+ }
81
+
82
+ /**
83
+ * Batch add nodes to the graph.
84
+ * @param {Node[]} nodes - a list of nodes to be added.
85
+ */
86
+ batchAddNodes(nodes: Node[]): void {
87
+ // convert an array of objects to an object
88
+ this._nodeMap = nodes.reduce(
89
+ (res, node) => {
90
+ res[node.getId()] = node;
91
+ this.dispatchEvent(new CustomEvent('onNodeAdded', {node} as any));
92
+ return res;
93
+ },
94
+ {...this._nodeMap}
95
+ );
96
+ this._bumpVersion();
97
+ }
98
+
99
+ /**
100
+ * Get all the nodes of the graph.
101
+ * @return {Node[]} - get all the nodes in the graph.
102
+ */
103
+ getNodes(): Node[] {
104
+ this._updateCache('nodes', () => Object.values(this._nodeMap));
105
+
106
+ return this._cache.get('nodes') as Node[];
107
+ }
108
+
109
+ /**
110
+ * Get the node map of the graph. The key of the map is the ID of the nodes.
111
+ * @return {Object} - a map of nodes keyed by node IDs.
112
+ */
113
+ getNodeMap(): Record<string | number, Node> {
114
+ return this._nodeMap;
115
+ }
116
+
117
+ /**
118
+ * Find a node by id
119
+ * @param {String} nodeId The id of the node
120
+ * @return {Object} Node
121
+ */
122
+ findNode(nodeId: string | number): Node | undefined {
123
+ return this._nodeMap[nodeId];
124
+ }
125
+
126
+ /**
127
+ * Update the indicated node to the provided value
128
+ * @param {Node} node
129
+ */
130
+ updateNode(node: Node): void {
131
+ this._nodeMap[node.getId()] = node;
132
+ this._bumpVersion();
133
+ this.dispatchEvent(new CustomEvent('onNodeUpdated', {node} as any));
134
+ }
135
+
136
+ /**
137
+ * Add a new edge to the graph.
138
+ * @param {Edge} edge - expect a Edge object to be added to the graph.
139
+ */
140
+ addEdge(edge: Edge): void {
141
+ const sourceNode = this.findNode(edge.getSourceNodeId());
142
+ const targetNode = this.findNode(edge.getTargetNodeId());
143
+
144
+ if (!sourceNode || !targetNode) {
145
+ log.warn(`Unable to add edge ${edge.id}, source or target node is missing.`)();
146
+ return;
147
+ }
148
+
149
+ this._edgeMap[edge.getId()] = edge;
150
+ sourceNode.addConnectedEdges(edge);
151
+ targetNode.addConnectedEdges(edge);
152
+ this._bumpVersion();
153
+ this.dispatchEvent(new CustomEvent('onEdgeAdded', {edge} as any));
154
+ }
155
+
156
+ /**
157
+ * Batch add edges to the graph
158
+ * @param {Edge[]} edges - a list of edges to be added.
159
+ */
160
+ batchAddEdges(edges: Edge[]): void {
161
+ edges.forEach((edge) => this.addEdge(edge));
162
+ this._bumpVersion();
163
+ }
164
+
165
+ /**
166
+ * Update the indicated edge to the provided value
167
+ * @param {Edge} edge
168
+ */
169
+ updateEdge(edge: Edge): void {
170
+ this._edgeMap[edge.getId()] = edge;
171
+ this._bumpVersion();
172
+ this.dispatchEvent(new CustomEvent('onEdgeUpdated', {edge} as any));
173
+ }
174
+
175
+ /**
176
+ * Remove a node from the graph by node ID
177
+ * @param {String|Number} nodeId - the ID of the target node.
178
+ */
179
+ removeNode(nodeId: string | number): void {
180
+ const node = this.findNode(nodeId);
181
+ if (!node) {
182
+ log.warn(`Unable to remove node ${nodeId} - doesn't exist`)();
183
+ return;
184
+ }
185
+ // remove all edges connect to this node from map
186
+ node.getConnectedEdges().forEach((e) => {
187
+ delete this._edgeMap[e.getId()];
188
+ });
189
+ // remove the node from map
190
+ delete this._nodeMap[nodeId];
191
+ this._bumpVersion();
192
+ this.dispatchEvent(new CustomEvent('onNodeRemoved', {node} as any));
193
+ }
194
+
195
+ /**
196
+ * Get all the edges of the graph.
197
+ * @return {Edge[]} get all the edges in the graph.
198
+ */
199
+ getEdges(): Edge[] {
200
+ this._updateCache('edges', () => Object.values(this._edgeMap));
201
+
202
+ return this._cache.get('edges') as Edge[];
203
+ }
204
+
205
+ /**
206
+ * Get the edge map of the graph. The key of the map is the ID of the edges.
207
+ * @return {Object} - a map of edges keyed by edge IDs.
208
+ */
209
+ getEdgeMap(): Record<string, Edge> {
210
+ return this._edgeMap;
211
+ }
212
+
213
+ /**
214
+ * Remove an edge from the graph by the edge ID
215
+ * @param {String|Number} edgeId - the target edge ID.
216
+ */
217
+ removeEdge(edgeId: string | number): void {
218
+ const edge = this.findEdge(edgeId);
219
+ if (!edge) {
220
+ log.warn(`Unable to remove edge ${edgeId} - doesn't exist`)();
221
+ return;
222
+ }
223
+ const sourceNode = this.findNode(edge.getSourceNodeId());
224
+ const targetNode = this.findNode(edge.getTargetNodeId());
225
+
226
+ delete this._edgeMap[edgeId];
227
+ sourceNode.removeConnectedEdges(edge);
228
+ targetNode.removeConnectedEdges(edge);
229
+ this._bumpVersion();
230
+ }
231
+
232
+ /**
233
+ * Find the edge by edge ID.
234
+ * @param {String|Number} id - the target edge ID
235
+ * @return {Edge} - the target edge.
236
+ */
237
+ findEdge(edgeId: string | number): Edge {
238
+ return this._edgeMap[edgeId];
239
+ }
240
+
241
+ /**
242
+ * Return all the connected edges of a node by nodeID.
243
+ * @param {String|Number} nodeId - the target node ID
244
+ * @return {Edge[]} - an array of the connected edges.
245
+ */
246
+ getConnectedEdges(nodeId: string | number): Edge[] {
247
+ const node = this.findNode(nodeId);
248
+ if (!node) {
249
+ log.warn(`Unable to find node ${nodeId} - doesn't exist`)();
250
+ return [];
251
+ }
252
+ return node.getConnectedEdges();
253
+ }
254
+
255
+ /**
256
+ * Return all the sibling nodes of a node by nodeID.
257
+ * @param {String|Number} nodeId - the target node ID
258
+ * @return {Node[]} - an array of the sibling nodes.
259
+ */
260
+ getNodeSiblings(nodeId: string | number): Node[] {
261
+ const node = this.findNode(nodeId);
262
+ if (!node) {
263
+ log.warn(`Unable to find node ${nodeId} - doesn't exist`)();
264
+ return [];
265
+ }
266
+ return node.getSiblingIds().map((siblingNodeId) => this.findNode(siblingNodeId));
267
+ }
268
+
269
+ /**
270
+ * Get the degree of a node.
271
+ * @param {String|Number} nodeId - the target node ID.
272
+ * @return {Number} - the degree of the node.
273
+ */
274
+ getDegree(nodeId: string | number): number {
275
+ const node = this.findNode(nodeId);
276
+ if (!node) {
277
+ log.warn(`Unable to find node ${nodeId} - doesn't exist`)();
278
+ return 0;
279
+ }
280
+ return node.getDegree();
281
+ }
282
+
283
+ /**
284
+ * Clean up all the nodes in the graph.
285
+ */
286
+ resetNodes(): void {
287
+ this._nodeMap = {};
288
+ this._bumpVersion();
289
+ }
290
+
291
+ /**
292
+ * Clean up all the edges in the graph.
293
+ */
294
+ resetEdges(): void {
295
+ this._edgeMap = {};
296
+ this._bumpVersion();
297
+ }
298
+
299
+ /**
300
+ * Clean up everything in the graph.
301
+ */
302
+ reset(): void {
303
+ this.resetNodes();
304
+ this.resetEdges();
305
+ this._bumpVersion();
306
+ }
307
+
308
+ /**
309
+ * Trigger an update to the graph.
310
+ */
311
+ triggerUpdate(): void {
312
+ this._bumpVersion();
313
+ }
314
+
315
+ /**
316
+ * Return true if the graph is empty.
317
+ * @return {Boolean} Return true if the graph is empty.
318
+ */
319
+ isEmpty(): boolean {
320
+ return Object.keys(this._nodeMap).length === 0;
321
+ }
322
+
323
+ /**
324
+ * Check the equality of two graphs data by checking last update time stamp
325
+ * @param {Object} g Another graph to be compared against itself
326
+ * @return {Bool} True if the graph is the same as itself.
327
+ */
328
+ equals(g: Graph): boolean {
329
+ if (!g || !(g instanceof Graph)) {
330
+ return false;
331
+ }
332
+ return this.version === g.version;
333
+ }
334
+
335
+ _bumpVersion(): void {
336
+ this.version += 1;
337
+ }
338
+
339
+ _updateCache(key: 'nodes' | 'edges', updateValue: unknown): void {
340
+ this._cache.set(key, updateValue as any, this.version);
341
+ }
342
+ }