@dagrejs/dagre 1.1.0 → 1.1.2

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