@statewalker/fsm-charts 0.0.1

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 (132) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1 -0
  4. package/dist/StateChart-DNGQd1XG.d.ts +53 -0
  5. package/dist/chunk-3GGM3ZWL.js +2685 -0
  6. package/dist/chunk-NXWOFQMO.js +10 -0
  7. package/dist/chunk-TPNWHU7Y.js +437 -0
  8. package/dist/index-layout.d.ts +96 -0
  9. package/dist/index-layout.js +2 -0
  10. package/dist/index-svg.d.ts +25 -0
  11. package/dist/index-svg.js +2 -0
  12. package/dist/index.d.ts +3 -0
  13. package/dist/index.js +3 -0
  14. package/package.json +60 -0
  15. package/src/FsmStateConfig.ts +5 -0
  16. package/src/dagre/acyclic.d.ts +2 -0
  17. package/src/dagre/acyclic.js +60 -0
  18. package/src/dagre/add-border-segments.d.ts +1 -0
  19. package/src/dagre/add-border-segments.js +36 -0
  20. package/src/dagre/coordinate-system.d.ts +2 -0
  21. package/src/dagre/coordinate-system.js +75 -0
  22. package/src/dagre/data/list.d.ts +12 -0
  23. package/src/dagre/data/list.js +55 -0
  24. package/src/dagre/debug.d.ts +2 -0
  25. package/src/dagre/debug.js +32 -0
  26. package/src/dagre/greedy-fas.d.ts +1 -0
  27. package/src/dagre/greedy-fas.js +126 -0
  28. package/src/dagre/index.d.ts +5 -0
  29. package/src/dagre/index.js +6 -0
  30. package/src/dagre/layout.d.ts +1 -0
  31. package/src/dagre/layout.js +466 -0
  32. package/src/dagre/nesting-graph.d.ts +2 -0
  33. package/src/dagre/nesting-graph.js +137 -0
  34. package/src/dagre/normalize.d.ts +2 -0
  35. package/src/dagre/normalize.js +91 -0
  36. package/src/dagre/order/add-subgraph-constraints.d.ts +1 -0
  37. package/src/dagre/order/add-subgraph-constraints.js +53 -0
  38. package/src/dagre/order/barycenter.d.ts +15 -0
  39. package/src/dagre/order/barycenter.js +31 -0
  40. package/src/dagre/order/build-layer-graph.d.ts +2 -0
  41. package/src/dagre/order/build-layer-graph.js +76 -0
  42. package/src/dagre/order/cross-count.d.ts +1 -0
  43. package/src/dagre/order/cross-count.js +82 -0
  44. package/src/dagre/order/index.d.ts +1 -0
  45. package/src/dagre/order/index.js +77 -0
  46. package/src/dagre/order/init-order.d.ts +1 -0
  47. package/src/dagre/order/init-order.js +44 -0
  48. package/src/dagre/order/resolve-conflicts.d.ts +1 -0
  49. package/src/dagre/order/resolve-conflicts.js +128 -0
  50. package/src/dagre/order/sort-subgraph.d.ts +8 -0
  51. package/src/dagre/order/sort-subgraph.js +78 -0
  52. package/src/dagre/order/sort.d.ts +6 -0
  53. package/src/dagre/order/sort.js +59 -0
  54. package/src/dagre/parent-dummy-chains.d.ts +1 -0
  55. package/src/dagre/parent-dummy-chains.js +86 -0
  56. package/src/dagre/position/bk.d.ts +31 -0
  57. package/src/dagre/position/bk.js +423 -0
  58. package/src/dagre/position/index.d.ts +1 -0
  59. package/src/dagre/position/index.js +31 -0
  60. package/src/dagre/rank/feasible-tree.d.ts +2 -0
  61. package/src/dagre/rank/feasible-tree.js +87 -0
  62. package/src/dagre/rank/index.d.ts +1 -0
  63. package/src/dagre/rank/index.js +52 -0
  64. package/src/dagre/rank/network-simplex.d.ts +16 -0
  65. package/src/dagre/rank/network-simplex.js +236 -0
  66. package/src/dagre/rank/util.d.ts +2 -0
  67. package/src/dagre/rank/util.js +63 -0
  68. package/src/dagre/util.d.ts +27 -0
  69. package/src/dagre/util.js +250 -0
  70. package/src/graphlib/alg/components.d.ts +1 -0
  71. package/src/graphlib/alg/components.js +27 -0
  72. package/src/graphlib/alg/dfs.d.ts +1 -0
  73. package/src/graphlib/alg/dfs.js +46 -0
  74. package/src/graphlib/alg/dijkstra-all.d.ts +1 -0
  75. package/src/graphlib/alg/dijkstra-all.js +14 -0
  76. package/src/graphlib/alg/dijkstra.d.ts +1 -0
  77. package/src/graphlib/alg/dijkstra.js +65 -0
  78. package/src/graphlib/alg/find-cycles.d.ts +1 -0
  79. package/src/graphlib/alg/find-cycles.js +10 -0
  80. package/src/graphlib/alg/floyd-warshall.d.ts +1 -0
  81. package/src/graphlib/alg/floyd-warshall.js +55 -0
  82. package/src/graphlib/alg/index.d.ts +24 -0
  83. package/src/graphlib/alg/index.js +25 -0
  84. package/src/graphlib/alg/is-acyclic.d.ts +1 -0
  85. package/src/graphlib/alg/is-acyclic.js +15 -0
  86. package/src/graphlib/alg/postorder.d.ts +1 -0
  87. package/src/graphlib/alg/postorder.js +7 -0
  88. package/src/graphlib/alg/preorder.d.ts +1 -0
  89. package/src/graphlib/alg/preorder.js +7 -0
  90. package/src/graphlib/alg/prim.d.ts +2 -0
  91. package/src/graphlib/alg/prim.js +52 -0
  92. package/src/graphlib/alg/tarjan.d.ts +1 -0
  93. package/src/graphlib/alg/tarjan.js +47 -0
  94. package/src/graphlib/alg/topsort.d.ts +5 -0
  95. package/src/graphlib/alg/topsort.js +36 -0
  96. package/src/graphlib/data/priority-queue.d.ts +59 -0
  97. package/src/graphlib/data/priority-queue.js +152 -0
  98. package/src/graphlib/graph.d.ts +55 -0
  99. package/src/graphlib/graph.js +510 -0
  100. package/src/graphlib/index.d.ts +3 -0
  101. package/src/graphlib/index.js +7 -0
  102. package/src/graphlib/json.d.ts +16 -0
  103. package/src/graphlib/json.js +63 -0
  104. package/src/index-layout.ts +1 -0
  105. package/src/index-svg.ts +1 -0
  106. package/src/index.ts +2 -0
  107. package/src/layout/Dimensions.ts +8 -0
  108. package/src/layout/GraphParamsProvider.ts +17 -0
  109. package/src/layout/Padding.ts +10 -0
  110. package/src/layout/Position.ts +4 -0
  111. package/src/layout/StateChart.ts +8 -0
  112. package/src/layout/StateGraphEdge.ts +14 -0
  113. package/src/layout/StateGraphNode.ts +12 -0
  114. package/src/layout/Transition.ts +5 -0
  115. package/src/layout/TransitionsGraph.ts +13 -0
  116. package/src/layout/buildCharts.ts +74 -0
  117. package/src/layout/buildFlatCharts.ts +142 -0
  118. package/src/layout/getGraphParamsProvider.ts +63 -0
  119. package/src/layout/getLabelDimensions.ts +59 -0
  120. package/src/layout/index.ts +15 -0
  121. package/src/lodash-es/_deleteme.js +291 -0
  122. package/src/lodash-es/index.ts +9 -0
  123. package/src/lodash-es/types.ts +35 -0
  124. package/src/svg/buildStatechartCss.ts +120 -0
  125. package/src/svg/buildStatechartSvg.ts +256 -0
  126. package/src/svg/buildStatechartsPanel.ts +38 -0
  127. package/src/svg/index.ts +3 -0
  128. package/src/utils/BasisCurve.ts +89 -0
  129. package/src/utils/getPadding.ts +13 -0
  130. package/src/utils/serializeAttrs.ts +28 -0
  131. package/src/utils/serializeStyle.ts +11 -0
  132. package/src/utils/toKebabCase.ts +18 -0
@@ -0,0 +1,466 @@
1
+ import { _ } from '../lodash-es/index.ts';
2
+ import { Graph } from '../graphlib/index.js';
3
+ import { addBorderSegments } from './add-border-segments.js';
4
+ import * as coordinateSystem from './coordinate-system.js';
5
+ import * as acyclic from './acyclic.js';
6
+ import * as normalize from './normalize.js';
7
+ import { rank } from './rank/index.js';
8
+ import * as nestingGraph from './nesting-graph.js';
9
+ import { order } from './order/index.js';
10
+ import { parentDummyChains } from './parent-dummy-chains.js';
11
+ import { position } from './position/index.js';
12
+ import * as util from './util.js';
13
+
14
+ export { layout };
15
+
16
+ function layout(g, opts) {
17
+ var time = opts && opts.debugTiming ? util.time : util.notime;
18
+ time('layout', function () {
19
+ var layoutGraph = time(' buildLayoutGraph', function () {
20
+ return buildLayoutGraph(g);
21
+ });
22
+ time(' runLayout', function () {
23
+ runLayout(layoutGraph, time);
24
+ });
25
+ time(' updateInputGraph', function () {
26
+ updateInputGraph(g, layoutGraph);
27
+ });
28
+ });
29
+ }
30
+
31
+ function runLayout(g, time) {
32
+ time(' makeSpaceForEdgeLabels', function () {
33
+ makeSpaceForEdgeLabels(g);
34
+ });
35
+ time(' removeSelfEdges', function () {
36
+ removeSelfEdges(g);
37
+ });
38
+ time(' acyclic', function () {
39
+ acyclic.run(g);
40
+ });
41
+ time(' nestingGraph.run', function () {
42
+ nestingGraph.run(g);
43
+ });
44
+ time(' rank', function () {
45
+ rank(util.asNonCompoundGraph(g));
46
+ });
47
+ time(' injectEdgeLabelProxies', function () {
48
+ injectEdgeLabelProxies(g);
49
+ });
50
+ time(' removeEmptyRanks', function () {
51
+ util.removeEmptyRanks(g);
52
+ });
53
+ time(' nestingGraph.cleanup', function () {
54
+ nestingGraph.cleanup(g);
55
+ });
56
+ time(' normalizeRanks', function () {
57
+ util.normalizeRanks(g);
58
+ });
59
+ time(' assignRankMinMax', function () {
60
+ assignRankMinMax(g);
61
+ });
62
+ time(' removeEdgeLabelProxies', function () {
63
+ removeEdgeLabelProxies(g);
64
+ });
65
+ time(' normalize.run', function () {
66
+ normalize.run(g);
67
+ });
68
+ time(' parentDummyChains', function () {
69
+ parentDummyChains(g);
70
+ });
71
+ time(' addBorderSegments', function () {
72
+ addBorderSegments(g);
73
+ });
74
+ time(' order', function () {
75
+ order(g);
76
+ });
77
+ time(' insertSelfEdges', function () {
78
+ insertSelfEdges(g);
79
+ });
80
+ time(' adjustCoordinateSystem', function () {
81
+ coordinateSystem.adjust(g);
82
+ });
83
+ time(' position', function () {
84
+ position(g);
85
+ });
86
+ time(' positionSelfEdges', function () {
87
+ positionSelfEdges(g);
88
+ });
89
+ time(' removeBorderNodes', function () {
90
+ removeBorderNodes(g);
91
+ });
92
+ time(' normalize.undo', function () {
93
+ normalize.undo(g);
94
+ });
95
+ time(' fixupEdgeLabelCoords', function () {
96
+ fixupEdgeLabelCoords(g);
97
+ });
98
+ time(' undoCoordinateSystem', function () {
99
+ coordinateSystem.undo(g);
100
+ });
101
+ time(' translateGraph', function () {
102
+ translateGraph(g);
103
+ });
104
+ time(' assignNodeIntersects', function () {
105
+ assignNodeIntersects(g);
106
+ });
107
+ time(' reversePoints', function () {
108
+ reversePointsForReversedEdges(g);
109
+ });
110
+ time(' acyclic.undo', function () {
111
+ acyclic.undo(g);
112
+ });
113
+ }
114
+
115
+ /*
116
+ * Copies final layout information from the layout graph back to the input
117
+ * graph. This process only copies whitelisted attributes from the layout graph
118
+ * to the input graph, so it serves as a good place to determine what
119
+ * attributes can influence layout.
120
+ */
121
+ function updateInputGraph(inputGraph, layoutGraph) {
122
+ _.forEach(inputGraph.nodes(), function (v) {
123
+ var inputLabel = inputGraph.node(v);
124
+ var layoutLabel = layoutGraph.node(v);
125
+
126
+ if (inputLabel) {
127
+ inputLabel.x = layoutLabel.x;
128
+ inputLabel.y = layoutLabel.y;
129
+
130
+ if (layoutGraph.children(v).length) {
131
+ inputLabel.width = layoutLabel.width;
132
+ inputLabel.height = layoutLabel.height;
133
+ }
134
+ }
135
+ });
136
+
137
+ _.forEach(inputGraph.edges(), function (e) {
138
+ var inputLabel = inputGraph.edge(e);
139
+ var layoutLabel = layoutGraph.edge(e);
140
+
141
+ inputLabel.points = layoutLabel.points;
142
+ if (_.has(layoutLabel, 'x')) {
143
+ inputLabel.x = layoutLabel.x;
144
+ inputLabel.y = layoutLabel.y;
145
+ }
146
+ });
147
+
148
+ inputGraph.graph().width = layoutGraph.graph().width;
149
+ inputGraph.graph().height = layoutGraph.graph().height;
150
+ }
151
+
152
+ var graphNumAttrs = ['nodesep', 'edgesep', 'ranksep', 'marginx', 'marginy'];
153
+ var graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: 'tb' };
154
+ var graphAttrs = ['acyclicer', 'ranker', 'rankdir', 'align'];
155
+ var nodeNumAttrs = ['width', 'height'];
156
+ var nodeDefaults = { width: 0, height: 0 };
157
+ var edgeNumAttrs = ['minlen', 'weight', 'width', 'height', 'labeloffset'];
158
+ var edgeDefaults = {
159
+ minlen: 1,
160
+ weight: 1,
161
+ width: 0,
162
+ height: 0,
163
+ labeloffset: 10,
164
+ labelpos: 'r',
165
+ };
166
+ var edgeAttrs = ['labelpos'];
167
+
168
+ /*
169
+ * Constructs a new graph from the input graph, which can be used for layout.
170
+ * This process copies only whitelisted attributes from the input graph to the
171
+ * layout graph. Thus this function serves as a good place to determine what
172
+ * attributes can influence layout.
173
+ */
174
+ function buildLayoutGraph(inputGraph) {
175
+ var g = new Graph({ multigraph: true, compound: true });
176
+ var graph = canonicalize(inputGraph.graph());
177
+
178
+ g.setGraph(
179
+ _.merge({}, graphDefaults, selectNumberAttrs(graph, graphNumAttrs), _.pick(graph, graphAttrs))
180
+ );
181
+
182
+ _.forEach(inputGraph.nodes(), function (v) {
183
+ var node = canonicalize(inputGraph.node(v));
184
+ g.setNode(v, _.defaults(selectNumberAttrs(node, nodeNumAttrs), nodeDefaults));
185
+ g.setParent(v, inputGraph.parent(v));
186
+ });
187
+
188
+ _.forEach(inputGraph.edges(), function (e) {
189
+ var edge = canonicalize(inputGraph.edge(e));
190
+ g.setEdge(
191
+ e,
192
+ _.merge({}, edgeDefaults, selectNumberAttrs(edge, edgeNumAttrs), _.pick(edge, edgeAttrs))
193
+ );
194
+ });
195
+
196
+ return g;
197
+ }
198
+
199
+ /*
200
+ * This idea comes from the Gansner paper: to account for edge labels in our
201
+ * layout we split each rank in half by doubling minlen and halving ranksep.
202
+ * Then we can place labels at these mid-points between nodes.
203
+ *
204
+ * We also add some minimal padding to the width to push the label for the edge
205
+ * away from the edge itself a bit.
206
+ */
207
+ function makeSpaceForEdgeLabels(g) {
208
+ var graph = g.graph();
209
+ graph.ranksep /= 2;
210
+ _.forEach(g.edges(), function (e) {
211
+ var edge = g.edge(e);
212
+ edge.minlen *= 2;
213
+ if (edge.labelpos.toLowerCase() !== 'c') {
214
+ if (graph.rankdir === 'TB' || graph.rankdir === 'BT') {
215
+ edge.width += edge.labeloffset;
216
+ } else {
217
+ edge.height += edge.labeloffset;
218
+ }
219
+ }
220
+ });
221
+ }
222
+
223
+ /*
224
+ * Creates temporary dummy nodes that capture the rank in which each edge's
225
+ * label is going to, if it has one of non-zero width and height. We do this
226
+ * so that we can safely remove empty ranks while preserving balance for the
227
+ * label's position.
228
+ */
229
+ function injectEdgeLabelProxies(g) {
230
+ _.forEach(g.edges(), function (e) {
231
+ var edge = g.edge(e);
232
+ if (edge.width && edge.height) {
233
+ var v = g.node(e.v);
234
+ var w = g.node(e.w);
235
+ var label = { rank: (w.rank - v.rank) / 2 + v.rank, e: e };
236
+ util.addDummyNode(g, 'edge-proxy', label, '_ep');
237
+ }
238
+ });
239
+ }
240
+
241
+ function assignRankMinMax(g) {
242
+ var maxRank = 0;
243
+ _.forEach(g.nodes(), function (v) {
244
+ var node = g.node(v);
245
+ if (node.borderTop) {
246
+ node.minRank = g.node(node.borderTop).rank;
247
+ node.maxRank = g.node(node.borderBottom).rank;
248
+ // @ts-expect-error
249
+ maxRank = _.max(maxRank, node.maxRank);
250
+ }
251
+ });
252
+ g.graph().maxRank = maxRank;
253
+ }
254
+
255
+ function removeEdgeLabelProxies(g) {
256
+ _.forEach(g.nodes(), function (v) {
257
+ var node = g.node(v);
258
+ if (node.dummy === 'edge-proxy') {
259
+ g.edge(node.e).labelRank = node.rank;
260
+ g.removeNode(v);
261
+ }
262
+ });
263
+ }
264
+
265
+ function translateGraph(g) {
266
+ var minX = Number.POSITIVE_INFINITY;
267
+ var maxX = 0;
268
+ var minY = Number.POSITIVE_INFINITY;
269
+ var maxY = 0;
270
+ var graphLabel = g.graph();
271
+ var marginX = graphLabel.marginx || 0;
272
+ var marginY = graphLabel.marginy || 0;
273
+
274
+ function getExtremes(attrs) {
275
+ var x = attrs.x;
276
+ var y = attrs.y;
277
+ var w = attrs.width;
278
+ var h = attrs.height;
279
+ minX = Math.min(minX, x - w / 2);
280
+ maxX = Math.max(maxX, x + w / 2);
281
+ minY = Math.min(minY, y - h / 2);
282
+ maxY = Math.max(maxY, y + h / 2);
283
+ }
284
+
285
+ _.forEach(g.nodes(), function (v) {
286
+ getExtremes(g.node(v));
287
+ });
288
+ _.forEach(g.edges(), function (e) {
289
+ var edge = g.edge(e);
290
+ if (_.has(edge, 'x')) {
291
+ getExtremes(edge);
292
+ }
293
+ });
294
+
295
+ minX -= marginX;
296
+ minY -= marginY;
297
+
298
+ _.forEach(g.nodes(), function (v) {
299
+ var node = g.node(v);
300
+ node.x -= minX;
301
+ node.y -= minY;
302
+ });
303
+
304
+ _.forEach(g.edges(), function (e) {
305
+ var edge = g.edge(e);
306
+ _.forEach(edge.points, function (p) {
307
+ p.x -= minX;
308
+ p.y -= minY;
309
+ });
310
+ if (_.has(edge, 'x')) {
311
+ edge.x -= minX;
312
+ }
313
+ if (_.has(edge, 'y')) {
314
+ edge.y -= minY;
315
+ }
316
+ });
317
+
318
+ graphLabel.width = maxX - minX + marginX;
319
+ graphLabel.height = maxY - minY + marginY;
320
+ }
321
+
322
+ function assignNodeIntersects(g) {
323
+ _.forEach(g.edges(), function (e) {
324
+ var edge = g.edge(e);
325
+ var nodeV = g.node(e.v);
326
+ var nodeW = g.node(e.w);
327
+ var p1, p2;
328
+ if (!edge.points) {
329
+ edge.points = [];
330
+ p1 = nodeW;
331
+ p2 = nodeV;
332
+ } else {
333
+ p1 = edge.points[0];
334
+ p2 = edge.points[edge.points.length - 1];
335
+ }
336
+ edge.points.unshift(util.intersectRect(nodeV, p1));
337
+ edge.points.push(util.intersectRect(nodeW, p2));
338
+ });
339
+ }
340
+
341
+ function fixupEdgeLabelCoords(g) {
342
+ _.forEach(g.edges(), function (e) {
343
+ var edge = g.edge(e);
344
+ if (_.has(edge, 'x')) {
345
+ if (edge.labelpos === 'l' || edge.labelpos === 'r') {
346
+ edge.width -= edge.labeloffset;
347
+ }
348
+ switch (edge.labelpos) {
349
+ case 'l':
350
+ edge.x -= edge.width / 2 + edge.labeloffset;
351
+ break;
352
+ case 'r':
353
+ edge.x += edge.width / 2 + edge.labeloffset;
354
+ break;
355
+ }
356
+ }
357
+ });
358
+ }
359
+
360
+ function reversePointsForReversedEdges(g) {
361
+ _.forEach(g.edges(), function (e) {
362
+ var edge = g.edge(e);
363
+ if (edge.reversed) {
364
+ edge.points.reverse();
365
+ }
366
+ });
367
+ }
368
+
369
+ function removeBorderNodes(g) {
370
+ _.forEach(g.nodes(), function (v) {
371
+ if (g.children(v).length) {
372
+ var node = g.node(v);
373
+ var t = g.node(node.borderTop);
374
+ var b = g.node(node.borderBottom);
375
+ var l = g.node(_.last(node.borderLeft));
376
+ var r = g.node(_.last(node.borderRight));
377
+
378
+ node.width = Math.abs(r.x - l.x);
379
+ node.height = Math.abs(b.y - t.y);
380
+ node.x = l.x + node.width / 2;
381
+ node.y = t.y + node.height / 2;
382
+ }
383
+ });
384
+
385
+ _.forEach(g.nodes(), function (v) {
386
+ if (g.node(v).dummy === 'border') {
387
+ g.removeNode(v);
388
+ }
389
+ });
390
+ }
391
+
392
+ function removeSelfEdges(g) {
393
+ _.forEach(g.edges(), function (e) {
394
+ if (e.v === e.w) {
395
+ var node = g.node(e.v);
396
+ if (!node.selfEdges) {
397
+ node.selfEdges = [];
398
+ }
399
+ node.selfEdges.push({ e: e, label: g.edge(e) });
400
+ g.removeEdge(e);
401
+ }
402
+ });
403
+ }
404
+
405
+ function insertSelfEdges(g) {
406
+ var layers = util.buildLayerMatrix(g);
407
+ _.forEach(layers, function (layer) {
408
+ var orderShift = 0;
409
+ _.forEach(layer, function (v, i) {
410
+ var node = g.node(v);
411
+ node.order = i + orderShift;
412
+ _.forEach(node.selfEdges, function (selfEdge) {
413
+ util.addDummyNode(
414
+ g,
415
+ 'selfedge',
416
+ {
417
+ width: selfEdge.label.width,
418
+ height: selfEdge.label.height,
419
+ rank: node.rank,
420
+ order: i + ++orderShift,
421
+ e: selfEdge.e,
422
+ label: selfEdge.label,
423
+ },
424
+ '_se'
425
+ );
426
+ });
427
+ delete node.selfEdges;
428
+ });
429
+ });
430
+ }
431
+
432
+ function positionSelfEdges(g) {
433
+ _.forEach(g.nodes(), function (v) {
434
+ var node = g.node(v);
435
+ if (node.dummy === 'selfedge') {
436
+ var selfNode = g.node(node.e.v);
437
+ var x = selfNode.x + selfNode.width / 2;
438
+ var y = selfNode.y;
439
+ var dx = node.x - x;
440
+ var dy = selfNode.height / 2;
441
+ g.setEdge(node.e, node.label);
442
+ g.removeNode(v);
443
+ node.label.points = [
444
+ { x: x + (2 * dx) / 3, y: y - dy },
445
+ { x: x + (5 * dx) / 6, y: y - dy },
446
+ { x: x + dx, y: y },
447
+ { x: x + (5 * dx) / 6, y: y + dy },
448
+ { x: x + (2 * dx) / 3, y: y + dy },
449
+ ];
450
+ node.label.x = node.x;
451
+ node.label.y = node.y;
452
+ }
453
+ });
454
+ }
455
+
456
+ function selectNumberAttrs(obj, attrs) {
457
+ return _.mapValues(_.pick(obj, attrs), Number);
458
+ }
459
+
460
+ function canonicalize(attrs) {
461
+ var newAttrs = {};
462
+ _.forEach(attrs, function (v, k) {
463
+ newAttrs[k.toLowerCase()] = v;
464
+ });
465
+ return newAttrs;
466
+ }
@@ -0,0 +1,2 @@
1
+ export function run(g: any): void;
2
+ export function cleanup(g: any): void;
@@ -0,0 +1,137 @@
1
+ import { _ } from '../lodash-es/index.ts';
2
+ import * as util from './util.js';
3
+
4
+ export { run, cleanup };
5
+
6
+ /*
7
+ * A nesting graph creates dummy nodes for the tops and bottoms of subgraphs,
8
+ * adds appropriate edges to ensure that all cluster nodes are placed between
9
+ * these boundries, and ensures that the graph is connected.
10
+ *
11
+ * In addition we ensure, through the use of the minlen property, that nodes
12
+ * and subgraph border nodes to not end up on the same rank.
13
+ *
14
+ * Preconditions:
15
+ *
16
+ * 1. Input graph is a DAG
17
+ * 2. Nodes in the input graph has a minlen attribute
18
+ *
19
+ * Postconditions:
20
+ *
21
+ * 1. Input graph is connected.
22
+ * 2. Dummy nodes are added for the tops and bottoms of subgraphs.
23
+ * 3. The minlen attribute for nodes is adjusted to ensure nodes do not
24
+ * get placed on the same rank as subgraph border nodes.
25
+ *
26
+ * The nesting graph idea comes from Sander, "Layout of Compound Directed
27
+ * Graphs."
28
+ */
29
+ function run(g) {
30
+ var root = util.addDummyNode(g, 'root', {}, '_root');
31
+ var depths = treeDepths(g);
32
+ var height = _.max(_.values(depths)) - 1; // Note: depths is an Object not an array
33
+ var nodeSep = 2 * height + 1;
34
+
35
+ g.graph().nestingRoot = root;
36
+
37
+ // Multiply minlen by nodeSep to align nodes on non-border ranks.
38
+ _.forEach(g.edges(), function (e) {
39
+ g.edge(e).minlen *= nodeSep;
40
+ });
41
+
42
+ // Calculate a weight that is sufficient to keep subgraphs vertically compact
43
+ var weight = sumWeights(g) + 1;
44
+
45
+ // Create border nodes and link them up
46
+ _.forEach(g.children(), function (child) {
47
+ dfs(g, root, nodeSep, weight, height, depths, child);
48
+ });
49
+
50
+ // Save the multiplier for node layers for later removal of empty border
51
+ // layers.
52
+ g.graph().nodeRankFactor = nodeSep;
53
+ }
54
+
55
+ function dfs(g, root, nodeSep, weight, height, depths, v) {
56
+ var children = g.children(v);
57
+ if (!children.length) {
58
+ if (v !== root) {
59
+ g.setEdge(root, v, { weight: 0, minlen: nodeSep });
60
+ }
61
+ return;
62
+ }
63
+
64
+ var top = util.addBorderNode(g, '_bt');
65
+ var bottom = util.addBorderNode(g, '_bb');
66
+ var label = g.node(v);
67
+
68
+ g.setParent(top, v);
69
+ label.borderTop = top;
70
+ g.setParent(bottom, v);
71
+ label.borderBottom = bottom;
72
+
73
+ _.forEach(children, function (child) {
74
+ dfs(g, root, nodeSep, weight, height, depths, child);
75
+
76
+ var childNode = g.node(child);
77
+ var childTop = childNode.borderTop ? childNode.borderTop : child;
78
+ var childBottom = childNode.borderBottom ? childNode.borderBottom : child;
79
+ var thisWeight = childNode.borderTop ? weight : 2 * weight;
80
+ var minlen = childTop !== childBottom ? 1 : height - depths[v] + 1;
81
+
82
+ g.setEdge(top, childTop, {
83
+ weight: thisWeight,
84
+ minlen: minlen,
85
+ nestingEdge: true,
86
+ });
87
+
88
+ g.setEdge(childBottom, bottom, {
89
+ weight: thisWeight,
90
+ minlen: minlen,
91
+ nestingEdge: true,
92
+ });
93
+ });
94
+
95
+ if (!g.parent(v)) {
96
+ g.setEdge(root, top, { weight: 0, minlen: height + depths[v] });
97
+ }
98
+ }
99
+
100
+ function treeDepths(g) {
101
+ var depths = {};
102
+ function dfs(v, depth) {
103
+ var children = g.children(v);
104
+ if (children && children.length) {
105
+ _.forEach(children, function (child) {
106
+ dfs(child, depth + 1);
107
+ });
108
+ }
109
+ depths[v] = depth;
110
+ }
111
+ _.forEach(g.children(), function (v) {
112
+ dfs(v, 1);
113
+ });
114
+ return depths;
115
+ }
116
+
117
+ function sumWeights(g) {
118
+ return _.reduce(
119
+ g.edges(),
120
+ function (acc, e) {
121
+ return acc + g.edge(e).weight;
122
+ },
123
+ 0
124
+ );
125
+ }
126
+
127
+ function cleanup(g) {
128
+ var graphLabel = g.graph();
129
+ g.removeNode(graphLabel.nestingRoot);
130
+ delete graphLabel.nestingRoot;
131
+ _.forEach(g.edges(), function (e) {
132
+ var edge = g.edge(e);
133
+ if (edge.nestingEdge) {
134
+ g.removeEdge(e);
135
+ }
136
+ });
137
+ }
@@ -0,0 +1,2 @@
1
+ export function run(g: any): void;
2
+ export function undo(g: any): void;
@@ -0,0 +1,91 @@
1
+ import { _ } from '../lodash-es/index.ts';
2
+ import * as util from './util.js';
3
+
4
+ export { run, undo };
5
+
6
+ /*
7
+ * Breaks any long edges in the graph into short segments that span 1 layer
8
+ * each. This operation is undoable with the denormalize function.
9
+ *
10
+ * Pre-conditions:
11
+ *
12
+ * 1. The input graph is a DAG.
13
+ * 2. Each node in the graph has a "rank" property.
14
+ *
15
+ * Post-condition:
16
+ *
17
+ * 1. All edges in the graph have a length of 1.
18
+ * 2. Dummy nodes are added where edges have been split into segments.
19
+ * 3. The graph is augmented with a "dummyChains" attribute which contains
20
+ * the first dummy in each chain of dummy nodes produced.
21
+ */
22
+ function run(g) {
23
+ g.graph().dummyChains = [];
24
+ _.forEach(g.edges(), function (edge) {
25
+ normalizeEdge(g, edge);
26
+ });
27
+ }
28
+
29
+ function normalizeEdge(g, e) {
30
+ var v = e.v;
31
+ var vRank = g.node(v).rank;
32
+ var w = e.w;
33
+ var wRank = g.node(w).rank;
34
+ var name = e.name;
35
+ var edgeLabel = g.edge(e);
36
+ var labelRank = edgeLabel.labelRank;
37
+
38
+ if (wRank === vRank + 1) return;
39
+
40
+ g.removeEdge(e);
41
+
42
+ var dummy, attrs, i;
43
+ for (i = 0, ++vRank; vRank < wRank; ++i, ++vRank) {
44
+ edgeLabel.points = [];
45
+ attrs = {
46
+ width: 0,
47
+ height: 0,
48
+ edgeLabel: edgeLabel,
49
+ edgeObj: e,
50
+ rank: vRank,
51
+ };
52
+ dummy = util.addDummyNode(g, 'edge', attrs, '_d');
53
+ if (vRank === labelRank) {
54
+ attrs.width = edgeLabel.width;
55
+ attrs.height = edgeLabel.height;
56
+ // @ts-expect-error
57
+ attrs.dummy = 'edge-label';
58
+ // @ts-expect-error
59
+ attrs.labelpos = edgeLabel.labelpos;
60
+ }
61
+ g.setEdge(v, dummy, { weight: edgeLabel.weight }, name);
62
+ if (i === 0) {
63
+ g.graph().dummyChains.push(dummy);
64
+ }
65
+ v = dummy;
66
+ }
67
+
68
+ g.setEdge(v, w, { weight: edgeLabel.weight }, name);
69
+ }
70
+
71
+ function undo(g) {
72
+ _.forEach(g.graph().dummyChains, function (v) {
73
+ var node = g.node(v);
74
+ var origLabel = node.edgeLabel;
75
+ var w;
76
+ g.setEdge(node.edgeObj, origLabel);
77
+ while (node.dummy) {
78
+ w = g.successors(v)[0];
79
+ g.removeNode(v);
80
+ origLabel.points.push({ x: node.x, y: node.y });
81
+ if (node.dummy === 'edge-label') {
82
+ origLabel.x = node.x;
83
+ origLabel.y = node.y;
84
+ origLabel.width = node.width;
85
+ origLabel.height = node.height;
86
+ }
87
+ v = w;
88
+ node = g.node(v);
89
+ }
90
+ });
91
+ }
@@ -0,0 +1 @@
1
+ export function addSubgraphConstraints(g: any, cg: any, vs: any): void;