@dagrejs/dagre 0.8.0 → 1.0.0
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 +15 -7
- package/dist/dagre.js +1503 -18369
- package/dist/dagre.min.js +349 -10394
- package/index.js +1 -1
- package/lib/acyclic.js +14 -14
- package/lib/add-border-segments.js +11 -12
- package/lib/coordinate-system.js +10 -12
- package/lib/data/list.js +5 -5
- package/lib/debug.js +6 -7
- package/lib/greedy-fas.js +33 -27
- package/lib/layout.js +114 -101
- package/lib/nesting-graph.js +17 -22
- package/lib/normalize.js +13 -14
- package/lib/order/add-subgraph-constraints.js +6 -8
- package/lib/order/barycenter.js +4 -6
- package/lib/order/build-layer-graph.js +11 -11
- package/lib/order/cross-count.js +10 -14
- package/lib/order/index.js +15 -22
- package/lib/order/init-order.js +9 -11
- package/lib/order/resolve-conflicts.js +17 -22
- package/lib/order/sort-subgraph.js +18 -21
- package/lib/order/sort.js +10 -11
- package/lib/parent-dummy-chains.js +19 -21
- package/lib/position/bk.js +116 -102
- package/lib/position/index.js +16 -14
- package/lib/rank/feasible-tree.js +21 -15
- package/lib/rank/index.js +8 -8
- package/lib/rank/network-simplex.js +46 -45
- package/lib/rank/util.js +8 -8
- package/lib/util.js +121 -51
- package/lib/version.js +1 -1
- package/package.json +31 -25
- package/.jscsrc +0 -6
- package/.jshintrc +0 -24
- package/.travis.yml +0 -7
- package/bower.json +0 -26
- package/dist/dagre.core.js +0 -2916
- package/dist/dagre.core.min.js +0 -474
- package/karma.conf.js +0 -68
- package/karma.core.conf.js +0 -70
- package/lib/graphlib.js +0 -15
- package/lib/lodash.js +0 -15
package/lib/position/bk.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
util = require("../util");
|
|
3
|
+
var Graph = require("@dagrejs/graphlib").Graph;
|
|
4
|
+
var util = require("../util");
|
|
6
5
|
|
|
7
6
|
/*
|
|
8
7
|
* This module provides coordinate assignment based on Brandes and Köpf, "Fast
|
|
@@ -51,17 +50,17 @@ function findType1Conflicts(g, layering) {
|
|
|
51
50
|
// segment.
|
|
52
51
|
scanPos = 0,
|
|
53
52
|
prevLayerLength = prevLayer.length,
|
|
54
|
-
lastNode =
|
|
53
|
+
lastNode = layer[layer.length - 1];
|
|
55
54
|
|
|
56
|
-
|
|
55
|
+
layer.forEach(function(v, i) {
|
|
57
56
|
var w = findOtherInnerSegmentNode(g, v),
|
|
58
|
-
|
|
57
|
+
k1 = w ? g.node(w).order : prevLayerLength;
|
|
59
58
|
|
|
60
59
|
if (w || v === lastNode) {
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
layer.slice(scanPos, i+1).forEach(function(scanNode) {
|
|
61
|
+
g.predecessors(scanNode).forEach(function(u) {
|
|
63
62
|
var uLabel = g.node(u),
|
|
64
|
-
|
|
63
|
+
uPos = uLabel.order;
|
|
65
64
|
if ((uPos < k0 || k1 < uPos) &&
|
|
66
65
|
!(uLabel.dummy && g.node(scanNode).dummy)) {
|
|
67
66
|
addConflict(conflicts, u, scanNode);
|
|
@@ -76,7 +75,7 @@ function findType1Conflicts(g, layering) {
|
|
|
76
75
|
return layer;
|
|
77
76
|
}
|
|
78
77
|
|
|
79
|
-
|
|
78
|
+
layering.reduce(visitLayer);
|
|
80
79
|
return conflicts;
|
|
81
80
|
}
|
|
82
81
|
|
|
@@ -85,10 +84,10 @@ function findType2Conflicts(g, layering) {
|
|
|
85
84
|
|
|
86
85
|
function scan(south, southPos, southEnd, prevNorthBorder, nextNorthBorder) {
|
|
87
86
|
var v;
|
|
88
|
-
|
|
87
|
+
util.range(southPos, southEnd).forEach(function(i) {
|
|
89
88
|
v = south[i];
|
|
90
89
|
if (g.node(v).dummy) {
|
|
91
|
-
|
|
90
|
+
g.predecessors(v).forEach(function(u) {
|
|
92
91
|
var uNode = g.node(u);
|
|
93
92
|
if (uNode.dummy &&
|
|
94
93
|
(uNode.order < prevNorthBorder || uNode.order > nextNorthBorder)) {
|
|
@@ -102,10 +101,10 @@ function findType2Conflicts(g, layering) {
|
|
|
102
101
|
|
|
103
102
|
function visitLayer(north, south) {
|
|
104
103
|
var prevNorthPos = -1,
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
nextNorthPos,
|
|
105
|
+
southPos = 0;
|
|
107
106
|
|
|
108
|
-
|
|
107
|
+
south.forEach(function(v, southLookahead) {
|
|
109
108
|
if (g.node(v).dummy === "border") {
|
|
110
109
|
var predecessors = g.predecessors(v);
|
|
111
110
|
if (predecessors.length) {
|
|
@@ -121,15 +120,13 @@ function findType2Conflicts(g, layering) {
|
|
|
121
120
|
return south;
|
|
122
121
|
}
|
|
123
122
|
|
|
124
|
-
|
|
123
|
+
layering.reduce(visitLayer);
|
|
125
124
|
return conflicts;
|
|
126
125
|
}
|
|
127
126
|
|
|
128
127
|
function findOtherInnerSegmentNode(g, v) {
|
|
129
128
|
if (g.node(v).dummy) {
|
|
130
|
-
return
|
|
131
|
-
return g.node(u).dummy;
|
|
132
|
-
});
|
|
129
|
+
return g.predecessors(v).find(u => g.node(u).dummy);
|
|
133
130
|
}
|
|
134
131
|
}
|
|
135
132
|
|
|
@@ -153,7 +150,7 @@ function hasConflict(conflicts, v, w) {
|
|
|
153
150
|
v = w;
|
|
154
151
|
w = tmp;
|
|
155
152
|
}
|
|
156
|
-
return
|
|
153
|
+
return !!conflicts[v] && conflicts[v].hasOwnProperty(w);
|
|
157
154
|
}
|
|
158
155
|
|
|
159
156
|
/*
|
|
@@ -166,26 +163,26 @@ function hasConflict(conflicts, v, w) {
|
|
|
166
163
|
*/
|
|
167
164
|
function verticalAlignment(g, layering, conflicts, neighborFn) {
|
|
168
165
|
var root = {},
|
|
169
|
-
|
|
170
|
-
|
|
166
|
+
align = {},
|
|
167
|
+
pos = {};
|
|
171
168
|
|
|
172
169
|
// We cache the position here based on the layering because the graph and
|
|
173
170
|
// layering may be out of sync. The layering matrix is manipulated to
|
|
174
171
|
// generate different extreme alignments.
|
|
175
|
-
|
|
176
|
-
|
|
172
|
+
layering.forEach(function(layer) {
|
|
173
|
+
layer.forEach(function(v, order) {
|
|
177
174
|
root[v] = v;
|
|
178
175
|
align[v] = v;
|
|
179
176
|
pos[v] = order;
|
|
180
177
|
});
|
|
181
178
|
});
|
|
182
179
|
|
|
183
|
-
|
|
180
|
+
layering.forEach(function(layer) {
|
|
184
181
|
var prevIdx = -1;
|
|
185
|
-
|
|
182
|
+
layer.forEach(function(v) {
|
|
186
183
|
var ws = neighborFn(v);
|
|
187
184
|
if (ws.length) {
|
|
188
|
-
ws =
|
|
185
|
+
ws = ws.sort((a, b) => pos[a] - pos[b]);
|
|
189
186
|
var mp = (ws.length - 1) / 2;
|
|
190
187
|
for (var i = Math.floor(mp), il = Math.ceil(mp); i <= il; ++i) {
|
|
191
188
|
var w = ws[i];
|
|
@@ -211,41 +208,50 @@ function horizontalCompaction(g, layering, root, align, reverseSep) {
|
|
|
211
208
|
// coordinates. The second sweep removes unused space by moving blocks to the
|
|
212
209
|
// greatest coordinates without violating separation.
|
|
213
210
|
var xs = {},
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
211
|
+
blockG = buildBlockGraph(g, layering, root, reverseSep),
|
|
212
|
+
borderType = reverseSep ? "borderLeft" : "borderRight";
|
|
213
|
+
|
|
214
|
+
function iterate(setXsFunc, nextNodesFunc) {
|
|
215
|
+
var stack = blockG.nodes();
|
|
216
|
+
var elem = stack.pop();
|
|
217
|
+
var visited = {};
|
|
218
|
+
while (elem) {
|
|
219
|
+
if (visited[elem]) {
|
|
220
|
+
setXsFunc(elem);
|
|
221
|
+
} else {
|
|
222
|
+
visited[elem] = true;
|
|
223
|
+
stack.push(elem);
|
|
224
|
+
stack = stack.concat(nextNodesFunc(elem));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
elem = stack.pop();
|
|
225
228
|
}
|
|
226
229
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
230
|
+
|
|
231
|
+
// First pass, assign smallest coordinates
|
|
232
|
+
function pass1(elem) {
|
|
233
|
+
xs[elem] = blockG.inEdges(elem).reduce(function(acc, e) {
|
|
234
|
+
return Math.max(acc, xs[e.v] + blockG.edge(e));
|
|
235
|
+
}, 0);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Second pass, assign greatest coordinates
|
|
239
|
+
function pass2(elem) {
|
|
240
|
+
var min = blockG.outEdges(elem).reduce(function(acc, e) {
|
|
241
|
+
return Math.min(acc, xs[e.w] - blockG.edge(e));
|
|
242
|
+
}, Number.POSITIVE_INFINITY);
|
|
243
|
+
|
|
244
|
+
var node = g.node(elem);
|
|
245
|
+
if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
|
|
246
|
+
xs[elem] = Math.max(xs[elem], min);
|
|
241
247
|
}
|
|
242
248
|
}
|
|
243
|
-
|
|
249
|
+
|
|
250
|
+
iterate(pass1, blockG.predecessors.bind(blockG));
|
|
251
|
+
iterate(pass2, blockG.successors.bind(blockG));
|
|
244
252
|
|
|
245
253
|
// Assign x coordinates to all nodes
|
|
246
|
-
|
|
247
|
-
xs[v] = xs[root[v]];
|
|
248
|
-
});
|
|
254
|
+
Object.keys(align).forEach(v => xs[v] = xs[root[v]]);
|
|
249
255
|
|
|
250
256
|
return xs;
|
|
251
257
|
}
|
|
@@ -253,17 +259,17 @@ function horizontalCompaction(g, layering, root, align, reverseSep) {
|
|
|
253
259
|
|
|
254
260
|
function buildBlockGraph(g, layering, root, reverseSep) {
|
|
255
261
|
var blockGraph = new Graph(),
|
|
256
|
-
|
|
257
|
-
|
|
262
|
+
graphLabel = g.graph(),
|
|
263
|
+
sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
|
|
258
264
|
|
|
259
|
-
|
|
265
|
+
layering.forEach(function(layer) {
|
|
260
266
|
var u;
|
|
261
|
-
|
|
267
|
+
layer.forEach(function(v) {
|
|
262
268
|
var vRoot = root[v];
|
|
263
269
|
blockGraph.setNode(vRoot);
|
|
264
270
|
if (u) {
|
|
265
271
|
var uRoot = root[u],
|
|
266
|
-
|
|
272
|
+
prevMax = blockGraph.edge(uRoot, vRoot);
|
|
267
273
|
blockGraph.setEdge(uRoot, vRoot, Math.max(sepFn(g, v, u), prevMax || 0));
|
|
268
274
|
}
|
|
269
275
|
u = v;
|
|
@@ -277,19 +283,23 @@ function buildBlockGraph(g, layering, root, reverseSep) {
|
|
|
277
283
|
* Returns the alignment that has the smallest width of the given alignments.
|
|
278
284
|
*/
|
|
279
285
|
function findSmallestWidthAlignment(g, xss) {
|
|
280
|
-
return
|
|
286
|
+
return Object.values(xss).reduce((currentMinAndXs, xs) => {
|
|
281
287
|
var max = Number.NEGATIVE_INFINITY;
|
|
282
288
|
var min = Number.POSITIVE_INFINITY;
|
|
283
289
|
|
|
284
|
-
|
|
290
|
+
Object.entries(xs).forEach(([v, x]) => {
|
|
285
291
|
var halfWidth = width(g, v) / 2;
|
|
286
292
|
|
|
287
293
|
max = Math.max(x + halfWidth, max);
|
|
288
294
|
min = Math.min(x - halfWidth, min);
|
|
289
295
|
});
|
|
290
296
|
|
|
291
|
-
|
|
292
|
-
|
|
297
|
+
const newMin = max - min;
|
|
298
|
+
if (newMin < currentMinAndXs[0]) {
|
|
299
|
+
currentMinAndXs = [newMin, xs];
|
|
300
|
+
}
|
|
301
|
+
return currentMinAndXs;
|
|
302
|
+
}, [Number.POSITIVE_INFINITY, null])[1];
|
|
293
303
|
}
|
|
294
304
|
|
|
295
305
|
/*
|
|
@@ -300,66 +310,70 @@ function findSmallestWidthAlignment(g, xss) {
|
|
|
300
310
|
* coordinate of the smallest width alignment.
|
|
301
311
|
*/
|
|
302
312
|
function alignCoordinates(xss, alignTo) {
|
|
303
|
-
var alignToVals =
|
|
304
|
-
|
|
305
|
-
|
|
313
|
+
var alignToVals = Object.values(alignTo),
|
|
314
|
+
alignToMin = Math.min(...alignToVals),
|
|
315
|
+
alignToMax = Math.max(...alignToVals);
|
|
306
316
|
|
|
307
|
-
|
|
308
|
-
|
|
317
|
+
["u", "d"].forEach(function(vert) {
|
|
318
|
+
["l", "r"].forEach(function(horiz) {
|
|
309
319
|
var alignment = vert + horiz,
|
|
310
|
-
|
|
311
|
-
|
|
320
|
+
xs = xss[alignment];
|
|
321
|
+
|
|
312
322
|
if (xs === alignTo) return;
|
|
313
323
|
|
|
314
|
-
var xsVals =
|
|
315
|
-
delta =
|
|
324
|
+
var xsVals = Object.values(xs);
|
|
325
|
+
let delta = alignToMin - Math.min(...xsVals);
|
|
326
|
+
if (horiz !== "l") {
|
|
327
|
+
delta = alignToMax - Math.max(...xsVals);
|
|
328
|
+
}
|
|
316
329
|
|
|
317
330
|
if (delta) {
|
|
318
|
-
xss[alignment] =
|
|
331
|
+
xss[alignment] = util.mapValues(xs, x => x + delta);
|
|
319
332
|
}
|
|
320
333
|
});
|
|
321
334
|
});
|
|
322
335
|
}
|
|
323
336
|
|
|
324
337
|
function balance(xss, align) {
|
|
325
|
-
return
|
|
338
|
+
return util.mapValues(xss.ul, function(num, v) {
|
|
326
339
|
if (align) {
|
|
327
340
|
return xss[align.toLowerCase()][v];
|
|
328
341
|
} else {
|
|
329
|
-
var xs =
|
|
342
|
+
var xs = Object.values(xss).map(xs => xs[v]).sort((a, b) => a - b);
|
|
330
343
|
return (xs[1] + xs[2]) / 2;
|
|
331
344
|
}
|
|
332
345
|
});
|
|
333
346
|
}
|
|
334
347
|
|
|
335
348
|
function positionX(g) {
|
|
336
|
-
var layering = util.buildLayerMatrix(g)
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
349
|
+
var layering = util.buildLayerMatrix(g);
|
|
350
|
+
var conflicts = Object.assign(
|
|
351
|
+
findType1Conflicts(g, layering),
|
|
352
|
+
findType2Conflicts(g, layering));
|
|
353
|
+
|
|
354
|
+
var xss = {};
|
|
355
|
+
var adjustedLayering;
|
|
356
|
+
["u", "d"].forEach(function(vert) {
|
|
357
|
+
adjustedLayering = vert === "u" ? layering : Object.values(layering).reverse();
|
|
358
|
+
["l", "r"].forEach(function(horiz) {
|
|
345
359
|
if (horiz === "r") {
|
|
346
|
-
adjustedLayering =
|
|
347
|
-
return
|
|
360
|
+
adjustedLayering = adjustedLayering.map(inner => {
|
|
361
|
+
return Object.values(inner).reverse();
|
|
348
362
|
});
|
|
349
363
|
}
|
|
350
364
|
|
|
351
|
-
var neighborFn =
|
|
365
|
+
var neighborFn = (vert === "u" ? g.predecessors : g.successors).bind(g);
|
|
352
366
|
var align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn);
|
|
353
367
|
var xs = horizontalCompaction(g, adjustedLayering,
|
|
354
|
-
|
|
355
|
-
horiz === "r");
|
|
368
|
+
align.root, align.align, horiz === "r");
|
|
356
369
|
if (horiz === "r") {
|
|
357
|
-
xs =
|
|
370
|
+
xs = util.mapValues(xs, x => -x);
|
|
358
371
|
}
|
|
359
372
|
xss[vert + horiz] = xs;
|
|
360
373
|
});
|
|
361
374
|
});
|
|
362
375
|
|
|
376
|
+
|
|
363
377
|
var smallestWidth = findSmallestWidthAlignment(g, xss);
|
|
364
378
|
alignCoordinates(xss, smallestWidth);
|
|
365
379
|
return balance(xss, g.graph().align);
|
|
@@ -367,16 +381,16 @@ function positionX(g) {
|
|
|
367
381
|
|
|
368
382
|
function sep(nodeSep, edgeSep, reverseSep) {
|
|
369
383
|
return function(g, v, w) {
|
|
370
|
-
var vLabel = g.node(v)
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
384
|
+
var vLabel = g.node(v);
|
|
385
|
+
var wLabel = g.node(w);
|
|
386
|
+
var sum = 0;
|
|
387
|
+
var delta;
|
|
374
388
|
|
|
375
389
|
sum += vLabel.width / 2;
|
|
376
|
-
if (
|
|
390
|
+
if (vLabel.hasOwnProperty("labelpos")) {
|
|
377
391
|
switch (vLabel.labelpos.toLowerCase()) {
|
|
378
|
-
|
|
379
|
-
|
|
392
|
+
case "l": delta = -vLabel.width / 2; break;
|
|
393
|
+
case "r": delta = vLabel.width / 2; break;
|
|
380
394
|
}
|
|
381
395
|
}
|
|
382
396
|
if (delta) {
|
|
@@ -388,10 +402,10 @@ function sep(nodeSep, edgeSep, reverseSep) {
|
|
|
388
402
|
sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
|
|
389
403
|
|
|
390
404
|
sum += wLabel.width / 2;
|
|
391
|
-
if (
|
|
405
|
+
if (wLabel.hasOwnProperty("labelpos")) {
|
|
392
406
|
switch (wLabel.labelpos.toLowerCase()) {
|
|
393
|
-
|
|
394
|
-
|
|
407
|
+
case "l": delta = wLabel.width / 2; break;
|
|
408
|
+
case "r": delta = -wLabel.width / 2; break;
|
|
395
409
|
}
|
|
396
410
|
}
|
|
397
411
|
if (delta) {
|
package/lib/position/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
positionX = require("./bk").positionX;
|
|
3
|
+
var util = require("../util");
|
|
4
|
+
var positionX = require("./bk").positionX;
|
|
6
5
|
|
|
7
6
|
module.exports = position;
|
|
8
7
|
|
|
@@ -10,20 +9,23 @@ function position(g) {
|
|
|
10
9
|
g = util.asNonCompoundGraph(g);
|
|
11
10
|
|
|
12
11
|
positionY(g);
|
|
13
|
-
|
|
14
|
-
g.node(v).x = x;
|
|
15
|
-
});
|
|
12
|
+
Object.entries(positionX(g)).forEach(([v, x]) => g.node(v).x = x);
|
|
16
13
|
}
|
|
17
14
|
|
|
18
15
|
function positionY(g) {
|
|
19
|
-
var layering = util.buildLayerMatrix(g)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
var layering = util.buildLayerMatrix(g);
|
|
17
|
+
var rankSep = g.graph().ranksep;
|
|
18
|
+
var prevY = 0;
|
|
19
|
+
layering.forEach(function(layer) {
|
|
20
|
+
const maxHeight = layer.reduce((acc, v) => {
|
|
21
|
+
const height = g.node(v).height;
|
|
22
|
+
if (acc > height) {
|
|
23
|
+
return acc;
|
|
24
|
+
} else {
|
|
25
|
+
return height;
|
|
26
|
+
}
|
|
27
|
+
}, 0);
|
|
28
|
+
layer.forEach(v => g.node(v).y = prevY + maxHeight / 2);
|
|
27
29
|
prevY += maxHeight + rankSep;
|
|
28
30
|
});
|
|
29
31
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
slack = require("./util").slack;
|
|
3
|
+
var Graph = require("@dagrejs/graphlib").Graph;
|
|
4
|
+
var slack = require("./util").slack;
|
|
6
5
|
|
|
7
6
|
module.exports = feasibleTree;
|
|
8
7
|
|
|
@@ -35,8 +34,8 @@ function feasibleTree(g) {
|
|
|
35
34
|
var t = new Graph({ directed: false });
|
|
36
35
|
|
|
37
36
|
// Choose arbitrary node from which to start our tree
|
|
38
|
-
var start = g.nodes()[0]
|
|
39
|
-
|
|
37
|
+
var start = g.nodes()[0];
|
|
38
|
+
var size = g.nodeCount();
|
|
40
39
|
t.setNode(start, {});
|
|
41
40
|
|
|
42
41
|
var edge, delta;
|
|
@@ -55,9 +54,9 @@ function feasibleTree(g) {
|
|
|
55
54
|
*/
|
|
56
55
|
function tightTree(t, g) {
|
|
57
56
|
function dfs(v) {
|
|
58
|
-
|
|
57
|
+
g.nodeEdges(v).forEach(function(e) {
|
|
59
58
|
var edgeV = e.v,
|
|
60
|
-
|
|
59
|
+
w = (v === edgeV) ? e.w : edgeV;
|
|
61
60
|
if (!t.hasNode(w) && !slack(g, e)) {
|
|
62
61
|
t.setNode(w, {});
|
|
63
62
|
t.setEdge(v, w, {});
|
|
@@ -66,7 +65,7 @@ function tightTree(t, g) {
|
|
|
66
65
|
});
|
|
67
66
|
}
|
|
68
67
|
|
|
69
|
-
|
|
68
|
+
t.nodes().forEach(dfs);
|
|
70
69
|
return t.nodeCount();
|
|
71
70
|
}
|
|
72
71
|
|
|
@@ -75,15 +74,22 @@ function tightTree(t, g) {
|
|
|
75
74
|
* it.
|
|
76
75
|
*/
|
|
77
76
|
function findMinSlackEdge(t, g) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
const edges = g.edges();
|
|
78
|
+
|
|
79
|
+
return edges.reduce((acc, edge) => {
|
|
80
|
+
let edgeSlack = Number.POSITIVE_INFINITY;
|
|
81
|
+
if (t.hasNode(edge.v) !== t.hasNode(edge.w)) {
|
|
82
|
+
edgeSlack = slack(g, edge);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (edgeSlack < acc[0]) {
|
|
86
|
+
return [edgeSlack, edge];
|
|
81
87
|
}
|
|
82
|
-
|
|
88
|
+
|
|
89
|
+
return acc;
|
|
90
|
+
}, [Number.POSITIVE_INFINITY, null])[1];
|
|
83
91
|
}
|
|
84
92
|
|
|
85
93
|
function shiftRanks(t, g, delta) {
|
|
86
|
-
|
|
87
|
-
g.node(v).rank += delta;
|
|
88
|
-
});
|
|
94
|
+
t.nodes().forEach(v => g.node(v).rank += delta);
|
|
89
95
|
}
|
package/lib/rank/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var rankUtil = require("./util")
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
var rankUtil = require("./util");
|
|
4
|
+
var longestPath = rankUtil.longestPath;
|
|
5
|
+
var feasibleTree = require("./feasible-tree");
|
|
6
|
+
var networkSimplex = require("./network-simplex");
|
|
7
7
|
|
|
8
8
|
module.exports = rank;
|
|
9
9
|
|
|
@@ -28,10 +28,10 @@ module.exports = rank;
|
|
|
28
28
|
*/
|
|
29
29
|
function rank(g) {
|
|
30
30
|
switch(g.graph().ranker) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
case "network-simplex": networkSimplexRanker(g); break;
|
|
32
|
+
case "tight-tree": tightTreeRanker(g); break;
|
|
33
|
+
case "longest-path": longestPathRanker(g); break;
|
|
34
|
+
default: networkSimplexRanker(g);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|