@deck.gl-community/graph-layers 9.1.1 → 9.2.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/dist/_deprecated/old-constants.d.ts +107 -0
  2. package/dist/_deprecated/old-constants.d.ts.map +1 -0
  3. package/dist/_deprecated/old-constants.js +111 -0
  4. package/dist/_deprecated/old-constants.js.map +1 -0
  5. package/dist/core/cache.d.ts +0 -1
  6. package/dist/core/cache.js +0 -1
  7. package/dist/core/constants.d.ts +12 -100
  8. package/dist/core/constants.d.ts.map +1 -1
  9. package/dist/core/constants.js +3 -44
  10. package/dist/core/constants.js.map +1 -1
  11. package/dist/core/graph-engine.d.ts +12 -11
  12. package/dist/core/graph-engine.d.ts.map +1 -1
  13. package/dist/core/graph-engine.js +22 -11
  14. package/dist/core/graph-engine.js.map +1 -1
  15. package/dist/core/graph-layout.d.ts +48 -21
  16. package/dist/core/graph-layout.d.ts.map +1 -1
  17. package/dist/core/graph-layout.js +91 -24
  18. package/dist/core/graph-layout.js.map +1 -1
  19. package/dist/core/interaction-manager.d.ts +6 -4
  20. package/dist/core/interaction-manager.d.ts.map +1 -1
  21. package/dist/core/interaction-manager.js +59 -17
  22. package/dist/core/interaction-manager.js.map +1 -1
  23. package/dist/graph/edge.d.ts +7 -7
  24. package/dist/graph/edge.d.ts.map +1 -1
  25. package/dist/graph/edge.js +3 -6
  26. package/dist/graph/edge.js.map +1 -1
  27. package/dist/graph/graph.d.ts +2 -3
  28. package/dist/graph/graph.js +8 -9
  29. package/dist/graph/graph.js.map +1 -1
  30. package/dist/graph/node.d.ts +7 -8
  31. package/dist/graph/node.d.ts.map +1 -1
  32. package/dist/graph/node.js +3 -5
  33. package/dist/graph/node.js.map +1 -1
  34. package/dist/graph-style-schema.cdn.d.ts +2 -0
  35. package/dist/graph-style-schema.cdn.js +2 -0
  36. package/dist/graph-style-schema.json +12 -0
  37. package/dist/index.cjs +2821 -549
  38. package/dist/index.cjs.map +4 -4
  39. package/dist/index.d.ts +28 -22
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +25 -21
  42. package/dist/index.js.map +1 -1
  43. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-fragment.glsl.d.ts +0 -1
  44. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-fragment.glsl.js +0 -1
  45. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex-tf.glsl.d.ts +0 -1
  46. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex-tf.glsl.js +0 -1
  47. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex.glsl.d.ts +0 -1
  48. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex.glsl.js +0 -1
  49. package/dist/layers/common-layers/flow-path-layer/flow-path-layer.d.ts +0 -1
  50. package/dist/layers/common-layers/flow-path-layer/flow-path-layer.js +0 -1
  51. package/dist/layers/common-layers/marker-layer/atlas-data-url.d.ts +0 -1
  52. package/dist/layers/common-layers/marker-layer/atlas-data-url.js +0 -1
  53. package/dist/layers/common-layers/marker-layer/marker-layer.d.ts +0 -1
  54. package/dist/layers/common-layers/marker-layer/marker-layer.js +2 -3
  55. package/dist/layers/common-layers/marker-layer/marker-list.d.ts +2 -63
  56. package/dist/layers/common-layers/marker-layer/marker-list.d.ts.map +1 -1
  57. package/dist/layers/common-layers/marker-layer/marker-list.js +1 -65
  58. package/dist/layers/common-layers/marker-layer/marker-list.js.map +1 -1
  59. package/dist/layers/common-layers/marker-layer/marker-mapping.d.ts +0 -1
  60. package/dist/layers/common-layers/marker-layer/marker-mapping.js +0 -1
  61. package/dist/layers/common-layers/spline-layer/spline-layer.d.ts +0 -1
  62. package/dist/layers/common-layers/spline-layer/spline-layer.js +0 -1
  63. package/dist/layers/common-layers/zoomable-text-layer/zoomable-text-layer.d.ts +0 -1
  64. package/dist/layers/common-layers/zoomable-text-layer/zoomable-text-layer.js +0 -1
  65. package/dist/layers/edge-attachment-helper.d.ts +15 -0
  66. package/dist/layers/edge-attachment-helper.d.ts.map +1 -0
  67. package/dist/layers/edge-attachment-helper.js +230 -0
  68. package/dist/layers/edge-attachment-helper.js.map +1 -0
  69. package/dist/layers/edge-layer.d.ts +1 -5
  70. package/dist/layers/edge-layer.d.ts.map +1 -1
  71. package/dist/layers/edge-layer.js +9 -11
  72. package/dist/layers/edge-layer.js.map +1 -1
  73. package/dist/layers/edge-layers/arrow-2d-geometry.d.ts +4 -0
  74. package/dist/layers/edge-layers/arrow-2d-geometry.d.ts.map +1 -0
  75. package/dist/layers/edge-layers/arrow-2d-geometry.js +42 -0
  76. package/dist/layers/edge-layers/arrow-2d-geometry.js.map +1 -0
  77. package/dist/layers/edge-layers/curved-edge-layer.d.ts +1 -2
  78. package/dist/layers/edge-layers/curved-edge-layer.js +1 -2
  79. package/dist/layers/edge-layers/edge-arrow-layer.d.ts +21 -0
  80. package/dist/layers/edge-layers/edge-arrow-layer.d.ts.map +1 -0
  81. package/dist/layers/edge-layers/edge-arrow-layer.js +131 -0
  82. package/dist/layers/edge-layers/edge-arrow-layer.js.map +1 -0
  83. package/dist/layers/edge-layers/edge-label-layer.d.ts +1 -2
  84. package/dist/layers/edge-layers/edge-label-layer.js +1 -2
  85. package/dist/layers/edge-layers/flow-layer.d.ts +1 -2
  86. package/dist/layers/edge-layers/flow-layer.js +1 -2
  87. package/dist/layers/edge-layers/path-edge-layer.d.ts +0 -1
  88. package/dist/layers/edge-layers/path-edge-layer.js +0 -1
  89. package/dist/layers/edge-layers/straight-line-edge-layer.d.ts +0 -1
  90. package/dist/layers/edge-layers/straight-line-edge-layer.js +0 -1
  91. package/dist/layers/graph-layer.d.ts +22 -23
  92. package/dist/layers/graph-layer.d.ts.map +1 -1
  93. package/dist/layers/graph-layer.js +218 -62
  94. package/dist/layers/graph-layer.js.map +1 -1
  95. package/dist/layers/node-layers/circle-layer.d.ts +0 -1
  96. package/dist/layers/node-layers/circle-layer.js +0 -1
  97. package/dist/layers/node-layers/image-layer.d.ts +0 -1
  98. package/dist/layers/node-layers/image-layer.js +0 -1
  99. package/dist/layers/node-layers/label-layer.d.ts +1 -2
  100. package/dist/layers/node-layers/label-layer.js +1 -2
  101. package/dist/layers/node-layers/path-rounded-rectangle-layer.d.ts +0 -1
  102. package/dist/layers/node-layers/path-rounded-rectangle-layer.js +1 -2
  103. package/dist/layers/node-layers/rectangle-layer.d.ts +0 -1
  104. package/dist/layers/node-layers/rectangle-layer.js +0 -1
  105. package/dist/layers/node-layers/rounded-rectangle-layer-fragment.d.ts +0 -1
  106. package/dist/layers/node-layers/rounded-rectangle-layer-fragment.js +0 -1
  107. package/dist/layers/node-layers/rounded-rectangle-layer.d.ts +1 -2
  108. package/dist/layers/node-layers/rounded-rectangle-layer.js +2 -3
  109. package/dist/layers/node-layers/zoomable-marker-layer.d.ts +1 -2
  110. package/dist/layers/node-layers/zoomable-marker-layer.js +1 -2
  111. package/dist/layouts/d3-dag/d3-dag-layout.d.ts +117 -0
  112. package/dist/layouts/d3-dag/d3-dag-layout.d.ts.map +1 -0
  113. package/dist/layouts/d3-dag/d3-dag-layout.js +716 -0
  114. package/dist/layouts/d3-dag/d3-dag-layout.js.map +1 -0
  115. package/dist/layouts/d3-force/d3-force-layout.d.ts +4 -4
  116. package/dist/layouts/d3-force/d3-force-layout.d.ts.map +1 -1
  117. package/dist/layouts/d3-force/d3-force-layout.js +25 -10
  118. package/dist/layouts/d3-force/d3-force-layout.js.map +1 -1
  119. package/dist/layouts/d3-force/worker.d.ts +0 -1
  120. package/dist/layouts/d3-force/worker.js +0 -1
  121. package/dist/layouts/experimental/force-multi-graph-layout.d.ts +9 -8
  122. package/dist/layouts/experimental/force-multi-graph-layout.d.ts.map +1 -1
  123. package/dist/layouts/experimental/force-multi-graph-layout.js +15 -11
  124. package/dist/layouts/experimental/force-multi-graph-layout.js.map +1 -1
  125. package/dist/layouts/experimental/hive-plot-layout.d.ts +11 -8
  126. package/dist/layouts/experimental/hive-plot-layout.d.ts.map +1 -1
  127. package/dist/layouts/experimental/hive-plot-layout.js +12 -7
  128. package/dist/layouts/experimental/hive-plot-layout.js.map +1 -1
  129. package/dist/layouts/experimental/radial-layout.d.ts +10 -7
  130. package/dist/layouts/experimental/radial-layout.d.ts.map +1 -1
  131. package/dist/layouts/experimental/radial-layout.js +11 -6
  132. package/dist/layouts/experimental/radial-layout.js.map +1 -1
  133. package/dist/layouts/gpu-force/gpu-force-layout.d.ts +4 -4
  134. package/dist/layouts/gpu-force/gpu-force-layout.d.ts.map +1 -1
  135. package/dist/layouts/gpu-force/gpu-force-layout.js +18 -9
  136. package/dist/layouts/gpu-force/gpu-force-layout.js.map +1 -1
  137. package/dist/layouts/gpu-force/worker.d.ts +0 -1
  138. package/dist/layouts/gpu-force/worker.js +0 -1
  139. package/dist/layouts/simple-layout.d.ts +19 -12
  140. package/dist/layouts/simple-layout.d.ts.map +1 -1
  141. package/dist/layouts/simple-layout.js +26 -15
  142. package/dist/layouts/simple-layout.js.map +1 -1
  143. package/dist/loaders/create-graph.d.ts +1 -2
  144. package/dist/loaders/create-graph.js +3 -4
  145. package/dist/loaders/edge-parsers.d.ts +1 -2
  146. package/dist/loaders/edge-parsers.js +2 -3
  147. package/dist/loaders/edge-parsers.js.map +1 -1
  148. package/dist/loaders/json-loader.d.ts +2 -3
  149. package/dist/loaders/json-loader.d.ts.map +1 -1
  150. package/dist/loaders/json-loader.js +5 -6
  151. package/dist/loaders/json-loader.js.map +1 -1
  152. package/dist/loaders/node-parsers.d.ts +1 -2
  153. package/dist/loaders/node-parsers.js +2 -3
  154. package/dist/loaders/node-parsers.js.map +1 -1
  155. package/dist/loaders/simple-json-graph-loader.d.ts +0 -1
  156. package/dist/loaders/simple-json-graph-loader.d.ts.map +1 -1
  157. package/dist/loaders/simple-json-graph-loader.js +5 -6
  158. package/dist/loaders/simple-json-graph-loader.js.map +1 -1
  159. package/dist/loaders/table-graph-loader.d.ts +3 -4
  160. package/dist/loaders/table-graph-loader.js +5 -6
  161. package/dist/loaders/table-graph-loader.js.map +1 -1
  162. package/dist/style/graph-layer-stylesheet.d.ts +34 -0
  163. package/dist/style/graph-layer-stylesheet.d.ts.map +1 -0
  164. package/dist/style/graph-layer-stylesheet.js +39 -0
  165. package/dist/style/graph-layer-stylesheet.js.map +1 -0
  166. package/dist/style/graph-style-accessor-map.d.ts +93 -0
  167. package/dist/style/graph-style-accessor-map.d.ts.map +1 -0
  168. package/dist/style/graph-style-accessor-map.js +93 -0
  169. package/dist/style/graph-style-accessor-map.js.map +1 -0
  170. package/dist/style/graph-style-engine.d.ts +10 -0
  171. package/dist/style/graph-style-engine.d.ts.map +1 -0
  172. package/dist/style/graph-style-engine.js +163 -0
  173. package/dist/style/graph-style-engine.js.map +1 -0
  174. package/dist/style/graph-stylesheet.schema.d.ts +310 -0
  175. package/dist/style/graph-stylesheet.schema.d.ts.map +1 -0
  176. package/dist/style/graph-stylesheet.schema.js +237 -0
  177. package/dist/style/graph-stylesheet.schema.js.map +1 -0
  178. package/dist/style/style-engine.d.ts +33 -0
  179. package/dist/style/style-engine.d.ts.map +1 -0
  180. package/dist/style/style-engine.js +121 -0
  181. package/dist/style/style-engine.js.map +1 -0
  182. package/dist/style/style-property.d.ts +2 -3
  183. package/dist/style/style-property.d.ts.map +1 -1
  184. package/dist/style/style-property.js +224 -48
  185. package/dist/style/style-property.js.map +1 -1
  186. package/dist/utils/collapsed-chains.d.ts +17 -0
  187. package/dist/utils/collapsed-chains.d.ts.map +1 -0
  188. package/dist/utils/collapsed-chains.js +197 -0
  189. package/dist/utils/collapsed-chains.js.map +1 -0
  190. package/dist/utils/layer-utils.d.ts +0 -1
  191. package/dist/utils/layer-utils.d.ts.map +1 -1
  192. package/dist/utils/layer-utils.js +0 -1
  193. package/dist/utils/log.d.ts +2 -1
  194. package/dist/utils/log.d.ts.map +1 -1
  195. package/dist/utils/log.js +12 -2
  196. package/dist/utils/log.js.map +1 -1
  197. package/dist/utils/node-boundary.d.ts +10 -0
  198. package/dist/utils/node-boundary.d.ts.map +1 -0
  199. package/dist/utils/node-boundary.js +130 -0
  200. package/dist/utils/node-boundary.js.map +1 -0
  201. package/dist/utils/polygon-calculations.d.ts +0 -1
  202. package/dist/utils/polygon-calculations.js +0 -1
  203. package/dist/widgets/long-press-button.d.ts +0 -1
  204. package/dist/widgets/long-press-button.js +0 -1
  205. package/dist/widgets/view-control-widget.d.ts +4 -5
  206. package/dist/widgets/view-control-widget.d.ts.map +1 -1
  207. package/dist/widgets/view-control-widget.js +10 -8
  208. package/dist/widgets/view-control-widget.js.map +1 -1
  209. package/package.json +23 -7
  210. package/src/_deprecated/old-constants.ts +122 -0
  211. package/src/core/constants.ts +21 -43
  212. package/src/core/graph-engine.ts +24 -9
  213. package/src/core/graph-layout.ts +133 -28
  214. package/src/core/interaction-manager.ts +80 -20
  215. package/src/graph/edge.ts +6 -6
  216. package/src/graph/graph.ts +7 -7
  217. package/src/graph/node.ts +6 -6
  218. package/src/index.ts +31 -6
  219. package/src/layers/common-layers/marker-layer/marker-list.ts +62 -64
  220. package/src/layers/edge-attachment-helper.ts +355 -0
  221. package/src/layers/edge-layer.ts +6 -7
  222. package/src/layers/edge-layers/arrow-2d-geometry.ts +51 -0
  223. package/src/layers/edge-layers/edge-arrow-layer.ts +171 -0
  224. package/src/layers/graph-layer.ts +304 -86
  225. package/src/layouts/d3-dag/d3-dag-layout.ts +969 -0
  226. package/src/layouts/d3-force/d3-force-layout.ts +33 -11
  227. package/src/layouts/experimental/force-multi-graph-layout.ts +22 -13
  228. package/src/layouts/experimental/hive-plot-layout.ts +22 -10
  229. package/src/layouts/experimental/radial-layout.ts +20 -8
  230. package/src/layouts/gpu-force/gpu-force-layout.ts +22 -10
  231. package/src/layouts/simple-layout.ts +48 -25
  232. package/src/loaders/edge-parsers.ts +2 -2
  233. package/src/loaders/json-loader.ts +2 -2
  234. package/src/loaders/node-parsers.ts +2 -2
  235. package/src/loaders/simple-json-graph-loader.ts +2 -2
  236. package/src/loaders/table-graph-loader.ts +2 -2
  237. package/src/style/graph-layer-stylesheet.ts +99 -0
  238. package/src/style/graph-style-accessor-map.ts +103 -0
  239. package/src/style/graph-style-engine.ts +229 -0
  240. package/src/style/graph-stylesheet.schema.ts +344 -0
  241. package/src/style/style-engine.ts +168 -0
  242. package/src/style/style-property.ts +314 -51
  243. package/src/utils/collapsed-chains.ts +261 -0
  244. package/src/utils/log.ts +15 -1
  245. package/src/utils/node-boundary.ts +238 -0
  246. package/src/widgets/view-control-widget.tsx +15 -13
  247. package/dist/style/style-sheet.d.ts +0 -11
  248. package/dist/style/style-sheet.d.ts.map +0 -1
  249. package/dist/style/style-sheet.js +0 -253
  250. package/dist/style/style-sheet.js.map +0 -1
  251. package/src/style/style-sheet.ts +0 -277
@@ -0,0 +1,355 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {InteractionManager} from '../core/interaction-manager';
6
+ import type {GraphEngine} from '../core/graph-engine';
7
+ import type {Node} from '../graph/node';
8
+
9
+ import {GraphStyleEngine, type GraphStylesheet} from '../style/graph-style-engine';
10
+ import type {GraphLayerNodeStyle} from '../style/graph-layer-stylesheet';
11
+ import {getNodeBoundaryIntersection, type GeometryNodeType, type NodeGeometry} from '../utils/node-boundary';
12
+ import {warn} from '../utils/log';
13
+
14
+ type NumericAccessor = ((node: Node) => number) | number | null | undefined;
15
+ type OffsetAccessor =
16
+ | ((node: Node) => [number, number])
17
+ | [number, number]
18
+ | null
19
+ | undefined;
20
+
21
+ type NodeStyleAccessors = {
22
+ type: GeometryNodeType;
23
+ getOffset?: OffsetAccessor;
24
+ getRadius?: NumericAccessor;
25
+ getWidth?: NumericAccessor;
26
+ getHeight?: NumericAccessor;
27
+ getCornerRadius?: NumericAccessor;
28
+ getSize?: NumericAccessor;
29
+ };
30
+
31
+ const GEOMETRY_NODE_TYPES: GeometryNodeType[] = [
32
+ 'circle',
33
+ 'rectangle',
34
+ 'rounded-rectangle',
35
+ 'path-rounded-rectangle',
36
+ 'marker'
37
+ ];
38
+
39
+ function evaluateNumericAccessor(accessor: NumericAccessor, node: Node): number | undefined {
40
+ if (typeof accessor === 'function') {
41
+ const value = accessor(node);
42
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
43
+ }
44
+ if (typeof accessor === 'number' && Number.isFinite(accessor)) {
45
+ return accessor;
46
+ }
47
+ return undefined;
48
+ }
49
+
50
+ function evaluateOffsetAccessor(accessor: OffsetAccessor, node: Node): [number, number] {
51
+ if (!accessor) {
52
+ return [0, 0];
53
+ }
54
+
55
+ let value = accessor as [number, number];
56
+ if (typeof accessor === 'function') {
57
+ value = accessor(node);
58
+ }
59
+
60
+ if (Array.isArray(value) && value.length >= 2) {
61
+ const offsetX = Number(value[0]);
62
+ const offsetY = Number(value[1]);
63
+ if (Number.isFinite(offsetX) && Number.isFinite(offsetY)) {
64
+ return [offsetX, offsetY];
65
+ }
66
+ }
67
+
68
+ return [0, 0];
69
+ }
70
+
71
+ function normalizePosition(value: any): [number, number] | null {
72
+ if (!value || typeof value !== 'object') {
73
+ return null;
74
+ }
75
+
76
+ const candidate = value as {length?: number; [index: number]: number};
77
+ if (typeof candidate.length === 'number' && candidate.length >= 2) {
78
+ const x = Number(candidate[0]);
79
+ const y = Number(candidate[1]);
80
+ if (Number.isFinite(x) && Number.isFinite(y)) {
81
+ return [x, y];
82
+ }
83
+ }
84
+
85
+ return null;
86
+ }
87
+
88
+ function resolveAccessorValue(accessor: NumericAccessor | undefined, node: Node) {
89
+ if (!accessor) {
90
+ return undefined;
91
+ }
92
+ return evaluateNumericAccessor(accessor, node);
93
+ }
94
+
95
+ function assignDimension(
96
+ geometry: NodeGeometry,
97
+ key: 'radius' | 'width' | 'height' | 'cornerRadius',
98
+ value: number | undefined
99
+ ) {
100
+ if (typeof value === 'number' && Number.isFinite(value)) {
101
+ geometry[key] = Math.max(value, 0);
102
+ }
103
+ }
104
+
105
+ function assignRectangleDimensions(
106
+ node: Node,
107
+ accessors: NodeStyleAccessors,
108
+ geometry: NodeGeometry
109
+ ) {
110
+ assignDimension(geometry, 'width', resolveAccessorValue(accessors.getWidth, node));
111
+ assignDimension(geometry, 'height', resolveAccessorValue(accessors.getHeight, node));
112
+ }
113
+
114
+ const GEOMETRY_APPLIERS: Record<
115
+ GeometryNodeType,
116
+ (node: Node, accessors: NodeStyleAccessors, geometry: NodeGeometry) => void
117
+ > = {
118
+ circle: (node, accessors, geometry) => {
119
+ assignDimension(geometry, 'radius', resolveAccessorValue(accessors.getRadius, node));
120
+ },
121
+ marker: (node, accessors, geometry) => {
122
+ const size = resolveAccessorValue(accessors.getSize, node);
123
+ assignDimension(geometry, 'radius', typeof size === 'number' ? size / 2 : undefined);
124
+ },
125
+ rectangle: (node, accessors, geometry) => {
126
+ assignRectangleDimensions(node, accessors, geometry);
127
+ },
128
+ 'rounded-rectangle': (node, accessors, geometry) => {
129
+ assignRectangleDimensions(node, accessors, geometry);
130
+ assignDimension(geometry, 'cornerRadius', resolveAccessorValue(accessors.getCornerRadius, node));
131
+ assignDimension(geometry, 'radius', resolveAccessorValue(accessors.getRadius, node));
132
+ },
133
+ 'path-rounded-rectangle': (node, accessors, geometry) => {
134
+ assignRectangleDimensions(node, accessors, geometry);
135
+ assignDimension(geometry, 'cornerRadius', resolveAccessorValue(accessors.getCornerRadius, node));
136
+ }
137
+ };
138
+
139
+ export class EdgeAttachmentHelper {
140
+ getLayoutAccessor({
141
+ engine,
142
+ interactionManager,
143
+ nodeStyle
144
+ }: {
145
+ engine: GraphEngine;
146
+ interactionManager: InteractionManager;
147
+ nodeStyle?: GraphLayerNodeStyle[] | GraphLayerNodeStyle;
148
+ }) {
149
+ const nodeAccessorMap = this._buildNodeStyleAccessorMap({
150
+ engine,
151
+ interactionManager,
152
+ nodeStyle
153
+ });
154
+
155
+ if (nodeAccessorMap.size === 0) {
156
+ return (edge: any) => engine.getEdgePosition(edge);
157
+ }
158
+
159
+ const nodeMap = engine
160
+ .getNodes()
161
+ .reduce((acc, node) => acc.set(node.getId(), node), new Map<string | number, Node>());
162
+
163
+ return (edge: any) =>
164
+ this._getAdjustedEdgeLayout(engine, nodeAccessorMap, nodeMap, edge);
165
+ }
166
+
167
+ private _buildNodeStyleAccessorMap({
168
+ engine,
169
+ interactionManager,
170
+ nodeStyle
171
+ }: {
172
+ engine: GraphEngine;
173
+ interactionManager: InteractionManager;
174
+ nodeStyle?: GraphLayerNodeStyle[] | GraphLayerNodeStyle;
175
+ }) {
176
+ const nodeAccessorMap = new Map<string | number, NodeStyleAccessors>();
177
+
178
+ if (!nodeStyle) {
179
+ return nodeAccessorMap;
180
+ }
181
+
182
+ const styles = Array.isArray(nodeStyle) ? nodeStyle : [nodeStyle];
183
+
184
+ styles
185
+ .filter(Boolean)
186
+ .forEach((style) => {
187
+ const {data = (nodes) => nodes, ...restStyle} = style;
188
+ const type = restStyle.type;
189
+
190
+ if (!type || !GEOMETRY_NODE_TYPES.includes(type as GeometryNodeType)) {
191
+ return;
192
+ }
193
+
194
+ let stylesheet: GraphStyleEngine | null = null;
195
+ try {
196
+ stylesheet = new GraphStyleEngine(restStyle as GraphStylesheet, {
197
+ stateUpdateTrigger: (interactionManager as any).getLastInteraction()
198
+ });
199
+ } catch (error) {
200
+ warn(
201
+ `GraphLayer: Failed to evaluate node stylesheet for edge attachment (${String(
202
+ (error as Error).message ?? error
203
+ )}).`
204
+ );
205
+ return;
206
+ }
207
+
208
+ const nodes = data(engine.getNodes());
209
+ if (!Array.isArray(nodes)) {
210
+ return;
211
+ }
212
+
213
+ const geometryType = type as GeometryNodeType;
214
+ const accessors = this._createAccessorsForType(geometryType, stylesheet);
215
+
216
+ nodes.forEach((node: Node) => {
217
+ const id = node.getId();
218
+ if (!nodeAccessorMap.has(id)) {
219
+ nodeAccessorMap.set(id, accessors);
220
+ }
221
+ });
222
+ });
223
+
224
+ return nodeAccessorMap;
225
+ }
226
+
227
+ private _getAdjustedEdgeLayout(
228
+ engine: GraphEngine,
229
+ nodeAccessorMap: Map<string | number, NodeStyleAccessors>,
230
+ nodeMap: Map<string | number, Node>,
231
+ edge: any
232
+ ) {
233
+ const layoutInfo = engine.getEdgePosition(edge);
234
+ if (!layoutInfo) {
235
+ return layoutInfo;
236
+ }
237
+
238
+ const sourceNode = nodeMap.get(edge.getSourceNodeId());
239
+ const targetNode = nodeMap.get(edge.getTargetNodeId());
240
+
241
+ if (!sourceNode || !targetNode) {
242
+ return layoutInfo;
243
+ }
244
+
245
+ const sourceGeometry = this._computeNodeGeometry(
246
+ engine,
247
+ sourceNode,
248
+ nodeAccessorMap.get(sourceNode.getId())
249
+ );
250
+ const targetGeometry = this._computeNodeGeometry(
251
+ engine,
252
+ targetNode,
253
+ nodeAccessorMap.get(targetNode.getId())
254
+ );
255
+
256
+ if (!sourceGeometry && !targetGeometry) {
257
+ return layoutInfo;
258
+ }
259
+
260
+ return this._applyGeometryToLayout(layoutInfo, sourceGeometry, targetGeometry);
261
+ }
262
+
263
+ private _applyGeometryToLayout(
264
+ layoutInfo: any,
265
+ sourceGeometry: NodeGeometry | null,
266
+ targetGeometry: NodeGeometry | null
267
+ ) {
268
+ const adjustedLayout = {...layoutInfo};
269
+
270
+ const targetReference = targetGeometry?.center ?? normalizePosition(layoutInfo.targetPosition);
271
+ const sourceReference = sourceGeometry?.center ?? normalizePosition(layoutInfo.sourcePosition);
272
+
273
+ if (sourceGeometry) {
274
+ adjustedLayout.sourcePosition = targetReference
275
+ ? getNodeBoundaryIntersection(sourceGeometry, targetReference)
276
+ : [...sourceGeometry.center];
277
+ }
278
+
279
+ if (targetGeometry) {
280
+ adjustedLayout.targetPosition = sourceReference
281
+ ? getNodeBoundaryIntersection(targetGeometry, sourceReference)
282
+ : [...targetGeometry.center];
283
+ }
284
+
285
+ return adjustedLayout;
286
+ }
287
+
288
+ private _createAccessorsForType(
289
+ geometryType: GeometryNodeType,
290
+ stylesheet: GraphStyleEngine
291
+ ): NodeStyleAccessors {
292
+ const base: NodeStyleAccessors = {
293
+ type: geometryType,
294
+ getOffset: stylesheet.getDeckGLAccessor('getOffset')
295
+ };
296
+
297
+ switch (geometryType) {
298
+ case 'circle':
299
+ base.getRadius = stylesheet.getDeckGLAccessor('getRadius');
300
+ break;
301
+ case 'marker':
302
+ base.getSize = stylesheet.getDeckGLAccessor('getSize');
303
+ break;
304
+ case 'rectangle':
305
+ base.getWidth = stylesheet.getDeckGLAccessor('getWidth');
306
+ base.getHeight = stylesheet.getDeckGLAccessor('getHeight');
307
+ break;
308
+ case 'rounded-rectangle':
309
+ base.getWidth = stylesheet.getDeckGLAccessor('getWidth');
310
+ base.getHeight = stylesheet.getDeckGLAccessor('getHeight');
311
+ base.getCornerRadius = stylesheet.getDeckGLAccessor('getCornerRadius');
312
+ base.getRadius = stylesheet.getDeckGLAccessor('getRadius');
313
+ break;
314
+ case 'path-rounded-rectangle':
315
+ base.getWidth = stylesheet.getDeckGLAccessor('getWidth');
316
+ base.getHeight = stylesheet.getDeckGLAccessor('getHeight');
317
+ base.getCornerRadius = stylesheet.getDeckGLAccessor('getCornerRadius');
318
+ break;
319
+ default:
320
+ break;
321
+ }
322
+
323
+ return base;
324
+ }
325
+
326
+ private _computeNodeGeometry(
327
+ engine: GraphEngine,
328
+ node: Node,
329
+ accessors?: NodeStyleAccessors
330
+ ): NodeGeometry | null {
331
+ const basePosition = engine.getNodePosition(node);
332
+ if (!basePosition) {
333
+ return null;
334
+ }
335
+
336
+ const offset = evaluateOffsetAccessor(accessors?.getOffset, node);
337
+ const center: [number, number] = [basePosition[0] + offset[0], basePosition[1] + offset[1]];
338
+
339
+ const geometry: NodeGeometry = {
340
+ type: accessors?.type,
341
+ center
342
+ };
343
+
344
+ if (!accessors || !accessors.type) {
345
+ return geometry;
346
+ }
347
+
348
+ const applier = GEOMETRY_APPLIERS[accessors.type];
349
+ if (applier) {
350
+ applier(node, accessors, geometry);
351
+ }
352
+
353
+ return geometry;
354
+ }
355
+ }
@@ -4,15 +4,14 @@
4
4
 
5
5
  import {COORDINATE_SYSTEM, CompositeLayer} from '@deck.gl/core';
6
6
 
7
- import {EDGE_TYPE} from '../core/constants';
8
7
  import {StraightLineEdgeLayer} from '../layers/edge-layers/straight-line-edge-layer';
9
8
  import {PathEdgeLayer} from './edge-layers/path-edge-layer';
10
9
  import {CurvedEdgeLayer} from './edge-layers/curved-edge-layer';
11
10
 
12
11
  const EDGE_LAYER_MAP = {
13
- [EDGE_TYPE.LINE]: StraightLineEdgeLayer,
14
- [EDGE_TYPE.PATH]: PathEdgeLayer,
15
- [EDGE_TYPE.SPLINE_CURVE]: CurvedEdgeLayer
12
+ 'line': StraightLineEdgeLayer,
13
+ 'path': PathEdgeLayer,
14
+ 'spline-curve': CurvedEdgeLayer
16
15
  };
17
16
 
18
17
  export class EdgeLayer extends CompositeLayer {
@@ -47,9 +46,9 @@ export class EdgeLayer extends CompositeLayer {
47
46
  return res;
48
47
  },
49
48
  {
50
- [EDGE_TYPE.LINE]: [],
51
- [EDGE_TYPE.PATH]: [],
52
- [EDGE_TYPE.SPLINE_CURVE]: []
49
+ 'line': [],
50
+ 'path': [],
51
+ 'spline-curve': []
53
52
  }
54
53
  );
55
54
  this.setState({typedEdgeData});
@@ -0,0 +1,51 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {Geometry} from '@luma.gl/engine';
6
+
7
+ // Mirror of the arrow geometry used by PathMarkerLayer, but only the head triangle.
8
+ export class Arrow2DGeometry extends Geometry {
9
+ constructor(opts = {}) {
10
+ super(
11
+ Object.assign({}, opts, {
12
+ attributes: getArrowAttributes(opts),
13
+ topology: 'triangle-list' as const
14
+ })
15
+ );
16
+ }
17
+ }
18
+
19
+ function getArrowAttributes({length = 1, headWidth = 1}) {
20
+ const halfLength = length / 2;
21
+ const halfWidth = headWidth / 2;
22
+
23
+ const positions = new Float32Array([
24
+ 0,
25
+ halfLength,
26
+ 0,
27
+ -halfWidth,
28
+ -halfLength,
29
+ 0,
30
+ halfWidth,
31
+ -halfLength,
32
+ 0
33
+ ]);
34
+
35
+ const normals = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1]);
36
+
37
+ const texCoords = new Float32Array([
38
+ 0.5,
39
+ 1,
40
+ 0,
41
+ 0,
42
+ 1,
43
+ 0
44
+ ]);
45
+
46
+ return {
47
+ positions: {size: 3, value: positions},
48
+ normals: {size: 3, value: normals},
49
+ texCoords: {size: 2, value: texCoords}
50
+ };
51
+ }
@@ -0,0 +1,171 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {CompositeLayer} from '@deck.gl/core';
6
+ import {SimpleMeshLayer} from '@deck.gl/mesh-layers';
7
+
8
+ import {Arrow2DGeometry} from './arrow-2d-geometry';
9
+
10
+ const DEFAULT_ARROW_GEOMETRY = new Arrow2DGeometry({length: 1, headWidth: 0.6});
11
+
12
+ type LayoutInfo = {
13
+ sourcePosition: number[];
14
+ targetPosition: number[];
15
+ controlPoints?: number[][];
16
+ };
17
+
18
+ const DEFAULT_Z = 0;
19
+
20
+ function resolveSize(value: unknown): number {
21
+ const numeric = Number(value);
22
+ return Number.isFinite(numeric) && numeric !== 0 ? numeric : 1;
23
+ }
24
+
25
+ function getOffsetComponents(offset: unknown): {along: number; perpendicular: number} {
26
+ if (!Array.isArray(offset)) {
27
+ return {along: 0, perpendicular: 0};
28
+ }
29
+ const along = Number(offset[0]);
30
+ const perpendicular = Number(offset[1]);
31
+ return {
32
+ along: Number.isFinite(along) ? along : 0,
33
+ perpendicular: Number.isFinite(perpendicular) ? perpendicular : 0
34
+ };
35
+ }
36
+
37
+ export function isEdgeDirected(edge: any): boolean {
38
+ if (!edge) {
39
+ return false;
40
+ }
41
+ if (typeof edge.isDirected === 'function') {
42
+ return Boolean(edge.isDirected());
43
+ }
44
+ if (typeof edge.directed === 'boolean') {
45
+ return edge.directed;
46
+ }
47
+ return false;
48
+ }
49
+
50
+ function normalizeVector(vector: number[]): number[] {
51
+ const length = Math.hypot(vector[0] ?? 0, vector[1] ?? 0, vector[2] ?? 0);
52
+ if (length === 0) {
53
+ return [0, 0, 0];
54
+ }
55
+ return [(vector[0] ?? 0) / length, (vector[1] ?? 0) / length, (vector[2] ?? 0) / length];
56
+ }
57
+
58
+ function getTerminalDirection({sourcePosition, targetPosition, controlPoints = []}: LayoutInfo): {
59
+ target: number[];
60
+ direction: number[];
61
+ } {
62
+ const anchor = controlPoints.length ? controlPoints[controlPoints.length - 1] : sourcePosition;
63
+ const direction = [
64
+ (targetPosition[0] ?? 0) - (anchor?.[0] ?? 0),
65
+ (targetPosition[1] ?? 0) - (anchor?.[1] ?? 0),
66
+ (targetPosition[2] ?? DEFAULT_Z) - (anchor?.[2] ?? DEFAULT_Z)
67
+ ];
68
+ return {target: targetPosition, direction};
69
+ }
70
+
71
+ export function getArrowTransform({
72
+ layout,
73
+ size,
74
+ offset = null
75
+ }: {
76
+ layout: LayoutInfo;
77
+ size: number;
78
+ offset?: number[] | null;
79
+ }): {position: [number, number, number]; angle: number} {
80
+ const {target, direction} = getTerminalDirection(layout);
81
+ const unit = normalizeVector(direction);
82
+
83
+ const hasDirection = unit[0] !== 0 || unit[1] !== 0 || unit[2] !== 0;
84
+ const resolvedSize = resolveSize(size);
85
+ const basePosition: [number, number, number] = [
86
+ target[0] ?? 0,
87
+ target[1] ?? 0,
88
+ target[2] ?? DEFAULT_Z
89
+ ];
90
+
91
+ if (!hasDirection) {
92
+ return {position: basePosition, angle: 0};
93
+ }
94
+
95
+ const {along, perpendicular} = getOffsetComponents(offset);
96
+ const alongDistance = resolvedSize * 0.5 + along;
97
+ const position: [number, number, number] = [
98
+ basePosition[0] - unit[0] * alongDistance,
99
+ basePosition[1] - unit[1] * alongDistance,
100
+ basePosition[2] - unit[2] * alongDistance
101
+ ];
102
+
103
+ if (perpendicular) {
104
+ const perp = [-unit[1], unit[0], 0];
105
+ position[0] += perp[0] * perpendicular;
106
+ position[1] += perp[1] * perpendicular;
107
+ position[2] += perp[2] * perpendicular;
108
+ }
109
+
110
+ const angle = (Math.atan2(unit[0], unit[1]) * 180) / Math.PI;
111
+
112
+ return {position, angle};
113
+ }
114
+
115
+ export class EdgeArrowLayer extends CompositeLayer {
116
+ static layerName = 'EdgeArrowLayer';
117
+
118
+ renderLayers() {
119
+ const {data, getLayoutInfo, positionUpdateTrigger = 0, stylesheet} = this.props as any;
120
+ const directedEdges = (data || []).filter(isEdgeDirected);
121
+
122
+ if (!directedEdges.length) {
123
+ return [];
124
+ }
125
+
126
+ const {getColor, getSize, getOffset} = stylesheet.getDeckGLAccessors();
127
+ const updateTriggers = stylesheet.getDeckGLUpdateTriggers();
128
+
129
+ return [
130
+ new SimpleMeshLayer(
131
+ this.getSubLayerProps({
132
+ id: '__edge-arrow-layer',
133
+ data: directedEdges,
134
+ mesh: DEFAULT_ARROW_GEOMETRY,
135
+ getColor,
136
+ getScale: (edge) => {
137
+ const size = resolveSize(getSize(edge));
138
+ return [size, size, size];
139
+ },
140
+ getOrientation: (edge) => {
141
+ const layout = getLayoutInfo(edge);
142
+ const size = resolveSize(getSize(edge));
143
+ const offset = getOffset ? getOffset(edge) : null;
144
+ const {angle} = getArrowTransform({layout, size, offset});
145
+ return [0, -angle, 0];
146
+ },
147
+ getPosition: (edge) => {
148
+ const layout = getLayoutInfo(edge);
149
+ const size = resolveSize(getSize(edge));
150
+ const offset = getOffset ? getOffset(edge) : null;
151
+ const {position} = getArrowTransform({layout, size, offset});
152
+ return position;
153
+ },
154
+ parameters: {
155
+ depthTest: false
156
+ },
157
+ updateTriggers: {
158
+ getColor: updateTriggers.getColor,
159
+ getScale: updateTriggers.getSize,
160
+ getOrientation: [
161
+ positionUpdateTrigger,
162
+ updateTriggers.getSize,
163
+ updateTriggers.getOffset
164
+ ],
165
+ getPosition: [positionUpdateTrigger, updateTriggers.getSize, updateTriggers.getOffset]
166
+ }
167
+ })
168
+ )
169
+ ];
170
+ }
171
+ }