@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,86 @@
1
+ import { _ } from '../lodash-es/index.ts';
2
+
3
+ export { parentDummyChains };
4
+
5
+ function parentDummyChains(g) {
6
+ var postorderNums = postorder(g);
7
+
8
+ _.forEach(g.graph().dummyChains, function (v) {
9
+ var node = g.node(v);
10
+ var edgeObj = node.edgeObj;
11
+ var pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w);
12
+ var path = pathData.path;
13
+ var lca = pathData.lca;
14
+ var pathIdx = 0;
15
+ var pathV = path[pathIdx];
16
+ var ascending = true;
17
+
18
+ while (v !== edgeObj.w) {
19
+ node = g.node(v);
20
+
21
+ if (ascending) {
22
+ while ((pathV = path[pathIdx]) !== lca && g.node(pathV).maxRank < node.rank) {
23
+ pathIdx++;
24
+ }
25
+
26
+ if (pathV === lca) {
27
+ ascending = false;
28
+ }
29
+ }
30
+
31
+ if (!ascending) {
32
+ while (
33
+ pathIdx < path.length - 1 &&
34
+ g.node((pathV = path[pathIdx + 1])).minRank <= node.rank
35
+ ) {
36
+ pathIdx++;
37
+ }
38
+ pathV = path[pathIdx];
39
+ }
40
+
41
+ g.setParent(v, pathV);
42
+ v = g.successors(v)[0];
43
+ }
44
+ });
45
+ }
46
+
47
+ // Find a path from v to w through the lowest common ancestor (LCA). Return the
48
+ // full path and the LCA.
49
+ function findPath(g, postorderNums, v, w) {
50
+ var vPath = [];
51
+ var wPath = [];
52
+ var low = Math.min(postorderNums[v].low, postorderNums[w].low);
53
+ var lim = Math.max(postorderNums[v].lim, postorderNums[w].lim);
54
+ var parent;
55
+ var lca;
56
+
57
+ // Traverse up from v to find the LCA
58
+ parent = v;
59
+ do {
60
+ parent = g.parent(parent);
61
+ vPath.push(parent);
62
+ } while (parent && (postorderNums[parent].low > low || lim > postorderNums[parent].lim));
63
+ lca = parent;
64
+
65
+ // Traverse from w to LCA
66
+ parent = w;
67
+ while ((parent = g.parent(parent)) !== lca) {
68
+ wPath.push(parent);
69
+ }
70
+
71
+ return { path: vPath.concat(wPath.reverse()), lca: lca };
72
+ }
73
+
74
+ function postorder(g) {
75
+ var result = {};
76
+ var lim = 0;
77
+
78
+ function dfs(v) {
79
+ var low = lim;
80
+ _.forEach(g.children(v), dfs);
81
+ result[v] = { low: low, lim: lim++ };
82
+ }
83
+ _.forEach(g.children(), dfs);
84
+
85
+ return result;
86
+ }
@@ -0,0 +1,31 @@
1
+ export function positionX(g: any): {
2
+ [x: string]: any;
3
+ };
4
+ export function findType1Conflicts(g: any, layering: any): {};
5
+ export function findType2Conflicts(g: any, layering: any): {};
6
+ export function addConflict(conflicts: any, v: any, w: any): void;
7
+ export function hasConflict(conflicts: any, v: any, w: any): boolean;
8
+ export function verticalAlignment(
9
+ g: any,
10
+ layering: any,
11
+ conflicts: any,
12
+ neighborFn: any
13
+ ): {
14
+ root: {};
15
+ align: {};
16
+ };
17
+ export function horizontalCompaction(
18
+ g: any,
19
+ layering: any,
20
+ root: any,
21
+ align: any,
22
+ reverseSep: any
23
+ ): {};
24
+ export function alignCoordinates(xss: any, alignTo: any): void;
25
+ export function findSmallestWidthAlignment(g: any, xss: any): any;
26
+ export function balance(
27
+ xss: any,
28
+ align: any
29
+ ): {
30
+ [x: string]: any;
31
+ };
@@ -0,0 +1,423 @@
1
+ import { _ } from '../../lodash-es/index.ts';
2
+ import { Graph } from '../../graphlib/index.js';
3
+ import * as util from '../util.js';
4
+
5
+ /*
6
+ * This module provides coordinate assignment based on Brandes and Köpf, "Fast
7
+ * and Simple Horizontal Coordinate Assignment."
8
+ */
9
+
10
+ export {
11
+ positionX,
12
+ findType1Conflicts,
13
+ findType2Conflicts,
14
+ addConflict,
15
+ hasConflict,
16
+ verticalAlignment,
17
+ horizontalCompaction,
18
+ alignCoordinates,
19
+ findSmallestWidthAlignment,
20
+ balance,
21
+ };
22
+
23
+ /*
24
+ * Marks all edges in the graph with a type-1 conflict with the "type1Conflict"
25
+ * property. A type-1 conflict is one where a non-inner segment crosses an
26
+ * inner segment. An inner segment is an edge with both incident nodes marked
27
+ * with the "dummy" property.
28
+ *
29
+ * This algorithm scans layer by layer, starting with the second, for type-1
30
+ * conflicts between the current layer and the previous layer. For each layer
31
+ * it scans the nodes from left to right until it reaches one that is incident
32
+ * on an inner segment. It then scans predecessors to determine if they have
33
+ * edges that cross that inner segment. At the end a final scan is done for all
34
+ * nodes on the current rank to see if they cross the last visited inner
35
+ * segment.
36
+ *
37
+ * This algorithm (safely) assumes that a dummy node will only be incident on a
38
+ * single node in the layers being scanned.
39
+ */
40
+ function findType1Conflicts(g, layering) {
41
+ var conflicts = {};
42
+
43
+ function visitLayer(prevLayer, layer) {
44
+ var // last visited node in the previous layer that is incident on an inner
45
+ // segment.
46
+ k0 = 0,
47
+ // Tracks the last node in this layer scanned for crossings with a type-1
48
+ // segment.
49
+ scanPos = 0,
50
+ prevLayerLength = prevLayer.length,
51
+ lastNode = _.last(layer);
52
+
53
+ _.forEach(layer, function (v, i) {
54
+ var w = findOtherInnerSegmentNode(g, v),
55
+ k1 = w ? g.node(w).order : prevLayerLength;
56
+
57
+ if (w || v === lastNode) {
58
+ _.forEach(layer.slice(scanPos, i + 1), function (scanNode) {
59
+ _.forEach(g.predecessors(scanNode), function (u) {
60
+ var uLabel = g.node(u),
61
+ uPos = uLabel.order;
62
+ if ((uPos < k0 || k1 < uPos) && !(uLabel.dummy && g.node(scanNode).dummy)) {
63
+ addConflict(conflicts, u, scanNode);
64
+ }
65
+ });
66
+ });
67
+ // @ts-expect-error
68
+ scanPos = i + 1;
69
+ k0 = k1;
70
+ }
71
+ });
72
+
73
+ return layer;
74
+ }
75
+
76
+ _.reduce(layering, visitLayer);
77
+ return conflicts;
78
+ }
79
+
80
+ function findType2Conflicts(g, layering) {
81
+ var conflicts = {};
82
+
83
+ function scan(south, southPos, southEnd, prevNorthBorder, nextNorthBorder) {
84
+ var v;
85
+ _.forEach(_.range(southPos, southEnd), function (i) {
86
+ v = south[i];
87
+ if (g.node(v).dummy) {
88
+ _.forEach(g.predecessors(v), function (u) {
89
+ var uNode = g.node(u);
90
+ if (uNode.dummy && (uNode.order < prevNorthBorder || uNode.order > nextNorthBorder)) {
91
+ addConflict(conflicts, u, v);
92
+ }
93
+ });
94
+ }
95
+ });
96
+ }
97
+
98
+ function visitLayer(north, south) {
99
+ var prevNorthPos = -1,
100
+ nextNorthPos,
101
+ southPos = 0;
102
+
103
+ _.forEach(south, function (v, southLookahead) {
104
+ if (g.node(v).dummy === 'border') {
105
+ var predecessors = g.predecessors(v);
106
+ if (predecessors.length) {
107
+ nextNorthPos = g.node(predecessors[0]).order;
108
+ scan(south, southPos, southLookahead, prevNorthPos, nextNorthPos);
109
+ // @ts-expect-error
110
+ southPos = southLookahead;
111
+ prevNorthPos = nextNorthPos;
112
+ }
113
+ }
114
+ scan(south, southPos, south.length, nextNorthPos, north.length);
115
+ });
116
+
117
+ return south;
118
+ }
119
+
120
+ _.reduce(layering, visitLayer);
121
+ return conflicts;
122
+ }
123
+
124
+ function findOtherInnerSegmentNode(g, v) {
125
+ if (g.node(v).dummy) {
126
+ return _.find(g.predecessors(v), function (u) {
127
+ return g.node(u).dummy;
128
+ });
129
+ }
130
+ }
131
+
132
+ function addConflict(conflicts, v, w) {
133
+ if (v > w) {
134
+ var tmp = v;
135
+ v = w;
136
+ w = tmp;
137
+ }
138
+
139
+ var conflictsV = conflicts[v];
140
+ if (!conflictsV) {
141
+ conflicts[v] = conflictsV = {};
142
+ }
143
+ conflictsV[w] = true;
144
+ }
145
+
146
+ function hasConflict(conflicts, v, w) {
147
+ if (v > w) {
148
+ var tmp = v;
149
+ v = w;
150
+ w = tmp;
151
+ }
152
+ return _.has(conflicts[v], w);
153
+ }
154
+
155
+ /*
156
+ * Try to align nodes into vertical "blocks" where possible. This algorithm
157
+ * attempts to align a node with one of its median neighbors. If the edge
158
+ * connecting a neighbor is a type-1 conflict then we ignore that possibility.
159
+ * If a previous node has already formed a block with a node after the node
160
+ * we're trying to form a block with, we also ignore that possibility - our
161
+ * blocks would be split in that scenario.
162
+ */
163
+ function verticalAlignment(g, layering, conflicts, neighborFn) {
164
+ var root = {},
165
+ align = {},
166
+ pos = {};
167
+
168
+ // We cache the position here based on the layering because the graph and
169
+ // layering may be out of sync. The layering matrix is manipulated to
170
+ // generate different extreme alignments.
171
+ _.forEach(layering, function (layer) {
172
+ _.forEach(layer, function (v, order) {
173
+ root[v] = v;
174
+ align[v] = v;
175
+ pos[v] = order;
176
+ });
177
+ });
178
+
179
+ _.forEach(layering, function (layer) {
180
+ var prevIdx = -1;
181
+ _.forEach(layer, function (v) {
182
+ var ws = neighborFn(v);
183
+ if (ws.length) {
184
+ ws = _.sortBy(ws, function (w) {
185
+ return pos[w];
186
+ });
187
+ var mp = (ws.length - 1) / 2;
188
+ for (var i = Math.floor(mp), il = Math.ceil(mp); i <= il; ++i) {
189
+ var w = ws[i];
190
+ if (align[v] === v && prevIdx < pos[w] && !hasConflict(conflicts, v, w)) {
191
+ align[w] = v;
192
+ align[v] = root[v] = root[w];
193
+ prevIdx = pos[w];
194
+ }
195
+ }
196
+ }
197
+ });
198
+ });
199
+
200
+ return { root: root, align: align };
201
+ }
202
+
203
+ function horizontalCompaction(g, layering, root, align, reverseSep) {
204
+ // This portion of the algorithm differs from BK due to a number of problems.
205
+ // Instead of their algorithm we construct a new block graph and do two
206
+ // sweeps. The first sweep places blocks with the smallest possible
207
+ // coordinates. The second sweep removes unused space by moving blocks to the
208
+ // greatest coordinates without violating separation.
209
+ var xs = {},
210
+ blockG = buildBlockGraph(g, layering, root, reverseSep),
211
+ borderType = reverseSep ? 'borderLeft' : 'borderRight';
212
+
213
+ function iterate(setXsFunc, nextNodesFunc) {
214
+ var stack = blockG.nodes();
215
+ var elem = stack.pop();
216
+ var visited = {};
217
+ while (elem) {
218
+ if (visited[elem]) {
219
+ setXsFunc(elem);
220
+ } else {
221
+ visited[elem] = true;
222
+ stack.push(elem);
223
+ stack = stack.concat(nextNodesFunc(elem));
224
+ }
225
+
226
+ elem = stack.pop();
227
+ }
228
+ }
229
+
230
+ // First pass, assign smallest coordinates
231
+ function pass1(elem) {
232
+ xs[elem] = blockG.inEdges(elem).reduce(function (acc, e) {
233
+ return Math.max(acc, xs[e.v] + blockG.edge(e));
234
+ }, 0);
235
+ }
236
+
237
+ // Second pass, assign greatest coordinates
238
+ function pass2(elem) {
239
+ var min = blockG.outEdges(elem).reduce(function (acc, e) {
240
+ return Math.min(acc, xs[e.w] - blockG.edge(e));
241
+ }, Number.POSITIVE_INFINITY);
242
+
243
+ var node = g.node(elem);
244
+ if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
245
+ xs[elem] = Math.max(xs[elem], min);
246
+ }
247
+ }
248
+
249
+ iterate(pass1, blockG.predecessors.bind(blockG));
250
+ iterate(pass2, blockG.successors.bind(blockG));
251
+
252
+ // Assign x coordinates to all nodes
253
+ _.forEach(align, function (v) {
254
+ xs[v] = xs[root[v]];
255
+ });
256
+
257
+ return xs;
258
+ }
259
+
260
+ function buildBlockGraph(g, layering, root, reverseSep) {
261
+ var blockGraph = new Graph(),
262
+ graphLabel = g.graph(),
263
+ sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
264
+
265
+ _.forEach(layering, function (layer) {
266
+ var u;
267
+ _.forEach(layer, function (v) {
268
+ var vRoot = root[v];
269
+ blockGraph.setNode(vRoot);
270
+ if (u) {
271
+ var uRoot = root[u],
272
+ prevMax = blockGraph.edge(uRoot, vRoot);
273
+ blockGraph.setEdge(uRoot, vRoot, Math.max(sepFn(g, v, u), prevMax || 0));
274
+ }
275
+ u = v;
276
+ });
277
+ });
278
+
279
+ return blockGraph;
280
+ }
281
+
282
+ /*
283
+ * Returns the alignment that has the smallest width of the given alignments.
284
+ */
285
+ function findSmallestWidthAlignment(g, xss) {
286
+ return _.minBy(_.values(xss), function (xs) {
287
+ var max = Number.NEGATIVE_INFINITY;
288
+ var min = Number.POSITIVE_INFINITY;
289
+
290
+ _.forIn(xs, function (x, v) {
291
+ var halfWidth = width(g, v) / 2;
292
+
293
+ max = Math.max(x + halfWidth, max);
294
+ min = Math.min(x - halfWidth, min);
295
+ });
296
+
297
+ return max - min;
298
+ });
299
+ }
300
+
301
+ /*
302
+ * Align the coordinates of each of the layout alignments such that
303
+ * left-biased alignments have their minimum coordinate at the same point as
304
+ * the minimum coordinate of the smallest width alignment and right-biased
305
+ * alignments have their maximum coordinate at the same point as the maximum
306
+ * coordinate of the smallest width alignment.
307
+ */
308
+ function alignCoordinates(xss, alignTo) {
309
+ var alignToVals = _.values(alignTo),
310
+ alignToMin = _.min(alignToVals),
311
+ alignToMax = _.max(alignToVals);
312
+
313
+ _.forEach(['u', 'd'], function (vert) {
314
+ _.forEach(['l', 'r'], function (horiz) {
315
+ var alignment = vert + horiz,
316
+ xs = xss[alignment],
317
+ delta;
318
+ if (xs === alignTo) return;
319
+
320
+ var xsVals = _.values(xs);
321
+ delta = horiz === 'l' ? alignToMin - _.min(xsVals) : alignToMax - _.max(xsVals);
322
+
323
+ if (delta) {
324
+ xss[alignment] = _.mapValues(xs, function (x) {
325
+ return x + delta;
326
+ });
327
+ }
328
+ });
329
+ });
330
+ }
331
+
332
+ function balance(xss, align) {
333
+ return _.mapValues(xss.ul, function (ignore, v) {
334
+ if (align) {
335
+ return xss[align.toLowerCase()][v];
336
+ } else {
337
+ var xs = _.sortBy(_.map(xss, v));
338
+ return (xs[1] + xs[2]) / 2;
339
+ }
340
+ });
341
+ }
342
+
343
+ function positionX(g) {
344
+ var layering = util.buildLayerMatrix(g);
345
+ var conflicts = _.merge(findType1Conflicts(g, layering), findType2Conflicts(g, layering));
346
+
347
+ var xss = {};
348
+ var adjustedLayering;
349
+ _.forEach(['u', 'd'], function (vert) {
350
+ adjustedLayering = vert === 'u' ? layering : _.values(layering).reverse();
351
+ _.forEach(['l', 'r'], function (horiz) {
352
+ if (horiz === 'r') {
353
+ adjustedLayering = _.map(adjustedLayering, function (inner) {
354
+ return _.values(inner).reverse();
355
+ });
356
+ }
357
+
358
+ var neighborFn = (vert === 'u' ? g.predecessors : g.successors).bind(g);
359
+ var align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn);
360
+ var xs = horizontalCompaction(g, adjustedLayering, align.root, align.align, horiz === 'r');
361
+ if (horiz === 'r') {
362
+ xs = _.mapValues(xs, function (x) {
363
+ return -x;
364
+ });
365
+ }
366
+ xss[vert + horiz] = xs;
367
+ });
368
+ });
369
+
370
+ var smallestWidth = findSmallestWidthAlignment(g, xss);
371
+ alignCoordinates(xss, smallestWidth);
372
+ return balance(xss, g.graph().align);
373
+ }
374
+
375
+ function sep(nodeSep, edgeSep, reverseSep) {
376
+ return function (g, v, w) {
377
+ var vLabel = g.node(v);
378
+ var wLabel = g.node(w);
379
+ var sum = 0;
380
+ var delta;
381
+
382
+ sum += vLabel.width / 2;
383
+ if (_.has(vLabel, 'labelpos')) {
384
+ switch (vLabel.labelpos.toLowerCase()) {
385
+ case 'l':
386
+ delta = -vLabel.width / 2;
387
+ break;
388
+ case 'r':
389
+ delta = vLabel.width / 2;
390
+ break;
391
+ }
392
+ }
393
+ if (delta) {
394
+ sum += reverseSep ? delta : -delta;
395
+ }
396
+ delta = 0;
397
+
398
+ sum += (vLabel.dummy ? edgeSep : nodeSep) / 2;
399
+ sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
400
+
401
+ sum += wLabel.width / 2;
402
+ if (_.has(wLabel, 'labelpos')) {
403
+ switch (wLabel.labelpos.toLowerCase()) {
404
+ case 'l':
405
+ delta = wLabel.width / 2;
406
+ break;
407
+ case 'r':
408
+ delta = -wLabel.width / 2;
409
+ break;
410
+ }
411
+ }
412
+ if (delta) {
413
+ sum += reverseSep ? delta : -delta;
414
+ }
415
+ delta = 0;
416
+
417
+ return sum;
418
+ };
419
+ }
420
+
421
+ function width(g, v) {
422
+ return g.node(v).width;
423
+ }
@@ -0,0 +1 @@
1
+ export function position(g: any): void;
@@ -0,0 +1,31 @@
1
+ import { _ } from '../../lodash-es/index.ts';
2
+ import * as util from '../util.js';
3
+ import { positionX } from './bk.js';
4
+
5
+ export { position };
6
+
7
+ function position(g) {
8
+ g = util.asNonCompoundGraph(g);
9
+
10
+ positionY(g);
11
+ _.forOwn(positionX(g), function (x, v) {
12
+ g.node(v).x = x;
13
+ });
14
+ }
15
+
16
+ function positionY(g) {
17
+ var layering = util.buildLayerMatrix(g);
18
+ var rankSep = g.graph().ranksep;
19
+ var prevY = 0;
20
+ _.forEach(layering, function (layer) {
21
+ var maxHeight = _.max(
22
+ _.map(layer, function (v) {
23
+ return g.node(v).height;
24
+ })
25
+ );
26
+ _.forEach(layer, function (v) {
27
+ g.node(v).y = prevY + maxHeight / 2;
28
+ });
29
+ prevY += maxHeight + rankSep;
30
+ });
31
+ }
@@ -0,0 +1,2 @@
1
+ export function feasibleTree(g: any): Graph;
2
+ import { Graph } from '../../graphlib/index.js';
@@ -0,0 +1,87 @@
1
+ import { _ } from '../../lodash-es/index.ts';
2
+ import { Graph } from '../../graphlib/index.js';
3
+ import { slack } from './util.js';
4
+
5
+ export { feasibleTree };
6
+
7
+ /*
8
+ * Constructs a spanning tree with tight edges and adjusted the input node's
9
+ * ranks to achieve this. A tight edge is one that is has a length that matches
10
+ * its "minlen" attribute.
11
+ *
12
+ * The basic structure for this function is derived from Gansner, et al., "A
13
+ * Technique for Drawing Directed Graphs."
14
+ *
15
+ * Pre-conditions:
16
+ *
17
+ * 1. Graph must be a DAG.
18
+ * 2. Graph must be connected.
19
+ * 3. Graph must have at least one node.
20
+ * 5. Graph nodes must have been previously assigned a "rank" property that
21
+ * respects the "minlen" property of incident edges.
22
+ * 6. Graph edges must have a "minlen" property.
23
+ *
24
+ * Post-conditions:
25
+ *
26
+ * - Graph nodes will have their rank adjusted to ensure that all edges are
27
+ * tight.
28
+ *
29
+ * Returns a tree (undirected graph) that is constructed using only "tight"
30
+ * edges.
31
+ */
32
+ function feasibleTree(g) {
33
+ var t = new Graph({ directed: false });
34
+
35
+ // Choose arbitrary node from which to start our tree
36
+ var start = g.nodes()[0];
37
+ var size = g.nodeCount();
38
+ t.setNode(start, {});
39
+
40
+ var edge, delta;
41
+ while (tightTree(t, g) < size) {
42
+ edge = findMinSlackEdge(t, g);
43
+ delta = t.hasNode(edge.v) ? slack(g, edge) : -slack(g, edge);
44
+ shiftRanks(t, g, delta);
45
+ }
46
+
47
+ return t;
48
+ }
49
+
50
+ /*
51
+ * Finds a maximal tree of tight edges and returns the number of nodes in the
52
+ * tree.
53
+ */
54
+ function tightTree(t, g) {
55
+ function dfs(v) {
56
+ _.forEach(g.nodeEdges(v), function (e) {
57
+ var edgeV = e.v,
58
+ w = v === edgeV ? e.w : edgeV;
59
+ if (!t.hasNode(w) && !slack(g, e)) {
60
+ t.setNode(w, {});
61
+ t.setEdge(v, w, {});
62
+ dfs(w);
63
+ }
64
+ });
65
+ }
66
+
67
+ _.forEach(t.nodes(), dfs);
68
+ return t.nodeCount();
69
+ }
70
+
71
+ /*
72
+ * Finds the edge with the smallest slack that is incident on tree and returns
73
+ * it.
74
+ */
75
+ function findMinSlackEdge(t, g) {
76
+ return _.minBy(g.edges(), function (e) {
77
+ if (t.hasNode(e.v) !== t.hasNode(e.w)) {
78
+ return slack(g, e);
79
+ }
80
+ });
81
+ }
82
+
83
+ function shiftRanks(t, g, delta) {
84
+ _.forEach(t.nodes(), function (v) {
85
+ g.node(v).rank += delta;
86
+ });
87
+ }
@@ -0,0 +1 @@
1
+ export function rank(g: any): void;