@dagrejs/dagre 1.0.2 → 1.0.4
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.
- package/README.md +0 -7
- package/dist/dagre.js +443 -445
- package/dist/dagre.min.js +52 -52
- package/index.d.ts +8 -1
- package/lib/acyclic.js +13 -13
- package/lib/add-border-segments.js +7 -7
- package/lib/coordinate-system.js +8 -8
- package/lib/data/list.js +34 -32
- package/lib/debug.js +9 -11
- package/lib/greedy-fas.js +29 -29
- package/lib/layout.js +96 -96
- package/lib/nesting-graph.js +20 -22
- package/lib/normalize.js +13 -13
- package/lib/order/add-subgraph-constraints.js +3 -3
- package/lib/order/barycenter.js +3 -3
- package/lib/order/build-layer-graph.js +8 -8
- package/lib/order/cross-count.js +11 -11
- package/lib/order/index.js +15 -15
- package/lib/order/init-order.js +7 -7
- package/lib/order/resolve-conflicts.js +12 -12
- package/lib/order/sort-subgraph.js +16 -16
- package/lib/order/sort.js +7 -7
- package/lib/parent-dummy-chains.js +19 -19
- package/lib/position/bk.js +67 -67
- package/lib/position/index.js +6 -6
- package/lib/rank/feasible-tree.js +1 -1
- package/lib/rank/network-simplex.js +4 -4
- package/lib/util.js +32 -32
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/dist/dagre.js
CHANGED
|
@@ -36,8 +36,8 @@ module.exports = {
|
|
|
36
36
|
},{"./lib/debug":6,"./lib/layout":8,"./lib/util":27,"./lib/version":28,"@dagrejs/graphlib":29}],2:[function(require,module,exports){
|
|
37
37
|
"use strict";
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
let greedyFAS = require("./greedy-fas");
|
|
40
|
+
let uniqueId = require("./util").uniqueId;
|
|
41
41
|
|
|
42
42
|
module.exports = {
|
|
43
43
|
run: run,
|
|
@@ -45,11 +45,11 @@ module.exports = {
|
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
function run(g) {
|
|
48
|
-
|
|
48
|
+
let fas = (g.graph().acyclicer === "greedy"
|
|
49
49
|
? greedyFAS(g, weightFn(g))
|
|
50
50
|
: dfsFAS(g));
|
|
51
|
-
fas.forEach(
|
|
52
|
-
|
|
51
|
+
fas.forEach(e => {
|
|
52
|
+
let label = g.edge(e);
|
|
53
53
|
g.removeEdge(e);
|
|
54
54
|
label.forwardName = e.name;
|
|
55
55
|
label.reversed = true;
|
|
@@ -57,16 +57,16 @@ function run(g) {
|
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
function weightFn(g) {
|
|
60
|
-
return
|
|
60
|
+
return e => {
|
|
61
61
|
return g.edge(e).weight;
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
function dfsFAS(g) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
let fas = [];
|
|
68
|
+
let stack = {};
|
|
69
|
+
let visited = {};
|
|
70
70
|
|
|
71
71
|
function dfs(v) {
|
|
72
72
|
if (visited.hasOwnProperty(v)) {
|
|
@@ -74,7 +74,7 @@ function dfsFAS(g) {
|
|
|
74
74
|
}
|
|
75
75
|
visited[v] = true;
|
|
76
76
|
stack[v] = true;
|
|
77
|
-
g.outEdges(v).forEach(
|
|
77
|
+
g.outEdges(v).forEach(e => {
|
|
78
78
|
if (stack.hasOwnProperty(e.w)) {
|
|
79
79
|
fas.push(e);
|
|
80
80
|
} else {
|
|
@@ -89,12 +89,12 @@ function dfsFAS(g) {
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
function undo(g) {
|
|
92
|
-
g.edges().forEach(
|
|
93
|
-
|
|
92
|
+
g.edges().forEach(e => {
|
|
93
|
+
let label = g.edge(e);
|
|
94
94
|
if (label.reversed) {
|
|
95
95
|
g.removeEdge(e);
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
let forwardName = label.forwardName;
|
|
98
98
|
delete label.reversed;
|
|
99
99
|
delete label.forwardName;
|
|
100
100
|
g.setEdge(e.w, e.v, label, forwardName);
|
|
@@ -103,14 +103,14 @@ function undo(g) {
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
},{"./greedy-fas":7,"./util":27}],3:[function(require,module,exports){
|
|
106
|
-
|
|
106
|
+
let util = require("./util");
|
|
107
107
|
|
|
108
108
|
module.exports = addBorderSegments;
|
|
109
109
|
|
|
110
110
|
function addBorderSegments(g) {
|
|
111
111
|
function dfs(v) {
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
let children = g.children(v);
|
|
113
|
+
let node = g.node(v);
|
|
114
114
|
if (children.length) {
|
|
115
115
|
children.forEach(dfs);
|
|
116
116
|
}
|
|
@@ -118,7 +118,7 @@ function addBorderSegments(g) {
|
|
|
118
118
|
if (node.hasOwnProperty("minRank")) {
|
|
119
119
|
node.borderLeft = [];
|
|
120
120
|
node.borderRight = [];
|
|
121
|
-
for (
|
|
121
|
+
for (let rank = node.minRank, maxRank = node.maxRank + 1;
|
|
122
122
|
rank < maxRank;
|
|
123
123
|
++rank) {
|
|
124
124
|
addBorderNode(g, "borderLeft", "_bl", v, node, rank);
|
|
@@ -131,9 +131,9 @@ function addBorderSegments(g) {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
function addBorderNode(g, prop, prefix, sg, sgNode, rank) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
let label = { width: 0, height: 0, rank: rank, borderType: prop };
|
|
135
|
+
let prev = sgNode[prop][rank - 1];
|
|
136
|
+
let curr = util.addDummyNode(g, "border", label, prefix);
|
|
137
137
|
sgNode[prop][rank] = curr;
|
|
138
138
|
g.setParent(curr, sg);
|
|
139
139
|
if (prev) {
|
|
@@ -150,14 +150,14 @@ module.exports = {
|
|
|
150
150
|
};
|
|
151
151
|
|
|
152
152
|
function adjust(g) {
|
|
153
|
-
|
|
153
|
+
let rankDir = g.graph().rankdir.toLowerCase();
|
|
154
154
|
if (rankDir === "lr" || rankDir === "rl") {
|
|
155
155
|
swapWidthHeight(g);
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
function undo(g) {
|
|
160
|
-
|
|
160
|
+
let rankDir = g.graph().rankdir.toLowerCase();
|
|
161
161
|
if (rankDir === "bt" || rankDir === "rl") {
|
|
162
162
|
reverseY(g);
|
|
163
163
|
}
|
|
@@ -174,7 +174,7 @@ function swapWidthHeight(g) {
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
function swapWidthHeightOne(attrs) {
|
|
177
|
-
|
|
177
|
+
let w = attrs.width;
|
|
178
178
|
attrs.width = attrs.height;
|
|
179
179
|
attrs.height = w;
|
|
180
180
|
}
|
|
@@ -182,8 +182,8 @@ function swapWidthHeightOne(attrs) {
|
|
|
182
182
|
function reverseY(g) {
|
|
183
183
|
g.nodes().forEach(v => reverseYOne(g.node(v)));
|
|
184
184
|
|
|
185
|
-
g.edges().forEach(
|
|
186
|
-
|
|
185
|
+
g.edges().forEach(e => {
|
|
186
|
+
let edge = g.edge(e);
|
|
187
187
|
edge.points.forEach(reverseYOne);
|
|
188
188
|
if (edge.hasOwnProperty("y")) {
|
|
189
189
|
reverseYOne(edge);
|
|
@@ -198,8 +198,8 @@ function reverseYOne(attrs) {
|
|
|
198
198
|
function swapXY(g) {
|
|
199
199
|
g.nodes().forEach(v => swapXYOne(g.node(v)));
|
|
200
200
|
|
|
201
|
-
g.edges().forEach(
|
|
202
|
-
|
|
201
|
+
g.edges().forEach(e => {
|
|
202
|
+
let edge = g.edge(e);
|
|
203
203
|
edge.points.forEach(swapXYOne);
|
|
204
204
|
if (edge.hasOwnProperty("x")) {
|
|
205
205
|
swapXYOne(edge);
|
|
@@ -208,7 +208,7 @@ function swapXY(g) {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
function swapXYOne(attrs) {
|
|
211
|
-
|
|
211
|
+
let x = attrs.x;
|
|
212
212
|
attrs.x = attrs.y;
|
|
213
213
|
attrs.y = x;
|
|
214
214
|
}
|
|
@@ -219,44 +219,44 @@ function swapXYOne(attrs) {
|
|
|
219
219
|
* "Introduction to Algorithms".
|
|
220
220
|
*/
|
|
221
221
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
this._sentinel = sentinel;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
List.prototype.dequeue = function() {
|
|
231
|
-
var sentinel = this._sentinel;
|
|
232
|
-
var entry = sentinel._prev;
|
|
233
|
-
if (entry !== sentinel) {
|
|
234
|
-
unlink(entry);
|
|
235
|
-
return entry;
|
|
222
|
+
class List {
|
|
223
|
+
constructor() {
|
|
224
|
+
let sentinel = {};
|
|
225
|
+
sentinel._next = sentinel._prev = sentinel;
|
|
226
|
+
this._sentinel = sentinel;
|
|
236
227
|
}
|
|
237
|
-
};
|
|
238
228
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
229
|
+
dequeue() {
|
|
230
|
+
let sentinel = this._sentinel;
|
|
231
|
+
let entry = sentinel._prev;
|
|
232
|
+
if (entry !== sentinel) {
|
|
233
|
+
unlink(entry);
|
|
234
|
+
return entry;
|
|
235
|
+
}
|
|
243
236
|
}
|
|
244
|
-
entry._next = sentinel._next;
|
|
245
|
-
sentinel._next._prev = entry;
|
|
246
|
-
sentinel._next = entry;
|
|
247
|
-
entry._prev = sentinel;
|
|
248
|
-
};
|
|
249
237
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
238
|
+
enqueue(entry) {
|
|
239
|
+
let sentinel = this._sentinel;
|
|
240
|
+
if (entry._prev && entry._next) {
|
|
241
|
+
unlink(entry);
|
|
242
|
+
}
|
|
243
|
+
entry._next = sentinel._next;
|
|
244
|
+
sentinel._next._prev = entry;
|
|
245
|
+
sentinel._next = entry;
|
|
246
|
+
entry._prev = sentinel;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
toString() {
|
|
250
|
+
let strs = [];
|
|
251
|
+
let sentinel = this._sentinel;
|
|
252
|
+
let curr = sentinel._prev;
|
|
253
|
+
while (curr !== sentinel) {
|
|
254
|
+
strs.push(JSON.stringify(curr, filterOutLinks));
|
|
255
|
+
curr = curr._prev;
|
|
256
|
+
}
|
|
257
|
+
return "[" + strs.join(", ") + "]";
|
|
257
258
|
}
|
|
258
|
-
|
|
259
|
-
};
|
|
259
|
+
}
|
|
260
260
|
|
|
261
261
|
function unlink(entry) {
|
|
262
262
|
entry._prev._next = entry._next;
|
|
@@ -271,9 +271,11 @@ function filterOutLinks(k, v) {
|
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
+
module.exports = List;
|
|
275
|
+
|
|
274
276
|
},{}],6:[function(require,module,exports){
|
|
275
|
-
|
|
276
|
-
|
|
277
|
+
let util = require("./util");
|
|
278
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
277
279
|
|
|
278
280
|
module.exports = {
|
|
279
281
|
debugOrdering: debugOrdering
|
|
@@ -281,23 +283,21 @@ module.exports = {
|
|
|
281
283
|
|
|
282
284
|
/* istanbul ignore next */
|
|
283
285
|
function debugOrdering(g) {
|
|
284
|
-
|
|
286
|
+
let layerMatrix = util.buildLayerMatrix(g);
|
|
285
287
|
|
|
286
|
-
|
|
288
|
+
let h = new Graph({ compound: true, multigraph: true }).setGraph({});
|
|
287
289
|
|
|
288
|
-
g.nodes().forEach(
|
|
290
|
+
g.nodes().forEach(v => {
|
|
289
291
|
h.setNode(v, { label: v });
|
|
290
292
|
h.setParent(v, "layer" + g.node(v).rank);
|
|
291
293
|
});
|
|
292
294
|
|
|
293
|
-
g.edges().forEach(
|
|
294
|
-
h.setEdge(e.v, e.w, {}, e.name);
|
|
295
|
-
});
|
|
295
|
+
g.edges().forEach(e => h.setEdge(e.v, e.w, {}, e.name));
|
|
296
296
|
|
|
297
|
-
layerMatrix.forEach(
|
|
298
|
-
|
|
297
|
+
layerMatrix.forEach((layer, i) => {
|
|
298
|
+
let layerV = "layer" + i;
|
|
299
299
|
h.setNode(layerV, { rank: "same" });
|
|
300
|
-
layer.reduce(
|
|
300
|
+
layer.reduce((u, v) => {
|
|
301
301
|
h.setEdge(u, v, { style: "invis" });
|
|
302
302
|
return v;
|
|
303
303
|
});
|
|
@@ -307,8 +307,8 @@ function debugOrdering(g) {
|
|
|
307
307
|
}
|
|
308
308
|
|
|
309
309
|
},{"./util":27,"@dagrejs/graphlib":29}],7:[function(require,module,exports){
|
|
310
|
-
|
|
311
|
-
|
|
310
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
311
|
+
let List = require("./data/list");
|
|
312
312
|
|
|
313
313
|
/*
|
|
314
314
|
* A greedy heuristic for finding a feedback arc set for a graph. A feedback
|
|
@@ -319,30 +319,30 @@ var List = require("./data/list");
|
|
|
319
319
|
*/
|
|
320
320
|
module.exports = greedyFAS;
|
|
321
321
|
|
|
322
|
-
|
|
322
|
+
let DEFAULT_WEIGHT_FN = () => 1;
|
|
323
323
|
|
|
324
324
|
function greedyFAS(g, weightFn) {
|
|
325
325
|
if (g.nodeCount() <= 1) {
|
|
326
326
|
return [];
|
|
327
327
|
}
|
|
328
|
-
|
|
329
|
-
|
|
328
|
+
let state = buildState(g, weightFn || DEFAULT_WEIGHT_FN);
|
|
329
|
+
let results = doGreedyFAS(state.graph, state.buckets, state.zeroIdx);
|
|
330
330
|
|
|
331
331
|
// Expand multi-edges
|
|
332
332
|
return results.flatMap(e => g.outEdges(e.v, e.w));
|
|
333
333
|
}
|
|
334
334
|
|
|
335
335
|
function doGreedyFAS(g, buckets, zeroIdx) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
336
|
+
let results = [];
|
|
337
|
+
let sources = buckets[buckets.length - 1];
|
|
338
|
+
let sinks = buckets[0];
|
|
339
339
|
|
|
340
|
-
|
|
340
|
+
let entry;
|
|
341
341
|
while (g.nodeCount()) {
|
|
342
342
|
while ((entry = sinks.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
|
|
343
343
|
while ((entry = sources.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
|
|
344
344
|
if (g.nodeCount()) {
|
|
345
|
-
for (
|
|
345
|
+
for (let i = buckets.length - 2; i > 0; --i) {
|
|
346
346
|
entry = buckets[i].dequeue();
|
|
347
347
|
if (entry) {
|
|
348
348
|
results = results.concat(removeNode(g, buckets, zeroIdx, entry, true));
|
|
@@ -356,11 +356,11 @@ function doGreedyFAS(g, buckets, zeroIdx) {
|
|
|
356
356
|
}
|
|
357
357
|
|
|
358
358
|
function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
|
|
359
|
-
|
|
359
|
+
let results = collectPredecessors ? [] : undefined;
|
|
360
360
|
|
|
361
|
-
g.inEdges(entry.v).forEach(
|
|
362
|
-
|
|
363
|
-
|
|
361
|
+
g.inEdges(entry.v).forEach(edge => {
|
|
362
|
+
let weight = g.edge(edge);
|
|
363
|
+
let uEntry = g.node(edge.v);
|
|
364
364
|
|
|
365
365
|
if (collectPredecessors) {
|
|
366
366
|
results.push({ v: edge.v, w: edge.w });
|
|
@@ -370,10 +370,10 @@ function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
|
|
|
370
370
|
assignBucket(buckets, zeroIdx, uEntry);
|
|
371
371
|
});
|
|
372
372
|
|
|
373
|
-
g.outEdges(entry.v).forEach(
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
373
|
+
g.outEdges(entry.v).forEach(edge => {
|
|
374
|
+
let weight = g.edge(edge);
|
|
375
|
+
let w = edge.w;
|
|
376
|
+
let wEntry = g.node(w);
|
|
377
377
|
wEntry["in"] -= weight;
|
|
378
378
|
assignBucket(buckets, zeroIdx, wEntry);
|
|
379
379
|
});
|
|
@@ -384,29 +384,29 @@ function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
|
|
|
384
384
|
}
|
|
385
385
|
|
|
386
386
|
function buildState(g, weightFn) {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
387
|
+
let fasGraph = new Graph();
|
|
388
|
+
let maxIn = 0;
|
|
389
|
+
let maxOut = 0;
|
|
390
390
|
|
|
391
|
-
g.nodes().forEach(
|
|
391
|
+
g.nodes().forEach(v => {
|
|
392
392
|
fasGraph.setNode(v, { v: v, "in": 0, out: 0 });
|
|
393
393
|
});
|
|
394
394
|
|
|
395
395
|
// Aggregate weights on nodes, but also sum the weights across multi-edges
|
|
396
396
|
// into a single edge for the fasGraph.
|
|
397
|
-
g.edges().forEach(
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
397
|
+
g.edges().forEach(e => {
|
|
398
|
+
let prevWeight = fasGraph.edge(e.v, e.w) || 0;
|
|
399
|
+
let weight = weightFn(e);
|
|
400
|
+
let edgeWeight = prevWeight + weight;
|
|
401
401
|
fasGraph.setEdge(e.v, e.w, edgeWeight);
|
|
402
402
|
maxOut = Math.max(maxOut, fasGraph.node(e.v).out += weight);
|
|
403
403
|
maxIn = Math.max(maxIn, fasGraph.node(e.w)["in"] += weight);
|
|
404
404
|
});
|
|
405
405
|
|
|
406
|
-
|
|
407
|
-
|
|
406
|
+
let buckets = range(maxOut + maxIn + 3).map(() => new List());
|
|
407
|
+
let zeroIdx = maxIn + 1;
|
|
408
408
|
|
|
409
|
-
fasGraph.nodes().forEach(
|
|
409
|
+
fasGraph.nodes().forEach(v => {
|
|
410
410
|
assignBucket(buckets, zeroIdx, fasGraph.node(v));
|
|
411
411
|
});
|
|
412
412
|
|
|
@@ -435,60 +435,60 @@ function range(limit) {
|
|
|
435
435
|
},{"./data/list":5,"@dagrejs/graphlib":29}],8:[function(require,module,exports){
|
|
436
436
|
"use strict";
|
|
437
437
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
438
|
+
let acyclic = require("./acyclic");
|
|
439
|
+
let normalize = require("./normalize");
|
|
440
|
+
let rank = require("./rank");
|
|
441
|
+
let normalizeRanks = require("./util").normalizeRanks;
|
|
442
|
+
let parentDummyChains = require("./parent-dummy-chains");
|
|
443
|
+
let removeEmptyRanks = require("./util").removeEmptyRanks;
|
|
444
|
+
let nestingGraph = require("./nesting-graph");
|
|
445
|
+
let addBorderSegments = require("./add-border-segments");
|
|
446
|
+
let coordinateSystem = require("./coordinate-system");
|
|
447
|
+
let order = require("./order");
|
|
448
|
+
let position = require("./position");
|
|
449
|
+
let util = require("./util");
|
|
450
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
451
451
|
|
|
452
452
|
module.exports = layout;
|
|
453
453
|
|
|
454
454
|
function layout(g, opts) {
|
|
455
|
-
|
|
456
|
-
time("layout",
|
|
457
|
-
|
|
458
|
-
time(" buildLayoutGraph",
|
|
459
|
-
time(" runLayout",
|
|
460
|
-
time(" updateInputGraph",
|
|
455
|
+
let time = opts && opts.debugTiming ? util.time : util.notime;
|
|
456
|
+
time("layout", () => {
|
|
457
|
+
let layoutGraph =
|
|
458
|
+
time(" buildLayoutGraph", () => buildLayoutGraph(g));
|
|
459
|
+
time(" runLayout", () => runLayout(layoutGraph, time));
|
|
460
|
+
time(" updateInputGraph", () => updateInputGraph(g, layoutGraph));
|
|
461
461
|
});
|
|
462
462
|
}
|
|
463
463
|
|
|
464
464
|
function runLayout(g, time) {
|
|
465
|
-
time(" makeSpaceForEdgeLabels",
|
|
466
|
-
time(" removeSelfEdges",
|
|
467
|
-
time(" acyclic",
|
|
468
|
-
time(" nestingGraph.run",
|
|
469
|
-
time(" rank",
|
|
470
|
-
time(" injectEdgeLabelProxies",
|
|
471
|
-
time(" removeEmptyRanks",
|
|
472
|
-
time(" nestingGraph.cleanup",
|
|
473
|
-
time(" normalizeRanks",
|
|
474
|
-
time(" assignRankMinMax",
|
|
475
|
-
time(" removeEdgeLabelProxies",
|
|
476
|
-
time(" normalize.run",
|
|
477
|
-
time(" parentDummyChains",
|
|
478
|
-
time(" addBorderSegments",
|
|
479
|
-
time(" order",
|
|
480
|
-
time(" insertSelfEdges",
|
|
481
|
-
time(" adjustCoordinateSystem",
|
|
482
|
-
time(" position",
|
|
483
|
-
time(" positionSelfEdges",
|
|
484
|
-
time(" removeBorderNodes",
|
|
485
|
-
time(" normalize.undo",
|
|
486
|
-
time(" fixupEdgeLabelCoords",
|
|
487
|
-
time(" undoCoordinateSystem",
|
|
488
|
-
time(" translateGraph",
|
|
489
|
-
time(" assignNodeIntersects",
|
|
490
|
-
time(" reversePoints",
|
|
491
|
-
time(" acyclic.undo",
|
|
465
|
+
time(" makeSpaceForEdgeLabels", () => makeSpaceForEdgeLabels(g));
|
|
466
|
+
time(" removeSelfEdges", () => removeSelfEdges(g));
|
|
467
|
+
time(" acyclic", () => acyclic.run(g));
|
|
468
|
+
time(" nestingGraph.run", () => nestingGraph.run(g));
|
|
469
|
+
time(" rank", () => rank(util.asNonCompoundGraph(g)));
|
|
470
|
+
time(" injectEdgeLabelProxies", () => injectEdgeLabelProxies(g));
|
|
471
|
+
time(" removeEmptyRanks", () => removeEmptyRanks(g));
|
|
472
|
+
time(" nestingGraph.cleanup", () => nestingGraph.cleanup(g));
|
|
473
|
+
time(" normalizeRanks", () => normalizeRanks(g));
|
|
474
|
+
time(" assignRankMinMax", () => assignRankMinMax(g));
|
|
475
|
+
time(" removeEdgeLabelProxies", () => removeEdgeLabelProxies(g));
|
|
476
|
+
time(" normalize.run", () => normalize.run(g));
|
|
477
|
+
time(" parentDummyChains", () => parentDummyChains(g));
|
|
478
|
+
time(" addBorderSegments", () => addBorderSegments(g));
|
|
479
|
+
time(" order", () => order(g));
|
|
480
|
+
time(" insertSelfEdges", () => insertSelfEdges(g));
|
|
481
|
+
time(" adjustCoordinateSystem", () => coordinateSystem.adjust(g));
|
|
482
|
+
time(" position", () => position(g));
|
|
483
|
+
time(" positionSelfEdges", () => positionSelfEdges(g));
|
|
484
|
+
time(" removeBorderNodes", () => removeBorderNodes(g));
|
|
485
|
+
time(" normalize.undo", () => normalize.undo(g));
|
|
486
|
+
time(" fixupEdgeLabelCoords", () => fixupEdgeLabelCoords(g));
|
|
487
|
+
time(" undoCoordinateSystem", () => coordinateSystem.undo(g));
|
|
488
|
+
time(" translateGraph", () => translateGraph(g));
|
|
489
|
+
time(" assignNodeIntersects", () => assignNodeIntersects(g));
|
|
490
|
+
time(" reversePoints", () => reversePointsForReversedEdges(g));
|
|
491
|
+
time(" acyclic.undo", () => acyclic.undo(g));
|
|
492
492
|
}
|
|
493
493
|
|
|
494
494
|
/*
|
|
@@ -499,8 +499,8 @@ function runLayout(g, time) {
|
|
|
499
499
|
*/
|
|
500
500
|
function updateInputGraph(inputGraph, layoutGraph) {
|
|
501
501
|
inputGraph.nodes().forEach(v => {
|
|
502
|
-
|
|
503
|
-
|
|
502
|
+
let inputLabel = inputGraph.node(v);
|
|
503
|
+
let layoutLabel = layoutGraph.node(v);
|
|
504
504
|
|
|
505
505
|
if (inputLabel) {
|
|
506
506
|
inputLabel.x = layoutLabel.x;
|
|
@@ -515,8 +515,8 @@ function updateInputGraph(inputGraph, layoutGraph) {
|
|
|
515
515
|
});
|
|
516
516
|
|
|
517
517
|
inputGraph.edges().forEach(e => {
|
|
518
|
-
|
|
519
|
-
|
|
518
|
+
let inputLabel = inputGraph.edge(e);
|
|
519
|
+
let layoutLabel = layoutGraph.edge(e);
|
|
520
520
|
|
|
521
521
|
inputLabel.points = layoutLabel.points;
|
|
522
522
|
if (layoutLabel.hasOwnProperty("x")) {
|
|
@@ -529,17 +529,17 @@ function updateInputGraph(inputGraph, layoutGraph) {
|
|
|
529
529
|
inputGraph.graph().height = layoutGraph.graph().height;
|
|
530
530
|
}
|
|
531
531
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
532
|
+
let graphNumAttrs = ["nodesep", "edgesep", "ranksep", "marginx", "marginy"];
|
|
533
|
+
let graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: "tb" };
|
|
534
|
+
let graphAttrs = ["acyclicer", "ranker", "rankdir", "align"];
|
|
535
|
+
let nodeNumAttrs = ["width", "height"];
|
|
536
|
+
let nodeDefaults = { width: 0, height: 0 };
|
|
537
|
+
let edgeNumAttrs = ["minlen", "weight", "width", "height", "labeloffset"];
|
|
538
|
+
let edgeDefaults = {
|
|
539
539
|
minlen: 1, weight: 1, width: 0, height: 0,
|
|
540
540
|
labeloffset: 10, labelpos: "r"
|
|
541
541
|
};
|
|
542
|
-
|
|
542
|
+
let edgeAttrs = ["labelpos"];
|
|
543
543
|
|
|
544
544
|
/*
|
|
545
545
|
* Constructs a new graph from the input graph, which can be used for layout.
|
|
@@ -548,8 +548,8 @@ var edgeAttrs = ["labelpos"];
|
|
|
548
548
|
* attributes can influence layout.
|
|
549
549
|
*/
|
|
550
550
|
function buildLayoutGraph(inputGraph) {
|
|
551
|
-
|
|
552
|
-
|
|
551
|
+
let g = new Graph({ multigraph: true, compound: true });
|
|
552
|
+
let graph = canonicalize(inputGraph.graph());
|
|
553
553
|
|
|
554
554
|
g.setGraph(Object.assign({},
|
|
555
555
|
graphDefaults,
|
|
@@ -557,7 +557,7 @@ function buildLayoutGraph(inputGraph) {
|
|
|
557
557
|
util.pick(graph, graphAttrs)));
|
|
558
558
|
|
|
559
559
|
inputGraph.nodes().forEach(v => {
|
|
560
|
-
|
|
560
|
+
let node = canonicalize(inputGraph.node(v));
|
|
561
561
|
const newNode = selectNumberAttrs(node, nodeNumAttrs);
|
|
562
562
|
Object.keys(nodeDefaults).forEach(k => {
|
|
563
563
|
if (newNode[k] === undefined) {
|
|
@@ -570,7 +570,7 @@ function buildLayoutGraph(inputGraph) {
|
|
|
570
570
|
});
|
|
571
571
|
|
|
572
572
|
inputGraph.edges().forEach(e => {
|
|
573
|
-
|
|
573
|
+
let edge = canonicalize(inputGraph.edge(e));
|
|
574
574
|
g.setEdge(e, Object.assign({},
|
|
575
575
|
edgeDefaults,
|
|
576
576
|
selectNumberAttrs(edge, edgeNumAttrs),
|
|
@@ -589,10 +589,10 @@ function buildLayoutGraph(inputGraph) {
|
|
|
589
589
|
* away from the edge itself a bit.
|
|
590
590
|
*/
|
|
591
591
|
function makeSpaceForEdgeLabels(g) {
|
|
592
|
-
|
|
592
|
+
let graph = g.graph();
|
|
593
593
|
graph.ranksep /= 2;
|
|
594
594
|
g.edges().forEach(e => {
|
|
595
|
-
|
|
595
|
+
let edge = g.edge(e);
|
|
596
596
|
edge.minlen *= 2;
|
|
597
597
|
if (edge.labelpos.toLowerCase() !== "c") {
|
|
598
598
|
if (graph.rankdir === "TB" || graph.rankdir === "BT") {
|
|
@@ -612,20 +612,20 @@ function makeSpaceForEdgeLabels(g) {
|
|
|
612
612
|
*/
|
|
613
613
|
function injectEdgeLabelProxies(g) {
|
|
614
614
|
g.edges().forEach(e => {
|
|
615
|
-
|
|
615
|
+
let edge = g.edge(e);
|
|
616
616
|
if (edge.width && edge.height) {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
617
|
+
let v = g.node(e.v);
|
|
618
|
+
let w = g.node(e.w);
|
|
619
|
+
let label = { rank: (w.rank - v.rank) / 2 + v.rank, e: e };
|
|
620
620
|
util.addDummyNode(g, "edge-proxy", label, "_ep");
|
|
621
621
|
}
|
|
622
622
|
});
|
|
623
623
|
}
|
|
624
624
|
|
|
625
625
|
function assignRankMinMax(g) {
|
|
626
|
-
|
|
626
|
+
let maxRank = 0;
|
|
627
627
|
g.nodes().forEach(v => {
|
|
628
|
-
|
|
628
|
+
let node = g.node(v);
|
|
629
629
|
if (node.borderTop) {
|
|
630
630
|
node.minRank = g.node(node.borderTop).rank;
|
|
631
631
|
node.maxRank = g.node(node.borderBottom).rank;
|
|
@@ -637,7 +637,7 @@ function assignRankMinMax(g) {
|
|
|
637
637
|
|
|
638
638
|
function removeEdgeLabelProxies(g) {
|
|
639
639
|
g.nodes().forEach(v => {
|
|
640
|
-
|
|
640
|
+
let node = g.node(v);
|
|
641
641
|
if (node.dummy === "edge-proxy") {
|
|
642
642
|
g.edge(node.e).labelRank = node.rank;
|
|
643
643
|
g.removeNode(v);
|
|
@@ -646,19 +646,19 @@ function removeEdgeLabelProxies(g) {
|
|
|
646
646
|
}
|
|
647
647
|
|
|
648
648
|
function translateGraph(g) {
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
649
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
650
|
+
let maxX = 0;
|
|
651
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
652
|
+
let maxY = 0;
|
|
653
|
+
let graphLabel = g.graph();
|
|
654
|
+
let marginX = graphLabel.marginx || 0;
|
|
655
|
+
let marginY = graphLabel.marginy || 0;
|
|
656
656
|
|
|
657
657
|
function getExtremes(attrs) {
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
658
|
+
let x = attrs.x;
|
|
659
|
+
let y = attrs.y;
|
|
660
|
+
let w = attrs.width;
|
|
661
|
+
let h = attrs.height;
|
|
662
662
|
minX = Math.min(minX, x - w / 2);
|
|
663
663
|
maxX = Math.max(maxX, x + w / 2);
|
|
664
664
|
minY = Math.min(minY, y - h / 2);
|
|
@@ -667,7 +667,7 @@ function translateGraph(g) {
|
|
|
667
667
|
|
|
668
668
|
g.nodes().forEach(v => getExtremes(g.node(v)));
|
|
669
669
|
g.edges().forEach(e => {
|
|
670
|
-
|
|
670
|
+
let edge = g.edge(e);
|
|
671
671
|
if (edge.hasOwnProperty("x")) {
|
|
672
672
|
getExtremes(edge);
|
|
673
673
|
}
|
|
@@ -677,13 +677,13 @@ function translateGraph(g) {
|
|
|
677
677
|
minY -= marginY;
|
|
678
678
|
|
|
679
679
|
g.nodes().forEach(v => {
|
|
680
|
-
|
|
680
|
+
let node = g.node(v);
|
|
681
681
|
node.x -= minX;
|
|
682
682
|
node.y -= minY;
|
|
683
683
|
});
|
|
684
684
|
|
|
685
685
|
g.edges().forEach(e => {
|
|
686
|
-
|
|
686
|
+
let edge = g.edge(e);
|
|
687
687
|
edge.points.forEach(p => {
|
|
688
688
|
p.x -= minX;
|
|
689
689
|
p.y -= minY;
|
|
@@ -698,10 +698,10 @@ function translateGraph(g) {
|
|
|
698
698
|
|
|
699
699
|
function assignNodeIntersects(g) {
|
|
700
700
|
g.edges().forEach(e => {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
701
|
+
let edge = g.edge(e);
|
|
702
|
+
let nodeV = g.node(e.v);
|
|
703
|
+
let nodeW = g.node(e.w);
|
|
704
|
+
let p1, p2;
|
|
705
705
|
if (!edge.points) {
|
|
706
706
|
edge.points = [];
|
|
707
707
|
p1 = nodeW;
|
|
@@ -717,7 +717,7 @@ function assignNodeIntersects(g) {
|
|
|
717
717
|
|
|
718
718
|
function fixupEdgeLabelCoords(g) {
|
|
719
719
|
g.edges().forEach(e => {
|
|
720
|
-
|
|
720
|
+
let edge = g.edge(e);
|
|
721
721
|
if (edge.hasOwnProperty("x")) {
|
|
722
722
|
if (edge.labelpos === "l" || edge.labelpos === "r") {
|
|
723
723
|
edge.width -= edge.labeloffset;
|
|
@@ -732,7 +732,7 @@ function fixupEdgeLabelCoords(g) {
|
|
|
732
732
|
|
|
733
733
|
function reversePointsForReversedEdges(g) {
|
|
734
734
|
g.edges().forEach(e => {
|
|
735
|
-
|
|
735
|
+
let edge = g.edge(e);
|
|
736
736
|
if (edge.reversed) {
|
|
737
737
|
edge.points.reverse();
|
|
738
738
|
}
|
|
@@ -742,11 +742,11 @@ function reversePointsForReversedEdges(g) {
|
|
|
742
742
|
function removeBorderNodes(g) {
|
|
743
743
|
g.nodes().forEach(v => {
|
|
744
744
|
if (g.children(v).length) {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
745
|
+
let node = g.node(v);
|
|
746
|
+
let t = g.node(node.borderTop);
|
|
747
|
+
let b = g.node(node.borderBottom);
|
|
748
|
+
let l = g.node(node.borderLeft[node.borderLeft.length - 1]);
|
|
749
|
+
let r = g.node(node.borderRight[node.borderRight.length - 1]);
|
|
750
750
|
|
|
751
751
|
node.width = Math.abs(r.x - l.x);
|
|
752
752
|
node.height = Math.abs(b.y - t.y);
|
|
@@ -840,17 +840,17 @@ function canonicalize(attrs) {
|
|
|
840
840
|
}
|
|
841
841
|
|
|
842
842
|
},{"./acyclic":2,"./add-border-segments":3,"./coordinate-system":4,"./nesting-graph":9,"./normalize":10,"./order":15,"./parent-dummy-chains":20,"./position":22,"./rank":24,"./util":27,"@dagrejs/graphlib":29}],9:[function(require,module,exports){
|
|
843
|
-
|
|
843
|
+
let util = require("./util");
|
|
844
844
|
|
|
845
845
|
module.exports = {
|
|
846
|
-
run
|
|
847
|
-
cleanup
|
|
846
|
+
run,
|
|
847
|
+
cleanup,
|
|
848
848
|
};
|
|
849
849
|
|
|
850
850
|
/*
|
|
851
851
|
* A nesting graph creates dummy nodes for the tops and bottoms of subgraphs,
|
|
852
852
|
* adds appropriate edges to ensure that all cluster nodes are placed between
|
|
853
|
-
* these
|
|
853
|
+
* these boundaries, and ensures that the graph is connected.
|
|
854
854
|
*
|
|
855
855
|
* In addition we ensure, through the use of the minlen property, that nodes
|
|
856
856
|
* and subgraph border nodes to not end up on the same rank.
|
|
@@ -871,10 +871,10 @@ module.exports = {
|
|
|
871
871
|
* Graphs."
|
|
872
872
|
*/
|
|
873
873
|
function run(g) {
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
874
|
+
let root = util.addDummyNode(g, "root", {}, "_root");
|
|
875
|
+
let depths = treeDepths(g);
|
|
876
|
+
let height = Math.max(...Object.values(depths)) - 1; // Note: depths is an Object not an array
|
|
877
|
+
let nodeSep = 2 * height + 1;
|
|
878
878
|
|
|
879
879
|
g.graph().nestingRoot = root;
|
|
880
880
|
|
|
@@ -882,12 +882,10 @@ function run(g) {
|
|
|
882
882
|
g.edges().forEach(e => g.edge(e).minlen *= nodeSep);
|
|
883
883
|
|
|
884
884
|
// Calculate a weight that is sufficient to keep subgraphs vertically compact
|
|
885
|
-
|
|
885
|
+
let weight = sumWeights(g) + 1;
|
|
886
886
|
|
|
887
887
|
// Create border nodes and link them up
|
|
888
|
-
g.children().forEach(
|
|
889
|
-
dfs(g, root, nodeSep, weight, height, depths, child);
|
|
890
|
-
});
|
|
888
|
+
g.children().forEach(child => dfs(g, root, nodeSep, weight, height, depths, child));
|
|
891
889
|
|
|
892
890
|
// Save the multiplier for node layers for later removal of empty border
|
|
893
891
|
// layers.
|
|
@@ -895,7 +893,7 @@ function run(g) {
|
|
|
895
893
|
}
|
|
896
894
|
|
|
897
895
|
function dfs(g, root, nodeSep, weight, height, depths, v) {
|
|
898
|
-
|
|
896
|
+
let children = g.children(v);
|
|
899
897
|
if (!children.length) {
|
|
900
898
|
if (v !== root) {
|
|
901
899
|
g.setEdge(root, v, { weight: 0, minlen: nodeSep });
|
|
@@ -903,23 +901,23 @@ function dfs(g, root, nodeSep, weight, height, depths, v) {
|
|
|
903
901
|
return;
|
|
904
902
|
}
|
|
905
903
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
904
|
+
let top = util.addBorderNode(g, "_bt");
|
|
905
|
+
let bottom = util.addBorderNode(g, "_bb");
|
|
906
|
+
let label = g.node(v);
|
|
909
907
|
|
|
910
908
|
g.setParent(top, v);
|
|
911
909
|
label.borderTop = top;
|
|
912
910
|
g.setParent(bottom, v);
|
|
913
911
|
label.borderBottom = bottom;
|
|
914
912
|
|
|
915
|
-
children.forEach(
|
|
913
|
+
children.forEach(child => {
|
|
916
914
|
dfs(g, root, nodeSep, weight, height, depths, child);
|
|
917
915
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
916
|
+
let childNode = g.node(child);
|
|
917
|
+
let childTop = childNode.borderTop ? childNode.borderTop : child;
|
|
918
|
+
let childBottom = childNode.borderBottom ? childNode.borderBottom : child;
|
|
919
|
+
let thisWeight = childNode.borderTop ? weight : 2 * weight;
|
|
920
|
+
let minlen = childTop !== childBottom ? 1 : height - depths[v] + 1;
|
|
923
921
|
|
|
924
922
|
g.setEdge(top, childTop, {
|
|
925
923
|
weight: thisWeight,
|
|
@@ -971,7 +969,7 @@ function cleanup(g) {
|
|
|
971
969
|
},{"./util":27}],10:[function(require,module,exports){
|
|
972
970
|
"use strict";
|
|
973
971
|
|
|
974
|
-
|
|
972
|
+
let util = require("./util");
|
|
975
973
|
|
|
976
974
|
module.exports = {
|
|
977
975
|
run: run,
|
|
@@ -1000,19 +998,19 @@ function run(g) {
|
|
|
1000
998
|
}
|
|
1001
999
|
|
|
1002
1000
|
function normalizeEdge(g, e) {
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1001
|
+
let v = e.v;
|
|
1002
|
+
let vRank = g.node(v).rank;
|
|
1003
|
+
let w = e.w;
|
|
1004
|
+
let wRank = g.node(w).rank;
|
|
1005
|
+
let name = e.name;
|
|
1006
|
+
let edgeLabel = g.edge(e);
|
|
1007
|
+
let labelRank = edgeLabel.labelRank;
|
|
1010
1008
|
|
|
1011
1009
|
if (wRank === vRank + 1) return;
|
|
1012
1010
|
|
|
1013
1011
|
g.removeEdge(e);
|
|
1014
1012
|
|
|
1015
|
-
|
|
1013
|
+
let dummy, attrs, i;
|
|
1016
1014
|
for (i = 0, ++vRank; vRank < wRank; ++i, ++vRank) {
|
|
1017
1015
|
edgeLabel.points = [];
|
|
1018
1016
|
attrs = {
|
|
@@ -1038,10 +1036,10 @@ function normalizeEdge(g, e) {
|
|
|
1038
1036
|
}
|
|
1039
1037
|
|
|
1040
1038
|
function undo(g) {
|
|
1041
|
-
g.graph().dummyChains.forEach(
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1039
|
+
g.graph().dummyChains.forEach(v => {
|
|
1040
|
+
let node = g.node(v);
|
|
1041
|
+
let origLabel = node.edgeLabel;
|
|
1042
|
+
let w;
|
|
1045
1043
|
g.setEdge(node.edgeObj, origLabel);
|
|
1046
1044
|
while (node.dummy) {
|
|
1047
1045
|
w = g.successors(v)[0];
|
|
@@ -1063,11 +1061,11 @@ function undo(g) {
|
|
|
1063
1061
|
module.exports = addSubgraphConstraints;
|
|
1064
1062
|
|
|
1065
1063
|
function addSubgraphConstraints(g, cg, vs) {
|
|
1066
|
-
|
|
1064
|
+
let prev = {},
|
|
1067
1065
|
rootPrev;
|
|
1068
1066
|
|
|
1069
|
-
vs.forEach(
|
|
1070
|
-
|
|
1067
|
+
vs.forEach(v => {
|
|
1068
|
+
let child = g.parent(v),
|
|
1071
1069
|
parent,
|
|
1072
1070
|
prevChild;
|
|
1073
1071
|
while (child) {
|
|
@@ -1117,12 +1115,12 @@ module.exports = barycenter;
|
|
|
1117
1115
|
|
|
1118
1116
|
function barycenter(g, movable = []) {
|
|
1119
1117
|
return movable.map(v => {
|
|
1120
|
-
|
|
1118
|
+
let inV = g.inEdges(v);
|
|
1121
1119
|
if (!inV.length) {
|
|
1122
1120
|
return { v: v };
|
|
1123
1121
|
} else {
|
|
1124
|
-
|
|
1125
|
-
|
|
1122
|
+
let result = inV.reduce((acc, e) => {
|
|
1123
|
+
let edge = g.edge(e),
|
|
1126
1124
|
nodeU = g.node(e.v);
|
|
1127
1125
|
return {
|
|
1128
1126
|
sum: acc.sum + (edge.weight * nodeU.order),
|
|
@@ -1141,8 +1139,8 @@ function barycenter(g, movable = []) {
|
|
|
1141
1139
|
|
|
1142
1140
|
|
|
1143
1141
|
},{}],13:[function(require,module,exports){
|
|
1144
|
-
|
|
1145
|
-
|
|
1142
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
1143
|
+
let util = require("../util");
|
|
1146
1144
|
|
|
1147
1145
|
module.exports = buildLayerGraph;
|
|
1148
1146
|
|
|
@@ -1177,12 +1175,12 @@ module.exports = buildLayerGraph;
|
|
|
1177
1175
|
* graph is not a multi-graph.
|
|
1178
1176
|
*/
|
|
1179
1177
|
function buildLayerGraph(g, rank, relationship) {
|
|
1180
|
-
|
|
1178
|
+
let root = createRootNode(g),
|
|
1181
1179
|
result = new Graph({ compound: true }).setGraph({ root: root })
|
|
1182
|
-
.setDefaultNodeLabel(
|
|
1180
|
+
.setDefaultNodeLabel(v => g.node(v));
|
|
1183
1181
|
|
|
1184
|
-
g.nodes().forEach(
|
|
1185
|
-
|
|
1182
|
+
g.nodes().forEach(v => {
|
|
1183
|
+
let node = g.node(v),
|
|
1186
1184
|
parent = g.parent(v);
|
|
1187
1185
|
|
|
1188
1186
|
if (node.rank === rank || node.minRank <= rank && rank <= node.maxRank) {
|
|
@@ -1190,8 +1188,8 @@ function buildLayerGraph(g, rank, relationship) {
|
|
|
1190
1188
|
result.setParent(v, parent || root);
|
|
1191
1189
|
|
|
1192
1190
|
// This assumes we have only short edges!
|
|
1193
|
-
g[relationship](v).forEach(
|
|
1194
|
-
|
|
1191
|
+
g[relationship](v).forEach(e => {
|
|
1192
|
+
let u = e.v === v ? e.w : e.v,
|
|
1195
1193
|
edge = result.edge(u, v),
|
|
1196
1194
|
weight = edge !== undefined ? edge.weight : 0;
|
|
1197
1195
|
result.setEdge(u, v, { weight: g.edge(e).weight + weight });
|
|
@@ -1218,7 +1216,7 @@ function createRootNode(g) {
|
|
|
1218
1216
|
},{"../util":27,"@dagrejs/graphlib":29}],14:[function(require,module,exports){
|
|
1219
1217
|
"use strict";
|
|
1220
1218
|
|
|
1221
|
-
|
|
1219
|
+
let zipObject = require("../util").zipObject;
|
|
1222
1220
|
|
|
1223
1221
|
module.exports = crossCount;
|
|
1224
1222
|
|
|
@@ -1239,8 +1237,8 @@ module.exports = crossCount;
|
|
|
1239
1237
|
* This algorithm is derived from Barth, et al., "Bilayer Cross Counting."
|
|
1240
1238
|
*/
|
|
1241
1239
|
function crossCount(g, layering) {
|
|
1242
|
-
|
|
1243
|
-
for (
|
|
1240
|
+
let cc = 0;
|
|
1241
|
+
for (let i = 1; i < layering.length; ++i) {
|
|
1244
1242
|
cc += twoLayerCrossCount(g, layering[i-1], layering[i]);
|
|
1245
1243
|
}
|
|
1246
1244
|
return cc;
|
|
@@ -1250,26 +1248,26 @@ function twoLayerCrossCount(g, northLayer, southLayer) {
|
|
|
1250
1248
|
// Sort all of the edges between the north and south layers by their position
|
|
1251
1249
|
// in the north layer and then the south. Map these edges to the position of
|
|
1252
1250
|
// their head in the south layer.
|
|
1253
|
-
|
|
1254
|
-
|
|
1251
|
+
let southPos = zipObject(southLayer, southLayer.map((v, i) => i));
|
|
1252
|
+
let southEntries = northLayer.flatMap(v => {
|
|
1255
1253
|
return g.outEdges(v).map(e => {
|
|
1256
1254
|
return { pos: southPos[e.w], weight: g.edge(e).weight };
|
|
1257
1255
|
}).sort((a, b) => a.pos - b.pos);
|
|
1258
1256
|
});
|
|
1259
1257
|
|
|
1260
1258
|
// Build the accumulator tree
|
|
1261
|
-
|
|
1259
|
+
let firstIndex = 1;
|
|
1262
1260
|
while (firstIndex < southLayer.length) firstIndex <<= 1;
|
|
1263
|
-
|
|
1261
|
+
let treeSize = 2 * firstIndex - 1;
|
|
1264
1262
|
firstIndex -= 1;
|
|
1265
|
-
|
|
1263
|
+
let tree = new Array(treeSize).fill(0);
|
|
1266
1264
|
|
|
1267
1265
|
// Calculate the weighted crossings
|
|
1268
|
-
|
|
1266
|
+
let cc = 0;
|
|
1269
1267
|
southEntries.forEach(entry => {
|
|
1270
|
-
|
|
1268
|
+
let index = entry.pos + firstIndex;
|
|
1271
1269
|
tree[index] += entry.weight;
|
|
1272
|
-
|
|
1270
|
+
let weightSum = 0;
|
|
1273
1271
|
while (index > 0) {
|
|
1274
1272
|
if (index % 2) {
|
|
1275
1273
|
weightSum += tree[index + 1];
|
|
@@ -1286,13 +1284,13 @@ function twoLayerCrossCount(g, northLayer, southLayer) {
|
|
|
1286
1284
|
},{"../util":27}],15:[function(require,module,exports){
|
|
1287
1285
|
"use strict";
|
|
1288
1286
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1287
|
+
let initOrder = require("./init-order");
|
|
1288
|
+
let crossCount = require("./cross-count");
|
|
1289
|
+
let sortSubgraph = require("./sort-subgraph");
|
|
1290
|
+
let buildLayerGraph = require("./build-layer-graph");
|
|
1291
|
+
let addSubgraphConstraints = require("./add-subgraph-constraints");
|
|
1292
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
1293
|
+
let util = require("../util");
|
|
1296
1294
|
|
|
1297
1295
|
module.exports = order;
|
|
1298
1296
|
|
|
@@ -1312,21 +1310,21 @@ module.exports = order;
|
|
|
1312
1310
|
* algorithm.
|
|
1313
1311
|
*/
|
|
1314
1312
|
function order(g) {
|
|
1315
|
-
|
|
1313
|
+
let maxRank = util.maxRank(g),
|
|
1316
1314
|
downLayerGraphs = buildLayerGraphs(g, util.range(1, maxRank + 1), "inEdges"),
|
|
1317
1315
|
upLayerGraphs = buildLayerGraphs(g, util.range(maxRank - 1, -1, -1), "outEdges");
|
|
1318
1316
|
|
|
1319
|
-
|
|
1317
|
+
let layering = initOrder(g);
|
|
1320
1318
|
assignOrder(g, layering);
|
|
1321
1319
|
|
|
1322
|
-
|
|
1320
|
+
let bestCC = Number.POSITIVE_INFINITY,
|
|
1323
1321
|
best;
|
|
1324
1322
|
|
|
1325
|
-
for (
|
|
1323
|
+
for (let i = 0, lastBest = 0; lastBest < 4; ++i, ++lastBest) {
|
|
1326
1324
|
sweepLayerGraphs(i % 2 ? downLayerGraphs : upLayerGraphs, i % 4 >= 2);
|
|
1327
1325
|
|
|
1328
1326
|
layering = util.buildLayerMatrix(g);
|
|
1329
|
-
|
|
1327
|
+
let cc = crossCount(g, layering);
|
|
1330
1328
|
if (cc < bestCC) {
|
|
1331
1329
|
lastBest = 0;
|
|
1332
1330
|
best = Object.assign({}, layering);
|
|
@@ -1344,10 +1342,10 @@ function buildLayerGraphs(g, ranks, relationship) {
|
|
|
1344
1342
|
}
|
|
1345
1343
|
|
|
1346
1344
|
function sweepLayerGraphs(layerGraphs, biasRight) {
|
|
1347
|
-
|
|
1345
|
+
let cg = new Graph();
|
|
1348
1346
|
layerGraphs.forEach(function(lg) {
|
|
1349
|
-
|
|
1350
|
-
|
|
1347
|
+
let root = lg.graph().root;
|
|
1348
|
+
let sorted = sortSubgraph(lg, root, cg, biasRight);
|
|
1351
1349
|
sorted.vs.forEach((v, i) => lg.node(v).order = i);
|
|
1352
1350
|
addSubgraphConstraints(lg, cg, sorted.vs);
|
|
1353
1351
|
});
|
|
@@ -1360,7 +1358,7 @@ function assignOrder(g, layering) {
|
|
|
1360
1358
|
},{"../util":27,"./add-subgraph-constraints":11,"./build-layer-graph":13,"./cross-count":14,"./init-order":16,"./sort-subgraph":18,"@dagrejs/graphlib":29}],16:[function(require,module,exports){
|
|
1361
1359
|
"use strict";
|
|
1362
1360
|
|
|
1363
|
-
|
|
1361
|
+
let util = require("../util");
|
|
1364
1362
|
|
|
1365
1363
|
module.exports = initOrder;
|
|
1366
1364
|
|
|
@@ -1376,20 +1374,20 @@ module.exports = initOrder;
|
|
|
1376
1374
|
* the order of its nodes.
|
|
1377
1375
|
*/
|
|
1378
1376
|
function initOrder(g) {
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1377
|
+
let visited = {};
|
|
1378
|
+
let simpleNodes = g.nodes().filter(v => !g.children(v).length);
|
|
1379
|
+
let maxRank = Math.max(...simpleNodes.map(v => g.node(v).rank));
|
|
1380
|
+
let layers = util.range(maxRank + 1).map(() => []);
|
|
1383
1381
|
|
|
1384
1382
|
function dfs(v) {
|
|
1385
1383
|
if (visited[v]) return;
|
|
1386
1384
|
visited[v] = true;
|
|
1387
|
-
|
|
1385
|
+
let node = g.node(v);
|
|
1388
1386
|
layers[node.rank].push(v);
|
|
1389
1387
|
g.successors(v).forEach(dfs);
|
|
1390
1388
|
}
|
|
1391
1389
|
|
|
1392
|
-
|
|
1390
|
+
let orderedVs = simpleNodes.sort((a, b) => g.node(a).rank - g.node(b).rank);
|
|
1393
1391
|
orderedVs.forEach(dfs);
|
|
1394
1392
|
|
|
1395
1393
|
return layers;
|
|
@@ -1398,7 +1396,7 @@ function initOrder(g) {
|
|
|
1398
1396
|
},{"../util":27}],17:[function(require,module,exports){
|
|
1399
1397
|
"use strict";
|
|
1400
1398
|
|
|
1401
|
-
|
|
1399
|
+
let util = require("../util");
|
|
1402
1400
|
|
|
1403
1401
|
module.exports = resolveConflicts;
|
|
1404
1402
|
|
|
@@ -1428,9 +1426,9 @@ module.exports = resolveConflicts;
|
|
|
1428
1426
|
* elements in `vs`.
|
|
1429
1427
|
*/
|
|
1430
1428
|
function resolveConflicts(entries, cg) {
|
|
1431
|
-
|
|
1429
|
+
let mappedEntries = {};
|
|
1432
1430
|
entries.forEach((entry, i) => {
|
|
1433
|
-
|
|
1431
|
+
let tmp = mappedEntries[entry.v] = {
|
|
1434
1432
|
indegree: 0,
|
|
1435
1433
|
"in": [],
|
|
1436
1434
|
out: [],
|
|
@@ -1444,24 +1442,24 @@ function resolveConflicts(entries, cg) {
|
|
|
1444
1442
|
});
|
|
1445
1443
|
|
|
1446
1444
|
cg.edges().forEach(e => {
|
|
1447
|
-
|
|
1448
|
-
|
|
1445
|
+
let entryV = mappedEntries[e.v];
|
|
1446
|
+
let entryW = mappedEntries[e.w];
|
|
1449
1447
|
if (entryV !== undefined && entryW !== undefined) {
|
|
1450
1448
|
entryW.indegree++;
|
|
1451
1449
|
entryV.out.push(mappedEntries[e.w]);
|
|
1452
1450
|
}
|
|
1453
1451
|
});
|
|
1454
1452
|
|
|
1455
|
-
|
|
1453
|
+
let sourceSet = Object.values(mappedEntries).filter(entry => !entry.indegree);
|
|
1456
1454
|
|
|
1457
1455
|
return doResolveConflicts(sourceSet);
|
|
1458
1456
|
}
|
|
1459
1457
|
|
|
1460
1458
|
function doResolveConflicts(sourceSet) {
|
|
1461
|
-
|
|
1459
|
+
let entries = [];
|
|
1462
1460
|
|
|
1463
1461
|
function handleIn(vEntry) {
|
|
1464
|
-
return
|
|
1462
|
+
return uEntry => {
|
|
1465
1463
|
if (uEntry.merged) {
|
|
1466
1464
|
return;
|
|
1467
1465
|
}
|
|
@@ -1474,7 +1472,7 @@ function doResolveConflicts(sourceSet) {
|
|
|
1474
1472
|
}
|
|
1475
1473
|
|
|
1476
1474
|
function handleOut(vEntry) {
|
|
1477
|
-
return
|
|
1475
|
+
return wEntry => {
|
|
1478
1476
|
wEntry["in"].push(vEntry);
|
|
1479
1477
|
if (--wEntry.indegree === 0) {
|
|
1480
1478
|
sourceSet.push(wEntry);
|
|
@@ -1483,7 +1481,7 @@ function doResolveConflicts(sourceSet) {
|
|
|
1483
1481
|
}
|
|
1484
1482
|
|
|
1485
1483
|
while (sourceSet.length) {
|
|
1486
|
-
|
|
1484
|
+
let entry = sourceSet.pop();
|
|
1487
1485
|
entries.push(entry);
|
|
1488
1486
|
entry["in"].reverse().forEach(handleIn(entry));
|
|
1489
1487
|
entry.out.forEach(handleOut(entry));
|
|
@@ -1495,8 +1493,8 @@ function doResolveConflicts(sourceSet) {
|
|
|
1495
1493
|
}
|
|
1496
1494
|
|
|
1497
1495
|
function mergeEntries(target, source) {
|
|
1498
|
-
|
|
1499
|
-
|
|
1496
|
+
let sum = 0;
|
|
1497
|
+
let weight = 0;
|
|
1500
1498
|
|
|
1501
1499
|
if (target.weight) {
|
|
1502
1500
|
sum += target.barycenter * target.weight;
|
|
@@ -1516,27 +1514,27 @@ function mergeEntries(target, source) {
|
|
|
1516
1514
|
}
|
|
1517
1515
|
|
|
1518
1516
|
},{"../util":27}],18:[function(require,module,exports){
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1517
|
+
let barycenter = require("./barycenter");
|
|
1518
|
+
let resolveConflicts = require("./resolve-conflicts");
|
|
1519
|
+
let sort = require("./sort");
|
|
1522
1520
|
|
|
1523
1521
|
module.exports = sortSubgraph;
|
|
1524
1522
|
|
|
1525
1523
|
function sortSubgraph(g, v, cg, biasRight) {
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1524
|
+
let movable = g.children(v);
|
|
1525
|
+
let node = g.node(v);
|
|
1526
|
+
let bl = node ? node.borderLeft : undefined;
|
|
1527
|
+
let br = node ? node.borderRight: undefined;
|
|
1528
|
+
let subgraphs = {};
|
|
1531
1529
|
|
|
1532
1530
|
if (bl) {
|
|
1533
1531
|
movable = movable.filter(w => w !== bl && w !== br);
|
|
1534
1532
|
}
|
|
1535
1533
|
|
|
1536
|
-
|
|
1537
|
-
barycenters.forEach(
|
|
1534
|
+
let barycenters = barycenter(g, movable);
|
|
1535
|
+
barycenters.forEach(entry => {
|
|
1538
1536
|
if (g.children(entry.v).length) {
|
|
1539
|
-
|
|
1537
|
+
let subgraphResult = sortSubgraph(g, entry.v, cg, biasRight);
|
|
1540
1538
|
subgraphs[entry.v] = subgraphResult;
|
|
1541
1539
|
if (subgraphResult.hasOwnProperty("barycenter")) {
|
|
1542
1540
|
mergeBarycenters(entry, subgraphResult);
|
|
@@ -1544,15 +1542,15 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
1544
1542
|
}
|
|
1545
1543
|
});
|
|
1546
1544
|
|
|
1547
|
-
|
|
1545
|
+
let entries = resolveConflicts(barycenters, cg);
|
|
1548
1546
|
expandSubgraphs(entries, subgraphs);
|
|
1549
1547
|
|
|
1550
|
-
|
|
1548
|
+
let result = sort(entries, biasRight);
|
|
1551
1549
|
|
|
1552
1550
|
if (bl) {
|
|
1553
1551
|
result.vs = [bl, result.vs, br].flat(true);
|
|
1554
1552
|
if (g.predecessors(bl).length) {
|
|
1555
|
-
|
|
1553
|
+
let blPred = g.node(g.predecessors(bl)[0]),
|
|
1556
1554
|
brPred = g.node(g.predecessors(br)[0]);
|
|
1557
1555
|
if (!result.hasOwnProperty("barycenter")) {
|
|
1558
1556
|
result.barycenter = 0;
|
|
@@ -1568,8 +1566,8 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
1568
1566
|
}
|
|
1569
1567
|
|
|
1570
1568
|
function expandSubgraphs(entries, subgraphs) {
|
|
1571
|
-
entries.forEach(
|
|
1572
|
-
entry.vs = entry.vs.flatMap(
|
|
1569
|
+
entries.forEach(entry => {
|
|
1570
|
+
entry.vs = entry.vs.flatMap(v => {
|
|
1573
1571
|
if (subgraphs[v]) {
|
|
1574
1572
|
return subgraphs[v].vs;
|
|
1575
1573
|
}
|
|
@@ -1591,15 +1589,15 @@ function mergeBarycenters(target, other) {
|
|
|
1591
1589
|
}
|
|
1592
1590
|
|
|
1593
1591
|
},{"./barycenter":12,"./resolve-conflicts":17,"./sort":19}],19:[function(require,module,exports){
|
|
1594
|
-
|
|
1592
|
+
let util = require("../util");
|
|
1595
1593
|
|
|
1596
1594
|
module.exports = sort;
|
|
1597
1595
|
|
|
1598
1596
|
function sort(entries, biasRight) {
|
|
1599
|
-
|
|
1597
|
+
let parts = util.partition(entries, entry => {
|
|
1600
1598
|
return entry.hasOwnProperty("barycenter");
|
|
1601
1599
|
});
|
|
1602
|
-
|
|
1600
|
+
let sortable = parts.lhs,
|
|
1603
1601
|
unsortable = parts.rhs.sort((a, b) => b.i - a.i),
|
|
1604
1602
|
vs = [],
|
|
1605
1603
|
sum = 0,
|
|
@@ -1610,7 +1608,7 @@ function sort(entries, biasRight) {
|
|
|
1610
1608
|
|
|
1611
1609
|
vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
|
|
1612
1610
|
|
|
1613
|
-
sortable.forEach(
|
|
1611
|
+
sortable.forEach(entry => {
|
|
1614
1612
|
vsIndex += entry.vs.length;
|
|
1615
1613
|
vs.push(entry.vs);
|
|
1616
1614
|
sum += entry.barycenter * entry.weight;
|
|
@@ -1618,7 +1616,7 @@ function sort(entries, biasRight) {
|
|
|
1618
1616
|
vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
|
|
1619
1617
|
});
|
|
1620
1618
|
|
|
1621
|
-
|
|
1619
|
+
let result = { vs: vs.flat(true) };
|
|
1622
1620
|
if (weight) {
|
|
1623
1621
|
result.barycenter = sum / weight;
|
|
1624
1622
|
result.weight = weight;
|
|
@@ -1627,7 +1625,7 @@ function sort(entries, biasRight) {
|
|
|
1627
1625
|
}
|
|
1628
1626
|
|
|
1629
1627
|
function consumeUnsortable(vs, unsortable, index) {
|
|
1630
|
-
|
|
1628
|
+
let last;
|
|
1631
1629
|
while (unsortable.length && (last = unsortable[unsortable.length - 1]).i <= index) {
|
|
1632
1630
|
unsortable.pop();
|
|
1633
1631
|
vs.push(last.vs);
|
|
@@ -1637,7 +1635,7 @@ function consumeUnsortable(vs, unsortable, index) {
|
|
|
1637
1635
|
}
|
|
1638
1636
|
|
|
1639
1637
|
function compareWithBias(bias) {
|
|
1640
|
-
return
|
|
1638
|
+
return (entryV, entryW) => {
|
|
1641
1639
|
if (entryV.barycenter < entryW.barycenter) {
|
|
1642
1640
|
return -1;
|
|
1643
1641
|
} else if (entryV.barycenter > entryW.barycenter) {
|
|
@@ -1652,17 +1650,17 @@ function compareWithBias(bias) {
|
|
|
1652
1650
|
module.exports = parentDummyChains;
|
|
1653
1651
|
|
|
1654
1652
|
function parentDummyChains(g) {
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
g.graph().dummyChains.forEach(
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1653
|
+
let postorderNums = postorder(g);
|
|
1654
|
+
|
|
1655
|
+
g.graph().dummyChains.forEach(v => {
|
|
1656
|
+
let node = g.node(v);
|
|
1657
|
+
let edgeObj = node.edgeObj;
|
|
1658
|
+
let pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w);
|
|
1659
|
+
let path = pathData.path;
|
|
1660
|
+
let lca = pathData.lca;
|
|
1661
|
+
let pathIdx = 0;
|
|
1662
|
+
let pathV = path[pathIdx];
|
|
1663
|
+
let ascending = true;
|
|
1666
1664
|
|
|
1667
1665
|
while (v !== edgeObj.w) {
|
|
1668
1666
|
node = g.node(v);
|
|
@@ -1695,12 +1693,12 @@ function parentDummyChains(g) {
|
|
|
1695
1693
|
// Find a path from v to w through the lowest common ancestor (LCA). Return the
|
|
1696
1694
|
// full path and the LCA.
|
|
1697
1695
|
function findPath(g, postorderNums, v, w) {
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1696
|
+
let vPath = [];
|
|
1697
|
+
let wPath = [];
|
|
1698
|
+
let low = Math.min(postorderNums[v].low, postorderNums[w].low);
|
|
1699
|
+
let lim = Math.max(postorderNums[v].lim, postorderNums[w].lim);
|
|
1700
|
+
let parent;
|
|
1701
|
+
let lca;
|
|
1704
1702
|
|
|
1705
1703
|
// Traverse up from v to find the LCA
|
|
1706
1704
|
parent = v;
|
|
@@ -1721,11 +1719,11 @@ function findPath(g, postorderNums, v, w) {
|
|
|
1721
1719
|
}
|
|
1722
1720
|
|
|
1723
1721
|
function postorder(g) {
|
|
1724
|
-
|
|
1725
|
-
|
|
1722
|
+
let result = {};
|
|
1723
|
+
let lim = 0;
|
|
1726
1724
|
|
|
1727
1725
|
function dfs(v) {
|
|
1728
|
-
|
|
1726
|
+
let low = lim;
|
|
1729
1727
|
g.children(v).forEach(dfs);
|
|
1730
1728
|
result[v] = { low: low, lim: lim++ };
|
|
1731
1729
|
}
|
|
@@ -1737,8 +1735,8 @@ function postorder(g) {
|
|
|
1737
1735
|
},{}],21:[function(require,module,exports){
|
|
1738
1736
|
"use strict";
|
|
1739
1737
|
|
|
1740
|
-
|
|
1741
|
-
|
|
1738
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
1739
|
+
let util = require("../util");
|
|
1742
1740
|
|
|
1743
1741
|
/*
|
|
1744
1742
|
* This module provides coordinate assignment based on Brandes and Köpf, "Fast
|
|
@@ -1776,10 +1774,10 @@ module.exports = {
|
|
|
1776
1774
|
* single node in the layers being scanned.
|
|
1777
1775
|
*/
|
|
1778
1776
|
function findType1Conflicts(g, layering) {
|
|
1779
|
-
|
|
1777
|
+
let conflicts = {};
|
|
1780
1778
|
|
|
1781
1779
|
function visitLayer(prevLayer, layer) {
|
|
1782
|
-
|
|
1780
|
+
let
|
|
1783
1781
|
// last visited node in the previous layer that is incident on an inner
|
|
1784
1782
|
// segment.
|
|
1785
1783
|
k0 = 0,
|
|
@@ -1789,14 +1787,14 @@ function findType1Conflicts(g, layering) {
|
|
|
1789
1787
|
prevLayerLength = prevLayer.length,
|
|
1790
1788
|
lastNode = layer[layer.length - 1];
|
|
1791
1789
|
|
|
1792
|
-
layer.forEach(
|
|
1793
|
-
|
|
1790
|
+
layer.forEach((v, i) => {
|
|
1791
|
+
let w = findOtherInnerSegmentNode(g, v),
|
|
1794
1792
|
k1 = w ? g.node(w).order : prevLayerLength;
|
|
1795
1793
|
|
|
1796
1794
|
if (w || v === lastNode) {
|
|
1797
|
-
layer.slice(scanPos, i+1).forEach(
|
|
1798
|
-
g.predecessors(scanNode).forEach(
|
|
1799
|
-
|
|
1795
|
+
layer.slice(scanPos, i+1).forEach(scanNode => {
|
|
1796
|
+
g.predecessors(scanNode).forEach(u => {
|
|
1797
|
+
let uLabel = g.node(u),
|
|
1800
1798
|
uPos = uLabel.order;
|
|
1801
1799
|
if ((uPos < k0 || k1 < uPos) &&
|
|
1802
1800
|
!(uLabel.dummy && g.node(scanNode).dummy)) {
|
|
@@ -1817,15 +1815,15 @@ function findType1Conflicts(g, layering) {
|
|
|
1817
1815
|
}
|
|
1818
1816
|
|
|
1819
1817
|
function findType2Conflicts(g, layering) {
|
|
1820
|
-
|
|
1818
|
+
let conflicts = {};
|
|
1821
1819
|
|
|
1822
1820
|
function scan(south, southPos, southEnd, prevNorthBorder, nextNorthBorder) {
|
|
1823
|
-
|
|
1824
|
-
util.range(southPos, southEnd).forEach(
|
|
1821
|
+
let v;
|
|
1822
|
+
util.range(southPos, southEnd).forEach(i => {
|
|
1825
1823
|
v = south[i];
|
|
1826
1824
|
if (g.node(v).dummy) {
|
|
1827
|
-
g.predecessors(v).forEach(
|
|
1828
|
-
|
|
1825
|
+
g.predecessors(v).forEach(u => {
|
|
1826
|
+
let uNode = g.node(u);
|
|
1829
1827
|
if (uNode.dummy &&
|
|
1830
1828
|
(uNode.order < prevNorthBorder || uNode.order > nextNorthBorder)) {
|
|
1831
1829
|
addConflict(conflicts, u, v);
|
|
@@ -1837,13 +1835,13 @@ function findType2Conflicts(g, layering) {
|
|
|
1837
1835
|
|
|
1838
1836
|
|
|
1839
1837
|
function visitLayer(north, south) {
|
|
1840
|
-
|
|
1838
|
+
let prevNorthPos = -1,
|
|
1841
1839
|
nextNorthPos,
|
|
1842
1840
|
southPos = 0;
|
|
1843
1841
|
|
|
1844
|
-
south.forEach(
|
|
1842
|
+
south.forEach((v, southLookahead) => {
|
|
1845
1843
|
if (g.node(v).dummy === "border") {
|
|
1846
|
-
|
|
1844
|
+
let predecessors = g.predecessors(v);
|
|
1847
1845
|
if (predecessors.length) {
|
|
1848
1846
|
nextNorthPos = g.node(predecessors[0]).order;
|
|
1849
1847
|
scan(south, southPos, southLookahead, prevNorthPos, nextNorthPos);
|
|
@@ -1869,12 +1867,12 @@ function findOtherInnerSegmentNode(g, v) {
|
|
|
1869
1867
|
|
|
1870
1868
|
function addConflict(conflicts, v, w) {
|
|
1871
1869
|
if (v > w) {
|
|
1872
|
-
|
|
1870
|
+
let tmp = v;
|
|
1873
1871
|
v = w;
|
|
1874
1872
|
w = tmp;
|
|
1875
1873
|
}
|
|
1876
1874
|
|
|
1877
|
-
|
|
1875
|
+
let conflictsV = conflicts[v];
|
|
1878
1876
|
if (!conflictsV) {
|
|
1879
1877
|
conflicts[v] = conflictsV = {};
|
|
1880
1878
|
}
|
|
@@ -1883,7 +1881,7 @@ function addConflict(conflicts, v, w) {
|
|
|
1883
1881
|
|
|
1884
1882
|
function hasConflict(conflicts, v, w) {
|
|
1885
1883
|
if (v > w) {
|
|
1886
|
-
|
|
1884
|
+
let tmp = v;
|
|
1887
1885
|
v = w;
|
|
1888
1886
|
w = tmp;
|
|
1889
1887
|
}
|
|
@@ -1899,30 +1897,30 @@ function hasConflict(conflicts, v, w) {
|
|
|
1899
1897
|
* blocks would be split in that scenario.
|
|
1900
1898
|
*/
|
|
1901
1899
|
function verticalAlignment(g, layering, conflicts, neighborFn) {
|
|
1902
|
-
|
|
1900
|
+
let root = {},
|
|
1903
1901
|
align = {},
|
|
1904
1902
|
pos = {};
|
|
1905
1903
|
|
|
1906
1904
|
// We cache the position here based on the layering because the graph and
|
|
1907
1905
|
// layering may be out of sync. The layering matrix is manipulated to
|
|
1908
1906
|
// generate different extreme alignments.
|
|
1909
|
-
layering.forEach(
|
|
1910
|
-
layer.forEach(
|
|
1907
|
+
layering.forEach(layer => {
|
|
1908
|
+
layer.forEach((v, order) => {
|
|
1911
1909
|
root[v] = v;
|
|
1912
1910
|
align[v] = v;
|
|
1913
1911
|
pos[v] = order;
|
|
1914
1912
|
});
|
|
1915
1913
|
});
|
|
1916
1914
|
|
|
1917
|
-
layering.forEach(
|
|
1918
|
-
|
|
1919
|
-
layer.forEach(
|
|
1920
|
-
|
|
1915
|
+
layering.forEach(layer => {
|
|
1916
|
+
let prevIdx = -1;
|
|
1917
|
+
layer.forEach(v => {
|
|
1918
|
+
let ws = neighborFn(v);
|
|
1921
1919
|
if (ws.length) {
|
|
1922
1920
|
ws = ws.sort((a, b) => pos[a] - pos[b]);
|
|
1923
|
-
|
|
1924
|
-
for (
|
|
1925
|
-
|
|
1921
|
+
let mp = (ws.length - 1) / 2;
|
|
1922
|
+
for (let i = Math.floor(mp), il = Math.ceil(mp); i <= il; ++i) {
|
|
1923
|
+
let w = ws[i];
|
|
1926
1924
|
if (align[v] === v &&
|
|
1927
1925
|
prevIdx < pos[w] &&
|
|
1928
1926
|
!hasConflict(conflicts, v, w)) {
|
|
@@ -1944,14 +1942,14 @@ function horizontalCompaction(g, layering, root, align, reverseSep) {
|
|
|
1944
1942
|
// sweeps. The first sweep places blocks with the smallest possible
|
|
1945
1943
|
// coordinates. The second sweep removes unused space by moving blocks to the
|
|
1946
1944
|
// greatest coordinates without violating separation.
|
|
1947
|
-
|
|
1945
|
+
let xs = {},
|
|
1948
1946
|
blockG = buildBlockGraph(g, layering, root, reverseSep),
|
|
1949
1947
|
borderType = reverseSep ? "borderLeft" : "borderRight";
|
|
1950
1948
|
|
|
1951
1949
|
function iterate(setXsFunc, nextNodesFunc) {
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1950
|
+
let stack = blockG.nodes();
|
|
1951
|
+
let elem = stack.pop();
|
|
1952
|
+
let visited = {};
|
|
1955
1953
|
while (elem) {
|
|
1956
1954
|
if (visited[elem]) {
|
|
1957
1955
|
setXsFunc(elem);
|
|
@@ -1967,18 +1965,18 @@ function horizontalCompaction(g, layering, root, align, reverseSep) {
|
|
|
1967
1965
|
|
|
1968
1966
|
// First pass, assign smallest coordinates
|
|
1969
1967
|
function pass1(elem) {
|
|
1970
|
-
xs[elem] = blockG.inEdges(elem).reduce(
|
|
1968
|
+
xs[elem] = blockG.inEdges(elem).reduce((acc, e) => {
|
|
1971
1969
|
return Math.max(acc, xs[e.v] + blockG.edge(e));
|
|
1972
1970
|
}, 0);
|
|
1973
1971
|
}
|
|
1974
1972
|
|
|
1975
1973
|
// Second pass, assign greatest coordinates
|
|
1976
1974
|
function pass2(elem) {
|
|
1977
|
-
|
|
1975
|
+
let min = blockG.outEdges(elem).reduce((acc, e) => {
|
|
1978
1976
|
return Math.min(acc, xs[e.w] - blockG.edge(e));
|
|
1979
1977
|
}, Number.POSITIVE_INFINITY);
|
|
1980
1978
|
|
|
1981
|
-
|
|
1979
|
+
let node = g.node(elem);
|
|
1982
1980
|
if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
|
|
1983
1981
|
xs[elem] = Math.max(xs[elem], min);
|
|
1984
1982
|
}
|
|
@@ -1995,14 +1993,14 @@ function horizontalCompaction(g, layering, root, align, reverseSep) {
|
|
|
1995
1993
|
|
|
1996
1994
|
|
|
1997
1995
|
function buildBlockGraph(g, layering, root, reverseSep) {
|
|
1998
|
-
|
|
1996
|
+
let blockGraph = new Graph(),
|
|
1999
1997
|
graphLabel = g.graph(),
|
|
2000
1998
|
sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
|
|
2001
1999
|
|
|
2002
|
-
layering.forEach(
|
|
2003
|
-
|
|
2004
|
-
layer.forEach(
|
|
2005
|
-
|
|
2000
|
+
layering.forEach(layer => {
|
|
2001
|
+
let u;
|
|
2002
|
+
layer.forEach(v => {
|
|
2003
|
+
let vRoot = root[v];
|
|
2006
2004
|
blockGraph.setNode(vRoot);
|
|
2007
2005
|
if (u) {
|
|
2008
2006
|
var uRoot = root[u],
|
|
@@ -2021,11 +2019,11 @@ function buildBlockGraph(g, layering, root, reverseSep) {
|
|
|
2021
2019
|
*/
|
|
2022
2020
|
function findSmallestWidthAlignment(g, xss) {
|
|
2023
2021
|
return Object.values(xss).reduce((currentMinAndXs, xs) => {
|
|
2024
|
-
|
|
2025
|
-
|
|
2022
|
+
let max = Number.NEGATIVE_INFINITY;
|
|
2023
|
+
let min = Number.POSITIVE_INFINITY;
|
|
2026
2024
|
|
|
2027
2025
|
Object.entries(xs).forEach(([v, x]) => {
|
|
2028
|
-
|
|
2026
|
+
let halfWidth = width(g, v) / 2;
|
|
2029
2027
|
|
|
2030
2028
|
max = Math.max(x + halfWidth, max);
|
|
2031
2029
|
min = Math.min(x - halfWidth, min);
|
|
@@ -2047,18 +2045,18 @@ function findSmallestWidthAlignment(g, xss) {
|
|
|
2047
2045
|
* coordinate of the smallest width alignment.
|
|
2048
2046
|
*/
|
|
2049
2047
|
function alignCoordinates(xss, alignTo) {
|
|
2050
|
-
|
|
2048
|
+
let alignToVals = Object.values(alignTo),
|
|
2051
2049
|
alignToMin = Math.min(...alignToVals),
|
|
2052
2050
|
alignToMax = Math.max(...alignToVals);
|
|
2053
2051
|
|
|
2054
|
-
["u", "d"].forEach(
|
|
2055
|
-
["l", "r"].forEach(
|
|
2056
|
-
|
|
2052
|
+
["u", "d"].forEach(vert => {
|
|
2053
|
+
["l", "r"].forEach(horiz => {
|
|
2054
|
+
let alignment = vert + horiz,
|
|
2057
2055
|
xs = xss[alignment];
|
|
2058
2056
|
|
|
2059
2057
|
if (xs === alignTo) return;
|
|
2060
2058
|
|
|
2061
|
-
|
|
2059
|
+
let xsVals = Object.values(xs);
|
|
2062
2060
|
let delta = alignToMin - Math.min(...xsVals);
|
|
2063
2061
|
if (horiz !== "l") {
|
|
2064
2062
|
delta = alignToMax - Math.max(...xsVals);
|
|
@@ -2072,36 +2070,36 @@ function alignCoordinates(xss, alignTo) {
|
|
|
2072
2070
|
}
|
|
2073
2071
|
|
|
2074
2072
|
function balance(xss, align) {
|
|
2075
|
-
return util.mapValues(xss.ul,
|
|
2073
|
+
return util.mapValues(xss.ul, (num, v) => {
|
|
2076
2074
|
if (align) {
|
|
2077
2075
|
return xss[align.toLowerCase()][v];
|
|
2078
2076
|
} else {
|
|
2079
|
-
|
|
2077
|
+
let xs = Object.values(xss).map(xs => xs[v]).sort((a, b) => a - b);
|
|
2080
2078
|
return (xs[1] + xs[2]) / 2;
|
|
2081
2079
|
}
|
|
2082
2080
|
});
|
|
2083
2081
|
}
|
|
2084
2082
|
|
|
2085
2083
|
function positionX(g) {
|
|
2086
|
-
|
|
2087
|
-
|
|
2084
|
+
let layering = util.buildLayerMatrix(g);
|
|
2085
|
+
let conflicts = Object.assign(
|
|
2088
2086
|
findType1Conflicts(g, layering),
|
|
2089
2087
|
findType2Conflicts(g, layering));
|
|
2090
2088
|
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
["u", "d"].forEach(
|
|
2089
|
+
let xss = {};
|
|
2090
|
+
let adjustedLayering;
|
|
2091
|
+
["u", "d"].forEach(vert => {
|
|
2094
2092
|
adjustedLayering = vert === "u" ? layering : Object.values(layering).reverse();
|
|
2095
|
-
["l", "r"].forEach(
|
|
2093
|
+
["l", "r"].forEach(horiz => {
|
|
2096
2094
|
if (horiz === "r") {
|
|
2097
2095
|
adjustedLayering = adjustedLayering.map(inner => {
|
|
2098
2096
|
return Object.values(inner).reverse();
|
|
2099
2097
|
});
|
|
2100
2098
|
}
|
|
2101
2099
|
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2100
|
+
let neighborFn = (vert === "u" ? g.predecessors : g.successors).bind(g);
|
|
2101
|
+
let align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn);
|
|
2102
|
+
let xs = horizontalCompaction(g, adjustedLayering,
|
|
2105
2103
|
align.root, align.align, horiz === "r");
|
|
2106
2104
|
if (horiz === "r") {
|
|
2107
2105
|
xs = util.mapValues(xs, x => -x);
|
|
@@ -2111,17 +2109,17 @@ function positionX(g) {
|
|
|
2111
2109
|
});
|
|
2112
2110
|
|
|
2113
2111
|
|
|
2114
|
-
|
|
2112
|
+
let smallestWidth = findSmallestWidthAlignment(g, xss);
|
|
2115
2113
|
alignCoordinates(xss, smallestWidth);
|
|
2116
2114
|
return balance(xss, g.graph().align);
|
|
2117
2115
|
}
|
|
2118
2116
|
|
|
2119
2117
|
function sep(nodeSep, edgeSep, reverseSep) {
|
|
2120
|
-
return
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2118
|
+
return (g, v, w) => {
|
|
2119
|
+
let vLabel = g.node(v);
|
|
2120
|
+
let wLabel = g.node(w);
|
|
2121
|
+
let sum = 0;
|
|
2122
|
+
let delta;
|
|
2125
2123
|
|
|
2126
2124
|
sum += vLabel.width / 2;
|
|
2127
2125
|
if (vLabel.hasOwnProperty("labelpos")) {
|
|
@@ -2161,8 +2159,8 @@ function width(g, v) {
|
|
|
2161
2159
|
},{"../util":27,"@dagrejs/graphlib":29}],22:[function(require,module,exports){
|
|
2162
2160
|
"use strict";
|
|
2163
2161
|
|
|
2164
|
-
|
|
2165
|
-
|
|
2162
|
+
let util = require("../util");
|
|
2163
|
+
let positionX = require("./bk").positionX;
|
|
2166
2164
|
|
|
2167
2165
|
module.exports = position;
|
|
2168
2166
|
|
|
@@ -2174,10 +2172,10 @@ function position(g) {
|
|
|
2174
2172
|
}
|
|
2175
2173
|
|
|
2176
2174
|
function positionY(g) {
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
layering.forEach(
|
|
2175
|
+
let layering = util.buildLayerMatrix(g);
|
|
2176
|
+
let rankSep = g.graph().ranksep;
|
|
2177
|
+
let prevY = 0;
|
|
2178
|
+
layering.forEach(layer => {
|
|
2181
2179
|
const maxHeight = layer.reduce((acc, v) => {
|
|
2182
2180
|
const height = g.node(v).height;
|
|
2183
2181
|
if (acc > height) {
|
|
@@ -2249,7 +2247,7 @@ function feasibleTree(g) {
|
|
|
2249
2247
|
*/
|
|
2250
2248
|
function tightTree(t, g) {
|
|
2251
2249
|
function dfs(v) {
|
|
2252
|
-
g.nodeEdges(v).forEach(
|
|
2250
|
+
g.nodeEdges(v).forEach(e => {
|
|
2253
2251
|
var edgeV = e.v,
|
|
2254
2252
|
w = (v === edgeV) ? e.w : edgeV;
|
|
2255
2253
|
if (!t.hasNode(w) && !slack(g, e)) {
|
|
@@ -2442,7 +2440,7 @@ function calcCutValue(t, g, child) {
|
|
|
2442
2440
|
|
|
2443
2441
|
cutValue = graphEdge.weight;
|
|
2444
2442
|
|
|
2445
|
-
g.nodeEdges(child).forEach(
|
|
2443
|
+
g.nodeEdges(child).forEach(e => {
|
|
2446
2444
|
var isOutEdge = e.v === child,
|
|
2447
2445
|
other = isOutEdge ? e.w : e.v;
|
|
2448
2446
|
|
|
@@ -2473,7 +2471,7 @@ function dfsAssignLowLim(tree, visited, nextLim, v, parent) {
|
|
|
2473
2471
|
var label = tree.node(v);
|
|
2474
2472
|
|
|
2475
2473
|
visited[v] = true;
|
|
2476
|
-
tree.neighbors(v).forEach(
|
|
2474
|
+
tree.neighbors(v).forEach(w => {
|
|
2477
2475
|
if (!visited.hasOwnProperty(w)) {
|
|
2478
2476
|
nextLim = dfsAssignLowLim(tree, visited, nextLim, w, v);
|
|
2479
2477
|
}
|
|
@@ -2519,7 +2517,7 @@ function enterEdge(t, g, edge) {
|
|
|
2519
2517
|
flip = true;
|
|
2520
2518
|
}
|
|
2521
2519
|
|
|
2522
|
-
var candidates = g.edges().filter(
|
|
2520
|
+
var candidates = g.edges().filter(edge => {
|
|
2523
2521
|
return flip === isDescendant(t, t.node(edge.v), tailLabel) &&
|
|
2524
2522
|
flip !== isDescendant(t, t.node(edge.w), tailLabel);
|
|
2525
2523
|
});
|
|
@@ -2547,7 +2545,7 @@ function updateRanks(t, g) {
|
|
|
2547
2545
|
var root = t.nodes().find(v => !g.node(v).parent);
|
|
2548
2546
|
var vs = preorder(t, root);
|
|
2549
2547
|
vs = vs.slice(1);
|
|
2550
|
-
vs.forEach(
|
|
2548
|
+
vs.forEach(v => {
|
|
2551
2549
|
var parent = t.node(v).parent,
|
|
2552
2550
|
edge = g.edge(v, parent),
|
|
2553
2551
|
flipped = false;
|
|
@@ -2646,7 +2644,7 @@ function slack(g, e) {
|
|
|
2646
2644
|
|
|
2647
2645
|
"use strict";
|
|
2648
2646
|
|
|
2649
|
-
|
|
2647
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
2650
2648
|
|
|
2651
2649
|
module.exports = {
|
|
2652
2650
|
addBorderNode,
|
|
@@ -2674,7 +2672,7 @@ module.exports = {
|
|
|
2674
2672
|
* Adds a dummy node to the graph and return v.
|
|
2675
2673
|
*/
|
|
2676
2674
|
function addDummyNode(g, type, attrs, name) {
|
|
2677
|
-
|
|
2675
|
+
let v;
|
|
2678
2676
|
do {
|
|
2679
2677
|
v = uniqueId(name);
|
|
2680
2678
|
} while (g.hasNode(v));
|
|
@@ -2689,11 +2687,11 @@ function addDummyNode(g, type, attrs, name) {
|
|
|
2689
2687
|
* associated with multi-edges.
|
|
2690
2688
|
*/
|
|
2691
2689
|
function simplify(g) {
|
|
2692
|
-
|
|
2690
|
+
let simplified = new Graph().setGraph(g.graph());
|
|
2693
2691
|
g.nodes().forEach(v => simplified.setNode(v, g.node(v)));
|
|
2694
2692
|
g.edges().forEach(e => {
|
|
2695
|
-
|
|
2696
|
-
|
|
2693
|
+
let simpleLabel = simplified.edge(e.v, e.w) || { weight: 0, minlen: 1 };
|
|
2694
|
+
let label = g.edge(e);
|
|
2697
2695
|
simplified.setEdge(e.v, e.w, {
|
|
2698
2696
|
weight: simpleLabel.weight + label.weight,
|
|
2699
2697
|
minlen: Math.max(simpleLabel.minlen, label.minlen)
|
|
@@ -2703,7 +2701,7 @@ function simplify(g) {
|
|
|
2703
2701
|
}
|
|
2704
2702
|
|
|
2705
2703
|
function asNonCompoundGraph(g) {
|
|
2706
|
-
|
|
2704
|
+
let simplified = new Graph({ multigraph: g.isMultigraph() }).setGraph(g.graph());
|
|
2707
2705
|
g.nodes().forEach(v => {
|
|
2708
2706
|
if (!g.children(v).length) {
|
|
2709
2707
|
simplified.setNode(v, g.node(v));
|
|
@@ -2716,8 +2714,8 @@ function asNonCompoundGraph(g) {
|
|
|
2716
2714
|
}
|
|
2717
2715
|
|
|
2718
2716
|
function successorWeights(g) {
|
|
2719
|
-
|
|
2720
|
-
|
|
2717
|
+
let weightMap = g.nodes().map(v => {
|
|
2718
|
+
let sucs = {};
|
|
2721
2719
|
g.outEdges(v).forEach(e => {
|
|
2722
2720
|
sucs[e.w] = (sucs[e.w] || 0) + g.edge(e).weight;
|
|
2723
2721
|
});
|
|
@@ -2727,8 +2725,8 @@ function successorWeights(g) {
|
|
|
2727
2725
|
}
|
|
2728
2726
|
|
|
2729
2727
|
function predecessorWeights(g) {
|
|
2730
|
-
|
|
2731
|
-
|
|
2728
|
+
let weightMap = g.nodes().map(v => {
|
|
2729
|
+
let preds = {};
|
|
2732
2730
|
g.inEdges(v).forEach(e => {
|
|
2733
2731
|
preds[e.v] = (preds[e.v] || 0) + g.edge(e).weight;
|
|
2734
2732
|
});
|
|
@@ -2742,21 +2740,21 @@ function predecessorWeights(g) {
|
|
|
2742
2740
|
* ({x, y, width, height}) if it were pointing at the rectangle's center.
|
|
2743
2741
|
*/
|
|
2744
2742
|
function intersectRect(rect, point) {
|
|
2745
|
-
|
|
2746
|
-
|
|
2743
|
+
let x = rect.x;
|
|
2744
|
+
let y = rect.y;
|
|
2747
2745
|
|
|
2748
2746
|
// Rectangle intersection algorithm from:
|
|
2749
2747
|
// http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2748
|
+
let dx = point.x - x;
|
|
2749
|
+
let dy = point.y - y;
|
|
2750
|
+
let w = rect.width / 2;
|
|
2751
|
+
let h = rect.height / 2;
|
|
2754
2752
|
|
|
2755
2753
|
if (!dx && !dy) {
|
|
2756
2754
|
throw new Error("Not possible to find intersection inside of the rectangle");
|
|
2757
2755
|
}
|
|
2758
2756
|
|
|
2759
|
-
|
|
2757
|
+
let sx, sy;
|
|
2760
2758
|
if (Math.abs(dy) * w > Math.abs(dx) * h) {
|
|
2761
2759
|
// Intersection is top or bottom of rect.
|
|
2762
2760
|
if (dy < 0) {
|
|
@@ -2781,10 +2779,10 @@ function intersectRect(rect, point) {
|
|
|
2781
2779
|
* function will produce a matrix with the ids of each node.
|
|
2782
2780
|
*/
|
|
2783
2781
|
function buildLayerMatrix(g) {
|
|
2784
|
-
|
|
2782
|
+
let layering = range(maxRank(g) + 1).map(() => []);
|
|
2785
2783
|
g.nodes().forEach(v => {
|
|
2786
|
-
|
|
2787
|
-
|
|
2784
|
+
let node = g.node(v);
|
|
2785
|
+
let rank = node.rank;
|
|
2788
2786
|
if (rank !== undefined) {
|
|
2789
2787
|
layering[rank][node.order] = v;
|
|
2790
2788
|
}
|
|
@@ -2797,8 +2795,8 @@ function buildLayerMatrix(g) {
|
|
|
2797
2795
|
* rank(v) >= 0 and at least one node w has rank(w) = 0.
|
|
2798
2796
|
*/
|
|
2799
2797
|
function normalizeRanks(g) {
|
|
2800
|
-
|
|
2801
|
-
|
|
2798
|
+
let min = Math.min(...g.nodes().map(v => {
|
|
2799
|
+
let rank = g.node(v).rank;
|
|
2802
2800
|
if (rank === undefined) {
|
|
2803
2801
|
return Number.MAX_VALUE;
|
|
2804
2802
|
}
|
|
@@ -2806,7 +2804,7 @@ function normalizeRanks(g) {
|
|
|
2806
2804
|
return rank;
|
|
2807
2805
|
}));
|
|
2808
2806
|
g.nodes().forEach(v => {
|
|
2809
|
-
|
|
2807
|
+
let node = g.node(v);
|
|
2810
2808
|
if (node.hasOwnProperty("rank")) {
|
|
2811
2809
|
node.rank -= min;
|
|
2812
2810
|
}
|
|
@@ -2815,19 +2813,19 @@ function normalizeRanks(g) {
|
|
|
2815
2813
|
|
|
2816
2814
|
function removeEmptyRanks(g) {
|
|
2817
2815
|
// Ranks may not start at 0, so we need to offset them
|
|
2818
|
-
|
|
2816
|
+
let offset = Math.min(...g.nodes().map(v => g.node(v).rank));
|
|
2819
2817
|
|
|
2820
|
-
|
|
2818
|
+
let layers = [];
|
|
2821
2819
|
g.nodes().forEach(v => {
|
|
2822
|
-
|
|
2820
|
+
let rank = g.node(v).rank - offset;
|
|
2823
2821
|
if (!layers[rank]) {
|
|
2824
2822
|
layers[rank] = [];
|
|
2825
2823
|
}
|
|
2826
2824
|
layers[rank].push(v);
|
|
2827
2825
|
});
|
|
2828
2826
|
|
|
2829
|
-
|
|
2830
|
-
|
|
2827
|
+
let delta = 0;
|
|
2828
|
+
let nodeRankFactor = g.graph().nodeRankFactor;
|
|
2831
2829
|
Array.from(layers).forEach((vs, i) => {
|
|
2832
2830
|
if (vs === undefined && i % nodeRankFactor !== 0) {
|
|
2833
2831
|
--delta;
|
|
@@ -2838,7 +2836,7 @@ function removeEmptyRanks(g) {
|
|
|
2838
2836
|
}
|
|
2839
2837
|
|
|
2840
2838
|
function addBorderNode(g, prefix, rank, order) {
|
|
2841
|
-
|
|
2839
|
+
let node = {
|
|
2842
2840
|
width: 0,
|
|
2843
2841
|
height: 0
|
|
2844
2842
|
};
|
|
@@ -2851,7 +2849,7 @@ function addBorderNode(g, prefix, rank, order) {
|
|
|
2851
2849
|
|
|
2852
2850
|
function maxRank(g) {
|
|
2853
2851
|
return Math.max(...g.nodes().map(v => {
|
|
2854
|
-
|
|
2852
|
+
let rank = g.node(v).rank;
|
|
2855
2853
|
if (rank === undefined) {
|
|
2856
2854
|
return Number.MIN_VALUE;
|
|
2857
2855
|
}
|
|
@@ -2866,7 +2864,7 @@ function maxRank(g) {
|
|
|
2866
2864
|
* into `rhs.
|
|
2867
2865
|
*/
|
|
2868
2866
|
function partition(collection, fn) {
|
|
2869
|
-
|
|
2867
|
+
let result = { lhs: [], rhs: [] };
|
|
2870
2868
|
collection.forEach(value => {
|
|
2871
2869
|
if (fn(value)) {
|
|
2872
2870
|
result.lhs.push(value);
|
|
@@ -2882,7 +2880,7 @@ function partition(collection, fn) {
|
|
|
2882
2880
|
* time it takes to execute the function.
|
|
2883
2881
|
*/
|
|
2884
2882
|
function time(name, fn) {
|
|
2885
|
-
|
|
2883
|
+
let start = Date.now();
|
|
2886
2884
|
try {
|
|
2887
2885
|
return fn();
|
|
2888
2886
|
} finally {
|
|
@@ -2950,7 +2948,7 @@ function zipObject(props, values) {
|
|
|
2950
2948
|
}
|
|
2951
2949
|
|
|
2952
2950
|
},{"@dagrejs/graphlib":29}],28:[function(require,module,exports){
|
|
2953
|
-
module.exports = "1.0.
|
|
2951
|
+
module.exports = "1.0.4";
|
|
2954
2952
|
|
|
2955
2953
|
},{}],29:[function(require,module,exports){
|
|
2956
2954
|
/**
|