@deck.gl-community/graph-layers 9.2.0-beta.2 → 9.2.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 (232) hide show
  1. package/dist/core/graph-engine.d.ts +63 -21
  2. package/dist/core/graph-engine.d.ts.map +1 -1
  3. package/dist/core/graph-engine.js +155 -75
  4. package/dist/core/graph-engine.js.map +1 -1
  5. package/dist/core/graph-layout.d.ts +22 -18
  6. package/dist/core/graph-layout.d.ts.map +1 -1
  7. package/dist/core/graph-layout.js +33 -18
  8. package/dist/core/graph-layout.js.map +1 -1
  9. package/dist/core/interaction-manager.d.ts +2 -2
  10. package/dist/core/interaction-manager.d.ts.map +1 -1
  11. package/dist/core/interaction-manager.js +7 -5
  12. package/dist/core/interaction-manager.js.map +1 -1
  13. package/dist/graph/arrow-graph.d.ts +69 -0
  14. package/dist/graph/arrow-graph.d.ts.map +1 -0
  15. package/dist/graph/arrow-graph.js +513 -0
  16. package/dist/graph/arrow-graph.js.map +1 -0
  17. package/dist/graph/classic-graph.d.ts +169 -0
  18. package/dist/graph/classic-graph.d.ts.map +1 -0
  19. package/dist/graph/classic-graph.js +390 -0
  20. package/dist/graph/classic-graph.js.map +1 -0
  21. package/dist/graph/edge.d.ts +6 -6
  22. package/dist/graph/edge.d.ts.map +1 -1
  23. package/dist/graph/edge.js.map +1 -1
  24. package/dist/graph/functions/arrow-utils.d.ts +6 -0
  25. package/dist/graph/functions/arrow-utils.d.ts.map +1 -0
  26. package/dist/graph/functions/arrow-utils.js +67 -0
  27. package/dist/graph/functions/arrow-utils.js.map +1 -0
  28. package/dist/graph/functions/create-graph-from-data.d.ts +3 -0
  29. package/dist/graph/functions/create-graph-from-data.d.ts.map +1 -0
  30. package/dist/graph/functions/create-graph-from-data.js +12 -0
  31. package/dist/graph/functions/create-graph-from-data.js.map +1 -0
  32. package/dist/graph/graph-normalization.d.ts +10 -0
  33. package/dist/graph/graph-normalization.d.ts.map +1 -0
  34. package/dist/graph/graph-normalization.js +65 -0
  35. package/dist/graph/graph-normalization.js.map +1 -0
  36. package/dist/graph/graph.d.ts +62 -155
  37. package/dist/graph/graph.d.ts.map +1 -1
  38. package/dist/graph/graph.js +11 -300
  39. package/dist/graph/graph.js.map +1 -1
  40. package/dist/graph/node.d.ts +6 -6
  41. package/dist/graph/node.d.ts.map +1 -1
  42. package/dist/graph/node.js +2 -2
  43. package/dist/graph/node.js.map +1 -1
  44. package/dist/graph-data/arrow-graph-data-builder.d.ts +21 -0
  45. package/dist/graph-data/arrow-graph-data-builder.d.ts.map +1 -0
  46. package/dist/graph-data/arrow-graph-data-builder.js +105 -0
  47. package/dist/graph-data/arrow-graph-data-builder.js.map +1 -0
  48. package/dist/graph-data/graph-data-builder.d.ts +6 -0
  49. package/dist/graph-data/graph-data-builder.d.ts.map +1 -0
  50. package/dist/graph-data/graph-data-builder.js +1 -0
  51. package/dist/graph-data/graph-data-builder.js.map +1 -0
  52. package/dist/graph-data/graph-data.d.ts +40 -0
  53. package/dist/graph-data/graph-data.d.ts.map +1 -0
  54. package/dist/graph-data/graph-data.js +11 -0
  55. package/dist/graph-data/graph-data.js.map +1 -0
  56. package/dist/graph-data/plain-graph-data-builder.d.ts +20 -0
  57. package/dist/graph-data/plain-graph-data-builder.d.ts.map +1 -0
  58. package/dist/graph-data/plain-graph-data-builder.js +105 -0
  59. package/dist/graph-data/plain-graph-data-builder.js.map +1 -0
  60. package/dist/graph-style-schema.cdn.js +1 -1
  61. package/dist/graph-style-schema.json +1 -1
  62. package/dist/index.cjs +6905 -4576
  63. package/dist/index.cjs.map +4 -4
  64. package/dist/index.d.ts +14 -7
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +24 -11
  67. package/dist/index.js.map +1 -1
  68. package/dist/layers/common-layers/flow-path-layer/flow-path-layer.d.ts.map +1 -1
  69. package/dist/layers/common-layers/flow-path-layer/flow-path-layer.js +1 -2
  70. package/dist/layers/common-layers/flow-path-layer/flow-path-layer.js.map +1 -1
  71. package/dist/layers/common-layers/grid-layer/grid-layer.d.ts +83 -0
  72. package/dist/layers/common-layers/grid-layer/grid-layer.d.ts.map +1 -0
  73. package/dist/layers/common-layers/grid-layer/grid-layer.js +133 -0
  74. package/dist/layers/common-layers/grid-layer/grid-layer.js.map +1 -0
  75. package/dist/layers/edge-attachment-helper.d.ts.map +1 -1
  76. package/dist/layers/edge-attachment-helper.js +1 -2
  77. package/dist/layers/edge-attachment-helper.js.map +1 -1
  78. package/dist/layers/graph-layer.d.ts +68 -11
  79. package/dist/layers/graph-layer.d.ts.map +1 -1
  80. package/dist/layers/graph-layer.js +435 -50
  81. package/dist/layers/graph-layer.js.map +1 -1
  82. package/dist/layouts/d3-dag/collapsable-d3-dag-layout.d.ts +24 -0
  83. package/dist/layouts/d3-dag/collapsable-d3-dag-layout.d.ts.map +1 -0
  84. package/dist/layouts/d3-dag/collapsable-d3-dag-layout.js +251 -0
  85. package/dist/layouts/d3-dag/collapsable-d3-dag-layout.js.map +1 -0
  86. package/dist/layouts/d3-dag/d3-dag-layout.d.ts +46 -61
  87. package/dist/layouts/d3-dag/d3-dag-layout.d.ts.map +1 -1
  88. package/dist/layouts/d3-dag/d3-dag-layout.js +85 -270
  89. package/dist/layouts/d3-dag/d3-dag-layout.js.map +1 -1
  90. package/dist/layouts/d3-force/d3-force-layout.d.ts +20 -8
  91. package/dist/layouts/d3-force/d3-force-layout.d.ts.map +1 -1
  92. package/dist/layouts/d3-force/d3-force-layout.js +39 -20
  93. package/dist/layouts/d3-force/d3-force-layout.js.map +1 -1
  94. package/dist/layouts/experimental/force-multi-graph-layout.d.ts +19 -15
  95. package/dist/layouts/experimental/force-multi-graph-layout.d.ts.map +1 -1
  96. package/dist/layouts/experimental/force-multi-graph-layout.js +47 -38
  97. package/dist/layouts/experimental/force-multi-graph-layout.js.map +1 -1
  98. package/dist/layouts/experimental/hive-plot-layout.d.ts +18 -15
  99. package/dist/layouts/experimental/hive-plot-layout.d.ts.map +1 -1
  100. package/dist/layouts/experimental/hive-plot-layout.js +33 -34
  101. package/dist/layouts/experimental/hive-plot-layout.js.map +1 -1
  102. package/dist/layouts/experimental/radial-layout.d.ts +12 -7
  103. package/dist/layouts/experimental/radial-layout.d.ts.map +1 -1
  104. package/dist/layouts/experimental/radial-layout.js +31 -14
  105. package/dist/layouts/experimental/radial-layout.js.map +1 -1
  106. package/dist/layouts/gpu-force/gpu-force-layout.d.ts +11 -8
  107. package/dist/layouts/gpu-force/gpu-force-layout.d.ts.map +1 -1
  108. package/dist/layouts/gpu-force/gpu-force-layout.js +59 -56
  109. package/dist/layouts/gpu-force/gpu-force-layout.js.map +1 -1
  110. package/dist/layouts/simple-layout.d.ts +8 -25
  111. package/dist/layouts/simple-layout.d.ts.map +1 -1
  112. package/dist/layouts/simple-layout.js +13 -17
  113. package/dist/layouts/simple-layout.js.map +1 -1
  114. package/dist/loaders/dot-graph-loader.d.ts +25 -0
  115. package/dist/loaders/dot-graph-loader.d.ts.map +1 -0
  116. package/dist/loaders/dot-graph-loader.js +668 -0
  117. package/dist/loaders/dot-graph-loader.js.map +1 -0
  118. package/dist/loaders/json-graph-loader.d.ts +6 -0
  119. package/dist/loaders/json-graph-loader.d.ts.map +1 -0
  120. package/dist/loaders/json-graph-loader.js +31 -0
  121. package/dist/loaders/json-graph-loader.js.map +1 -0
  122. package/dist/loaders/{edge-parsers.d.ts → parsers/edge-parsers.d.ts} +1 -1
  123. package/dist/loaders/parsers/edge-parsers.d.ts.map +1 -0
  124. package/dist/loaders/{edge-parsers.js → parsers/edge-parsers.js} +1 -1
  125. package/dist/loaders/parsers/edge-parsers.js.map +1 -0
  126. package/dist/loaders/{node-parsers.d.ts → parsers/node-parsers.d.ts} +1 -1
  127. package/dist/loaders/parsers/node-parsers.d.ts.map +1 -0
  128. package/dist/loaders/{node-parsers.js → parsers/node-parsers.js} +1 -1
  129. package/dist/loaders/parsers/node-parsers.js.map +1 -0
  130. package/dist/loaders/parsers/parse-json-graph.d.ts +29 -0
  131. package/dist/loaders/parsers/parse-json-graph.d.ts.map +1 -0
  132. package/dist/loaders/parsers/parse-json-graph.js +78 -0
  133. package/dist/loaders/parsers/parse-json-graph.js.map +1 -0
  134. package/dist/style/graph-style-engine.d.ts +4 -2
  135. package/dist/style/graph-style-engine.d.ts.map +1 -1
  136. package/dist/style/graph-style-engine.js +3 -2
  137. package/dist/style/graph-style-engine.js.map +1 -1
  138. package/dist/style/{style-engine.d.ts → stylesheet-engine.d.ts} +3 -3
  139. package/dist/style/stylesheet-engine.d.ts.map +1 -0
  140. package/dist/style/{style-engine.js → stylesheet-engine.js} +1 -1
  141. package/dist/style/stylesheet-engine.js.map +1 -0
  142. package/dist/utils/collapsed-chains.d.ts +8 -8
  143. package/dist/utils/collapsed-chains.d.ts.map +1 -1
  144. package/dist/utils/collapsed-chains.js +1 -6
  145. package/dist/utils/collapsed-chains.js.map +1 -1
  146. package/dist/utils/rank-grid.d.ts +30 -0
  147. package/dist/utils/rank-grid.d.ts.map +1 -0
  148. package/dist/utils/rank-grid.js +306 -0
  149. package/dist/utils/rank-grid.js.map +1 -0
  150. package/package.json +4 -8
  151. package/src/_disabled/arrow-graph-data.ts.disabled +18 -0
  152. package/src/_disabled/columnar-graph-data-builder.ts.disabled +250 -0
  153. package/src/_disabled/graph-runtime-layout.ts.disabled +29 -0
  154. package/src/core/graph-engine.ts +201 -84
  155. package/src/core/graph-layout.ts +52 -29
  156. package/src/core/interaction-manager.ts +20 -20
  157. package/src/graph/arrow-graph.ts +648 -0
  158. package/src/graph/classic-graph.ts +447 -0
  159. package/src/graph/edge.ts +7 -7
  160. package/src/graph/functions/arrow-utils.ts +72 -0
  161. package/src/graph/functions/convert-arrow-graph-to-classic-graph.ts.disabled +47 -0
  162. package/src/graph/functions/convert-plain-graph-to-arrow-graph.ts.disabled +119 -0
  163. package/src/graph/functions/create-graph-from-data.ts +16 -0
  164. package/src/graph/functions/create-plain-graph-from-data.ts.disabled +176 -0
  165. package/src/graph/graph-normalization.ts +87 -0
  166. package/src/graph/graph.ts +68 -339
  167. package/src/graph/node.ts +9 -9
  168. package/src/graph/tabular-graph.ts.disabled +761 -0
  169. package/src/graph-data/arrow-graph-data-builder.ts +165 -0
  170. package/src/graph-data/graph-data-builder.ts +7 -0
  171. package/src/graph-data/graph-data.ts +57 -0
  172. package/src/graph-data/plain-graph-data-builder.ts +132 -0
  173. package/src/index.ts +53 -13
  174. package/src/layers/common-layers/flow-path-layer/flow-path-layer.ts +1 -2
  175. package/src/layers/common-layers/grid-layer/grid-layer.ts +237 -0
  176. package/src/layers/edge-attachment-helper.ts +22 -16
  177. package/src/layers/graph-layer.ts +642 -62
  178. package/src/layouts/d3-dag/collapsable-d3-dag-layout.ts +330 -0
  179. package/src/layouts/d3-dag/d3-dag-layout.ts +166 -396
  180. package/src/layouts/d3-force/d3-force-layout.ts +52 -30
  181. package/src/layouts/experimental/force-multi-graph-layout.ts +55 -49
  182. package/src/layouts/experimental/hive-plot-layout.ts +41 -42
  183. package/src/layouts/experimental/radial-layout.ts +39 -20
  184. package/src/layouts/gpu-force/gpu-force-layout.ts +72 -70
  185. package/src/layouts/simple-layout.ts +20 -44
  186. package/src/loaders/{create-graph.ts → deprecated/create-graph.ts.disabled} +6 -6
  187. package/src/loaders/deprecated/json-classic-graph-loader.ts.disabled +33 -0
  188. package/src/loaders/{simple-json-graph-loader.ts → deprecated/simple-json-graph-loader.ts.disabled} +3 -3
  189. package/src/loaders/{table-graph-loader.ts → deprecated/table-graph-loader.ts.disabled} +8 -8
  190. package/src/loaders/dot-graph-loader.ts +860 -0
  191. package/src/loaders/json-graph-loader.ts +48 -0
  192. package/src/loaders/parsers/create-graph-data.ts.disabled +45 -0
  193. package/src/loaders/{edge-parsers.ts → parsers/edge-parsers.ts} +2 -2
  194. package/src/loaders/{node-parsers.ts → parsers/node-parsers.ts} +2 -2
  195. package/src/loaders/parsers/parse-json-graph.ts +134 -0
  196. package/src/style/graph-style-engine.ts +5 -2
  197. package/src/style/{style-engine.ts → stylesheet-engine.ts} +3 -3
  198. package/src/utils/collapsed-chains.ts +11 -17
  199. package/src/utils/rank-grid.ts +426 -0
  200. package/dist/loaders/create-graph.d.ts +0 -12
  201. package/dist/loaders/create-graph.d.ts.map +0 -1
  202. package/dist/loaders/create-graph.js +0 -38
  203. package/dist/loaders/create-graph.js.map +0 -1
  204. package/dist/loaders/edge-parsers.d.ts.map +0 -1
  205. package/dist/loaders/edge-parsers.js.map +0 -1
  206. package/dist/loaders/json-loader.d.ts +0 -7
  207. package/dist/loaders/json-loader.d.ts.map +0 -1
  208. package/dist/loaders/json-loader.js +0 -16
  209. package/dist/loaders/json-loader.js.map +0 -1
  210. package/dist/loaders/node-parsers.d.ts.map +0 -1
  211. package/dist/loaders/node-parsers.js.map +0 -1
  212. package/dist/loaders/simple-json-graph-loader.d.ts +0 -11
  213. package/dist/loaders/simple-json-graph-loader.d.ts.map +0 -1
  214. package/dist/loaders/simple-json-graph-loader.js +0 -20
  215. package/dist/loaders/simple-json-graph-loader.js.map +0 -1
  216. package/dist/loaders/table-graph-loader.d.ts +0 -16
  217. package/dist/loaders/table-graph-loader.d.ts.map +0 -1
  218. package/dist/loaders/table-graph-loader.js +0 -91
  219. package/dist/loaders/table-graph-loader.js.map +0 -1
  220. package/dist/style/style-engine.d.ts.map +0 -1
  221. package/dist/style/style-engine.js.map +0 -1
  222. package/dist/widgets/long-press-button.d.ts +0 -12
  223. package/dist/widgets/long-press-button.d.ts.map +0 -1
  224. package/dist/widgets/long-press-button.js +0 -31
  225. package/dist/widgets/long-press-button.js.map +0 -1
  226. package/dist/widgets/view-control-widget.d.ts +0 -77
  227. package/dist/widgets/view-control-widget.d.ts.map +0 -1
  228. package/dist/widgets/view-control-widget.js +0 -197
  229. package/dist/widgets/view-control-widget.js.map +0 -1
  230. package/src/loaders/json-loader.ts +0 -19
  231. package/src/widgets/long-press-button.tsx +0 -50
  232. package/src/widgets/view-control-widget.tsx +0 -339
@@ -0,0 +1,761 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+
6
+ import type {EdgeState, NodeState} from '../core/constants';
7
+ import type {EdgeInterface, NodeInterface, GraphProps} from './graph';
8
+ import {Graph} from './graph';
9
+ import {ClassicGraph} from './classic-graph';
10
+ import {Node} from './node';
11
+ import {Edge} from './edge';
12
+
13
+ export interface TabularNodeAccessors<Handle> {
14
+ getId(this: void, node: Handle): string | number;
15
+ getState?(this: void, node: Handle): NodeState;
16
+ setState?(this: void, node: Handle, state: NodeState): void;
17
+ isSelectable?(this: void, node: Handle): boolean;
18
+ shouldHighlightConnectedEdges?(this: void, node: Handle): boolean;
19
+ getPropertyValue?(this: void, node: Handle, key: string): unknown;
20
+ setData?(this: void, node: Handle, data: Record<string, unknown>): void;
21
+ setDataProperty?(this: void, node: Handle, key: string, value: unknown): void;
22
+ getData?(this: void, node: Handle): Record<string, unknown> | null | undefined;
23
+ }
24
+
25
+ export interface TabularEdgeAccessors<Handle> {
26
+ getId(this: void, edge: Handle): string | number;
27
+ getSourceId(this: void, edge: Handle): string | number;
28
+ getTargetId(this: void, edge: Handle): string | number;
29
+ isDirected?(this: void, edge: Handle): boolean;
30
+ getState?(this: void, edge: Handle): EdgeState;
31
+ setState?(this: void, edge: Handle, state: EdgeState): void;
32
+ getPropertyValue?(this: void, edge: Handle, key: string): unknown;
33
+ setData?(this: void, edge: Handle, data: Record<string, unknown>): void;
34
+ setDataProperty?(this: void, edge: Handle, key: string, value: unknown): void;
35
+ getData?(this: void, edge: Handle): Record<string, unknown> | null | undefined;
36
+ }
37
+
38
+ export type TabularGraphAccessors<NodeHandle, EdgeHandle> = {
39
+ node: TabularNodeAccessors<NodeHandle>;
40
+ edge: TabularEdgeAccessors<EdgeHandle>;
41
+ };
42
+
43
+ export interface TabularGraphSource<NodeHandle = unknown, EdgeHandle = unknown> {
44
+ readonly version: number;
45
+ getNodes(): Iterable<NodeHandle>;
46
+ getEdges(): Iterable<EdgeHandle>;
47
+ getAccessors(): TabularGraphAccessors<NodeHandle, EdgeHandle>;
48
+ findNodeById?(id: string | number): NodeHandle | null | undefined;
49
+ }
50
+
51
+ export type NodeIndex = number;
52
+ export type EdgeIndex = number;
53
+
54
+ type TabularNodeRecord<Handle> = {
55
+ handle: Handle;
56
+ id: string | number;
57
+ state: NodeState;
58
+ selectable: boolean;
59
+ highlightConnectedEdges: boolean;
60
+ data: Record<string, unknown>;
61
+ connectedEdgeIndices: EdgeIndex[];
62
+ };
63
+
64
+ type TabularEdgeRecord<Handle> = {
65
+ handle: Handle;
66
+ id: string | number;
67
+ state: EdgeState;
68
+ directed: boolean;
69
+ sourceId: string | number;
70
+ targetId: string | number;
71
+ data: Record<string, unknown>;
72
+ };
73
+
74
+ export class TabularNode<NodeHandle = unknown, EdgeHandle = unknown> implements NodeInterface {
75
+ public readonly isNode = true;
76
+ public readonly index: NodeIndex;
77
+ public get id(): string | number {
78
+ return this.getId();
79
+ }
80
+
81
+ public get state(): NodeState {
82
+ return this.getState();
83
+ }
84
+
85
+ public set state(state: NodeState) {
86
+ this.setState(state);
87
+ }
88
+
89
+ private readonly graph: TabularGraph<NodeHandle, EdgeHandle>;
90
+
91
+ constructor(graph: TabularGraph<NodeHandle, EdgeHandle>, index: NodeIndex) {
92
+ this.graph = graph;
93
+ this.index = index;
94
+ }
95
+
96
+ getId(): string | number {
97
+ return this.graph.getNodeIdByIndex(this.index);
98
+ }
99
+
100
+ getDegree(): number {
101
+ return this.graph.getNodeDegreeByIndex(this.index);
102
+ }
103
+
104
+ getInDegree(): number {
105
+ return this.graph.getNodeInDegreeByIndex(this.index);
106
+ }
107
+
108
+ getOutDegree(): number {
109
+ return this.graph.getNodeOutDegreeByIndex(this.index);
110
+ }
111
+
112
+ getSiblingIds(): (string | number)[] {
113
+ return this.graph.getNodeSiblingIdsByIndex(this.index);
114
+ }
115
+
116
+ getConnectedEdges(): EdgeInterface[] {
117
+ return this.graph.getNodeConnectedEdgesByIndex(this.index);
118
+ }
119
+
120
+ addConnectedEdges(edge: EdgeInterface | EdgeInterface[]): void {
121
+ const edges = Array.isArray(edge) ? edge : [edge];
122
+ for (const candidate of edges) {
123
+ candidate.addNode(this);
124
+ }
125
+ }
126
+
127
+ removeConnectedEdges(edge: EdgeInterface | EdgeInterface[]): void {
128
+ const edges = Array.isArray(edge) ? edge : [edge];
129
+ for (const candidate of edges) {
130
+ candidate.removeNode(this);
131
+ }
132
+ }
133
+
134
+ clearConnectedEdges(): void {
135
+ const edges = this.getConnectedEdges();
136
+ for (const edge of edges) {
137
+ edge.removeNode(this);
138
+ }
139
+ }
140
+
141
+ getPropertyValue(key: string): unknown {
142
+ return this.graph.getNodePropertyValueByIndex(this.index, key);
143
+ }
144
+
145
+ setData(data: Record<string, unknown>): void {
146
+ this.graph.setNodeDataByIndex(this.index, data);
147
+ }
148
+
149
+ setDataProperty(key: string, value: unknown): void {
150
+ this.graph.setNodeDataPropertyByIndex(this.index, key, value);
151
+ }
152
+
153
+ setState(state: NodeState): void {
154
+ this.graph.setNodeStateByIndex(this.index, state);
155
+ }
156
+
157
+ getState(): NodeState {
158
+ return this.graph.getNodeStateByIndex(this.index);
159
+ }
160
+
161
+ isSelectable(): boolean {
162
+ return this.graph.isNodeSelectableByIndex(this.index);
163
+ }
164
+
165
+ shouldHighlightConnectedEdges(): boolean {
166
+ return this.graph.shouldHighlightConnectedEdgesByIndex(this.index);
167
+ }
168
+ }
169
+
170
+ type EdgeNodeReference = {
171
+ id: string | number;
172
+ node: NodeInterface;
173
+ };
174
+
175
+ export class TabularEdge<NodeHandle = unknown, EdgeHandle = unknown> implements EdgeInterface {
176
+ public readonly isEdge = true;
177
+ public readonly index: EdgeIndex;
178
+ public get id(): string | number {
179
+ return this.getId();
180
+ }
181
+
182
+ public get directed(): boolean {
183
+ return this.isDirected();
184
+ }
185
+
186
+ public get state(): EdgeState {
187
+ return this.getState();
188
+ }
189
+
190
+ public set state(state: EdgeState) {
191
+ this.setState(state);
192
+ }
193
+
194
+ private readonly graph: TabularGraph<NodeHandle, EdgeHandle>;
195
+ private _connectedNodes: Record<string, NodeInterface> = {};
196
+
197
+ constructor(
198
+ graph: TabularGraph<NodeHandle, EdgeHandle>,
199
+ index: EdgeIndex,
200
+ connectedNodes: EdgeNodeReference[] = []
201
+ ) {
202
+ this.graph = graph;
203
+ this.index = index;
204
+ for (const reference of connectedNodes) {
205
+ this._connectedNodes[reference.id] = reference.node;
206
+ }
207
+ }
208
+
209
+ getId(): string | number {
210
+ return this.graph.getEdgeIdByIndex(this.index);
211
+ }
212
+
213
+ isDirected(): boolean {
214
+ return this.graph.isEdgeDirectedByIndex(this.index);
215
+ }
216
+
217
+ getSourceNodeId(): string | number {
218
+ return this.graph.getEdgeSourceIdByIndex(this.index);
219
+ }
220
+
221
+ getTargetNodeId(): string | number {
222
+ return this.graph.getEdgeTargetIdByIndex(this.index);
223
+ }
224
+
225
+ getConnectedNodes(): NodeInterface[] {
226
+ return Object.values(this._connectedNodes);
227
+ }
228
+
229
+ addNode(node: NodeInterface): void {
230
+ this._connectedNodes[node.getId()] = node;
231
+ this.graph.registerEdgeForNode(node, this);
232
+ }
233
+
234
+ removeNode(node: NodeInterface): void {
235
+ delete this._connectedNodes[node.getId()];
236
+ this.graph.unregisterEdgeForNode(node, this);
237
+ }
238
+
239
+ getPropertyValue(key: string): unknown {
240
+ return this.graph.getEdgePropertyValueByIndex(this.index, key);
241
+ }
242
+
243
+ setData(data: Record<string, unknown>): void {
244
+ this.graph.setEdgeDataByIndex(this.index, data);
245
+ }
246
+
247
+ setDataProperty(key: string, value: unknown): void {
248
+ this.graph.setEdgeDataPropertyByIndex(this.index, key, value);
249
+ }
250
+
251
+ setState(state: EdgeState): void {
252
+ this.graph.setEdgeStateByIndex(this.index, state);
253
+ }
254
+
255
+ getState(): EdgeState {
256
+ return this.graph.getEdgeStateByIndex(this.index);
257
+ }
258
+ }
259
+
260
+ export class TabularGraph<NodeHandle = unknown, EdgeHandle = unknown> extends Graph {
261
+ private readonly source: TabularGraphSource<NodeHandle, EdgeHandle>;
262
+
263
+ private _nodes: TabularNode<NodeHandle, EdgeHandle>[] | null = null;
264
+ private _edges: TabularEdge<NodeHandle, EdgeHandle>[] | null = null;
265
+ private _nodeMap: Map<string | number, TabularNode<NodeHandle, EdgeHandle>> | null = null;
266
+ private _nodeTable: TabularNodeRecord<NodeHandle>[] | null = null;
267
+ private _edgeTable: TabularEdgeRecord<EdgeHandle>[] | null = null;
268
+ private _nodeIndices: WeakMap<NodeInterface, NodeIndex> = new WeakMap();
269
+ private _edgeIndices: WeakMap<EdgeInterface, EdgeIndex> = new WeakMap();
270
+ private _accessors: TabularGraphAccessors<NodeHandle, EdgeHandle> | null = null;
271
+ private _lastVersion = -1;
272
+
273
+ constructor(source: TabularGraphSource<NodeHandle, EdgeHandle>, props: GraphProps = {}) {
274
+ super(props);
275
+ this.source = source;
276
+ }
277
+
278
+ get version(): number {
279
+ return this.source.version;
280
+ }
281
+
282
+ getNodes(): Iterable<NodeInterface> {
283
+ this._synchronize();
284
+ return this._nodes ?? [];
285
+ }
286
+
287
+ getEdges(): Iterable<EdgeInterface> {
288
+ this._synchronize();
289
+ return this._edges ?? [];
290
+ }
291
+
292
+ findNode(id: string | number): NodeInterface | undefined {
293
+ this._synchronize();
294
+ return this._nodeMap?.get(id);
295
+ }
296
+
297
+ findNodeById(id: string | number): NodeInterface | undefined {
298
+ return this.findNode(id);
299
+ }
300
+
301
+ destroy(): void {
302
+ this._nodes = null;
303
+ this._edges = null;
304
+ this._nodeMap = null;
305
+ this._nodeTable = null;
306
+ this._edgeTable = null;
307
+ this._nodeIndices = new WeakMap();
308
+ this._edgeIndices = new WeakMap();
309
+ this._accessors = null;
310
+ }
311
+
312
+ toClassicGraph(): ClassicGraph {
313
+ this._synchronize();
314
+
315
+ const nodeTable = this._nodeTable ?? [];
316
+ const edgeTable = this._edgeTable ?? [];
317
+
318
+ const legacyNodes: Node[] = nodeTable.map((record) => {
319
+ const node = new Node({
320
+ id: record.id,
321
+ selectable: record.selectable,
322
+ highlightConnectedEdges: record.highlightConnectedEdges,
323
+ data: cloneRecord(record.data)
324
+ });
325
+ node.setState(record.state);
326
+ return node;
327
+ });
328
+
329
+ const legacyEdges: Edge[] = edgeTable.map((record) => {
330
+ const edge = new Edge({
331
+ id: record.id,
332
+ sourceId: record.sourceId,
333
+ targetId: record.targetId,
334
+ directed: record.directed,
335
+ data: cloneRecord(record.data)
336
+ });
337
+ edge.setState(record.state);
338
+ return edge;
339
+ });
340
+
341
+ const graph = new ClassicGraph(this.props);
342
+ if (legacyNodes.length > 0) {
343
+ graph.batchAddNodes(legacyNodes);
344
+ }
345
+ if (legacyEdges.length > 0) {
346
+ graph.batchAddEdges(legacyEdges);
347
+ }
348
+ return graph;
349
+ }
350
+
351
+ getNodeIdByIndex(index: NodeIndex): string | number {
352
+ return this._getNodeRecord(index).id;
353
+ }
354
+
355
+ getNodeStateByIndex(index: NodeIndex): NodeState {
356
+ return this._getNodeRecord(index).state;
357
+ }
358
+
359
+ setNodeStateByIndex(index: NodeIndex, state: NodeState): void {
360
+ const record = this._getNodeRecord(index);
361
+ record.state = state;
362
+ const accessors = this._getAccessors();
363
+ accessors.node.setState?.(record.handle, state);
364
+ }
365
+
366
+ isNodeSelectableByIndex(index: NodeIndex): boolean {
367
+ return this._getNodeRecord(index).selectable;
368
+ }
369
+
370
+ shouldHighlightConnectedEdgesByIndex(index: NodeIndex): boolean {
371
+ return this._getNodeRecord(index).highlightConnectedEdges;
372
+ }
373
+
374
+ getNodeDegreeByIndex(index: NodeIndex): number {
375
+ return this._getNodeRecord(index).connectedEdgeIndices.length;
376
+ }
377
+
378
+ getNodeInDegreeByIndex(index: NodeIndex): number {
379
+ const nodeId = this.getNodeIdByIndex(index);
380
+ return this._getNodeRecord(index).connectedEdgeIndices.reduce((count, edgeIndex) => {
381
+ const edgeRecord = this._getEdgeRecord(edgeIndex);
382
+ if (edgeRecord.directed && edgeRecord.targetId === nodeId) {
383
+ return count + 1;
384
+ }
385
+ return count;
386
+ }, 0);
387
+ }
388
+
389
+ getNodeOutDegreeByIndex(index: NodeIndex): number {
390
+ const nodeId = this.getNodeIdByIndex(index);
391
+ return this._getNodeRecord(index).connectedEdgeIndices.reduce((count, edgeIndex) => {
392
+ const edgeRecord = this._getEdgeRecord(edgeIndex);
393
+ if (edgeRecord.directed && edgeRecord.sourceId === nodeId) {
394
+ return count + 1;
395
+ }
396
+ return count;
397
+ }, 0);
398
+ }
399
+
400
+ getNodeSiblingIdsByIndex(index: NodeIndex): (string | number)[] {
401
+ const nodeId = this.getNodeIdByIndex(index);
402
+ return this._getNodeRecord(index).connectedEdgeIndices.reduce<(string | number)[]>(
403
+ (siblings, edgeIndex) => {
404
+ const edgeRecord = this._getEdgeRecord(edgeIndex);
405
+ if (edgeRecord.targetId === nodeId) {
406
+ siblings.push(edgeRecord.sourceId);
407
+ } else {
408
+ siblings.push(edgeRecord.targetId);
409
+ }
410
+ return siblings;
411
+ },
412
+ []
413
+ );
414
+ }
415
+
416
+ getNodeConnectedEdgesByIndex(index: NodeIndex): EdgeInterface[] {
417
+ const edges = this._edges ?? [];
418
+ const record = this._getNodeRecord(index);
419
+ return record.connectedEdgeIndices
420
+ .map((edgeIndex) => edges[edgeIndex])
421
+ .filter((edge): edge is TabularEdge<NodeHandle, EdgeHandle> => Boolean(edge));
422
+ }
423
+
424
+ setNodeDataByIndex(index: NodeIndex, data: Record<string, unknown>): void {
425
+ const record = this._getNodeRecord(index);
426
+ record.data = {...data};
427
+ const accessors = this._getAccessors();
428
+ accessors.node.setData?.(record.handle, record.data);
429
+ }
430
+
431
+ setNodeDataPropertyByIndex(index: NodeIndex, key: string, value: unknown): void {
432
+ const record = this._getNodeRecord(index);
433
+ record.data = {...record.data, [key]: value};
434
+ const accessors = this._getAccessors();
435
+ if (accessors.node.setDataProperty) {
436
+ accessors.node.setDataProperty(record.handle, key, value);
437
+ } else if (accessors.node.setData) {
438
+ accessors.node.setData(record.handle, record.data);
439
+ }
440
+ }
441
+
442
+ getNodeDataByIndex(index: NodeIndex): Record<string, unknown> {
443
+ return {...this._getNodeRecord(index).data};
444
+ }
445
+
446
+ getNodePropertyValueByIndex(index: NodeIndex, key: string): unknown {
447
+ const record = this._getNodeRecord(index);
448
+ // eslint-disable-next-line @typescript-eslint/unbound-method
449
+ const accessor = this._getAccessors().node.getPropertyValue;
450
+ if (accessor) {
451
+ const value = accessor(record.handle, key);
452
+ if (value !== undefined) {
453
+ return value;
454
+ }
455
+ }
456
+ return record.data[key];
457
+ }
458
+
459
+ registerEdgeForNode(node: NodeInterface, edge: EdgeInterface): void {
460
+ const nodeIndex = this._findNodeIndex(node);
461
+ const edgeIndex = this._findEdgeIndex(edge);
462
+ if (nodeIndex === undefined || edgeIndex === undefined) {
463
+ return;
464
+ }
465
+ const record = this._getNodeRecord(nodeIndex);
466
+ if (!record.connectedEdgeIndices.includes(edgeIndex)) {
467
+ record.connectedEdgeIndices = [...record.connectedEdgeIndices, edgeIndex];
468
+ }
469
+ }
470
+
471
+ unregisterEdgeForNode(node: NodeInterface, edge: EdgeInterface): void {
472
+ const nodeIndex = this._findNodeIndex(node);
473
+ const edgeIndex = this._findEdgeIndex(edge);
474
+ if (nodeIndex === undefined || edgeIndex === undefined) {
475
+ return;
476
+ }
477
+ const record = this._getNodeRecord(nodeIndex);
478
+ record.connectedEdgeIndices = record.connectedEdgeIndices.filter((idx) => idx !== edgeIndex);
479
+ }
480
+
481
+ getEdgeIdByIndex(index: EdgeIndex): string | number {
482
+ return this._getEdgeRecord(index).id;
483
+ }
484
+
485
+ getEdgeStateByIndex(index: EdgeIndex): EdgeState {
486
+ return this._getEdgeRecord(index).state;
487
+ }
488
+
489
+ setEdgeStateByIndex(index: EdgeIndex, state: EdgeState): void {
490
+ const record = this._getEdgeRecord(index);
491
+ record.state = state;
492
+ const accessors = this._getAccessors();
493
+ accessors.edge.setState?.(record.handle, state);
494
+ }
495
+
496
+ isEdgeDirectedByIndex(index: EdgeIndex): boolean {
497
+ return this._getEdgeRecord(index).directed;
498
+ }
499
+
500
+ getEdgeSourceIdByIndex(index: EdgeIndex): string | number {
501
+ return this._getEdgeRecord(index).sourceId;
502
+ }
503
+
504
+ getEdgeTargetIdByIndex(index: EdgeIndex): string | number {
505
+ return this._getEdgeRecord(index).targetId;
506
+ }
507
+
508
+ getEdgePropertyValueByIndex(index: EdgeIndex, key: string): unknown {
509
+ const record = this._getEdgeRecord(index);
510
+ // eslint-disable-next-line @typescript-eslint/unbound-method
511
+ const accessor = this._getAccessors().edge.getPropertyValue;
512
+ if (accessor) {
513
+ const value = accessor(record.handle, key);
514
+ if (value !== undefined) {
515
+ return value;
516
+ }
517
+ }
518
+ return record.data[key];
519
+ }
520
+
521
+ setEdgeDataByIndex(index: EdgeIndex, data: Record<string, unknown>): void {
522
+ const record = this._getEdgeRecord(index);
523
+ record.data = {...data};
524
+ const accessors = this._getAccessors();
525
+ accessors.edge.setData?.(record.handle, record.data);
526
+ }
527
+
528
+ setEdgeDataPropertyByIndex(index: EdgeIndex, key: string, value: unknown): void {
529
+ const record = this._getEdgeRecord(index);
530
+ record.data = {...record.data, [key]: value};
531
+ const accessors = this._getAccessors();
532
+ if (accessors.edge.setDataProperty) {
533
+ accessors.edge.setDataProperty(record.handle, key, value);
534
+ } else if (accessors.edge.setData) {
535
+ accessors.edge.setData(record.handle, record.data);
536
+ }
537
+ }
538
+
539
+ getEdgeDataByIndex(index: EdgeIndex): Record<string, unknown> {
540
+ return {...this._getEdgeRecord(index).data};
541
+ }
542
+
543
+ private _synchronize(): void {
544
+ if (
545
+ this._lastVersion === this.source.version &&
546
+ this._nodes &&
547
+ this._edges &&
548
+ this._nodeMap &&
549
+ this._nodeTable &&
550
+ this._edgeTable
551
+ ) {
552
+ return;
553
+ }
554
+
555
+ const {nodes, edges, nodeMap, nodeTable, edgeTable, nodeIndices, edgeIndices, accessors} =
556
+ this._createEntities();
557
+ this._nodes = nodes;
558
+ this._edges = edges;
559
+ this._nodeMap = nodeMap;
560
+ this._nodeTable = nodeTable;
561
+ this._edgeTable = edgeTable;
562
+ this._nodeIndices = nodeIndices;
563
+ this._edgeIndices = edgeIndices;
564
+ this._accessors = accessors;
565
+ this._lastVersion = this.source.version;
566
+ }
567
+
568
+ // eslint-disable-next-line max-statements
569
+ private _createEntities(): {
570
+ nodes: TabularNode<NodeHandle, EdgeHandle>[];
571
+ edges: TabularEdge<NodeHandle, EdgeHandle>[];
572
+ nodeMap: Map<string | number, TabularNode<NodeHandle, EdgeHandle>>;
573
+ nodeTable: TabularNodeRecord<NodeHandle>[];
574
+ edgeTable: TabularEdgeRecord<EdgeHandle>[];
575
+ nodeIndices: WeakMap<NodeInterface, NodeIndex>;
576
+ edgeIndices: WeakMap<EdgeInterface, EdgeIndex>;
577
+ accessors: TabularGraphAccessors<NodeHandle, EdgeHandle>;
578
+ } {
579
+ const accessors = this.source.getAccessors();
580
+ const {nodeTable, nodes, nodeMap, nodeIndexById, nodeIndices} = this._buildNodeEntities(accessors);
581
+ const {edgeTable, edges, edgeIndices} = this._buildEdgeEntities(
582
+ accessors,
583
+ nodeTable,
584
+ nodes,
585
+ nodeIndexById
586
+ );
587
+
588
+ return {nodes, edges, nodeMap, nodeTable, edgeTable, nodeIndices, edgeIndices, accessors};
589
+ }
590
+
591
+ private _buildNodeEntities(accessors: TabularGraphAccessors<NodeHandle, EdgeHandle>): {
592
+ nodeTable: TabularNodeRecord<NodeHandle>[];
593
+ nodes: TabularNode<NodeHandle, EdgeHandle>[];
594
+ nodeMap: Map<string | number, TabularNode<NodeHandle, EdgeHandle>>;
595
+ nodeIndexById: Map<string | number, NodeIndex>;
596
+ nodeIndices: WeakMap<NodeInterface, NodeIndex>;
597
+ } {
598
+ const nodeTable: TabularNodeRecord<NodeHandle>[] = [];
599
+ const nodes: TabularNode<NodeHandle, EdgeHandle>[] = [];
600
+ const nodeMap = new Map<string | number, TabularNode<NodeHandle, EdgeHandle>>();
601
+ const nodeIndexById = new Map<string | number, NodeIndex>();
602
+ const nodeIndices = new WeakMap<NodeInterface, NodeIndex>();
603
+
604
+ let nodeIndex: NodeIndex = 0;
605
+ for (const handle of this.source.getNodes()) {
606
+ const id = accessors.node.getId(handle);
607
+ const selectable = Boolean(accessors.node.isSelectable?.(handle));
608
+ const highlightConnectedEdges = Boolean(
609
+ accessors.node.shouldHighlightConnectedEdges?.(handle)
610
+ );
611
+ const state = accessors.node.getState?.(handle) ?? 'default';
612
+ const data = cloneRecord(accessors.node.getData?.(handle));
613
+
614
+ nodeTable.push({
615
+ handle,
616
+ id,
617
+ selectable,
618
+ highlightConnectedEdges,
619
+ state,
620
+ data,
621
+ connectedEdgeIndices: []
622
+ });
623
+
624
+ const node = new TabularNode<NodeHandle, EdgeHandle>(this, nodeIndex);
625
+ nodes.push(node);
626
+ nodeMap.set(id, node);
627
+ nodeIndexById.set(id, nodeIndex);
628
+ nodeIndices.set(node, nodeIndex);
629
+ nodeIndex += 1;
630
+ }
631
+
632
+ return {nodeTable, nodes, nodeMap, nodeIndexById, nodeIndices};
633
+ }
634
+
635
+ private _buildEdgeEntities(
636
+ accessors: TabularGraphAccessors<NodeHandle, EdgeHandle>,
637
+ nodeTable: TabularNodeRecord<NodeHandle>[],
638
+ nodes: TabularNode<NodeHandle, EdgeHandle>[],
639
+ nodeIndexById: Map<string | number, NodeIndex>
640
+ ): {
641
+ edgeTable: TabularEdgeRecord<EdgeHandle>[];
642
+ edges: TabularEdge<NodeHandle, EdgeHandle>[];
643
+ edgeIndices: WeakMap<EdgeInterface, EdgeIndex>;
644
+ } {
645
+ const edgeTable: TabularEdgeRecord<EdgeHandle>[] = [];
646
+ const edges: TabularEdge<NodeHandle, EdgeHandle>[] = [];
647
+ const edgeIndices = new WeakMap<EdgeInterface, EdgeIndex>();
648
+
649
+ let edgeIndex: EdgeIndex = 0;
650
+ for (const handle of this.source.getEdges()) {
651
+ const id = accessors.edge.getId(handle);
652
+ const sourceId = accessors.edge.getSourceId(handle);
653
+ const targetId = accessors.edge.getTargetId(handle);
654
+ const directed = Boolean(accessors.edge.isDirected?.(handle));
655
+ const state = accessors.edge.getState?.(handle) ?? 'default';
656
+ const data = cloneRecord(accessors.edge.getData?.(handle));
657
+
658
+ const connectedNodes = this._resolveConnectedNodes({
659
+ nodeTable,
660
+ nodes,
661
+ nodeIndexById,
662
+ sourceId,
663
+ targetId,
664
+ edgeIndex
665
+ });
666
+
667
+ edgeTable.push({
668
+ handle,
669
+ id,
670
+ sourceId,
671
+ targetId,
672
+ directed,
673
+ state,
674
+ data
675
+ });
676
+
677
+ const edge = new TabularEdge<NodeHandle, EdgeHandle>(this, edgeIndex, connectedNodes);
678
+ edges.push(edge);
679
+ edgeIndices.set(edge, edgeIndex);
680
+ edgeIndex += 1;
681
+ }
682
+
683
+ return {edgeTable, edges, edgeIndices};
684
+ }
685
+
686
+ private _resolveConnectedNodes({
687
+ nodeTable,
688
+ nodes,
689
+ nodeIndexById,
690
+ sourceId,
691
+ targetId,
692
+ edgeIndex
693
+ }: {
694
+ nodeTable: TabularNodeRecord<NodeHandle>[];
695
+ nodes: TabularNode<NodeHandle, EdgeHandle>[];
696
+ nodeIndexById: Map<string | number, NodeIndex>;
697
+ sourceId: string | number;
698
+ targetId: string | number;
699
+ edgeIndex: EdgeIndex;
700
+ }): EdgeNodeReference[] {
701
+ const connectedNodes: EdgeNodeReference[] = [];
702
+ const sourceIndex = nodeIndexById.get(sourceId);
703
+ if (sourceIndex !== undefined) {
704
+ nodeTable[sourceIndex].connectedEdgeIndices.push(edgeIndex);
705
+ connectedNodes.push({
706
+ id: nodeTable[sourceIndex].id,
707
+ node: nodes[sourceIndex]
708
+ });
709
+ }
710
+ const targetIndex = nodeIndexById.get(targetId);
711
+ if (targetIndex !== undefined) {
712
+ nodeTable[targetIndex].connectedEdgeIndices.push(edgeIndex);
713
+ if (targetIndex !== sourceIndex) {
714
+ connectedNodes.push({
715
+ id: nodeTable[targetIndex].id,
716
+ node: nodes[targetIndex]
717
+ });
718
+ }
719
+ }
720
+
721
+ return connectedNodes;
722
+ }
723
+
724
+ private _getNodeRecord(index: NodeIndex): TabularNodeRecord<NodeHandle> {
725
+ if (!this._nodeTable || !this._nodeTable[index]) {
726
+ throw new Error(`Node record not found for index ${index}`);
727
+ }
728
+ return this._nodeTable[index];
729
+ }
730
+
731
+ private _getEdgeRecord(index: EdgeIndex): TabularEdgeRecord<EdgeHandle> {
732
+ if (!this._edgeTable || !this._edgeTable[index]) {
733
+ throw new Error(`Edge record not found for index ${index}`);
734
+ }
735
+ return this._edgeTable[index];
736
+ }
737
+
738
+ private _getAccessors(): TabularGraphAccessors<NodeHandle, EdgeHandle> {
739
+ if (!this._accessors) {
740
+ this._accessors = this.source.getAccessors();
741
+ }
742
+ return this._accessors;
743
+ }
744
+
745
+ private _findEdgeIndex(edge: EdgeInterface): EdgeIndex | undefined {
746
+ return this._edgeIndices.get(edge);
747
+ }
748
+
749
+ private _findNodeIndex(node: NodeInterface): NodeIndex | undefined {
750
+ return this._nodeIndices.get(node);
751
+ }
752
+ }
753
+
754
+ function cloneRecord(
755
+ value: Record<string, unknown> | null | undefined
756
+ ): Record<string, unknown> {
757
+ if (!value || typeof value !== 'object') {
758
+ return {};
759
+ }
760
+ return {...value};
761
+ }