@dagrejs/dagre 0.8.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -7
- package/dist/dagre.js +1514 -18367
- package/dist/dagre.min.js +353 -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/order/cross-count.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var zipObject = require("../util").zipObject;
|
|
4
4
|
|
|
5
5
|
module.exports = crossCount;
|
|
6
6
|
|
|
@@ -32,27 +32,23 @@ function twoLayerCrossCount(g, northLayer, southLayer) {
|
|
|
32
32
|
// Sort all of the edges between the north and south layers by their position
|
|
33
33
|
// in the north layer and then the south. Map these edges to the position of
|
|
34
34
|
// their head in the south layer.
|
|
35
|
-
var southPos =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
})
|
|
42
|
-
.sortBy("pos")
|
|
43
|
-
.value();
|
|
44
|
-
}), true);
|
|
35
|
+
var southPos = zipObject(southLayer, southLayer.map((v, i) => i));
|
|
36
|
+
var southEntries = northLayer.flatMap(v => {
|
|
37
|
+
return g.outEdges(v).map(e => {
|
|
38
|
+
return { pos: southPos[e.w], weight: g.edge(e).weight };
|
|
39
|
+
}).sort((a, b) => a.pos - b.pos);
|
|
40
|
+
});
|
|
45
41
|
|
|
46
42
|
// Build the accumulator tree
|
|
47
43
|
var firstIndex = 1;
|
|
48
44
|
while (firstIndex < southLayer.length) firstIndex <<= 1;
|
|
49
45
|
var treeSize = 2 * firstIndex - 1;
|
|
50
46
|
firstIndex -= 1;
|
|
51
|
-
var tree =
|
|
47
|
+
var tree = new Array(treeSize).fill(0);
|
|
52
48
|
|
|
53
49
|
// Calculate the weighted crossings
|
|
54
50
|
var cc = 0;
|
|
55
|
-
|
|
51
|
+
southEntries.forEach(entry => {
|
|
56
52
|
var index = entry.pos + firstIndex;
|
|
57
53
|
tree[index] += entry.weight;
|
|
58
54
|
var weightSum = 0;
|
|
@@ -64,7 +60,7 @@ function twoLayerCrossCount(g, northLayer, southLayer) {
|
|
|
64
60
|
tree[index] += entry.weight;
|
|
65
61
|
}
|
|
66
62
|
cc += entry.weight * weightSum;
|
|
67
|
-
})
|
|
63
|
+
});
|
|
68
64
|
|
|
69
65
|
return cc;
|
|
70
66
|
}
|
package/lib/order/index.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
util = require("../util");
|
|
3
|
+
var initOrder = require("./init-order");
|
|
4
|
+
var crossCount = require("./cross-count");
|
|
5
|
+
var sortSubgraph = require("./sort-subgraph");
|
|
6
|
+
var buildLayerGraph = require("./build-layer-graph");
|
|
7
|
+
var addSubgraphConstraints = require("./add-subgraph-constraints");
|
|
8
|
+
var Graph = require("@dagrejs/graphlib").Graph;
|
|
9
|
+
var util = require("../util");
|
|
11
10
|
|
|
12
11
|
module.exports = order;
|
|
13
12
|
|
|
@@ -28,14 +27,14 @@ module.exports = order;
|
|
|
28
27
|
*/
|
|
29
28
|
function order(g) {
|
|
30
29
|
var maxRank = util.maxRank(g),
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
downLayerGraphs = buildLayerGraphs(g, util.range(1, maxRank + 1), "inEdges"),
|
|
31
|
+
upLayerGraphs = buildLayerGraphs(g, util.range(maxRank - 1, -1, -1), "outEdges");
|
|
33
32
|
|
|
34
33
|
var layering = initOrder(g);
|
|
35
34
|
assignOrder(g, layering);
|
|
36
35
|
|
|
37
36
|
var bestCC = Number.POSITIVE_INFINITY,
|
|
38
|
-
|
|
37
|
+
best;
|
|
39
38
|
|
|
40
39
|
for (var i = 0, lastBest = 0; lastBest < 4; ++i, ++lastBest) {
|
|
41
40
|
sweepLayerGraphs(i % 2 ? downLayerGraphs : upLayerGraphs, i % 4 >= 2);
|
|
@@ -44,7 +43,7 @@ function order(g) {
|
|
|
44
43
|
var cc = crossCount(g, layering);
|
|
45
44
|
if (cc < bestCC) {
|
|
46
45
|
lastBest = 0;
|
|
47
|
-
best =
|
|
46
|
+
best = Object.assign({}, layering);
|
|
48
47
|
bestCC = cc;
|
|
49
48
|
}
|
|
50
49
|
}
|
|
@@ -53,27 +52,21 @@ function order(g) {
|
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
function buildLayerGraphs(g, ranks, relationship) {
|
|
56
|
-
return
|
|
55
|
+
return ranks.map(function(rank) {
|
|
57
56
|
return buildLayerGraph(g, rank, relationship);
|
|
58
57
|
});
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
function sweepLayerGraphs(layerGraphs, biasRight) {
|
|
62
61
|
var cg = new Graph();
|
|
63
|
-
|
|
62
|
+
layerGraphs.forEach(function(lg) {
|
|
64
63
|
var root = lg.graph().root;
|
|
65
64
|
var sorted = sortSubgraph(lg, root, cg, biasRight);
|
|
66
|
-
|
|
67
|
-
lg.node(v).order = i;
|
|
68
|
-
});
|
|
65
|
+
sorted.vs.forEach((v, i) => lg.node(v).order = i);
|
|
69
66
|
addSubgraphConstraints(lg, cg, sorted.vs);
|
|
70
67
|
});
|
|
71
68
|
}
|
|
72
69
|
|
|
73
70
|
function assignOrder(g, layering) {
|
|
74
|
-
|
|
75
|
-
_.forEach(layer, function(v, i) {
|
|
76
|
-
g.node(v).order = i;
|
|
77
|
-
});
|
|
78
|
-
});
|
|
71
|
+
Object.values(layering).forEach(layer => layer.forEach((v, i) => g.node(v).order = i));
|
|
79
72
|
}
|
package/lib/order/init-order.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var util = require("../util");
|
|
4
4
|
|
|
5
5
|
module.exports = initOrder;
|
|
6
6
|
|
|
@@ -16,23 +16,21 @@ module.exports = initOrder;
|
|
|
16
16
|
* the order of its nodes.
|
|
17
17
|
*/
|
|
18
18
|
function initOrder(g) {
|
|
19
|
-
var visited = {}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
maxRank = _.max(_.map(simpleNodes, function(v) { return g.node(v).rank; })),
|
|
24
|
-
layers = _.map(_.range(maxRank + 1), function() { return []; });
|
|
19
|
+
var visited = {};
|
|
20
|
+
var simpleNodes = g.nodes().filter(v => !g.children(v).length);
|
|
21
|
+
var maxRank = Math.max(...simpleNodes.map(v => g.node(v).rank));
|
|
22
|
+
var layers = util.range(maxRank + 1).map(() => []);
|
|
25
23
|
|
|
26
24
|
function dfs(v) {
|
|
27
|
-
if (
|
|
25
|
+
if (visited[v]) return;
|
|
28
26
|
visited[v] = true;
|
|
29
27
|
var node = g.node(v);
|
|
30
28
|
layers[node.rank].push(v);
|
|
31
|
-
|
|
29
|
+
g.successors(v).forEach(dfs);
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
var orderedVs =
|
|
35
|
-
|
|
32
|
+
var orderedVs = simpleNodes.sort((a, b) => g.node(a).rank - g.node(b).rank);
|
|
33
|
+
orderedVs.forEach(dfs);
|
|
36
34
|
|
|
37
35
|
return layers;
|
|
38
36
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var util = require("../util");
|
|
4
4
|
|
|
5
5
|
module.exports = resolveConflicts;
|
|
6
6
|
|
|
@@ -31,7 +31,7 @@ module.exports = resolveConflicts;
|
|
|
31
31
|
*/
|
|
32
32
|
function resolveConflicts(entries, cg) {
|
|
33
33
|
var mappedEntries = {};
|
|
34
|
-
|
|
34
|
+
entries.forEach((entry, i) => {
|
|
35
35
|
var tmp = mappedEntries[entry.v] = {
|
|
36
36
|
indegree: 0,
|
|
37
37
|
"in": [],
|
|
@@ -39,24 +39,22 @@ function resolveConflicts(entries, cg) {
|
|
|
39
39
|
vs: [entry.v],
|
|
40
40
|
i: i
|
|
41
41
|
};
|
|
42
|
-
if (
|
|
42
|
+
if (entry.barycenter !== undefined) {
|
|
43
43
|
tmp.barycenter = entry.barycenter;
|
|
44
44
|
tmp.weight = entry.weight;
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
var entryV = mappedEntries[e.v]
|
|
50
|
-
|
|
51
|
-
if (
|
|
48
|
+
cg.edges().forEach(e => {
|
|
49
|
+
var entryV = mappedEntries[e.v];
|
|
50
|
+
var entryW = mappedEntries[e.w];
|
|
51
|
+
if (entryV !== undefined && entryW !== undefined) {
|
|
52
52
|
entryW.indegree++;
|
|
53
53
|
entryV.out.push(mappedEntries[e.w]);
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
var sourceSet =
|
|
58
|
-
return !entry.indegree;
|
|
59
|
-
});
|
|
57
|
+
var sourceSet = Object.values(mappedEntries).filter(entry => !entry.indegree);
|
|
60
58
|
|
|
61
59
|
return doResolveConflicts(sourceSet);
|
|
62
60
|
}
|
|
@@ -69,8 +67,8 @@ function doResolveConflicts(sourceSet) {
|
|
|
69
67
|
if (uEntry.merged) {
|
|
70
68
|
return;
|
|
71
69
|
}
|
|
72
|
-
if (
|
|
73
|
-
|
|
70
|
+
if (uEntry.barycenter === undefined ||
|
|
71
|
+
vEntry.barycenter === undefined ||
|
|
74
72
|
uEntry.barycenter >= vEntry.barycenter) {
|
|
75
73
|
mergeEntries(vEntry, uEntry);
|
|
76
74
|
}
|
|
@@ -89,21 +87,18 @@ function doResolveConflicts(sourceSet) {
|
|
|
89
87
|
while (sourceSet.length) {
|
|
90
88
|
var entry = sourceSet.pop();
|
|
91
89
|
entries.push(entry);
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
entry["in"].reverse().forEach(handleIn(entry));
|
|
91
|
+
entry.out.forEach(handleOut(entry));
|
|
94
92
|
}
|
|
95
93
|
|
|
96
|
-
return
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return _.pick(entry, ["vs", "i", "barycenter", "weight"]);
|
|
100
|
-
})
|
|
101
|
-
.value();
|
|
94
|
+
return entries.filter(entry => !entry.merged).map(entry => {
|
|
95
|
+
return util.pick(entry, ["vs", "i", "barycenter", "weight"]);
|
|
96
|
+
});
|
|
102
97
|
}
|
|
103
98
|
|
|
104
99
|
function mergeEntries(target, source) {
|
|
105
|
-
var sum = 0
|
|
106
|
-
|
|
100
|
+
var sum = 0;
|
|
101
|
+
var weight = 0;
|
|
107
102
|
|
|
108
103
|
if (target.weight) {
|
|
109
104
|
sum += target.barycenter * target.weight;
|
|
@@ -1,29 +1,26 @@
|
|
|
1
|
-
var
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
sort = require("./sort");
|
|
1
|
+
var barycenter = require("./barycenter");
|
|
2
|
+
var resolveConflicts = require("./resolve-conflicts");
|
|
3
|
+
var sort = require("./sort");
|
|
5
4
|
|
|
6
5
|
module.exports = sortSubgraph;
|
|
7
6
|
|
|
8
7
|
function sortSubgraph(g, v, cg, biasRight) {
|
|
9
|
-
var movable = g.children(v)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
var movable = g.children(v);
|
|
9
|
+
var node = g.node(v);
|
|
10
|
+
var bl = node ? node.borderLeft : undefined;
|
|
11
|
+
var br = node ? node.borderRight: undefined;
|
|
12
|
+
var subgraphs = {};
|
|
14
13
|
|
|
15
14
|
if (bl) {
|
|
16
|
-
movable =
|
|
17
|
-
return w !== bl && w !== br;
|
|
18
|
-
});
|
|
15
|
+
movable = movable.filter(w => w !== bl && w !== br);
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
var barycenters = barycenter(g, movable);
|
|
22
|
-
|
|
19
|
+
barycenters.forEach(function(entry) {
|
|
23
20
|
if (g.children(entry.v).length) {
|
|
24
21
|
var subgraphResult = sortSubgraph(g, entry.v, cg, biasRight);
|
|
25
22
|
subgraphs[entry.v] = subgraphResult;
|
|
26
|
-
if (
|
|
23
|
+
if (subgraphResult.hasOwnProperty("barycenter")) {
|
|
27
24
|
mergeBarycenters(entry, subgraphResult);
|
|
28
25
|
}
|
|
29
26
|
}
|
|
@@ -35,11 +32,11 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
35
32
|
var result = sort(entries, biasRight);
|
|
36
33
|
|
|
37
34
|
if (bl) {
|
|
38
|
-
result.vs =
|
|
35
|
+
result.vs = [bl, result.vs, br].flat(true);
|
|
39
36
|
if (g.predecessors(bl).length) {
|
|
40
37
|
var blPred = g.node(g.predecessors(bl)[0]),
|
|
41
|
-
|
|
42
|
-
if (!
|
|
38
|
+
brPred = g.node(g.predecessors(br)[0]);
|
|
39
|
+
if (!result.hasOwnProperty("barycenter")) {
|
|
43
40
|
result.barycenter = 0;
|
|
44
41
|
result.weight = 0;
|
|
45
42
|
}
|
|
@@ -53,18 +50,18 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
53
50
|
}
|
|
54
51
|
|
|
55
52
|
function expandSubgraphs(entries, subgraphs) {
|
|
56
|
-
|
|
57
|
-
entry.vs =
|
|
53
|
+
entries.forEach(function(entry) {
|
|
54
|
+
entry.vs = entry.vs.flatMap(function(v) {
|
|
58
55
|
if (subgraphs[v]) {
|
|
59
56
|
return subgraphs[v].vs;
|
|
60
57
|
}
|
|
61
58
|
return v;
|
|
62
|
-
})
|
|
59
|
+
});
|
|
63
60
|
});
|
|
64
61
|
}
|
|
65
62
|
|
|
66
63
|
function mergeBarycenters(target, other) {
|
|
67
|
-
if (
|
|
64
|
+
if (target.barycenter !== undefined) {
|
|
68
65
|
target.barycenter = (target.barycenter * target.weight +
|
|
69
66
|
other.barycenter * other.weight) /
|
|
70
67
|
(target.weight + other.weight);
|
package/lib/order/sort.js
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
var
|
|
2
|
-
util = require("../util");
|
|
1
|
+
var util = require("../util");
|
|
3
2
|
|
|
4
3
|
module.exports = sort;
|
|
5
4
|
|
|
6
5
|
function sort(entries, biasRight) {
|
|
7
6
|
var parts = util.partition(entries, function(entry) {
|
|
8
|
-
return
|
|
7
|
+
return entry.hasOwnProperty("barycenter");
|
|
9
8
|
});
|
|
10
9
|
var sortable = parts.lhs,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
unsortable = parts.rhs.sort((a, b) => b.i - a.i),
|
|
11
|
+
vs = [],
|
|
12
|
+
sum = 0,
|
|
13
|
+
weight = 0,
|
|
14
|
+
vsIndex = 0;
|
|
16
15
|
|
|
17
16
|
sortable.sort(compareWithBias(!!biasRight));
|
|
18
17
|
|
|
19
18
|
vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
sortable.forEach(function (entry) {
|
|
22
21
|
vsIndex += entry.vs.length;
|
|
23
22
|
vs.push(entry.vs);
|
|
24
23
|
sum += entry.barycenter * entry.weight;
|
|
@@ -26,7 +25,7 @@ function sort(entries, biasRight) {
|
|
|
26
25
|
vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
|
|
27
26
|
});
|
|
28
27
|
|
|
29
|
-
var result = { vs:
|
|
28
|
+
var result = { vs: vs.flat(true) };
|
|
30
29
|
if (weight) {
|
|
31
30
|
result.barycenter = sum / weight;
|
|
32
31
|
result.weight = weight;
|
|
@@ -36,7 +35,7 @@ function sort(entries, biasRight) {
|
|
|
36
35
|
|
|
37
36
|
function consumeUnsortable(vs, unsortable, index) {
|
|
38
37
|
var last;
|
|
39
|
-
while (unsortable.length && (last =
|
|
38
|
+
while (unsortable.length && (last = unsortable[unsortable.length - 1]).i <= index) {
|
|
40
39
|
unsortable.pop();
|
|
41
40
|
vs.push(last.vs);
|
|
42
41
|
index++;
|
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
var _ = require("./lodash");
|
|
2
|
-
|
|
3
1
|
module.exports = parentDummyChains;
|
|
4
2
|
|
|
5
3
|
function parentDummyChains(g) {
|
|
6
4
|
var postorderNums = postorder(g);
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
var node = g.node(v)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
g.graph().dummyChains.forEach(function(v) {
|
|
7
|
+
var node = g.node(v);
|
|
8
|
+
var edgeObj = node.edgeObj;
|
|
9
|
+
var pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w);
|
|
10
|
+
var path = pathData.path;
|
|
11
|
+
var lca = pathData.lca;
|
|
12
|
+
var pathIdx = 0;
|
|
13
|
+
var pathV = path[pathIdx];
|
|
14
|
+
var ascending = true;
|
|
17
15
|
|
|
18
16
|
while (v !== edgeObj.w) {
|
|
19
17
|
node = g.node(v);
|
|
@@ -46,12 +44,12 @@ function parentDummyChains(g) {
|
|
|
46
44
|
// Find a path from v to w through the lowest common ancestor (LCA). Return the
|
|
47
45
|
// full path and the LCA.
|
|
48
46
|
function findPath(g, postorderNums, v, w) {
|
|
49
|
-
var vPath = []
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
47
|
+
var vPath = [];
|
|
48
|
+
var wPath = [];
|
|
49
|
+
var low = Math.min(postorderNums[v].low, postorderNums[w].low);
|
|
50
|
+
var lim = Math.max(postorderNums[v].lim, postorderNums[w].lim);
|
|
51
|
+
var parent;
|
|
52
|
+
var lca;
|
|
55
53
|
|
|
56
54
|
// Traverse up from v to find the LCA
|
|
57
55
|
parent = v;
|
|
@@ -72,15 +70,15 @@ function findPath(g, postorderNums, v, w) {
|
|
|
72
70
|
}
|
|
73
71
|
|
|
74
72
|
function postorder(g) {
|
|
75
|
-
var result = {}
|
|
76
|
-
|
|
73
|
+
var result = {};
|
|
74
|
+
var lim = 0;
|
|
77
75
|
|
|
78
76
|
function dfs(v) {
|
|
79
77
|
var low = lim;
|
|
80
|
-
|
|
78
|
+
g.children(v).forEach(dfs);
|
|
81
79
|
result[v] = { low: low, lim: lim++ };
|
|
82
80
|
}
|
|
83
|
-
|
|
81
|
+
g.children().forEach(dfs);
|
|
84
82
|
|
|
85
83
|
return result;
|
|
86
84
|
}
|