@deck.gl-community/graph-layers 9.1.0-beta.8 → 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 (252) hide show
  1. package/LICENSE +1 -1
  2. package/dist/_deprecated/old-constants.d.ts +107 -0
  3. package/dist/_deprecated/old-constants.d.ts.map +1 -0
  4. package/dist/_deprecated/old-constants.js +111 -0
  5. package/dist/_deprecated/old-constants.js.map +1 -0
  6. package/dist/core/cache.d.ts +0 -1
  7. package/dist/core/cache.js +0 -1
  8. package/dist/core/constants.d.ts +12 -100
  9. package/dist/core/constants.d.ts.map +1 -1
  10. package/dist/core/constants.js +3 -44
  11. package/dist/core/constants.js.map +1 -1
  12. package/dist/core/graph-engine.d.ts +12 -11
  13. package/dist/core/graph-engine.d.ts.map +1 -1
  14. package/dist/core/graph-engine.js +22 -11
  15. package/dist/core/graph-engine.js.map +1 -1
  16. package/dist/core/graph-layout.d.ts +48 -21
  17. package/dist/core/graph-layout.d.ts.map +1 -1
  18. package/dist/core/graph-layout.js +91 -24
  19. package/dist/core/graph-layout.js.map +1 -1
  20. package/dist/core/interaction-manager.d.ts +6 -4
  21. package/dist/core/interaction-manager.d.ts.map +1 -1
  22. package/dist/core/interaction-manager.js +59 -17
  23. package/dist/core/interaction-manager.js.map +1 -1
  24. package/dist/graph/edge.d.ts +7 -7
  25. package/dist/graph/edge.d.ts.map +1 -1
  26. package/dist/graph/edge.js +3 -6
  27. package/dist/graph/edge.js.map +1 -1
  28. package/dist/graph/graph.d.ts +2 -3
  29. package/dist/graph/graph.js +8 -9
  30. package/dist/graph/graph.js.map +1 -1
  31. package/dist/graph/node.d.ts +7 -8
  32. package/dist/graph/node.d.ts.map +1 -1
  33. package/dist/graph/node.js +3 -5
  34. package/dist/graph/node.js.map +1 -1
  35. package/dist/graph-style-schema.cdn.d.ts +2 -0
  36. package/dist/graph-style-schema.cdn.js +2 -0
  37. package/dist/graph-style-schema.json +12 -0
  38. package/dist/index.cjs +2821 -549
  39. package/dist/index.cjs.map +4 -4
  40. package/dist/index.d.ts +28 -22
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +25 -21
  43. package/dist/index.js.map +1 -1
  44. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-fragment.glsl.d.ts +0 -1
  45. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-fragment.glsl.js +0 -1
  46. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex-tf.glsl.d.ts +0 -1
  47. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex-tf.glsl.js +0 -1
  48. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex.glsl.d.ts +0 -1
  49. package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex.glsl.js +0 -1
  50. package/dist/layers/common-layers/flow-path-layer/flow-path-layer.d.ts +0 -1
  51. package/dist/layers/common-layers/flow-path-layer/flow-path-layer.js +0 -1
  52. package/dist/layers/common-layers/marker-layer/atlas-data-url.d.ts +0 -1
  53. package/dist/layers/common-layers/marker-layer/atlas-data-url.js +0 -1
  54. package/dist/layers/common-layers/marker-layer/marker-layer.d.ts +0 -1
  55. package/dist/layers/common-layers/marker-layer/marker-layer.js +2 -3
  56. package/dist/layers/common-layers/marker-layer/marker-list.d.ts +2 -63
  57. package/dist/layers/common-layers/marker-layer/marker-list.d.ts.map +1 -1
  58. package/dist/layers/common-layers/marker-layer/marker-list.js +1 -65
  59. package/dist/layers/common-layers/marker-layer/marker-list.js.map +1 -1
  60. package/dist/layers/common-layers/marker-layer/marker-mapping.d.ts +0 -1
  61. package/dist/layers/common-layers/marker-layer/marker-mapping.js +0 -1
  62. package/dist/layers/common-layers/spline-layer/spline-layer.d.ts +0 -1
  63. package/dist/layers/common-layers/spline-layer/spline-layer.js +0 -1
  64. package/dist/layers/common-layers/zoomable-text-layer/zoomable-text-layer.d.ts +0 -1
  65. package/dist/layers/common-layers/zoomable-text-layer/zoomable-text-layer.js +0 -1
  66. package/dist/layers/edge-attachment-helper.d.ts +15 -0
  67. package/dist/layers/edge-attachment-helper.d.ts.map +1 -0
  68. package/dist/layers/edge-attachment-helper.js +230 -0
  69. package/dist/layers/edge-attachment-helper.js.map +1 -0
  70. package/dist/layers/edge-layer.d.ts +1 -5
  71. package/dist/layers/edge-layer.d.ts.map +1 -1
  72. package/dist/layers/edge-layer.js +9 -11
  73. package/dist/layers/edge-layer.js.map +1 -1
  74. package/dist/layers/edge-layers/arrow-2d-geometry.d.ts +4 -0
  75. package/dist/layers/edge-layers/arrow-2d-geometry.d.ts.map +1 -0
  76. package/dist/layers/edge-layers/arrow-2d-geometry.js +42 -0
  77. package/dist/layers/edge-layers/arrow-2d-geometry.js.map +1 -0
  78. package/dist/layers/edge-layers/curved-edge-layer.d.ts +1 -2
  79. package/dist/layers/edge-layers/curved-edge-layer.js +1 -2
  80. package/dist/layers/edge-layers/edge-arrow-layer.d.ts +21 -0
  81. package/dist/layers/edge-layers/edge-arrow-layer.d.ts.map +1 -0
  82. package/dist/layers/edge-layers/edge-arrow-layer.js +131 -0
  83. package/dist/layers/edge-layers/edge-arrow-layer.js.map +1 -0
  84. package/dist/layers/edge-layers/edge-label-layer.d.ts +1 -2
  85. package/dist/layers/edge-layers/edge-label-layer.js +1 -2
  86. package/dist/layers/edge-layers/flow-layer.d.ts +1 -2
  87. package/dist/layers/edge-layers/flow-layer.js +1 -2
  88. package/dist/layers/edge-layers/path-edge-layer.d.ts +0 -1
  89. package/dist/layers/edge-layers/path-edge-layer.js +0 -1
  90. package/dist/layers/edge-layers/straight-line-edge-layer.d.ts +0 -1
  91. package/dist/layers/edge-layers/straight-line-edge-layer.js +0 -1
  92. package/dist/layers/graph-layer.d.ts +22 -23
  93. package/dist/layers/graph-layer.d.ts.map +1 -1
  94. package/dist/layers/graph-layer.js +218 -62
  95. package/dist/layers/graph-layer.js.map +1 -1
  96. package/dist/layers/node-layers/circle-layer.d.ts +0 -1
  97. package/dist/layers/node-layers/circle-layer.js +0 -1
  98. package/dist/layers/node-layers/image-layer.d.ts +0 -1
  99. package/dist/layers/node-layers/image-layer.js +0 -1
  100. package/dist/layers/node-layers/label-layer.d.ts +1 -2
  101. package/dist/layers/node-layers/label-layer.js +1 -2
  102. package/dist/layers/node-layers/path-rounded-rectangle-layer.d.ts +0 -1
  103. package/dist/layers/node-layers/path-rounded-rectangle-layer.js +1 -2
  104. package/dist/layers/node-layers/rectangle-layer.d.ts +0 -1
  105. package/dist/layers/node-layers/rectangle-layer.js +0 -1
  106. package/dist/layers/node-layers/rounded-rectangle-layer-fragment.d.ts +0 -1
  107. package/dist/layers/node-layers/rounded-rectangle-layer-fragment.js +0 -1
  108. package/dist/layers/node-layers/rounded-rectangle-layer.d.ts +1 -2
  109. package/dist/layers/node-layers/rounded-rectangle-layer.js +2 -3
  110. package/dist/layers/node-layers/zoomable-marker-layer.d.ts +1 -2
  111. package/dist/layers/node-layers/zoomable-marker-layer.js +1 -2
  112. package/dist/layouts/d3-dag/d3-dag-layout.d.ts +117 -0
  113. package/dist/layouts/d3-dag/d3-dag-layout.d.ts.map +1 -0
  114. package/dist/layouts/d3-dag/d3-dag-layout.js +716 -0
  115. package/dist/layouts/d3-dag/d3-dag-layout.js.map +1 -0
  116. package/dist/layouts/d3-force/d3-force-layout.d.ts +4 -4
  117. package/dist/layouts/d3-force/d3-force-layout.d.ts.map +1 -1
  118. package/dist/layouts/d3-force/d3-force-layout.js +25 -10
  119. package/dist/layouts/d3-force/d3-force-layout.js.map +1 -1
  120. package/dist/layouts/d3-force/worker.d.ts +0 -1
  121. package/dist/layouts/d3-force/worker.js +0 -1
  122. package/dist/layouts/experimental/force-multi-graph-layout.d.ts +9 -8
  123. package/dist/layouts/experimental/force-multi-graph-layout.d.ts.map +1 -1
  124. package/dist/layouts/experimental/force-multi-graph-layout.js +15 -11
  125. package/dist/layouts/experimental/force-multi-graph-layout.js.map +1 -1
  126. package/dist/layouts/experimental/hive-plot-layout.d.ts +11 -8
  127. package/dist/layouts/experimental/hive-plot-layout.d.ts.map +1 -1
  128. package/dist/layouts/experimental/hive-plot-layout.js +12 -7
  129. package/dist/layouts/experimental/hive-plot-layout.js.map +1 -1
  130. package/dist/layouts/experimental/radial-layout.d.ts +10 -7
  131. package/dist/layouts/experimental/radial-layout.d.ts.map +1 -1
  132. package/dist/layouts/experimental/radial-layout.js +11 -6
  133. package/dist/layouts/experimental/radial-layout.js.map +1 -1
  134. package/dist/layouts/gpu-force/gpu-force-layout.d.ts +4 -4
  135. package/dist/layouts/gpu-force/gpu-force-layout.d.ts.map +1 -1
  136. package/dist/layouts/gpu-force/gpu-force-layout.js +18 -9
  137. package/dist/layouts/gpu-force/gpu-force-layout.js.map +1 -1
  138. package/dist/layouts/gpu-force/worker.d.ts +0 -1
  139. package/dist/layouts/gpu-force/worker.js +0 -1
  140. package/dist/layouts/simple-layout.d.ts +19 -12
  141. package/dist/layouts/simple-layout.d.ts.map +1 -1
  142. package/dist/layouts/simple-layout.js +26 -15
  143. package/dist/layouts/simple-layout.js.map +1 -1
  144. package/dist/loaders/create-graph.d.ts +1 -2
  145. package/dist/loaders/create-graph.js +3 -4
  146. package/dist/loaders/edge-parsers.d.ts +1 -2
  147. package/dist/loaders/edge-parsers.js +2 -3
  148. package/dist/loaders/edge-parsers.js.map +1 -1
  149. package/dist/loaders/json-loader.d.ts +2 -3
  150. package/dist/loaders/json-loader.d.ts.map +1 -1
  151. package/dist/loaders/json-loader.js +5 -6
  152. package/dist/loaders/json-loader.js.map +1 -1
  153. package/dist/loaders/node-parsers.d.ts +1 -2
  154. package/dist/loaders/node-parsers.js +2 -3
  155. package/dist/loaders/node-parsers.js.map +1 -1
  156. package/dist/loaders/simple-json-graph-loader.d.ts +0 -1
  157. package/dist/loaders/simple-json-graph-loader.d.ts.map +1 -1
  158. package/dist/loaders/simple-json-graph-loader.js +5 -6
  159. package/dist/loaders/simple-json-graph-loader.js.map +1 -1
  160. package/dist/loaders/table-graph-loader.d.ts +3 -4
  161. package/dist/loaders/table-graph-loader.js +5 -6
  162. package/dist/loaders/table-graph-loader.js.map +1 -1
  163. package/dist/style/graph-layer-stylesheet.d.ts +34 -0
  164. package/dist/style/graph-layer-stylesheet.d.ts.map +1 -0
  165. package/dist/style/graph-layer-stylesheet.js +39 -0
  166. package/dist/style/graph-layer-stylesheet.js.map +1 -0
  167. package/dist/style/graph-style-accessor-map.d.ts +93 -0
  168. package/dist/style/graph-style-accessor-map.d.ts.map +1 -0
  169. package/dist/style/graph-style-accessor-map.js +93 -0
  170. package/dist/style/graph-style-accessor-map.js.map +1 -0
  171. package/dist/style/graph-style-engine.d.ts +10 -0
  172. package/dist/style/graph-style-engine.d.ts.map +1 -0
  173. package/dist/style/graph-style-engine.js +163 -0
  174. package/dist/style/graph-style-engine.js.map +1 -0
  175. package/dist/style/graph-stylesheet.schema.d.ts +310 -0
  176. package/dist/style/graph-stylesheet.schema.d.ts.map +1 -0
  177. package/dist/style/graph-stylesheet.schema.js +237 -0
  178. package/dist/style/graph-stylesheet.schema.js.map +1 -0
  179. package/dist/style/style-engine.d.ts +33 -0
  180. package/dist/style/style-engine.d.ts.map +1 -0
  181. package/dist/style/style-engine.js +121 -0
  182. package/dist/style/style-engine.js.map +1 -0
  183. package/dist/style/style-property.d.ts +2 -3
  184. package/dist/style/style-property.d.ts.map +1 -1
  185. package/dist/style/style-property.js +224 -48
  186. package/dist/style/style-property.js.map +1 -1
  187. package/dist/utils/collapsed-chains.d.ts +17 -0
  188. package/dist/utils/collapsed-chains.d.ts.map +1 -0
  189. package/dist/utils/collapsed-chains.js +197 -0
  190. package/dist/utils/collapsed-chains.js.map +1 -0
  191. package/dist/utils/layer-utils.d.ts +0 -1
  192. package/dist/utils/layer-utils.d.ts.map +1 -1
  193. package/dist/utils/layer-utils.js +0 -1
  194. package/dist/utils/log.d.ts +2 -1
  195. package/dist/utils/log.d.ts.map +1 -1
  196. package/dist/utils/log.js +12 -2
  197. package/dist/utils/log.js.map +1 -1
  198. package/dist/utils/node-boundary.d.ts +10 -0
  199. package/dist/utils/node-boundary.d.ts.map +1 -0
  200. package/dist/utils/node-boundary.js +130 -0
  201. package/dist/utils/node-boundary.js.map +1 -0
  202. package/dist/utils/polygon-calculations.d.ts +0 -1
  203. package/dist/utils/polygon-calculations.js +0 -1
  204. package/dist/widgets/long-press-button.d.ts +0 -1
  205. package/dist/widgets/long-press-button.js +0 -1
  206. package/dist/widgets/view-control-widget.d.ts +4 -5
  207. package/dist/widgets/view-control-widget.d.ts.map +1 -1
  208. package/dist/widgets/view-control-widget.js +10 -8
  209. package/dist/widgets/view-control-widget.js.map +1 -1
  210. package/package.json +23 -7
  211. package/src/_deprecated/old-constants.ts +122 -0
  212. package/src/core/constants.ts +21 -43
  213. package/src/core/graph-engine.ts +24 -9
  214. package/src/core/graph-layout.ts +133 -28
  215. package/src/core/interaction-manager.ts +80 -20
  216. package/src/graph/edge.ts +6 -6
  217. package/src/graph/graph.ts +7 -7
  218. package/src/graph/node.ts +6 -6
  219. package/src/index.ts +31 -6
  220. package/src/layers/common-layers/marker-layer/marker-list.ts +62 -64
  221. package/src/layers/edge-attachment-helper.ts +355 -0
  222. package/src/layers/edge-layer.ts +6 -7
  223. package/src/layers/edge-layers/arrow-2d-geometry.ts +51 -0
  224. package/src/layers/edge-layers/edge-arrow-layer.ts +171 -0
  225. package/src/layers/graph-layer.ts +304 -86
  226. package/src/layouts/d3-dag/d3-dag-layout.ts +969 -0
  227. package/src/layouts/d3-force/d3-force-layout.ts +33 -11
  228. package/src/layouts/experimental/force-multi-graph-layout.ts +22 -13
  229. package/src/layouts/experimental/hive-plot-layout.ts +22 -10
  230. package/src/layouts/experimental/radial-layout.ts +20 -8
  231. package/src/layouts/gpu-force/gpu-force-layout.ts +22 -10
  232. package/src/layouts/simple-layout.ts +48 -25
  233. package/src/loaders/edge-parsers.ts +2 -2
  234. package/src/loaders/json-loader.ts +2 -2
  235. package/src/loaders/node-parsers.ts +2 -2
  236. package/src/loaders/simple-json-graph-loader.ts +2 -2
  237. package/src/loaders/table-graph-loader.ts +2 -2
  238. package/src/style/graph-layer-stylesheet.ts +99 -0
  239. package/src/style/graph-style-accessor-map.ts +103 -0
  240. package/src/style/graph-style-engine.ts +229 -0
  241. package/src/style/graph-stylesheet.schema.ts +344 -0
  242. package/src/style/style-engine.ts +168 -0
  243. package/src/style/style-property.ts +314 -51
  244. package/src/utils/collapsed-chains.ts +261 -0
  245. package/src/utils/log.ts +15 -1
  246. package/src/utils/node-boundary.ts +238 -0
  247. package/src/widgets/view-control-widget.tsx +15 -13
  248. package/dist/style/style-sheet.d.ts +0 -11
  249. package/dist/style/style-sheet.d.ts.map +0 -1
  250. package/dist/style/style-sheet.js +0 -253
  251. package/dist/style/style-sheet.js.map +0 -1
  252. package/src/style/style-sheet.ts +0 -277
@@ -0,0 +1,716 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+ /* eslint-disable no-continue, complexity, max-statements */
5
+ import { GraphLayout } from '../../core/graph-layout';
6
+ import { Node } from '../../graph/node';
7
+ import { Edge } from '../../graph/edge';
8
+ import { coordCenter, coordGreedy, coordQuad, coordSimplex, coordTopological, decrossDfs, decrossOpt, decrossTwoLayer, graph as createDagGraph, graphConnect, graphStratify, grid, layeringLongestPath, layeringSimplex, layeringTopological, sugiyama, zherebko } from 'd3-dag';
9
+ import { log } from '../../utils/log';
10
+ const DEFAULT_NODE_SIZE = [140, 120];
11
+ const DEFAULT_GAP = [0, 0];
12
+ const LAYERING_FACTORIES = {
13
+ simplex: layeringSimplex,
14
+ longestPath: layeringLongestPath,
15
+ topological: layeringTopological
16
+ };
17
+ const DECROSS_FACTORIES = {
18
+ twoLayer: decrossTwoLayer,
19
+ opt: decrossOpt,
20
+ dfs: decrossDfs
21
+ };
22
+ const COORD_FACTORIES = {
23
+ simplex: coordSimplex,
24
+ greedy: coordGreedy,
25
+ quad: coordQuad,
26
+ center: coordCenter,
27
+ topological: coordTopological
28
+ };
29
+ const LAYOUT_FACTORIES = {
30
+ sugiyama: () => sugiyama(),
31
+ grid: () => grid(),
32
+ zherebko: () => zherebko()
33
+ };
34
+ const DAG_ID_SEPARATOR = '::';
35
+ /**
36
+ * Layout that orchestrates d3-dag operators from declarative options.
37
+ */
38
+ export class D3DagLayout extends GraphLayout {
39
+ static defaultProps = {
40
+ layout: 'sugiyama',
41
+ layering: 'topological',
42
+ decross: 'twoLayer',
43
+ coord: 'greedy',
44
+ nodeSize: DEFAULT_NODE_SIZE,
45
+ gap: DEFAULT_GAP,
46
+ separation: DEFAULT_GAP,
47
+ orientation: 'TB',
48
+ center: true,
49
+ dagBuilder: 'graph',
50
+ collapseLinearChains: false
51
+ };
52
+ _name = 'D3DagLayout';
53
+ _graph = null;
54
+ _dag = null;
55
+ _layoutOperator = null;
56
+ _rawNodePositions = new Map();
57
+ _rawEdgePoints = new Map();
58
+ _nodePositions = new Map();
59
+ _edgePoints = new Map();
60
+ _edgeControlPoints = new Map();
61
+ _lockedNodePositions = new Map();
62
+ _dagBounds = null;
63
+ _nodeLookup = new Map();
64
+ _stringIdLookup = new Map();
65
+ _edgeLookup = new Map();
66
+ _incomingParentMap = new Map();
67
+ _chainDescriptors = new Map();
68
+ _nodeToChainId = new Map();
69
+ _collapsedChainState = new Map();
70
+ _hiddenNodeIds = new Set();
71
+ constructor(options = {}) {
72
+ super({ ...D3DagLayout.defaultProps, ...options });
73
+ }
74
+ initializeGraph(graph) {
75
+ this.updateGraph(graph);
76
+ }
77
+ updateGraph(graph) {
78
+ this._graph = graph;
79
+ this._nodeLookup = new Map();
80
+ this._stringIdLookup = new Map();
81
+ this._edgeLookup = new Map();
82
+ this._incomingParentMap = new Map();
83
+ this._chainDescriptors = new Map();
84
+ this._nodeToChainId = new Map();
85
+ this._hiddenNodeIds = new Set();
86
+ for (const node of graph.getNodes()) {
87
+ const id = node.getId();
88
+ const key = this._toDagId(id);
89
+ this._nodeLookup.set(id, node);
90
+ this._stringIdLookup.set(key, id);
91
+ }
92
+ for (const edge of graph.getEdges()) {
93
+ if (!edge.isDirected()) {
94
+ continue;
95
+ }
96
+ const key = this._edgeKey(edge.getSourceNodeId(), edge.getTargetNodeId());
97
+ this._edgeLookup.set(key, edge);
98
+ const targetId = edge.getTargetNodeId();
99
+ const parents = this._incomingParentMap.get(targetId) ?? [];
100
+ parents.push(edge.getSourceNodeId());
101
+ this._incomingParentMap.set(targetId, parents);
102
+ }
103
+ }
104
+ start() {
105
+ this._runLayout();
106
+ }
107
+ update() {
108
+ this._runLayout();
109
+ }
110
+ resume() {
111
+ this._runLayout();
112
+ }
113
+ stop() { }
114
+ toggleCollapsedChain(chainId) {
115
+ if (!this._graph) {
116
+ log.log(1, `D3DagLayout: toggleCollapsedChain(${chainId}) ignored (no graph)`);
117
+ return;
118
+ }
119
+ if (!this._chainDescriptors.has(chainId)) {
120
+ this._refreshCollapsedChains();
121
+ }
122
+ if (!this._chainDescriptors.has(chainId)) {
123
+ log.log(1, `D3DagLayout: toggleCollapsedChain(${chainId}) skipped (unknown chain)`);
124
+ return;
125
+ }
126
+ const collapsed = this._isChainCollapsed(chainId);
127
+ const nextState = !collapsed;
128
+ log.log(0, `D3DagLayout: toggleCollapsedChain(${chainId}) -> ${nextState ? 'collapsed' : 'expanded'}`);
129
+ // eslint-disable-next-line no-console
130
+ console.log(`D3DagLayout: toggleCollapsedChain(${chainId}) -> ${nextState ? 'collapsed' : 'expanded'}`);
131
+ this._collapsedChainState.set(chainId, nextState);
132
+ this._runLayout();
133
+ }
134
+ setCollapsedChains(chainIds) {
135
+ if (!this._graph) {
136
+ log.log(1, 'D3DagLayout: setCollapsedChains ignored (no graph)');
137
+ return;
138
+ }
139
+ if (!this._chainDescriptors.size) {
140
+ this._refreshCollapsedChains();
141
+ }
142
+ const desired = new Set(chainIds);
143
+ log.log(0, `D3DagLayout: setCollapsedChains(${desired.size}) requested`);
144
+ let changed = false;
145
+ for (const chainId of this._chainDescriptors.keys()) {
146
+ const next = desired.has(chainId);
147
+ if (this._isChainCollapsed(chainId) !== next) {
148
+ this._collapsedChainState.set(chainId, next);
149
+ changed = true;
150
+ }
151
+ }
152
+ if (changed) {
153
+ log.log(0, 'D3DagLayout: setCollapsedChains -> changes detected, rerunning layout');
154
+ // eslint-disable-next-line no-console
155
+ console.log('D3DagLayout: setCollapsedChains -> changes detected, rerunning layout');
156
+ this._runLayout();
157
+ }
158
+ else {
159
+ log.log(1, 'D3DagLayout: setCollapsedChains -> no changes');
160
+ // eslint-disable-next-line no-console
161
+ console.log('D3DagLayout: setCollapsedChains -> no changes');
162
+ }
163
+ }
164
+ setPipelineOptions(options) {
165
+ this._options = { ...this._options, ...options };
166
+ if (options.layout !== undefined ||
167
+ options.layering !== undefined ||
168
+ options.decross !== undefined ||
169
+ options.coord !== undefined ||
170
+ options.nodeSize !== undefined ||
171
+ options.gap !== undefined ||
172
+ options.separation !== undefined) {
173
+ this._layoutOperator = null;
174
+ }
175
+ if (options.collapseLinearChains !== undefined && this._graph) {
176
+ this._runLayout();
177
+ }
178
+ }
179
+ getNodePosition(node) {
180
+ if (this._shouldSkipNode(node.getId())) {
181
+ return null;
182
+ }
183
+ const mappedId = this._mapNodeId(node.getId());
184
+ return this._nodePositions.get(mappedId) || null;
185
+ }
186
+ getEdgePosition(edge) {
187
+ const mappedSourceId = this._mapNodeId(edge.getSourceNodeId());
188
+ const mappedTargetId = this._mapNodeId(edge.getTargetNodeId());
189
+ if (mappedSourceId === mappedTargetId) {
190
+ return null;
191
+ }
192
+ const sourcePosition = this._nodePositions.get(mappedSourceId);
193
+ const targetPosition = this._nodePositions.get(mappedTargetId);
194
+ if (!sourcePosition || !targetPosition) {
195
+ return null;
196
+ }
197
+ if (!this._edgePoints.has(edge.getId())) {
198
+ return null;
199
+ }
200
+ // const points = this._edgePoints.get(edge.getId()) || [sourcePosition, targetPosition];
201
+ const controlPoints = this._edgeControlPoints.get(edge.getId()) || [];
202
+ const edgeType = controlPoints.length ? 'spline-curve' : 'line';
203
+ return {
204
+ type: edgeType,
205
+ sourcePosition,
206
+ targetPosition,
207
+ controlPoints
208
+ };
209
+ }
210
+ getLinkControlPoints(edge) {
211
+ return this._edgeControlPoints.get(edge.getId()) || [];
212
+ }
213
+ lockNodePosition(node, x, y) {
214
+ this._lockedNodePositions.set(node.getId(), [x, y]);
215
+ this._nodePositions.set(node.getId(), [x, y]);
216
+ this._onLayoutChange();
217
+ this._onLayoutDone();
218
+ }
219
+ unlockNodePosition(node) {
220
+ this._lockedNodePositions.delete(node.getId());
221
+ }
222
+ _runLayout() {
223
+ if (!this._graph) {
224
+ return;
225
+ }
226
+ this._refreshCollapsedChains();
227
+ this._onLayoutStart();
228
+ try {
229
+ this._dag = this._buildDag();
230
+ const layout = this._getLayoutOperator();
231
+ layout(this._dag);
232
+ this._cacheGeometry();
233
+ this._onLayoutChange();
234
+ this._onLayoutDone();
235
+ }
236
+ catch (error) {
237
+ this._onLayoutError();
238
+ throw error;
239
+ }
240
+ }
241
+ _refreshCollapsedChains() {
242
+ const previousChainCount = this._chainDescriptors.size;
243
+ if (!this._graph) {
244
+ if (previousChainCount > 0) {
245
+ log.log(0, 'D3DagLayout: clearing collapsed chains (graph unavailable)');
246
+ // eslint-disable-next-line no-console
247
+ console.log('D3DagLayout: clearing collapsed chains (graph unavailable)');
248
+ }
249
+ this._chainDescriptors.clear();
250
+ this._nodeToChainId.clear();
251
+ this._hiddenNodeIds.clear();
252
+ return;
253
+ }
254
+ log.log(0, `D3DagLayout: refreshing collapsed chains (previous=${previousChainCount})`);
255
+ // eslint-disable-next-line no-console
256
+ console.log(`D3DagLayout: refreshing collapsed chains (previous=${previousChainCount})`);
257
+ const collapseDefault = this._options.collapseLinearChains ?? D3DagLayout.defaultProps.collapseLinearChains;
258
+ const previousStates = new Map(this._collapsedChainState);
259
+ this._chainDescriptors.clear();
260
+ this._nodeToChainId.clear();
261
+ this._hiddenNodeIds.clear();
262
+ const nodes = this._graph.getNodes();
263
+ const candidateNodes = new Set();
264
+ const incomingCache = new Map();
265
+ const outgoingCache = new Map();
266
+ for (const node of nodes) {
267
+ const incoming = this._getIncomingEdges(node);
268
+ const outgoing = this._getOutgoingEdges(node);
269
+ incomingCache.set(node.getId(), incoming);
270
+ outgoingCache.set(node.getId(), outgoing);
271
+ if (incoming.length <= 1 && outgoing.length <= 1 && incoming.length + outgoing.length > 0) {
272
+ candidateNodes.add(node.getId());
273
+ }
274
+ }
275
+ const visited = new Set();
276
+ for (const node of nodes) {
277
+ const nodeId = node.getId();
278
+ if (!candidateNodes.has(nodeId) || visited.has(nodeId)) {
279
+ continue;
280
+ }
281
+ const incoming = incomingCache.get(nodeId) ?? [];
282
+ const hasCandidateParent = incoming.length === 1 && candidateNodes.has(incoming[0].getSourceNodeId());
283
+ if (hasCandidateParent) {
284
+ continue;
285
+ }
286
+ const chainNodeIds = [];
287
+ const chainEdgeIds = [];
288
+ let currentNode = node;
289
+ while (currentNode) {
290
+ const currentId = currentNode.getId();
291
+ if (!candidateNodes.has(currentId) || visited.has(currentId)) {
292
+ break;
293
+ }
294
+ visited.add(currentId);
295
+ chainNodeIds.push(currentId);
296
+ const outgoing = outgoingCache.get(currentId) ?? [];
297
+ if (outgoing.length !== 1) {
298
+ break;
299
+ }
300
+ const nextEdge = outgoing[0];
301
+ const nextNodeId = nextEdge.getTargetNodeId();
302
+ if (!candidateNodes.has(nextNodeId)) {
303
+ break;
304
+ }
305
+ const nextIncoming = incomingCache.get(nextNodeId) ?? [];
306
+ if (nextIncoming.length !== 1) {
307
+ break;
308
+ }
309
+ chainEdgeIds.push(nextEdge.getId());
310
+ currentNode = this._nodeLookup.get(nextNodeId);
311
+ }
312
+ if (chainNodeIds.length > 1) {
313
+ const chainId = this._createChainId(chainNodeIds);
314
+ const collapsed = previousStates.has(chainId)
315
+ ? previousStates.get(chainId)
316
+ : collapseDefault;
317
+ this._chainDescriptors.set(chainId, {
318
+ id: chainId,
319
+ nodeIds: chainNodeIds,
320
+ edgeIds: chainEdgeIds,
321
+ representativeId: chainNodeIds[0]
322
+ });
323
+ this._collapsedChainState.set(chainId, collapsed);
324
+ for (const chainNodeId of chainNodeIds) {
325
+ this._nodeToChainId.set(chainNodeId, chainId);
326
+ }
327
+ }
328
+ }
329
+ for (const key of previousStates.keys()) {
330
+ if (!this._chainDescriptors.has(key)) {
331
+ this._collapsedChainState.delete(key);
332
+ }
333
+ }
334
+ this._hiddenNodeIds.clear();
335
+ for (const [chainId, descriptor] of this._chainDescriptors) {
336
+ const collapsed = this._isChainCollapsed(chainId);
337
+ if (collapsed) {
338
+ for (const nodeId of descriptor.nodeIds) {
339
+ // eslint-disable-next-line max-depth
340
+ if (nodeId !== descriptor.representativeId) {
341
+ this._hiddenNodeIds.add(nodeId);
342
+ }
343
+ }
344
+ }
345
+ }
346
+ this._updateCollapsedChainNodeMetadata();
347
+ let collapsedCount = 0;
348
+ for (const chainId of this._chainDescriptors.keys()) {
349
+ if (this._isChainCollapsed(chainId)) {
350
+ collapsedCount++;
351
+ }
352
+ }
353
+ log.log(0, `D3DagLayout: refreshed collapsed chains -> total=${this._chainDescriptors.size}, collapsed=${collapsedCount}`);
354
+ }
355
+ _buildDag() {
356
+ const builder = this._options.dagBuilder ?? D3DagLayout.defaultProps.dagBuilder;
357
+ if (typeof builder === 'function') {
358
+ const dag = builder(this._graph);
359
+ return this._ensureEdgeData(dag);
360
+ }
361
+ switch (builder) {
362
+ case 'connect':
363
+ return this._buildDagWithConnect();
364
+ case 'stratify':
365
+ return this._buildDagWithStratify();
366
+ case 'graph':
367
+ default:
368
+ return this._buildDagWithGraph();
369
+ }
370
+ }
371
+ _buildDagWithGraph() {
372
+ const dag = createDagGraph();
373
+ const dagNodeLookup = new Map();
374
+ for (const node of this._graph.getNodes()) {
375
+ if (this._shouldSkipNode(node.getId())) {
376
+ continue;
377
+ }
378
+ const dagNode = dag.node(node);
379
+ dagNodeLookup.set(node.getId(), dagNode);
380
+ }
381
+ for (const edge of this._graph.getEdges()) {
382
+ if (!edge.isDirected()) {
383
+ continue;
384
+ }
385
+ const sourceId = this._mapNodeId(edge.getSourceNodeId());
386
+ const targetId = this._mapNodeId(edge.getTargetNodeId());
387
+ if (sourceId === targetId) {
388
+ continue;
389
+ }
390
+ const source = dagNodeLookup.get(sourceId);
391
+ const target = dagNodeLookup.get(targetId);
392
+ if (!source || !target) {
393
+ continue;
394
+ }
395
+ dag.link(source, target, edge);
396
+ }
397
+ return dag;
398
+ }
399
+ _buildDagWithConnect() {
400
+ const connect = graphConnect()
401
+ .sourceId(({ source }) => source)
402
+ .targetId(({ target }) => target)
403
+ .nodeDatum((id) => this._nodeLookup.get(this._fromDagId(id)) ?? new Node({ id }))
404
+ .single(true);
405
+ const data = this._graph
406
+ .getEdges()
407
+ .filter((edge) => edge.isDirected())
408
+ .map((edge) => {
409
+ const sourceId = this._mapNodeId(edge.getSourceNodeId());
410
+ const targetId = this._mapNodeId(edge.getTargetNodeId());
411
+ return { sourceId, targetId, edge };
412
+ })
413
+ .filter(({ sourceId, targetId }) => sourceId !== targetId)
414
+ .map(({ sourceId, targetId, edge }) => ({
415
+ source: this._toDagId(sourceId),
416
+ target: this._toDagId(targetId),
417
+ edge
418
+ }));
419
+ const dag = connect(data);
420
+ const seenIds = new Set();
421
+ for (const dagNode of dag.nodes()) {
422
+ const datum = dagNode.data;
423
+ if (datum instanceof Node) {
424
+ seenIds.add(datum.getId());
425
+ }
426
+ }
427
+ for (const node of this._graph.getNodes()) {
428
+ if (this._shouldSkipNode(node.getId())) {
429
+ continue;
430
+ }
431
+ if (!seenIds.has(node.getId())) {
432
+ dag.node(node);
433
+ }
434
+ }
435
+ return this._ensureEdgeData(dag);
436
+ }
437
+ _buildDagWithStratify() {
438
+ const stratify = graphStratify()
439
+ .id((node) => this._toDagId(node.getId()))
440
+ .parentIds((node) => {
441
+ const parentIds = this._incomingParentMap.get(node.getId()) ?? [];
442
+ const mapped = new Set();
443
+ for (const parentId of parentIds) {
444
+ if (!this._nodeLookup.has(parentId)) {
445
+ continue;
446
+ }
447
+ const mappedId = this._mapNodeId(parentId);
448
+ if (mappedId === node.getId()) {
449
+ continue;
450
+ }
451
+ mapped.add(this._toDagId(mappedId));
452
+ }
453
+ return mapped;
454
+ });
455
+ const dag = stratify(this._graph.getNodes().filter((node) => !this._shouldSkipNode(node.getId())));
456
+ return this._ensureEdgeData(dag);
457
+ }
458
+ _isChainCollapsed(chainId) {
459
+ const collapseDefault = this._options.collapseLinearChains ?? D3DagLayout.defaultProps.collapseLinearChains;
460
+ return this._collapsedChainState.get(chainId) ?? collapseDefault;
461
+ }
462
+ _shouldSkipNode(nodeId) {
463
+ return this._hiddenNodeIds.has(nodeId);
464
+ }
465
+ _mapNodeId(nodeId) {
466
+ const chainId = this._nodeToChainId.get(nodeId);
467
+ if (!chainId) {
468
+ return nodeId;
469
+ }
470
+ const descriptor = this._chainDescriptors.get(chainId);
471
+ if (!descriptor) {
472
+ return nodeId;
473
+ }
474
+ return this._isChainCollapsed(chainId) ? descriptor.representativeId : nodeId;
475
+ }
476
+ _updateCollapsedChainNodeMetadata() {
477
+ if (!this._graph) {
478
+ return;
479
+ }
480
+ for (const node of this._graph.getNodes()) {
481
+ const nodeId = node.getId();
482
+ const chainId = this._nodeToChainId.get(nodeId);
483
+ if (!chainId) {
484
+ node.setDataProperty('collapsedChainId', null);
485
+ node.setDataProperty('collapsedChainLength', 1);
486
+ node.setDataProperty('collapsedNodeIds', []);
487
+ node.setDataProperty('collapsedEdgeIds', []);
488
+ node.setDataProperty('collapsedChainRepresentativeId', null);
489
+ node.setDataProperty('isCollapsedChain', false);
490
+ continue;
491
+ }
492
+ const descriptor = this._chainDescriptors.get(chainId);
493
+ if (!descriptor) {
494
+ node.setDataProperty('collapsedChainId', null);
495
+ node.setDataProperty('collapsedChainLength', 1);
496
+ node.setDataProperty('collapsedNodeIds', []);
497
+ node.setDataProperty('collapsedEdgeIds', []);
498
+ node.setDataProperty('collapsedChainRepresentativeId', null);
499
+ node.setDataProperty('isCollapsedChain', false);
500
+ continue;
501
+ }
502
+ const collapsed = this._isChainCollapsed(chainId);
503
+ node.setDataProperty('collapsedChainId', chainId);
504
+ node.setDataProperty('collapsedChainLength', collapsed ? descriptor.nodeIds.length : 1);
505
+ node.setDataProperty('collapsedNodeIds', descriptor.nodeIds);
506
+ node.setDataProperty('collapsedEdgeIds', descriptor.edgeIds);
507
+ node.setDataProperty('collapsedChainRepresentativeId', descriptor.representativeId);
508
+ node.setDataProperty('isCollapsedChain', collapsed);
509
+ }
510
+ }
511
+ _createChainId(nodeIds) {
512
+ return `chain:${nodeIds.map((id) => this._toDagId(id)).join('>')}`;
513
+ }
514
+ _getIncomingEdges(node) {
515
+ const nodeId = node.getId();
516
+ return node
517
+ .getConnectedEdges()
518
+ .filter((edge) => edge.isDirected() && edge.getTargetNodeId() === nodeId);
519
+ }
520
+ _getOutgoingEdges(node) {
521
+ const nodeId = node.getId();
522
+ return node
523
+ .getConnectedEdges()
524
+ .filter((edge) => edge.isDirected() && edge.getSourceNodeId() === nodeId);
525
+ }
526
+ _ensureEdgeData(dag) {
527
+ for (const link of dag.links()) {
528
+ if (link.data instanceof Edge) {
529
+ continue;
530
+ }
531
+ const sourceNode = link.source.data;
532
+ const targetNode = link.target.data;
533
+ if (!(sourceNode instanceof Node) || !(targetNode instanceof Node)) {
534
+ continue;
535
+ }
536
+ const key = this._edgeKey(sourceNode.getId(), targetNode.getId());
537
+ const edge = this._edgeLookup.get(key);
538
+ if (edge) {
539
+ link.data = edge;
540
+ }
541
+ }
542
+ return dag;
543
+ }
544
+ _getLayoutOperator() {
545
+ if (this._layoutOperator) {
546
+ return this._layoutOperator;
547
+ }
548
+ const layoutOption = this._options.layout ?? D3DagLayout.defaultProps.layout;
549
+ let layout;
550
+ if (typeof layoutOption === 'string') {
551
+ layout = LAYOUT_FACTORIES[layoutOption]();
552
+ }
553
+ else {
554
+ layout = layoutOption;
555
+ }
556
+ if (layout.layering && this._options.layering) {
557
+ layout = layout.layering(this._resolveLayering(this._options.layering));
558
+ }
559
+ if (layout.decross && this._options.decross) {
560
+ layout = layout.decross(this._resolveDecross(this._options.decross));
561
+ }
562
+ if (layout.coord && this._options.coord) {
563
+ layout = layout.coord(this._resolveCoord(this._options.coord));
564
+ }
565
+ const nodeSize = this._options.nodeSize ?? DEFAULT_NODE_SIZE;
566
+ if (layout.nodeSize) {
567
+ layout = layout.nodeSize(nodeSize);
568
+ }
569
+ const gap = this._options.separation ?? this._options.gap ?? DEFAULT_GAP;
570
+ if (layout.gap) {
571
+ layout = layout.gap(gap);
572
+ }
573
+ this._layoutOperator = layout;
574
+ return layout;
575
+ }
576
+ _resolveLayering(option) {
577
+ if (typeof option === 'string') {
578
+ return LAYERING_FACTORIES[option]();
579
+ }
580
+ return option;
581
+ }
582
+ _resolveDecross(option) {
583
+ if (typeof option === 'string') {
584
+ return DECROSS_FACTORIES[option]();
585
+ }
586
+ return option;
587
+ }
588
+ _resolveCoord(option) {
589
+ if (typeof option === 'string') {
590
+ return COORD_FACTORIES[option]();
591
+ }
592
+ return option;
593
+ }
594
+ _cacheGeometry() {
595
+ this._rawNodePositions.clear();
596
+ this._rawEdgePoints.clear();
597
+ if (!this._dag) {
598
+ this._dagBounds = null;
599
+ this._bounds = null;
600
+ return;
601
+ }
602
+ let minX = Number.POSITIVE_INFINITY;
603
+ let maxX = Number.NEGATIVE_INFINITY;
604
+ let minY = Number.POSITIVE_INFINITY;
605
+ let maxY = Number.NEGATIVE_INFINITY;
606
+ for (const dagNode of this._dag.nodes()) {
607
+ const node = dagNode.data;
608
+ const id = node.getId();
609
+ const x = dagNode.x ?? 0;
610
+ const y = dagNode.y ?? 0;
611
+ minX = Math.min(minX, x);
612
+ maxX = Math.max(maxX, x);
613
+ minY = Math.min(minY, y);
614
+ maxY = Math.max(maxY, y);
615
+ this._rawNodePositions.set(id, [x, y]);
616
+ }
617
+ if (minX === Number.POSITIVE_INFINITY) {
618
+ this._dagBounds = null;
619
+ this._bounds = null;
620
+ this._nodePositions.clear();
621
+ this._edgePoints.clear();
622
+ this._edgeControlPoints.clear();
623
+ return;
624
+ }
625
+ this._dagBounds = {
626
+ minX,
627
+ maxX,
628
+ minY,
629
+ maxY,
630
+ centerX: (minX + maxX) / 2,
631
+ centerY: (minY + maxY) / 2
632
+ };
633
+ for (const link of this._dag.links()) {
634
+ const source = link.source.data;
635
+ const target = link.target.data;
636
+ const edge = link.data instanceof Edge ? link.data : this._edgeLookup.get(this._edgeKey(source.getId(), target.getId()));
637
+ if (!edge) {
638
+ continue;
639
+ }
640
+ const points = (link.points && link.points.length ? link.points : [[link.source.x ?? 0, link.source.y ?? 0], [link.target.x ?? 0, link.target.y ?? 0]]);
641
+ this._rawEdgePoints.set(edge.getId(), points.map((point) => [...point]));
642
+ }
643
+ this._updateTransformedGeometry();
644
+ }
645
+ _updateTransformedGeometry() {
646
+ this._nodePositions.clear();
647
+ this._edgePoints.clear();
648
+ this._edgeControlPoints.clear();
649
+ if (!this._dagBounds) {
650
+ this._bounds = null;
651
+ return;
652
+ }
653
+ const { offsetX, offsetY } = this._getOffsets();
654
+ const orientation = this._options.orientation ?? D3DagLayout.defaultProps.orientation;
655
+ const transform = (x, y) => {
656
+ const localX = x - offsetX;
657
+ const localY = y - offsetY;
658
+ switch (orientation) {
659
+ case 'BT':
660
+ return [localX, localY];
661
+ case 'LR':
662
+ return [localY, localX];
663
+ case 'RL':
664
+ return [-localY, localX];
665
+ case 'TB':
666
+ default:
667
+ return [localX, -localY];
668
+ }
669
+ };
670
+ for (const [id, [x, y]] of this._rawNodePositions) {
671
+ this._nodePositions.set(id, transform(x, y));
672
+ }
673
+ for (const [edgeId, points] of this._rawEdgePoints) {
674
+ const transformed = points.map(([x, y]) => transform(x, y));
675
+ this._edgePoints.set(edgeId, transformed);
676
+ this._edgeControlPoints.set(edgeId, transformed.length > 2 ? transformed.slice(1, -1) : []);
677
+ }
678
+ for (const [id, position] of this._lockedNodePositions) {
679
+ this._nodePositions.set(id, position);
680
+ }
681
+ this._bounds = this._calculateBounds(this._nodePositions.values());
682
+ }
683
+ _getOffsets() {
684
+ if (!this._dagBounds) {
685
+ return { offsetX: 0, offsetY: 0 };
686
+ }
687
+ const centerOption = this._options.center ?? true;
688
+ let offsetX = 0;
689
+ let offsetY = 0;
690
+ if (centerOption === true) {
691
+ offsetX = this._dagBounds.centerX;
692
+ offsetY = this._dagBounds.centerY;
693
+ }
694
+ else if (centerOption && typeof centerOption === 'object') {
695
+ if (centerOption.x) {
696
+ offsetX = this._dagBounds.centerX;
697
+ }
698
+ if (centerOption.y) {
699
+ offsetY = this._dagBounds.centerY;
700
+ }
701
+ }
702
+ return { offsetX, offsetY };
703
+ }
704
+ _updateBounds() {
705
+ this._bounds = this._calculateBounds(this._nodePositions.values());
706
+ }
707
+ _edgeKey(sourceId, targetId) {
708
+ return `${this._toDagId(sourceId)}${DAG_ID_SEPARATOR}${this._toDagId(targetId)}`;
709
+ }
710
+ _toDagId(id) {
711
+ return String(id);
712
+ }
713
+ _fromDagId(id) {
714
+ return this._stringIdLookup.get(id) ?? id;
715
+ }
716
+ }