@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
@@ -5,9 +5,8 @@
5
5
  /* eslint-disable no-continue, complexity, max-statements */
6
6
 
7
7
  import {GraphLayout, GraphLayoutProps} from '../../core/graph-layout';
8
- import type {Graph} from '../../graph/graph';
8
+ import type {Graph, NodeInterface, EdgeInterface} from '../../graph/graph';
9
9
  import {Node} from '../../graph/node';
10
- import {Edge} from '../../graph/edge';
11
10
  import {
12
11
  coordCenter,
13
12
  coordGreedy,
@@ -26,8 +25,8 @@ import {
26
25
  layeringTopological,
27
26
  sugiyama,
28
27
  zherebko,
29
- type Coord,
30
- type Decross,
28
+ // type Coord,
29
+ // type Decross,
31
30
  type DefaultGrid,
32
31
  type DefaultSugiyama,
33
32
  type DefaultZherebko,
@@ -39,46 +38,44 @@ import {
39
38
  } from 'd3-dag';
40
39
  import {log} from '../../utils/log';
41
40
 
42
- export type D3DagLayoutBuilderName = 'sugiyama' | 'grid' | 'zherebko';
43
- export type D3DagLayeringName = 'simplex' | 'longestPath' | 'topological';
44
- export type D3DagDecrossName = 'twoLayer' | 'opt' | 'dfs';
45
- export type D3DagCoordName = 'simplex' | 'greedy' | 'quad' | 'center' | 'topological';
46
- export type D3DagDagBuilderName = 'graph' | 'connect' | 'stratify';
47
- export type D3DagOrientation = 'TB' | 'BT' | 'LR' | 'RL';
48
- export type D3DagCenterOption = boolean | {x?: boolean; y?: boolean};
49
-
50
- export type D3DagLayoutOperator =
51
- | DefaultSugiyama
52
- | DefaultGrid
53
- | DefaultZherebko
54
- | ((dag: MutGraph<Node, Edge>) => LayoutResult);
55
-
56
- export type D3DagLayoutOptions = GraphLayoutProps & {
41
+ export type D3DagLayoutProps = GraphLayoutProps & {
57
42
  /** Which high-level layout operator to use. */
58
- layout?: D3DagLayoutBuilderName | D3DagLayoutOperator;
43
+ layout?: 'sugiyama' | 'grid' | 'zherebko';
59
44
  /** Layering operator used by sugiyama layouts. */
60
- layering?: D3DagLayeringName | LayeringOperator;
45
+ layering?: 'simplex' | 'longestPath' | 'topological';
46
+ /** Accessor for node rank for layering */
47
+ nodeRank?: string | ((node: NodeInterface) => number | undefined);
61
48
  /** Decrossing operator used by sugiyama layouts. */
62
- decross?: D3DagDecrossName | DecrossOperator;
49
+ decross?: 'twoLayer' | 'opt' | 'dfs';
63
50
  /** Coordinate assignment operator used by sugiyama layouts. */
64
- coord?: D3DagCoordName | CoordOperator;
51
+ coord?: 'simplex' | 'greedy' | 'quad' | 'center' | 'topological';
65
52
  /** Node sizing accessor passed to the active layout. */
66
- nodeSize?: NodeSize<Node, Edge>;
53
+ nodeSize?: NodeSize<NodeInterface, EdgeInterface>;
67
54
  /** Optional gap between nodes. Alias: separation. */
68
55
  gap?: readonly [number, number];
69
56
  /** Optional gap between nodes. */
70
57
  separation?: readonly [number, number];
71
58
  /** Orientation transform applied after the layout finishes. */
72
- orientation?: D3DagOrientation;
59
+ orientation?: 'TB' | 'BT' | 'LR' | 'RL';
73
60
  /** Whether to center the layout along each axis. */
74
- center?: D3DagCenterOption;
61
+ center?: boolean | {x?: boolean; y?: boolean};
75
62
  /** How to convert the Graph into a DAG. */
76
- dagBuilder?: D3DagDagBuilderName | DagBuilder;
77
- /** Whether to collapse linear chains of nodes into a single representative. */
78
- collapseLinearChains?: boolean;
63
+ dagBuilder?: 'graph' | 'connect' | 'stratify';
64
+
65
+ customDagBuilder?: DagBuilder;
66
+ customLayout?: D3DagLayoutOperator;
67
+ customLayering?: LayeringOperator;
68
+ customDecross?: DecrossOperator;
69
+ customCoord?: CoordOperator;
79
70
  };
80
71
 
81
- type DagBuilder = (graph: Graph) => MutGraph<Node, Edge>;
72
+ export type D3DagLayoutOperator =
73
+ | DefaultSugiyama
74
+ | DefaultGrid
75
+ | DefaultZherebko
76
+ | ((dag: MutGraph<NodeInterface, EdgeInterface>) => LayoutResult);
77
+
78
+ type DagBuilder = (graph: Graph) => MutGraph<NodeInterface, EdgeInterface>;
82
79
 
83
80
  type LayeringOperator =
84
81
  | ReturnType<typeof layeringSimplex>
@@ -95,23 +92,16 @@ type CoordOperator =
95
92
  | ReturnType<typeof coordSimplex>
96
93
  | ReturnType<typeof coordTopological>;
97
94
 
98
- type LayoutCallable = (dag: MutGraph<Node, Edge>) => LayoutResult;
95
+ type LayoutCallable = (dag: MutGraph<NodeInterface, EdgeInterface>) => LayoutResult;
99
96
 
100
97
  type LayoutWithConfiguration = LayoutCallable & {
101
98
  layering?: (layer?: any) => any;
102
99
  decross?: (decross?: any) => any;
103
100
  coord?: (coord?: any) => any;
104
- nodeSize?: (size?: NodeSize<Node, Edge>) => any;
101
+ nodeSize?: (size?: NodeSize<NodeInterface, EdgeInterface>) => any;
105
102
  gap?: (gap?: readonly [number, number]) => any;
106
103
  };
107
104
 
108
- type CollapsedChainDescriptor = {
109
- id: string;
110
- nodeIds: (string | number)[];
111
- edgeIds: (string | number)[];
112
- representativeId: string | number;
113
- };
114
-
115
105
  type DagBounds = {
116
106
  minX: number;
117
107
  maxX: number;
@@ -121,59 +111,74 @@ type DagBounds = {
121
111
  centerY: number;
122
112
  };
123
113
 
114
+ const DAG_ID_SEPARATOR = '::';
115
+
124
116
  const DEFAULT_NODE_SIZE: readonly [number, number] = [140, 120];
125
117
  const DEFAULT_GAP: readonly [number, number] = [0, 0];
126
118
 
127
- const LAYERING_FACTORIES: Record<D3DagLayeringName, () => LayeringOperator> = {
119
+ const LAYERING_FACTORIES = {
128
120
  simplex: layeringSimplex,
129
121
  longestPath: layeringLongestPath,
130
122
  topological: layeringTopological
131
- };
123
+ } as const satisfies Record<string, () => LayeringOperator>;
132
124
 
133
- const DECROSS_FACTORIES: Record<D3DagDecrossName, () => DecrossOperator> = {
125
+ const DECROSS_FACTORIES = {
134
126
  twoLayer: decrossTwoLayer,
135
127
  opt: decrossOpt,
136
128
  dfs: decrossDfs
137
- };
129
+ } as const satisfies Record<string, () => DecrossOperator>;
138
130
 
139
- const COORD_FACTORIES: Record<D3DagCoordName, () => CoordOperator> = {
131
+ const COORD_FACTORIES = {
140
132
  simplex: coordSimplex,
141
133
  greedy: coordGreedy,
142
134
  quad: coordQuad,
143
135
  center: coordCenter,
144
136
  topological: coordTopological
145
- };
137
+ } as const satisfies Record<string, () => CoordOperator>;
146
138
 
147
- const LAYOUT_FACTORIES: Record<D3DagLayoutBuilderName, () => LayoutWithConfiguration> = {
139
+ const LAYOUT_FACTORIES = {
148
140
  sugiyama: () => sugiyama(),
149
141
  grid: () => grid(),
150
142
  zherebko: () => zherebko()
151
- };
143
+ } as const satisfies Record<string, () => LayoutWithConfiguration>;
152
144
 
153
- const DAG_ID_SEPARATOR = '::';
145
+ function isNodeInterface(value: unknown): value is NodeInterface {
146
+ return Boolean(value) && typeof value === 'object' && (value as NodeInterface).isNode === true;
147
+ }
148
+
149
+ function isEdgeInterface(value: unknown): value is EdgeInterface {
150
+ return Boolean(value) && typeof value === 'object' && (value as EdgeInterface).isEdge === true;
151
+ }
154
152
 
155
153
  /**
156
154
  * Layout that orchestrates d3-dag operators from declarative options.
157
155
  */
158
- export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
159
- static defaultProps: Required<Omit<D3DagLayoutOptions, 'layout'>> & {layout: D3DagLayoutBuilderName} = {
156
+ export class D3DagLayout<PropsT extends D3DagLayoutProps = D3DagLayoutProps> extends GraphLayout<PropsT> {
157
+ static defaultProps: Readonly<Required<D3DagLayoutProps>> = {
158
+ ...GraphLayout.defaultProps,
160
159
  layout: 'sugiyama',
161
160
  layering: 'topological',
162
161
  decross: 'twoLayer',
163
162
  coord: 'greedy',
163
+ nodeRank: undefined,
164
164
  nodeSize: DEFAULT_NODE_SIZE,
165
165
  gap: DEFAULT_GAP,
166
166
  separation: DEFAULT_GAP,
167
167
  orientation: 'TB',
168
168
  center: true,
169
169
  dagBuilder: 'graph',
170
- collapseLinearChains: false
171
- };
170
+
171
+ customLayout: undefined,
172
+ customLayering: undefined,
173
+ customDecross: undefined,
174
+ customCoord: undefined,
175
+ customDagBuilder: undefined
176
+ } as const;
172
177
 
173
178
  protected readonly _name = 'D3DagLayout';
174
179
 
175
- private _graph: Graph | null = null;
176
- private _dag: MutGraph<Node, Edge> | null = null;
180
+ protected _graph: Graph | null = null;
181
+ private _dag: MutGraph<NodeInterface, EdgeInterface> | null = null;
177
182
  private _layoutOperator: LayoutWithConfiguration | null = null;
178
183
  private _rawNodePositions = new Map<string | number, [number, number]>();
179
184
  private _rawEdgePoints = new Map<string | number, [number, number][]>();
@@ -183,19 +188,32 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
183
188
  private _lockedNodePositions = new Map<string | number, [number, number]>();
184
189
  private _dagBounds: DagBounds | null = null;
185
190
 
186
- private _nodeLookup = new Map<string | number, Node>();
187
- private _stringIdLookup = new Map<string, string | number>();
188
- private _edgeLookup = new Map<string, Edge>();
189
- private _incomingParentMap = new Map<string | number, (string | number)[]>();
190
- private _chainDescriptors = new Map<string, CollapsedChainDescriptor>();
191
- private _nodeToChainId = new Map<string | number, string>();
192
- private _collapsedChainState = new Map<string, boolean>();
193
- private _hiddenNodeIds = new Set<string | number>();
191
+ protected _nodeLookup = new Map<string | number, NodeInterface>();
192
+ protected _stringIdLookup = new Map<string, string | number>();
193
+ protected _edgeLookup = new Map<string, EdgeInterface>();
194
+ protected _incomingParentMap = new Map<string | number, (string | number)[]>();
194
195
 
195
- constructor(options: D3DagLayoutOptions = {}) {
196
- super({...D3DagLayout.defaultProps, ...options});
196
+ constructor(props: D3DagLayoutProps, defaultProps?: Required<PropsT>) {
197
+ // @ts-expect-error TS2345 - Type 'Required<D3DagLayoutProps>' is not assignable to type 'Required<PropsT>'.
198
+ super(props, defaultProps || D3DagLayout.defaultProps);
197
199
  }
198
200
 
201
+ setProps(options: Partial<D3DagLayoutProps>): void {
202
+ this.props = {...this.props, ...options};
203
+ if (
204
+ options.layout !== undefined ||
205
+ options.layering !== undefined ||
206
+ options.decross !== undefined ||
207
+ options.coord !== undefined ||
208
+ options.nodeSize !== undefined ||
209
+ options.gap !== undefined ||
210
+ options.separation !== undefined
211
+ ) {
212
+ this._layoutOperator = null;
213
+ }
214
+ }
215
+
216
+
199
217
  initializeGraph(graph: Graph): void {
200
218
  this.updateGraph(graph);
201
219
  }
@@ -206,9 +224,6 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
206
224
  this._stringIdLookup = new Map();
207
225
  this._edgeLookup = new Map();
208
226
  this._incomingParentMap = new Map();
209
- this._chainDescriptors = new Map();
210
- this._nodeToChainId = new Map();
211
- this._hiddenNodeIds = new Set();
212
227
 
213
228
  for (const node of graph.getNodes()) {
214
229
  const id = node.getId();
@@ -246,80 +261,15 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
246
261
  stop(): void {}
247
262
 
248
263
  toggleCollapsedChain(chainId: string): void {
249
- if (!this._graph) {
250
- log.log(1, `D3DagLayout: toggleCollapsedChain(${chainId}) ignored (no graph)`);
251
- return;
252
- }
253
- if (!this._chainDescriptors.has(chainId)) {
254
- this._refreshCollapsedChains();
255
- }
256
- if (!this._chainDescriptors.has(chainId)) {
257
- log.log(1, `D3DagLayout: toggleCollapsedChain(${chainId}) skipped (unknown chain)`);
258
- return;
259
- }
260
- const collapsed = this._isChainCollapsed(chainId);
261
- const nextState = !collapsed;
262
- log.log(
263
- 0,
264
- `D3DagLayout: toggleCollapsedChain(${chainId}) -> ${nextState ? 'collapsed' : 'expanded'}`
265
- );
266
- // eslint-disable-next-line no-console
267
- console.log(
268
- `D3DagLayout: toggleCollapsedChain(${chainId}) -> ${nextState ? 'collapsed' : 'expanded'}`
269
- );
270
- this._collapsedChainState.set(chainId, nextState);
271
- this._runLayout();
264
+ log.log(1, `D3DagLayout: toggleCollapsedChain(${chainId}) ignored (collapsing disabled)`);
272
265
  }
273
266
 
274
267
  setCollapsedChains(chainIds: Iterable<string>): void {
275
- if (!this._graph) {
276
- log.log(1, 'D3DagLayout: setCollapsedChains ignored (no graph)');
277
- return;
278
- }
279
- if (!this._chainDescriptors.size) {
280
- this._refreshCollapsedChains();
281
- }
282
- const desired = new Set(chainIds);
283
- log.log(0, `D3DagLayout: setCollapsedChains(${desired.size}) requested`);
284
- let changed = false;
285
- for (const chainId of this._chainDescriptors.keys()) {
286
- const next = desired.has(chainId);
287
- if (this._isChainCollapsed(chainId) !== next) {
288
- this._collapsedChainState.set(chainId, next);
289
- changed = true;
290
- }
291
- }
292
- if (changed) {
293
- log.log(0, 'D3DagLayout: setCollapsedChains -> changes detected, rerunning layout');
294
- // eslint-disable-next-line no-console
295
- console.log('D3DagLayout: setCollapsedChains -> changes detected, rerunning layout');
296
- this._runLayout();
297
- } else {
298
- log.log(1, 'D3DagLayout: setCollapsedChains -> no changes');
299
- // eslint-disable-next-line no-console
300
- console.log('D3DagLayout: setCollapsedChains -> no changes');
301
- }
302
- }
303
-
304
- setPipelineOptions(options: Partial<D3DagLayoutOptions>): void {
305
- this._options = {...this._options, ...options};
306
- if (
307
- options.layout !== undefined ||
308
- options.layering !== undefined ||
309
- options.decross !== undefined ||
310
- options.coord !== undefined ||
311
- options.nodeSize !== undefined ||
312
- options.gap !== undefined ||
313
- options.separation !== undefined
314
- ) {
315
- this._layoutOperator = null;
316
- }
317
- if (options.collapseLinearChains !== undefined && this._graph) {
318
- this._runLayout();
319
- }
268
+ const desired = Array.isArray(chainIds) ? chainIds : Array.from(chainIds);
269
+ log.log(1, `D3DagLayout: setCollapsedChains(${desired.length}) ignored (collapsing disabled)`);
320
270
  }
321
271
 
322
- getNodePosition(node: Node): [number, number] | null {
272
+ getNodePosition(node: NodeInterface): [number, number] | null {
323
273
  if (this._shouldSkipNode(node.getId())) {
324
274
  return null;
325
275
  }
@@ -327,7 +277,7 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
327
277
  return this._nodePositions.get(mappedId) || null;
328
278
  }
329
279
 
330
- getEdgePosition(edge: Edge):
280
+ getEdgePosition(edge: EdgeInterface):
331
281
  | {
332
282
  type: string;
333
283
  sourcePosition: [number, number];
@@ -363,22 +313,22 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
363
313
  };
364
314
  }
365
315
 
366
- getLinkControlPoints(edge: Edge): [number, number][] {
316
+ getLinkControlPoints(edge: EdgeInterface): [number, number][] {
367
317
  return this._edgeControlPoints.get(edge.getId()) || [];
368
318
  }
369
319
 
370
- lockNodePosition(node: Node, x: number, y: number): void {
320
+ lockNodePosition(node: NodeInterface, x: number, y: number): void {
371
321
  this._lockedNodePositions.set(node.getId(), [x, y]);
372
322
  this._nodePositions.set(node.getId(), [x, y]);
373
323
  this._onLayoutChange();
374
324
  this._onLayoutDone();
375
325
  }
376
326
 
377
- unlockNodePosition(node: Node): void {
327
+ unlockNodePosition(node: NodeInterface): void {
378
328
  this._lockedNodePositions.delete(node.getId());
379
329
  }
380
330
 
381
- private _runLayout(): void {
331
+ protected _runLayout(): void {
382
332
  if (!this._graph) {
383
333
  return;
384
334
  }
@@ -398,160 +348,17 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
398
348
  }
399
349
  }
400
350
 
401
- private _refreshCollapsedChains(): void {
402
- const previousChainCount = this._chainDescriptors.size;
403
- if (!this._graph) {
404
- if (previousChainCount > 0) {
405
- log.log(0, 'D3DagLayout: clearing collapsed chains (graph unavailable)');
406
- // eslint-disable-next-line no-console
407
- console.log('D3DagLayout: clearing collapsed chains (graph unavailable)');
408
- }
409
- this._chainDescriptors.clear();
410
- this._nodeToChainId.clear();
411
- this._hiddenNodeIds.clear();
412
- return;
413
- }
414
-
415
- log.log(
416
- 0,
417
- `D3DagLayout: refreshing collapsed chains (previous=${previousChainCount})`
418
- );
419
- // eslint-disable-next-line no-console
420
- console.log(
421
- `D3DagLayout: refreshing collapsed chains (previous=${previousChainCount})`
422
- );
423
-
424
- const collapseDefault =
425
- this._options.collapseLinearChains ?? D3DagLayout.defaultProps.collapseLinearChains;
426
-
427
- const previousStates = new Map(this._collapsedChainState);
428
-
429
- this._chainDescriptors.clear();
430
- this._nodeToChainId.clear();
431
- this._hiddenNodeIds.clear();
432
-
433
- const nodes = this._graph.getNodes();
434
- const candidateNodes = new Set<string | number>();
435
- const incomingCache = new Map<string | number, Edge[]>();
436
- const outgoingCache = new Map<string | number, Edge[]>();
437
-
438
- for (const node of nodes) {
439
- const incoming = this._getIncomingEdges(node);
440
- const outgoing = this._getOutgoingEdges(node);
441
- incomingCache.set(node.getId(), incoming);
442
- outgoingCache.set(node.getId(), outgoing);
443
- if (incoming.length <= 1 && outgoing.length <= 1 && incoming.length + outgoing.length > 0) {
444
- candidateNodes.add(node.getId());
445
- }
446
- }
447
-
448
- const visited = new Set<string | number>();
449
- for (const node of nodes) {
450
- const nodeId = node.getId();
451
- if (!candidateNodes.has(nodeId) || visited.has(nodeId)) {
452
- continue;
453
- }
454
-
455
- const incoming = incomingCache.get(nodeId) ?? [];
456
- const hasCandidateParent =
457
- incoming.length === 1 && candidateNodes.has(incoming[0].getSourceNodeId());
458
- if (hasCandidateParent) {
459
- continue;
460
- }
461
-
462
- const chainNodeIds: (string | number)[] = [];
463
- const chainEdgeIds: (string | number)[] = [];
464
- let currentNode: Node | undefined = node;
465
-
466
- while (currentNode) {
467
- const currentId = currentNode.getId();
468
- if (!candidateNodes.has(currentId) || visited.has(currentId)) {
469
- break;
470
- }
471
-
472
- visited.add(currentId);
473
- chainNodeIds.push(currentId);
474
-
475
- const outgoing = outgoingCache.get(currentId) ?? [];
476
- if (outgoing.length !== 1) {
477
- break;
478
- }
479
-
480
- const nextEdge = outgoing[0];
481
- const nextNodeId = nextEdge.getTargetNodeId();
482
- if (!candidateNodes.has(nextNodeId)) {
483
- break;
484
- }
485
-
486
- const nextIncoming = incomingCache.get(nextNodeId) ?? [];
487
- if (nextIncoming.length !== 1) {
488
- break;
489
- }
490
-
491
- chainEdgeIds.push(nextEdge.getId());
492
- currentNode = this._nodeLookup.get(nextNodeId);
493
- }
494
-
495
- if (chainNodeIds.length > 1) {
496
- const chainId = this._createChainId(chainNodeIds);
497
- const collapsed = previousStates.has(chainId)
498
- ? previousStates.get(chainId)
499
- : collapseDefault;
500
- this._chainDescriptors.set(chainId, {
501
- id: chainId,
502
- nodeIds: chainNodeIds,
503
- edgeIds: chainEdgeIds,
504
- representativeId: chainNodeIds[0]
505
- });
506
- this._collapsedChainState.set(chainId, collapsed);
507
- for (const chainNodeId of chainNodeIds) {
508
- this._nodeToChainId.set(chainNodeId, chainId);
509
- }
510
- }
511
- }
512
-
513
- for (const key of previousStates.keys()) {
514
- if (!this._chainDescriptors.has(key)) {
515
- this._collapsedChainState.delete(key);
516
- }
517
- }
518
-
519
- this._hiddenNodeIds.clear();
520
- for (const [chainId, descriptor] of this._chainDescriptors) {
521
- const collapsed = this._isChainCollapsed(chainId);
522
- if (collapsed) {
523
- for (const nodeId of descriptor.nodeIds) {
524
- // eslint-disable-next-line max-depth
525
- if (nodeId !== descriptor.representativeId) {
526
- this._hiddenNodeIds.add(nodeId);
527
- }
528
- }
529
- }
530
- }
531
-
351
+ protected _refreshCollapsedChains(): void {
532
352
  this._updateCollapsedChainNodeMetadata();
533
-
534
- let collapsedCount = 0;
535
- for (const chainId of this._chainDescriptors.keys()) {
536
- if (this._isChainCollapsed(chainId)) {
537
- collapsedCount++;
538
- }
539
- }
540
- log.log(
541
- 0,
542
- `D3DagLayout: refreshed collapsed chains -> total=${this._chainDescriptors.size}, collapsed=${collapsedCount}`
543
- );
544
353
  }
545
354
 
546
- private _buildDag(): MutGraph<Node, Edge> {
547
- const builder = this._options.dagBuilder ?? D3DagLayout.defaultProps.dagBuilder;
548
-
549
- if (typeof builder === 'function') {
550
- const dag = builder(this._graph);
355
+ private _buildDag(): MutGraph<NodeInterface, EdgeInterface> {
356
+ if (this.props.customDagBuilder) {
357
+ const dag = this.props.customDagBuilder(this._graph);
551
358
  return this._ensureEdgeData(dag);
552
359
  }
553
360
 
554
- switch (builder) {
361
+ switch (this.props.dagBuilder) {
555
362
  case 'connect':
556
363
  return this._buildDagWithConnect();
557
364
  case 'stratify':
@@ -562,9 +369,9 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
562
369
  }
563
370
  }
564
371
 
565
- private _buildDagWithGraph(): MutGraph<Node, Edge> {
566
- const dag = createDagGraph<Node, Edge>();
567
- const dagNodeLookup = new Map<string | number, MutGraphNode<Node, Edge>>();
372
+ private _buildDagWithGraph(): MutGraph<NodeInterface, EdgeInterface> {
373
+ const dag = createDagGraph<NodeInterface, EdgeInterface>();
374
+ const dagNodeLookup = new Map<string | number, MutGraphNode<NodeInterface, EdgeInterface>>();
568
375
 
569
376
  for (const node of this._graph.getNodes()) {
570
377
  if (this._shouldSkipNode(node.getId())) {
@@ -594,17 +401,18 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
594
401
  return dag;
595
402
  }
596
403
 
597
- private _buildDagWithConnect(): MutGraph<Node, Edge> {
598
- type ConnectDatum = {source: string; target: string; edge: Edge};
404
+ private _buildDagWithConnect(): MutGraph<NodeInterface, EdgeInterface> {
405
+ type ConnectDatum = {source: string; target: string; edge: EdgeInterface};
599
406
 
600
407
  const connect = graphConnect()
601
408
  .sourceId(({source}: ConnectDatum): string => source)
602
409
  .targetId(({target}: ConnectDatum): string => target)
603
- .nodeDatum((id: string): Node => this._nodeLookup.get(this._fromDagId(id)) ?? new Node({id}))
410
+ .nodeDatum((id: string): NodeInterface => this._nodeLookup.get(this._fromDagId(id)) ?? new Node({id}))
604
411
  .single(true);
605
412
 
606
- const data: ConnectDatum[] = this._graph
607
- .getEdges()
413
+ const edges = Array.from(this._graph.getEdges());
414
+
415
+ const data: ConnectDatum[] = edges
608
416
  .filter((edge) => edge.isDirected())
609
417
  .map((edge) => {
610
418
  const sourceId = this._mapNodeId(edge.getSourceNodeId());
@@ -623,7 +431,7 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
623
431
  const seenIds = new Set<string | number>();
624
432
  for (const dagNode of dag.nodes()) {
625
433
  const datum = dagNode.data;
626
- if (datum instanceof Node) {
434
+ if (isNodeInterface(datum)) {
627
435
  seenIds.add(datum.getId());
628
436
  }
629
437
  }
@@ -640,10 +448,10 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
640
448
  return this._ensureEdgeData(dag);
641
449
  }
642
450
 
643
- private _buildDagWithStratify(): MutGraph<Node, Edge> {
451
+ private _buildDagWithStratify(): MutGraph<NodeInterface, EdgeInterface> {
644
452
  const stratify = graphStratify()
645
- .id((node: Node): string => this._toDagId(node.getId()))
646
- .parentIds((node: Node): Iterable<string> => {
453
+ .id((node: NodeInterface): string => this._toDagId(node.getId()))
454
+ .parentIds((node: NodeInterface): Iterable<string> => {
647
455
  const parentIds = this._incomingParentMap.get(node.getId()) ?? [];
648
456
  const mapped = new Set<string>();
649
457
  for (const parentId of parentIds) {
@@ -659,104 +467,65 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
659
467
  return mapped;
660
468
  });
661
469
 
662
- const dag = stratify(this._graph.getNodes().filter((node) => !this._shouldSkipNode(node.getId())));
470
+ const nodes = Array.from(this._graph.getNodes());
471
+ const dag = stratify(nodes.filter((node) => !this._shouldSkipNode(node.getId())));
663
472
  return this._ensureEdgeData(dag);
664
473
  }
665
474
 
666
- private _isChainCollapsed(chainId: string): boolean {
667
- const collapseDefault =
668
- this._options.collapseLinearChains ?? D3DagLayout.defaultProps.collapseLinearChains;
669
- return this._collapsedChainState.get(chainId) ?? collapseDefault;
670
- }
671
-
672
- private _shouldSkipNode(nodeId: string | number): boolean {
673
- return this._hiddenNodeIds.has(nodeId);
475
+ protected _shouldSkipNode(_nodeId: string | number): boolean {
476
+ return false;
674
477
  }
675
478
 
676
- private _mapNodeId(nodeId: string | number): string | number {
677
- const chainId = this._nodeToChainId.get(nodeId);
678
- if (!chainId) {
679
- return nodeId;
680
- }
681
- const descriptor = this._chainDescriptors.get(chainId);
682
- if (!descriptor) {
683
- return nodeId;
684
- }
685
- return this._isChainCollapsed(chainId) ? descriptor.representativeId : nodeId;
479
+ protected _mapNodeId(nodeId: string | number): string | number {
480
+ return nodeId;
686
481
  }
687
482
 
688
- private _updateCollapsedChainNodeMetadata(): void {
483
+ protected _updateCollapsedChainNodeMetadata(): void {
689
484
  if (!this._graph) {
690
485
  return;
691
486
  }
692
487
  for (const node of this._graph.getNodes()) {
693
- const nodeId = node.getId();
694
- const chainId = this._nodeToChainId.get(nodeId);
695
- if (!chainId) {
696
- node.setDataProperty('collapsedChainId', null);
697
- node.setDataProperty('collapsedChainLength', 1);
698
- node.setDataProperty('collapsedNodeIds', []);
699
- node.setDataProperty('collapsedEdgeIds', []);
700
- node.setDataProperty('collapsedChainRepresentativeId', null);
701
- node.setDataProperty('isCollapsedChain', false);
702
- continue;
703
- }
704
- const descriptor = this._chainDescriptors.get(chainId);
705
- if (!descriptor) {
706
- node.setDataProperty('collapsedChainId', null);
707
- node.setDataProperty('collapsedChainLength', 1);
708
- node.setDataProperty('collapsedNodeIds', []);
709
- node.setDataProperty('collapsedEdgeIds', []);
710
- node.setDataProperty('collapsedChainRepresentativeId', null);
711
- node.setDataProperty('isCollapsedChain', false);
712
- continue;
713
- }
714
- const collapsed = this._isChainCollapsed(chainId);
715
- node.setDataProperty('collapsedChainId', chainId);
716
- node.setDataProperty('collapsedChainLength', collapsed ? descriptor.nodeIds.length : 1);
717
- node.setDataProperty('collapsedNodeIds', descriptor.nodeIds);
718
- node.setDataProperty('collapsedEdgeIds', descriptor.edgeIds);
719
- node.setDataProperty('collapsedChainRepresentativeId', descriptor.representativeId);
720
- node.setDataProperty('isCollapsedChain', collapsed);
488
+ node.setDataProperty('collapsedChainId', null);
489
+ node.setDataProperty('collapsedChainLength', 1);
490
+ node.setDataProperty('collapsedNodeIds', []);
491
+ node.setDataProperty('collapsedEdgeIds', []);
492
+ node.setDataProperty('collapsedChainRepresentativeId', null);
493
+ node.setDataProperty('isCollapsedChain', false);
721
494
  }
722
495
  }
723
496
 
724
- private _createChainId(nodeIds: (string | number)[]): string {
725
- return `chain:${nodeIds.map((id) => this._toDagId(id)).join('>')}`;
726
- }
727
-
728
- private _getIncomingEdges(node: Node): Edge[] {
497
+ protected _getIncomingEdges(node: NodeInterface): EdgeInterface[] {
729
498
  const nodeId = node.getId();
730
499
  return node
731
500
  .getConnectedEdges()
732
501
  .filter((edge) => edge.isDirected() && edge.getTargetNodeId() === nodeId);
733
502
  }
734
503
 
735
- private _getOutgoingEdges(node: Node): Edge[] {
504
+ protected _getOutgoingEdges(node: NodeInterface): EdgeInterface[] {
736
505
  const nodeId = node.getId();
737
506
  return node
738
507
  .getConnectedEdges()
739
508
  .filter((edge) => edge.isDirected() && edge.getSourceNodeId() === nodeId);
740
509
  }
741
510
 
742
- private _ensureEdgeData<T>(dag: MutGraph<Node, T>): MutGraph<Node, Edge> {
511
+ private _ensureEdgeData<T>(dag: MutGraph<NodeInterface, T>): MutGraph<NodeInterface, EdgeInterface> {
743
512
  for (const link of dag.links()) {
744
- if (link.data instanceof Edge) {
513
+ if (isEdgeInterface(link.data)) {
745
514
  continue;
746
515
  }
747
516
  const sourceNode = link.source.data;
748
517
  const targetNode = link.target.data;
749
- if (!(sourceNode instanceof Node) || !(targetNode instanceof Node)) {
518
+ if (!isNodeInterface(sourceNode) || !isNodeInterface(targetNode)) {
750
519
  continue;
751
520
  }
752
521
  const key = this._edgeKey(sourceNode.getId(), targetNode.getId());
753
522
  const edge = this._edgeLookup.get(key);
754
523
  if (edge) {
755
- (link as unknown as MutGraphLink<Node, Edge>).data = edge;
524
+ (link as unknown as MutGraphLink<NodeInterface, EdgeInterface>).data = edge;
756
525
  }
757
526
  }
758
527
 
759
- return dag as unknown as MutGraph<Node, Edge>;
528
+ return dag as unknown as MutGraph<NodeInterface, EdgeInterface>;
760
529
  }
761
530
 
762
531
  private _getLayoutOperator(): LayoutWithConfiguration {
@@ -764,7 +533,7 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
764
533
  return this._layoutOperator;
765
534
  }
766
535
 
767
- const layoutOption = this._options.layout ?? D3DagLayout.defaultProps.layout;
536
+ const layoutOption = this.props.layout ?? D3DagLayout.defaultProps.layout;
768
537
  let layout: LayoutWithConfiguration;
769
538
 
770
539
  if (typeof layoutOption === 'string') {
@@ -773,24 +542,41 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
773
542
  layout = layoutOption as LayoutWithConfiguration;
774
543
  }
775
544
 
776
- if (layout.layering && this._options.layering) {
777
- layout = layout.layering(this._resolveLayering(this._options.layering));
545
+ // TODO - is 'none' operator an option in d3-dag?
546
+ if (layout.layering && this.props.layering) {
547
+ let layeringOperator = this.props.customLayering || LAYERING_FACTORIES[this.props.layering]();
548
+ layout = layout.layering(layeringOperator);
549
+ const {nodeRank} = this.props;
550
+ if (nodeRank) {
551
+ // @ts-expect-error TS2345 - Argument of type '(dagNode: MutGraphNode<NodeInterface, EdgeInterface>) => number | undefined' is not assignable to parameter of type '(dagNode: MutGraphNode<NodeInterface, EdgeInterface>) => number'.
552
+ layeringOperator = layeringOperator.rank((dagNode) => {
553
+ const node = dagNode.data as NodeInterface;
554
+ const rank = typeof nodeRank === 'function' ? nodeRank?.(node) : node?.getPropertyValue(nodeRank) || undefined;
555
+ // if (rank !== undefined) {
556
+ // console.log(`Node ${node.getId()} assigned to rank ${rank}`);
557
+ // }
558
+ return rank;
559
+ });
560
+ }
561
+ layout = layout.layering(layeringOperator);
778
562
  }
779
563
 
780
- if (layout.decross && this._options.decross) {
781
- layout = layout.decross(this._resolveDecross(this._options.decross));
564
+ if (layout.decross && this.props.decross) {
565
+ const decrossOperator = this.props.customDecross || DECROSS_FACTORIES[this.props.decross]();
566
+ layout = layout.decross(decrossOperator);
782
567
  }
783
568
 
784
- if (layout.coord && this._options.coord) {
785
- layout = layout.coord(this._resolveCoord(this._options.coord));
569
+ if (layout.coord && this.props.coord) {
570
+ const coordOperator = this.props.customCoord || COORD_FACTORIES[this.props.coord]();
571
+ layout = layout.coord(coordOperator);
786
572
  }
787
573
 
788
- const nodeSize = this._options.nodeSize ?? DEFAULT_NODE_SIZE;
574
+ const nodeSize = this.props.nodeSize ?? DEFAULT_NODE_SIZE;
789
575
  if (layout.nodeSize) {
790
576
  layout = layout.nodeSize(nodeSize);
791
577
  }
792
578
 
793
- const gap = this._options.separation ?? this._options.gap ?? DEFAULT_GAP;
579
+ const gap = this.props.separation ?? this.props.gap ?? DEFAULT_GAP;
794
580
  if (layout.gap) {
795
581
  layout = layout.gap(gap);
796
582
  }
@@ -799,27 +585,6 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
799
585
  return layout;
800
586
  }
801
587
 
802
- private _resolveLayering(option: D3DagLayeringName | LayeringOperator): LayeringOperator {
803
- if (typeof option === 'string') {
804
- return LAYERING_FACTORIES[option]();
805
- }
806
- return option;
807
- }
808
-
809
- private _resolveDecross(option: D3DagDecrossName | DecrossOperator): Decross<Node, Edge> {
810
- if (typeof option === 'string') {
811
- return DECROSS_FACTORIES[option]();
812
- }
813
- return option;
814
- }
815
-
816
- private _resolveCoord(option: D3DagCoordName | CoordOperator): Coord<Node, Edge> {
817
- if (typeof option === 'string') {
818
- return COORD_FACTORIES[option]();
819
- }
820
- return option;
821
- }
822
-
823
588
  private _cacheGeometry(): void {
824
589
  this._rawNodePositions.clear();
825
590
  this._rawEdgePoints.clear();
@@ -870,7 +635,12 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
870
635
  for (const link of this._dag.links()) {
871
636
  const source = link.source.data;
872
637
  const target = link.target.data;
873
- const edge = link.data instanceof Edge ? link.data : this._edgeLookup.get(this._edgeKey(source.getId(), target.getId()));
638
+ if (!isNodeInterface(source) || !isNodeInterface(target)) {
639
+ continue;
640
+ }
641
+ const edge = isEdgeInterface(link.data)
642
+ ? link.data
643
+ : this._edgeLookup.get(this._edgeKey(source.getId(), target.getId()));
874
644
  if (!edge) {
875
645
  continue;
876
646
  }
@@ -892,7 +662,7 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
892
662
  }
893
663
 
894
664
  const {offsetX, offsetY} = this._getOffsets();
895
- const orientation = this._options.orientation ?? D3DagLayout.defaultProps.orientation;
665
+ const orientation = this.props.orientation ?? D3DagLayout.defaultProps.orientation;
896
666
 
897
667
  const transform = (x: number, y: number): [number, number] => {
898
668
  const localX = x - offsetX;
@@ -934,7 +704,7 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
934
704
  if (!this._dagBounds) {
935
705
  return {offsetX: 0, offsetY: 0};
936
706
  }
937
- const centerOption = this._options.center ?? true;
707
+ const centerOption = this.props.center ?? true;
938
708
  let offsetX = 0;
939
709
  let offsetY = 0;
940
710
  if (centerOption === true) {
@@ -955,15 +725,15 @@ export class D3DagLayout extends GraphLayout<D3DagLayoutOptions> {
955
725
  this._bounds = this._calculateBounds(this._nodePositions.values());
956
726
  }
957
727
 
958
- private _edgeKey(sourceId: string | number, targetId: string | number): string {
728
+ protected _edgeKey(sourceId: string | number, targetId: string | number): string {
959
729
  return `${this._toDagId(sourceId)}${DAG_ID_SEPARATOR}${this._toDagId(targetId)}`;
960
730
  }
961
731
 
962
- private _toDagId(id: string | number): string {
732
+ protected _toDagId(id: string | number): string {
963
733
  return String(id);
964
734
  }
965
735
 
966
- private _fromDagId(id: string): string | number {
736
+ protected _fromDagId(id: string): string | number {
967
737
  return this._stringIdLookup.get(id) ?? id;
968
738
  }
969
739
  }