@dagrejs/dagre 1.0.1 → 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 +139 -0
- 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 +3 -1
package/lib/order/init-order.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
let util = require("../util");
|
|
4
4
|
|
|
5
5
|
module.exports = initOrder;
|
|
6
6
|
|
|
@@ -16,20 +16,20 @@ module.exports = initOrder;
|
|
|
16
16
|
* the order of its nodes.
|
|
17
17
|
*/
|
|
18
18
|
function initOrder(g) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
let visited = {};
|
|
20
|
+
let simpleNodes = g.nodes().filter(v => !g.children(v).length);
|
|
21
|
+
let maxRank = Math.max(...simpleNodes.map(v => g.node(v).rank));
|
|
22
|
+
let layers = util.range(maxRank + 1).map(() => []);
|
|
23
23
|
|
|
24
24
|
function dfs(v) {
|
|
25
25
|
if (visited[v]) return;
|
|
26
26
|
visited[v] = true;
|
|
27
|
-
|
|
27
|
+
let node = g.node(v);
|
|
28
28
|
layers[node.rank].push(v);
|
|
29
29
|
g.successors(v).forEach(dfs);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
let orderedVs = simpleNodes.sort((a, b) => g.node(a).rank - g.node(b).rank);
|
|
33
33
|
orderedVs.forEach(dfs);
|
|
34
34
|
|
|
35
35
|
return layers;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
let util = require("../util");
|
|
4
4
|
|
|
5
5
|
module.exports = resolveConflicts;
|
|
6
6
|
|
|
@@ -30,9 +30,9 @@ module.exports = resolveConflicts;
|
|
|
30
30
|
* elements in `vs`.
|
|
31
31
|
*/
|
|
32
32
|
function resolveConflicts(entries, cg) {
|
|
33
|
-
|
|
33
|
+
let mappedEntries = {};
|
|
34
34
|
entries.forEach((entry, i) => {
|
|
35
|
-
|
|
35
|
+
let tmp = mappedEntries[entry.v] = {
|
|
36
36
|
indegree: 0,
|
|
37
37
|
"in": [],
|
|
38
38
|
out: [],
|
|
@@ -46,24 +46,24 @@ function resolveConflicts(entries, cg) {
|
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
cg.edges().forEach(e => {
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
let entryV = mappedEntries[e.v];
|
|
50
|
+
let entryW = mappedEntries[e.w];
|
|
51
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
|
-
|
|
57
|
+
let sourceSet = Object.values(mappedEntries).filter(entry => !entry.indegree);
|
|
58
58
|
|
|
59
59
|
return doResolveConflicts(sourceSet);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function doResolveConflicts(sourceSet) {
|
|
63
|
-
|
|
63
|
+
let entries = [];
|
|
64
64
|
|
|
65
65
|
function handleIn(vEntry) {
|
|
66
|
-
return
|
|
66
|
+
return uEntry => {
|
|
67
67
|
if (uEntry.merged) {
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
@@ -76,7 +76,7 @@ function doResolveConflicts(sourceSet) {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
function handleOut(vEntry) {
|
|
79
|
-
return
|
|
79
|
+
return wEntry => {
|
|
80
80
|
wEntry["in"].push(vEntry);
|
|
81
81
|
if (--wEntry.indegree === 0) {
|
|
82
82
|
sourceSet.push(wEntry);
|
|
@@ -85,7 +85,7 @@ function doResolveConflicts(sourceSet) {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
while (sourceSet.length) {
|
|
88
|
-
|
|
88
|
+
let entry = sourceSet.pop();
|
|
89
89
|
entries.push(entry);
|
|
90
90
|
entry["in"].reverse().forEach(handleIn(entry));
|
|
91
91
|
entry.out.forEach(handleOut(entry));
|
|
@@ -97,8 +97,8 @@ function doResolveConflicts(sourceSet) {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
function mergeEntries(target, source) {
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
let sum = 0;
|
|
101
|
+
let weight = 0;
|
|
102
102
|
|
|
103
103
|
if (target.weight) {
|
|
104
104
|
sum += target.barycenter * target.weight;
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
let barycenter = require("./barycenter");
|
|
2
|
+
let resolveConflicts = require("./resolve-conflicts");
|
|
3
|
+
let sort = require("./sort");
|
|
4
4
|
|
|
5
5
|
module.exports = sortSubgraph;
|
|
6
6
|
|
|
7
7
|
function sortSubgraph(g, v, cg, biasRight) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
let movable = g.children(v);
|
|
9
|
+
let node = g.node(v);
|
|
10
|
+
let bl = node ? node.borderLeft : undefined;
|
|
11
|
+
let br = node ? node.borderRight: undefined;
|
|
12
|
+
let subgraphs = {};
|
|
13
13
|
|
|
14
14
|
if (bl) {
|
|
15
15
|
movable = movable.filter(w => w !== bl && w !== br);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
barycenters.forEach(
|
|
18
|
+
let barycenters = barycenter(g, movable);
|
|
19
|
+
barycenters.forEach(entry => {
|
|
20
20
|
if (g.children(entry.v).length) {
|
|
21
|
-
|
|
21
|
+
let subgraphResult = sortSubgraph(g, entry.v, cg, biasRight);
|
|
22
22
|
subgraphs[entry.v] = subgraphResult;
|
|
23
23
|
if (subgraphResult.hasOwnProperty("barycenter")) {
|
|
24
24
|
mergeBarycenters(entry, subgraphResult);
|
|
@@ -26,15 +26,15 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
26
26
|
}
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
let entries = resolveConflicts(barycenters, cg);
|
|
30
30
|
expandSubgraphs(entries, subgraphs);
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
let result = sort(entries, biasRight);
|
|
33
33
|
|
|
34
34
|
if (bl) {
|
|
35
35
|
result.vs = [bl, result.vs, br].flat(true);
|
|
36
36
|
if (g.predecessors(bl).length) {
|
|
37
|
-
|
|
37
|
+
let blPred = g.node(g.predecessors(bl)[0]),
|
|
38
38
|
brPred = g.node(g.predecessors(br)[0]);
|
|
39
39
|
if (!result.hasOwnProperty("barycenter")) {
|
|
40
40
|
result.barycenter = 0;
|
|
@@ -50,8 +50,8 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
function expandSubgraphs(entries, subgraphs) {
|
|
53
|
-
entries.forEach(
|
|
54
|
-
entry.vs = entry.vs.flatMap(
|
|
53
|
+
entries.forEach(entry => {
|
|
54
|
+
entry.vs = entry.vs.flatMap(v => {
|
|
55
55
|
if (subgraphs[v]) {
|
|
56
56
|
return subgraphs[v].vs;
|
|
57
57
|
}
|
package/lib/order/sort.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
let util = require("../util");
|
|
2
2
|
|
|
3
3
|
module.exports = sort;
|
|
4
4
|
|
|
5
5
|
function sort(entries, biasRight) {
|
|
6
|
-
|
|
6
|
+
let parts = util.partition(entries, entry => {
|
|
7
7
|
return entry.hasOwnProperty("barycenter");
|
|
8
8
|
});
|
|
9
|
-
|
|
9
|
+
let sortable = parts.lhs,
|
|
10
10
|
unsortable = parts.rhs.sort((a, b) => b.i - a.i),
|
|
11
11
|
vs = [],
|
|
12
12
|
sum = 0,
|
|
@@ -17,7 +17,7 @@ function sort(entries, biasRight) {
|
|
|
17
17
|
|
|
18
18
|
vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
|
|
19
19
|
|
|
20
|
-
sortable.forEach(
|
|
20
|
+
sortable.forEach(entry => {
|
|
21
21
|
vsIndex += entry.vs.length;
|
|
22
22
|
vs.push(entry.vs);
|
|
23
23
|
sum += entry.barycenter * entry.weight;
|
|
@@ -25,7 +25,7 @@ function sort(entries, biasRight) {
|
|
|
25
25
|
vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
let result = { vs: vs.flat(true) };
|
|
29
29
|
if (weight) {
|
|
30
30
|
result.barycenter = sum / weight;
|
|
31
31
|
result.weight = weight;
|
|
@@ -34,7 +34,7 @@ function sort(entries, biasRight) {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
function consumeUnsortable(vs, unsortable, index) {
|
|
37
|
-
|
|
37
|
+
let last;
|
|
38
38
|
while (unsortable.length && (last = unsortable[unsortable.length - 1]).i <= index) {
|
|
39
39
|
unsortable.pop();
|
|
40
40
|
vs.push(last.vs);
|
|
@@ -44,7 +44,7 @@ function consumeUnsortable(vs, unsortable, index) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
function compareWithBias(bias) {
|
|
47
|
-
return
|
|
47
|
+
return (entryV, entryW) => {
|
|
48
48
|
if (entryV.barycenter < entryW.barycenter) {
|
|
49
49
|
return -1;
|
|
50
50
|
} else if (entryV.barycenter > entryW.barycenter) {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
module.exports = parentDummyChains;
|
|
2
2
|
|
|
3
3
|
function parentDummyChains(g) {
|
|
4
|
-
|
|
4
|
+
let postorderNums = postorder(g);
|
|
5
5
|
|
|
6
|
-
g.graph().dummyChains.forEach(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
g.graph().dummyChains.forEach(v => {
|
|
7
|
+
let node = g.node(v);
|
|
8
|
+
let edgeObj = node.edgeObj;
|
|
9
|
+
let pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w);
|
|
10
|
+
let path = pathData.path;
|
|
11
|
+
let lca = pathData.lca;
|
|
12
|
+
let pathIdx = 0;
|
|
13
|
+
let pathV = path[pathIdx];
|
|
14
|
+
let ascending = true;
|
|
15
15
|
|
|
16
16
|
while (v !== edgeObj.w) {
|
|
17
17
|
node = g.node(v);
|
|
@@ -44,12 +44,12 @@ function parentDummyChains(g) {
|
|
|
44
44
|
// Find a path from v to w through the lowest common ancestor (LCA). Return the
|
|
45
45
|
// full path and the LCA.
|
|
46
46
|
function findPath(g, postorderNums, v, w) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
let vPath = [];
|
|
48
|
+
let wPath = [];
|
|
49
|
+
let low = Math.min(postorderNums[v].low, postorderNums[w].low);
|
|
50
|
+
let lim = Math.max(postorderNums[v].lim, postorderNums[w].lim);
|
|
51
|
+
let parent;
|
|
52
|
+
let lca;
|
|
53
53
|
|
|
54
54
|
// Traverse up from v to find the LCA
|
|
55
55
|
parent = v;
|
|
@@ -70,11 +70,11 @@ function findPath(g, postorderNums, v, w) {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
function postorder(g) {
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
let result = {};
|
|
74
|
+
let lim = 0;
|
|
75
75
|
|
|
76
76
|
function dfs(v) {
|
|
77
|
-
|
|
77
|
+
let low = lim;
|
|
78
78
|
g.children(v).forEach(dfs);
|
|
79
79
|
result[v] = { low: low, lim: lim++ };
|
|
80
80
|
}
|
package/lib/position/bk.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
4
|
+
let util = require("../util");
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* This module provides coordinate assignment based on Brandes and Köpf, "Fast
|
|
@@ -39,10 +39,10 @@ module.exports = {
|
|
|
39
39
|
* single node in the layers being scanned.
|
|
40
40
|
*/
|
|
41
41
|
function findType1Conflicts(g, layering) {
|
|
42
|
-
|
|
42
|
+
let conflicts = {};
|
|
43
43
|
|
|
44
44
|
function visitLayer(prevLayer, layer) {
|
|
45
|
-
|
|
45
|
+
let
|
|
46
46
|
// last visited node in the previous layer that is incident on an inner
|
|
47
47
|
// segment.
|
|
48
48
|
k0 = 0,
|
|
@@ -52,14 +52,14 @@ function findType1Conflicts(g, layering) {
|
|
|
52
52
|
prevLayerLength = prevLayer.length,
|
|
53
53
|
lastNode = layer[layer.length - 1];
|
|
54
54
|
|
|
55
|
-
layer.forEach(
|
|
56
|
-
|
|
55
|
+
layer.forEach((v, i) => {
|
|
56
|
+
let w = findOtherInnerSegmentNode(g, v),
|
|
57
57
|
k1 = w ? g.node(w).order : prevLayerLength;
|
|
58
58
|
|
|
59
59
|
if (w || v === lastNode) {
|
|
60
|
-
layer.slice(scanPos, i+1).forEach(
|
|
61
|
-
g.predecessors(scanNode).forEach(
|
|
62
|
-
|
|
60
|
+
layer.slice(scanPos, i+1).forEach(scanNode => {
|
|
61
|
+
g.predecessors(scanNode).forEach(u => {
|
|
62
|
+
let uLabel = g.node(u),
|
|
63
63
|
uPos = uLabel.order;
|
|
64
64
|
if ((uPos < k0 || k1 < uPos) &&
|
|
65
65
|
!(uLabel.dummy && g.node(scanNode).dummy)) {
|
|
@@ -80,15 +80,15 @@ function findType1Conflicts(g, layering) {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
function findType2Conflicts(g, layering) {
|
|
83
|
-
|
|
83
|
+
let conflicts = {};
|
|
84
84
|
|
|
85
85
|
function scan(south, southPos, southEnd, prevNorthBorder, nextNorthBorder) {
|
|
86
|
-
|
|
87
|
-
util.range(southPos, southEnd).forEach(
|
|
86
|
+
let v;
|
|
87
|
+
util.range(southPos, southEnd).forEach(i => {
|
|
88
88
|
v = south[i];
|
|
89
89
|
if (g.node(v).dummy) {
|
|
90
|
-
g.predecessors(v).forEach(
|
|
91
|
-
|
|
90
|
+
g.predecessors(v).forEach(u => {
|
|
91
|
+
let uNode = g.node(u);
|
|
92
92
|
if (uNode.dummy &&
|
|
93
93
|
(uNode.order < prevNorthBorder || uNode.order > nextNorthBorder)) {
|
|
94
94
|
addConflict(conflicts, u, v);
|
|
@@ -100,13 +100,13 @@ function findType2Conflicts(g, layering) {
|
|
|
100
100
|
|
|
101
101
|
|
|
102
102
|
function visitLayer(north, south) {
|
|
103
|
-
|
|
103
|
+
let prevNorthPos = -1,
|
|
104
104
|
nextNorthPos,
|
|
105
105
|
southPos = 0;
|
|
106
106
|
|
|
107
|
-
south.forEach(
|
|
107
|
+
south.forEach((v, southLookahead) => {
|
|
108
108
|
if (g.node(v).dummy === "border") {
|
|
109
|
-
|
|
109
|
+
let predecessors = g.predecessors(v);
|
|
110
110
|
if (predecessors.length) {
|
|
111
111
|
nextNorthPos = g.node(predecessors[0]).order;
|
|
112
112
|
scan(south, southPos, southLookahead, prevNorthPos, nextNorthPos);
|
|
@@ -132,12 +132,12 @@ function findOtherInnerSegmentNode(g, v) {
|
|
|
132
132
|
|
|
133
133
|
function addConflict(conflicts, v, w) {
|
|
134
134
|
if (v > w) {
|
|
135
|
-
|
|
135
|
+
let tmp = v;
|
|
136
136
|
v = w;
|
|
137
137
|
w = tmp;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
let conflictsV = conflicts[v];
|
|
141
141
|
if (!conflictsV) {
|
|
142
142
|
conflicts[v] = conflictsV = {};
|
|
143
143
|
}
|
|
@@ -146,7 +146,7 @@ function addConflict(conflicts, v, w) {
|
|
|
146
146
|
|
|
147
147
|
function hasConflict(conflicts, v, w) {
|
|
148
148
|
if (v > w) {
|
|
149
|
-
|
|
149
|
+
let tmp = v;
|
|
150
150
|
v = w;
|
|
151
151
|
w = tmp;
|
|
152
152
|
}
|
|
@@ -162,30 +162,30 @@ function hasConflict(conflicts, v, w) {
|
|
|
162
162
|
* blocks would be split in that scenario.
|
|
163
163
|
*/
|
|
164
164
|
function verticalAlignment(g, layering, conflicts, neighborFn) {
|
|
165
|
-
|
|
165
|
+
let root = {},
|
|
166
166
|
align = {},
|
|
167
167
|
pos = {};
|
|
168
168
|
|
|
169
169
|
// We cache the position here based on the layering because the graph and
|
|
170
170
|
// layering may be out of sync. The layering matrix is manipulated to
|
|
171
171
|
// generate different extreme alignments.
|
|
172
|
-
layering.forEach(
|
|
173
|
-
layer.forEach(
|
|
172
|
+
layering.forEach(layer => {
|
|
173
|
+
layer.forEach((v, order) => {
|
|
174
174
|
root[v] = v;
|
|
175
175
|
align[v] = v;
|
|
176
176
|
pos[v] = order;
|
|
177
177
|
});
|
|
178
178
|
});
|
|
179
179
|
|
|
180
|
-
layering.forEach(
|
|
181
|
-
|
|
182
|
-
layer.forEach(
|
|
183
|
-
|
|
180
|
+
layering.forEach(layer => {
|
|
181
|
+
let prevIdx = -1;
|
|
182
|
+
layer.forEach(v => {
|
|
183
|
+
let ws = neighborFn(v);
|
|
184
184
|
if (ws.length) {
|
|
185
185
|
ws = ws.sort((a, b) => pos[a] - pos[b]);
|
|
186
|
-
|
|
187
|
-
for (
|
|
188
|
-
|
|
186
|
+
let mp = (ws.length - 1) / 2;
|
|
187
|
+
for (let i = Math.floor(mp), il = Math.ceil(mp); i <= il; ++i) {
|
|
188
|
+
let w = ws[i];
|
|
189
189
|
if (align[v] === v &&
|
|
190
190
|
prevIdx < pos[w] &&
|
|
191
191
|
!hasConflict(conflicts, v, w)) {
|
|
@@ -207,14 +207,14 @@ function horizontalCompaction(g, layering, root, align, reverseSep) {
|
|
|
207
207
|
// sweeps. The first sweep places blocks with the smallest possible
|
|
208
208
|
// coordinates. The second sweep removes unused space by moving blocks to the
|
|
209
209
|
// greatest coordinates without violating separation.
|
|
210
|
-
|
|
210
|
+
let xs = {},
|
|
211
211
|
blockG = buildBlockGraph(g, layering, root, reverseSep),
|
|
212
212
|
borderType = reverseSep ? "borderLeft" : "borderRight";
|
|
213
213
|
|
|
214
214
|
function iterate(setXsFunc, nextNodesFunc) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
215
|
+
let stack = blockG.nodes();
|
|
216
|
+
let elem = stack.pop();
|
|
217
|
+
let visited = {};
|
|
218
218
|
while (elem) {
|
|
219
219
|
if (visited[elem]) {
|
|
220
220
|
setXsFunc(elem);
|
|
@@ -230,18 +230,18 @@ function horizontalCompaction(g, layering, root, align, reverseSep) {
|
|
|
230
230
|
|
|
231
231
|
// First pass, assign smallest coordinates
|
|
232
232
|
function pass1(elem) {
|
|
233
|
-
xs[elem] = blockG.inEdges(elem).reduce(
|
|
233
|
+
xs[elem] = blockG.inEdges(elem).reduce((acc, e) => {
|
|
234
234
|
return Math.max(acc, xs[e.v] + blockG.edge(e));
|
|
235
235
|
}, 0);
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
// Second pass, assign greatest coordinates
|
|
239
239
|
function pass2(elem) {
|
|
240
|
-
|
|
240
|
+
let min = blockG.outEdges(elem).reduce((acc, e) => {
|
|
241
241
|
return Math.min(acc, xs[e.w] - blockG.edge(e));
|
|
242
242
|
}, Number.POSITIVE_INFINITY);
|
|
243
243
|
|
|
244
|
-
|
|
244
|
+
let node = g.node(elem);
|
|
245
245
|
if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
|
|
246
246
|
xs[elem] = Math.max(xs[elem], min);
|
|
247
247
|
}
|
|
@@ -258,14 +258,14 @@ function horizontalCompaction(g, layering, root, align, reverseSep) {
|
|
|
258
258
|
|
|
259
259
|
|
|
260
260
|
function buildBlockGraph(g, layering, root, reverseSep) {
|
|
261
|
-
|
|
261
|
+
let blockGraph = new Graph(),
|
|
262
262
|
graphLabel = g.graph(),
|
|
263
263
|
sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
|
|
264
264
|
|
|
265
|
-
layering.forEach(
|
|
266
|
-
|
|
267
|
-
layer.forEach(
|
|
268
|
-
|
|
265
|
+
layering.forEach(layer => {
|
|
266
|
+
let u;
|
|
267
|
+
layer.forEach(v => {
|
|
268
|
+
let vRoot = root[v];
|
|
269
269
|
blockGraph.setNode(vRoot);
|
|
270
270
|
if (u) {
|
|
271
271
|
var uRoot = root[u],
|
|
@@ -284,11 +284,11 @@ function buildBlockGraph(g, layering, root, reverseSep) {
|
|
|
284
284
|
*/
|
|
285
285
|
function findSmallestWidthAlignment(g, xss) {
|
|
286
286
|
return Object.values(xss).reduce((currentMinAndXs, xs) => {
|
|
287
|
-
|
|
288
|
-
|
|
287
|
+
let max = Number.NEGATIVE_INFINITY;
|
|
288
|
+
let min = Number.POSITIVE_INFINITY;
|
|
289
289
|
|
|
290
290
|
Object.entries(xs).forEach(([v, x]) => {
|
|
291
|
-
|
|
291
|
+
let halfWidth = width(g, v) / 2;
|
|
292
292
|
|
|
293
293
|
max = Math.max(x + halfWidth, max);
|
|
294
294
|
min = Math.min(x - halfWidth, min);
|
|
@@ -310,18 +310,18 @@ function findSmallestWidthAlignment(g, xss) {
|
|
|
310
310
|
* coordinate of the smallest width alignment.
|
|
311
311
|
*/
|
|
312
312
|
function alignCoordinates(xss, alignTo) {
|
|
313
|
-
|
|
313
|
+
let alignToVals = Object.values(alignTo),
|
|
314
314
|
alignToMin = Math.min(...alignToVals),
|
|
315
315
|
alignToMax = Math.max(...alignToVals);
|
|
316
316
|
|
|
317
|
-
["u", "d"].forEach(
|
|
318
|
-
["l", "r"].forEach(
|
|
319
|
-
|
|
317
|
+
["u", "d"].forEach(vert => {
|
|
318
|
+
["l", "r"].forEach(horiz => {
|
|
319
|
+
let alignment = vert + horiz,
|
|
320
320
|
xs = xss[alignment];
|
|
321
321
|
|
|
322
322
|
if (xs === alignTo) return;
|
|
323
323
|
|
|
324
|
-
|
|
324
|
+
let xsVals = Object.values(xs);
|
|
325
325
|
let delta = alignToMin - Math.min(...xsVals);
|
|
326
326
|
if (horiz !== "l") {
|
|
327
327
|
delta = alignToMax - Math.max(...xsVals);
|
|
@@ -335,36 +335,36 @@ function alignCoordinates(xss, alignTo) {
|
|
|
335
335
|
}
|
|
336
336
|
|
|
337
337
|
function balance(xss, align) {
|
|
338
|
-
return util.mapValues(xss.ul,
|
|
338
|
+
return util.mapValues(xss.ul, (num, v) => {
|
|
339
339
|
if (align) {
|
|
340
340
|
return xss[align.toLowerCase()][v];
|
|
341
341
|
} else {
|
|
342
|
-
|
|
342
|
+
let xs = Object.values(xss).map(xs => xs[v]).sort((a, b) => a - b);
|
|
343
343
|
return (xs[1] + xs[2]) / 2;
|
|
344
344
|
}
|
|
345
345
|
});
|
|
346
346
|
}
|
|
347
347
|
|
|
348
348
|
function positionX(g) {
|
|
349
|
-
|
|
350
|
-
|
|
349
|
+
let layering = util.buildLayerMatrix(g);
|
|
350
|
+
let conflicts = Object.assign(
|
|
351
351
|
findType1Conflicts(g, layering),
|
|
352
352
|
findType2Conflicts(g, layering));
|
|
353
353
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
["u", "d"].forEach(
|
|
354
|
+
let xss = {};
|
|
355
|
+
let adjustedLayering;
|
|
356
|
+
["u", "d"].forEach(vert => {
|
|
357
357
|
adjustedLayering = vert === "u" ? layering : Object.values(layering).reverse();
|
|
358
|
-
["l", "r"].forEach(
|
|
358
|
+
["l", "r"].forEach(horiz => {
|
|
359
359
|
if (horiz === "r") {
|
|
360
360
|
adjustedLayering = adjustedLayering.map(inner => {
|
|
361
361
|
return Object.values(inner).reverse();
|
|
362
362
|
});
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
365
|
+
let neighborFn = (vert === "u" ? g.predecessors : g.successors).bind(g);
|
|
366
|
+
let align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn);
|
|
367
|
+
let xs = horizontalCompaction(g, adjustedLayering,
|
|
368
368
|
align.root, align.align, horiz === "r");
|
|
369
369
|
if (horiz === "r") {
|
|
370
370
|
xs = util.mapValues(xs, x => -x);
|
|
@@ -374,17 +374,17 @@ function positionX(g) {
|
|
|
374
374
|
});
|
|
375
375
|
|
|
376
376
|
|
|
377
|
-
|
|
377
|
+
let smallestWidth = findSmallestWidthAlignment(g, xss);
|
|
378
378
|
alignCoordinates(xss, smallestWidth);
|
|
379
379
|
return balance(xss, g.graph().align);
|
|
380
380
|
}
|
|
381
381
|
|
|
382
382
|
function sep(nodeSep, edgeSep, reverseSep) {
|
|
383
|
-
return
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
383
|
+
return (g, v, w) => {
|
|
384
|
+
let vLabel = g.node(v);
|
|
385
|
+
let wLabel = g.node(w);
|
|
386
|
+
let sum = 0;
|
|
387
|
+
let delta;
|
|
388
388
|
|
|
389
389
|
sum += vLabel.width / 2;
|
|
390
390
|
if (vLabel.hasOwnProperty("labelpos")) {
|
package/lib/position/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
let util = require("../util");
|
|
4
|
+
let positionX = require("./bk").positionX;
|
|
5
5
|
|
|
6
6
|
module.exports = position;
|
|
7
7
|
|
|
@@ -13,10 +13,10 @@ function position(g) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
function positionY(g) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
layering.forEach(
|
|
16
|
+
let layering = util.buildLayerMatrix(g);
|
|
17
|
+
let rankSep = g.graph().ranksep;
|
|
18
|
+
let prevY = 0;
|
|
19
|
+
layering.forEach(layer => {
|
|
20
20
|
const maxHeight = layer.reduce((acc, v) => {
|
|
21
21
|
const height = g.node(v).height;
|
|
22
22
|
if (acc > height) {
|
|
@@ -100,7 +100,7 @@ function calcCutValue(t, g, child) {
|
|
|
100
100
|
|
|
101
101
|
cutValue = graphEdge.weight;
|
|
102
102
|
|
|
103
|
-
g.nodeEdges(child).forEach(
|
|
103
|
+
g.nodeEdges(child).forEach(e => {
|
|
104
104
|
var isOutEdge = e.v === child,
|
|
105
105
|
other = isOutEdge ? e.w : e.v;
|
|
106
106
|
|
|
@@ -131,7 +131,7 @@ function dfsAssignLowLim(tree, visited, nextLim, v, parent) {
|
|
|
131
131
|
var label = tree.node(v);
|
|
132
132
|
|
|
133
133
|
visited[v] = true;
|
|
134
|
-
tree.neighbors(v).forEach(
|
|
134
|
+
tree.neighbors(v).forEach(w => {
|
|
135
135
|
if (!visited.hasOwnProperty(w)) {
|
|
136
136
|
nextLim = dfsAssignLowLim(tree, visited, nextLim, w, v);
|
|
137
137
|
}
|
|
@@ -177,7 +177,7 @@ function enterEdge(t, g, edge) {
|
|
|
177
177
|
flip = true;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
var candidates = g.edges().filter(
|
|
180
|
+
var candidates = g.edges().filter(edge => {
|
|
181
181
|
return flip === isDescendant(t, t.node(edge.v), tailLabel) &&
|
|
182
182
|
flip !== isDescendant(t, t.node(edge.w), tailLabel);
|
|
183
183
|
});
|
|
@@ -205,7 +205,7 @@ function updateRanks(t, g) {
|
|
|
205
205
|
var root = t.nodes().find(v => !g.node(v).parent);
|
|
206
206
|
var vs = preorder(t, root);
|
|
207
207
|
vs = vs.slice(1);
|
|
208
|
-
vs.forEach(
|
|
208
|
+
vs.forEach(v => {
|
|
209
209
|
var parent = t.node(v).parent,
|
|
210
210
|
edge = g.edge(v, parent),
|
|
211
211
|
flipped = false;
|