@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/layout.js
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
Graph = require("./graphlib").Graph;
|
|
3
|
+
var acyclic = require("./acyclic");
|
|
4
|
+
var normalize = require("./normalize");
|
|
5
|
+
var rank = require("./rank");
|
|
6
|
+
var normalizeRanks = require("./util").normalizeRanks;
|
|
7
|
+
var parentDummyChains = require("./parent-dummy-chains");
|
|
8
|
+
var removeEmptyRanks = require("./util").removeEmptyRanks;
|
|
9
|
+
var nestingGraph = require("./nesting-graph");
|
|
10
|
+
var addBorderSegments = require("./add-border-segments");
|
|
11
|
+
var coordinateSystem = require("./coordinate-system");
|
|
12
|
+
var order = require("./order");
|
|
13
|
+
var position = require("./position");
|
|
14
|
+
var util = require("./util");
|
|
15
|
+
var Graph = require("@dagrejs/graphlib").Graph;
|
|
17
16
|
|
|
18
17
|
module.exports = layout;
|
|
19
18
|
|
|
20
19
|
function layout(g, opts) {
|
|
21
20
|
var time = opts && opts.debugTiming ? util.time : util.notime;
|
|
22
21
|
time("layout", function() {
|
|
23
|
-
var layoutGraph =
|
|
24
|
-
|
|
22
|
+
var layoutGraph =
|
|
23
|
+
time(" buildLayoutGraph", function() { return buildLayoutGraph(g); });
|
|
25
24
|
time(" runLayout", function() { runLayout(layoutGraph, time); });
|
|
26
25
|
time(" updateInputGraph", function() { updateInputGraph(g, layoutGraph); });
|
|
27
26
|
});
|
|
@@ -64,13 +63,14 @@ function runLayout(g, time) {
|
|
|
64
63
|
* attributes can influence layout.
|
|
65
64
|
*/
|
|
66
65
|
function updateInputGraph(inputGraph, layoutGraph) {
|
|
67
|
-
|
|
68
|
-
var inputLabel = inputGraph.node(v)
|
|
69
|
-
|
|
66
|
+
inputGraph.nodes().forEach(v => {
|
|
67
|
+
var inputLabel = inputGraph.node(v);
|
|
68
|
+
var layoutLabel = layoutGraph.node(v);
|
|
70
69
|
|
|
71
70
|
if (inputLabel) {
|
|
72
71
|
inputLabel.x = layoutLabel.x;
|
|
73
72
|
inputLabel.y = layoutLabel.y;
|
|
73
|
+
inputLabel.rank = layoutLabel.rank;
|
|
74
74
|
|
|
75
75
|
if (layoutGraph.children(v).length) {
|
|
76
76
|
inputLabel.width = layoutLabel.width;
|
|
@@ -79,12 +79,12 @@ function updateInputGraph(inputGraph, layoutGraph) {
|
|
|
79
79
|
}
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
var inputLabel = inputGraph.edge(e)
|
|
84
|
-
|
|
82
|
+
inputGraph.edges().forEach(e => {
|
|
83
|
+
var inputLabel = inputGraph.edge(e);
|
|
84
|
+
var layoutLabel = layoutGraph.edge(e);
|
|
85
85
|
|
|
86
86
|
inputLabel.points = layoutLabel.points;
|
|
87
|
-
if (
|
|
87
|
+
if (layoutLabel.hasOwnProperty("x")) {
|
|
88
88
|
inputLabel.x = layoutLabel.x;
|
|
89
89
|
inputLabel.y = layoutLabel.y;
|
|
90
90
|
}
|
|
@@ -94,17 +94,17 @@ function updateInputGraph(inputGraph, layoutGraph) {
|
|
|
94
94
|
inputGraph.graph().height = layoutGraph.graph().height;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
var graphNumAttrs = ["nodesep", "edgesep", "ranksep", "marginx", "marginy"]
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
97
|
+
var graphNumAttrs = ["nodesep", "edgesep", "ranksep", "marginx", "marginy"];
|
|
98
|
+
var graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: "tb" };
|
|
99
|
+
var graphAttrs = ["acyclicer", "ranker", "rankdir", "align"];
|
|
100
|
+
var nodeNumAttrs = ["width", "height"];
|
|
101
|
+
var nodeDefaults = { width: 0, height: 0 };
|
|
102
|
+
var edgeNumAttrs = ["minlen", "weight", "width", "height", "labeloffset"];
|
|
103
|
+
var edgeDefaults = {
|
|
104
|
+
minlen: 1, weight: 1, width: 0, height: 0,
|
|
105
|
+
labeloffset: 10, labelpos: "r"
|
|
106
|
+
};
|
|
107
|
+
var edgeAttrs = ["labelpos"];
|
|
108
108
|
|
|
109
109
|
/*
|
|
110
110
|
* Constructs a new graph from the input graph, which can be used for layout.
|
|
@@ -113,26 +113,33 @@ var graphNumAttrs = ["nodesep", "edgesep", "ranksep", "marginx", "marginy"],
|
|
|
113
113
|
* attributes can influence layout.
|
|
114
114
|
*/
|
|
115
115
|
function buildLayoutGraph(inputGraph) {
|
|
116
|
-
var g = new Graph({ multigraph: true, compound: true })
|
|
117
|
-
|
|
116
|
+
var g = new Graph({ multigraph: true, compound: true });
|
|
117
|
+
var graph = canonicalize(inputGraph.graph());
|
|
118
118
|
|
|
119
|
-
g.setGraph(
|
|
119
|
+
g.setGraph(Object.assign({},
|
|
120
120
|
graphDefaults,
|
|
121
121
|
selectNumberAttrs(graph, graphNumAttrs),
|
|
122
|
-
|
|
122
|
+
util.pick(graph, graphAttrs)));
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
inputGraph.nodes().forEach(v => {
|
|
125
125
|
var node = canonicalize(inputGraph.node(v));
|
|
126
|
-
|
|
126
|
+
const newNode = selectNumberAttrs(node, nodeNumAttrs);
|
|
127
|
+
Object.keys(nodeDefaults).forEach(k => {
|
|
128
|
+
if (newNode[k] === undefined) {
|
|
129
|
+
newNode[k] = nodeDefaults[k];
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
g.setNode(v, newNode);
|
|
127
134
|
g.setParent(v, inputGraph.parent(v));
|
|
128
135
|
});
|
|
129
136
|
|
|
130
|
-
|
|
137
|
+
inputGraph.edges().forEach(e => {
|
|
131
138
|
var edge = canonicalize(inputGraph.edge(e));
|
|
132
|
-
g.setEdge(e,
|
|
139
|
+
g.setEdge(e, Object.assign({},
|
|
133
140
|
edgeDefaults,
|
|
134
141
|
selectNumberAttrs(edge, edgeNumAttrs),
|
|
135
|
-
|
|
142
|
+
util.pick(edge, edgeAttrs)));
|
|
136
143
|
});
|
|
137
144
|
|
|
138
145
|
return g;
|
|
@@ -149,7 +156,7 @@ function buildLayoutGraph(inputGraph) {
|
|
|
149
156
|
function makeSpaceForEdgeLabels(g) {
|
|
150
157
|
var graph = g.graph();
|
|
151
158
|
graph.ranksep /= 2;
|
|
152
|
-
|
|
159
|
+
g.edges().forEach(e => {
|
|
153
160
|
var edge = g.edge(e);
|
|
154
161
|
edge.minlen *= 2;
|
|
155
162
|
if (edge.labelpos.toLowerCase() !== "c") {
|
|
@@ -169,12 +176,12 @@ function makeSpaceForEdgeLabels(g) {
|
|
|
169
176
|
* label's position.
|
|
170
177
|
*/
|
|
171
178
|
function injectEdgeLabelProxies(g) {
|
|
172
|
-
|
|
179
|
+
g.edges().forEach(e => {
|
|
173
180
|
var edge = g.edge(e);
|
|
174
181
|
if (edge.width && edge.height) {
|
|
175
|
-
var v = g.node(e.v)
|
|
176
|
-
|
|
177
|
-
|
|
182
|
+
var v = g.node(e.v);
|
|
183
|
+
var w = g.node(e.w);
|
|
184
|
+
var label = { rank: (w.rank - v.rank) / 2 + v.rank, e: e };
|
|
178
185
|
util.addDummyNode(g, "edge-proxy", label, "_ep");
|
|
179
186
|
}
|
|
180
187
|
});
|
|
@@ -182,19 +189,19 @@ function injectEdgeLabelProxies(g) {
|
|
|
182
189
|
|
|
183
190
|
function assignRankMinMax(g) {
|
|
184
191
|
var maxRank = 0;
|
|
185
|
-
|
|
192
|
+
g.nodes().forEach(v => {
|
|
186
193
|
var node = g.node(v);
|
|
187
194
|
if (node.borderTop) {
|
|
188
195
|
node.minRank = g.node(node.borderTop).rank;
|
|
189
196
|
node.maxRank = g.node(node.borderBottom).rank;
|
|
190
|
-
maxRank =
|
|
197
|
+
maxRank = Math.max(maxRank, node.maxRank);
|
|
191
198
|
}
|
|
192
199
|
});
|
|
193
200
|
g.graph().maxRank = maxRank;
|
|
194
201
|
}
|
|
195
202
|
|
|
196
203
|
function removeEdgeLabelProxies(g) {
|
|
197
|
-
|
|
204
|
+
g.nodes().forEach(v => {
|
|
198
205
|
var node = g.node(v);
|
|
199
206
|
if (node.dummy === "edge-proxy") {
|
|
200
207
|
g.edge(node.e).labelRank = node.rank;
|
|
@@ -204,29 +211,29 @@ function removeEdgeLabelProxies(g) {
|
|
|
204
211
|
}
|
|
205
212
|
|
|
206
213
|
function translateGraph(g) {
|
|
207
|
-
var minX = Number.POSITIVE_INFINITY
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
+
var minX = Number.POSITIVE_INFINITY;
|
|
215
|
+
var maxX = 0;
|
|
216
|
+
var minY = Number.POSITIVE_INFINITY;
|
|
217
|
+
var maxY = 0;
|
|
218
|
+
var graphLabel = g.graph();
|
|
219
|
+
var marginX = graphLabel.marginx || 0;
|
|
220
|
+
var marginY = graphLabel.marginy || 0;
|
|
214
221
|
|
|
215
222
|
function getExtremes(attrs) {
|
|
216
|
-
var x = attrs.x
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
223
|
+
var x = attrs.x;
|
|
224
|
+
var y = attrs.y;
|
|
225
|
+
var w = attrs.width;
|
|
226
|
+
var h = attrs.height;
|
|
220
227
|
minX = Math.min(minX, x - w / 2);
|
|
221
228
|
maxX = Math.max(maxX, x + w / 2);
|
|
222
229
|
minY = Math.min(minY, y - h / 2);
|
|
223
230
|
maxY = Math.max(maxY, y + h / 2);
|
|
224
231
|
}
|
|
225
232
|
|
|
226
|
-
|
|
227
|
-
|
|
233
|
+
g.nodes().forEach(v => getExtremes(g.node(v)));
|
|
234
|
+
g.edges().forEach(e => {
|
|
228
235
|
var edge = g.edge(e);
|
|
229
|
-
if (
|
|
236
|
+
if (edge.hasOwnProperty("x")) {
|
|
230
237
|
getExtremes(edge);
|
|
231
238
|
}
|
|
232
239
|
});
|
|
@@ -234,20 +241,20 @@ function translateGraph(g) {
|
|
|
234
241
|
minX -= marginX;
|
|
235
242
|
minY -= marginY;
|
|
236
243
|
|
|
237
|
-
|
|
244
|
+
g.nodes().forEach(v => {
|
|
238
245
|
var node = g.node(v);
|
|
239
246
|
node.x -= minX;
|
|
240
247
|
node.y -= minY;
|
|
241
248
|
});
|
|
242
249
|
|
|
243
|
-
|
|
250
|
+
g.edges().forEach(e => {
|
|
244
251
|
var edge = g.edge(e);
|
|
245
|
-
|
|
252
|
+
edge.points.forEach(p => {
|
|
246
253
|
p.x -= minX;
|
|
247
254
|
p.y -= minY;
|
|
248
255
|
});
|
|
249
|
-
if (
|
|
250
|
-
if (
|
|
256
|
+
if (edge.hasOwnProperty("x")) { edge.x -= minX; }
|
|
257
|
+
if (edge.hasOwnProperty("y")) { edge.y -= minY; }
|
|
251
258
|
});
|
|
252
259
|
|
|
253
260
|
graphLabel.width = maxX - minX + marginX;
|
|
@@ -255,11 +262,11 @@ function translateGraph(g) {
|
|
|
255
262
|
}
|
|
256
263
|
|
|
257
264
|
function assignNodeIntersects(g) {
|
|
258
|
-
|
|
259
|
-
var edge = g.edge(e)
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
265
|
+
g.edges().forEach(e => {
|
|
266
|
+
var edge = g.edge(e);
|
|
267
|
+
var nodeV = g.node(e.v);
|
|
268
|
+
var nodeW = g.node(e.w);
|
|
269
|
+
var p1, p2;
|
|
263
270
|
if (!edge.points) {
|
|
264
271
|
edge.points = [];
|
|
265
272
|
p1 = nodeW;
|
|
@@ -274,22 +281,22 @@ function assignNodeIntersects(g) {
|
|
|
274
281
|
}
|
|
275
282
|
|
|
276
283
|
function fixupEdgeLabelCoords(g) {
|
|
277
|
-
|
|
284
|
+
g.edges().forEach(e => {
|
|
278
285
|
var edge = g.edge(e);
|
|
279
|
-
if (
|
|
286
|
+
if (edge.hasOwnProperty("x")) {
|
|
280
287
|
if (edge.labelpos === "l" || edge.labelpos === "r") {
|
|
281
288
|
edge.width -= edge.labeloffset;
|
|
282
289
|
}
|
|
283
290
|
switch (edge.labelpos) {
|
|
284
|
-
|
|
285
|
-
|
|
291
|
+
case "l": edge.x -= edge.width / 2 + edge.labeloffset; break;
|
|
292
|
+
case "r": edge.x += edge.width / 2 + edge.labeloffset; break;
|
|
286
293
|
}
|
|
287
294
|
}
|
|
288
295
|
});
|
|
289
296
|
}
|
|
290
297
|
|
|
291
298
|
function reversePointsForReversedEdges(g) {
|
|
292
|
-
|
|
299
|
+
g.edges().forEach(e => {
|
|
293
300
|
var edge = g.edge(e);
|
|
294
301
|
if (edge.reversed) {
|
|
295
302
|
edge.points.reverse();
|
|
@@ -298,13 +305,13 @@ function reversePointsForReversedEdges(g) {
|
|
|
298
305
|
}
|
|
299
306
|
|
|
300
307
|
function removeBorderNodes(g) {
|
|
301
|
-
|
|
308
|
+
g.nodes().forEach(v => {
|
|
302
309
|
if (g.children(v).length) {
|
|
303
|
-
var node = g.node(v)
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
310
|
+
var node = g.node(v);
|
|
311
|
+
var t = g.node(node.borderTop);
|
|
312
|
+
var b = g.node(node.borderBottom);
|
|
313
|
+
var l = g.node(node.borderLeft[node.borderLeft.length - 1]);
|
|
314
|
+
var r = g.node(node.borderRight[node.borderRight.length - 1]);
|
|
308
315
|
|
|
309
316
|
node.width = Math.abs(r.x - l.x);
|
|
310
317
|
node.height = Math.abs(b.y - t.y);
|
|
@@ -313,7 +320,7 @@ function removeBorderNodes(g) {
|
|
|
313
320
|
}
|
|
314
321
|
});
|
|
315
322
|
|
|
316
|
-
|
|
323
|
+
g.nodes().forEach(v => {
|
|
317
324
|
if (g.node(v).dummy === "border") {
|
|
318
325
|
g.removeNode(v);
|
|
319
326
|
}
|
|
@@ -321,7 +328,7 @@ function removeBorderNodes(g) {
|
|
|
321
328
|
}
|
|
322
329
|
|
|
323
330
|
function removeSelfEdges(g) {
|
|
324
|
-
|
|
331
|
+
g.edges().forEach(e => {
|
|
325
332
|
if (e.v === e.w) {
|
|
326
333
|
var node = g.node(e.v);
|
|
327
334
|
if (!node.selfEdges) {
|
|
@@ -335,12 +342,12 @@ function removeSelfEdges(g) {
|
|
|
335
342
|
|
|
336
343
|
function insertSelfEdges(g) {
|
|
337
344
|
var layers = util.buildLayerMatrix(g);
|
|
338
|
-
|
|
345
|
+
layers.forEach(layer => {
|
|
339
346
|
var orderShift = 0;
|
|
340
|
-
|
|
347
|
+
layer.forEach((v, i) => {
|
|
341
348
|
var node = g.node(v);
|
|
342
349
|
node.order = i + orderShift;
|
|
343
|
-
|
|
350
|
+
(node.selfEdges || []).forEach(selfEdge => {
|
|
344
351
|
util.addDummyNode(g, "selfedge", {
|
|
345
352
|
width: selfEdge.label.width,
|
|
346
353
|
height: selfEdge.label.height,
|
|
@@ -356,14 +363,14 @@ function insertSelfEdges(g) {
|
|
|
356
363
|
}
|
|
357
364
|
|
|
358
365
|
function positionSelfEdges(g) {
|
|
359
|
-
|
|
366
|
+
g.nodes().forEach(v => {
|
|
360
367
|
var node = g.node(v);
|
|
361
368
|
if (node.dummy === "selfedge") {
|
|
362
|
-
var selfNode = g.node(node.e.v)
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
369
|
+
var selfNode = g.node(node.e.v);
|
|
370
|
+
var x = selfNode.x + selfNode.width / 2;
|
|
371
|
+
var y = selfNode.y;
|
|
372
|
+
var dx = node.x - x;
|
|
373
|
+
var dy = selfNode.height / 2;
|
|
367
374
|
g.setEdge(node.e, node.label);
|
|
368
375
|
g.removeNode(v);
|
|
369
376
|
node.label.points = [
|
|
@@ -380,13 +387,19 @@ function positionSelfEdges(g) {
|
|
|
380
387
|
}
|
|
381
388
|
|
|
382
389
|
function selectNumberAttrs(obj, attrs) {
|
|
383
|
-
return
|
|
390
|
+
return util.mapValues(util.pick(obj, attrs), Number);
|
|
384
391
|
}
|
|
385
392
|
|
|
386
393
|
function canonicalize(attrs) {
|
|
387
394
|
var newAttrs = {};
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
395
|
+
if (attrs) {
|
|
396
|
+
Object.entries(attrs).forEach(([k, v]) => {
|
|
397
|
+
if (typeof k === "string") {
|
|
398
|
+
k = k.toLowerCase();
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
newAttrs[k] = v;
|
|
402
|
+
});
|
|
403
|
+
}
|
|
391
404
|
return newAttrs;
|
|
392
405
|
}
|
package/lib/nesting-graph.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
var
|
|
2
|
-
util = require("./util");
|
|
1
|
+
var util = require("./util");
|
|
3
2
|
|
|
4
3
|
module.exports = {
|
|
5
4
|
run: run,
|
|
@@ -32,19 +31,19 @@ module.exports = {
|
|
|
32
31
|
function run(g) {
|
|
33
32
|
var root = util.addDummyNode(g, "root", {}, "_root");
|
|
34
33
|
var depths = treeDepths(g);
|
|
35
|
-
var height =
|
|
34
|
+
var height = Math.max(...Object.values(depths)) - 1; // Note: depths is an Object not an array
|
|
36
35
|
var nodeSep = 2 * height + 1;
|
|
37
36
|
|
|
38
37
|
g.graph().nestingRoot = root;
|
|
39
38
|
|
|
40
39
|
// Multiply minlen by nodeSep to align nodes on non-border ranks.
|
|
41
|
-
|
|
40
|
+
g.edges().forEach(e => g.edge(e).minlen *= nodeSep);
|
|
42
41
|
|
|
43
42
|
// Calculate a weight that is sufficient to keep subgraphs vertically compact
|
|
44
43
|
var weight = sumWeights(g) + 1;
|
|
45
44
|
|
|
46
45
|
// Create border nodes and link them up
|
|
47
|
-
|
|
46
|
+
g.children().forEach(function(child) {
|
|
48
47
|
dfs(g, root, nodeSep, weight, height, depths, child);
|
|
49
48
|
});
|
|
50
49
|
|
|
@@ -62,23 +61,23 @@ function dfs(g, root, nodeSep, weight, height, depths, v) {
|
|
|
62
61
|
return;
|
|
63
62
|
}
|
|
64
63
|
|
|
65
|
-
var top = util.addBorderNode(g, "_bt")
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
var top = util.addBorderNode(g, "_bt");
|
|
65
|
+
var bottom = util.addBorderNode(g, "_bb");
|
|
66
|
+
var label = g.node(v);
|
|
68
67
|
|
|
69
68
|
g.setParent(top, v);
|
|
70
69
|
label.borderTop = top;
|
|
71
70
|
g.setParent(bottom, v);
|
|
72
71
|
label.borderBottom = bottom;
|
|
73
72
|
|
|
74
|
-
|
|
73
|
+
children.forEach(function(child) {
|
|
75
74
|
dfs(g, root, nodeSep, weight, height, depths, child);
|
|
76
75
|
|
|
77
|
-
var childNode = g.node(child)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
76
|
+
var childNode = g.node(child);
|
|
77
|
+
var childTop = childNode.borderTop ? childNode.borderTop : child;
|
|
78
|
+
var childBottom = childNode.borderBottom ? childNode.borderBottom : child;
|
|
79
|
+
var thisWeight = childNode.borderTop ? weight : 2 * weight;
|
|
80
|
+
var minlen = childTop !== childBottom ? 1 : height - depths[v] + 1;
|
|
82
81
|
|
|
83
82
|
g.setEdge(top, childTop, {
|
|
84
83
|
weight: thisWeight,
|
|
@@ -103,27 +102,23 @@ function treeDepths(g) {
|
|
|
103
102
|
function dfs(v, depth) {
|
|
104
103
|
var children = g.children(v);
|
|
105
104
|
if (children && children.length) {
|
|
106
|
-
|
|
107
|
-
dfs(child, depth + 1);
|
|
108
|
-
});
|
|
105
|
+
children.forEach(child => dfs(child, depth + 1));
|
|
109
106
|
}
|
|
110
107
|
depths[v] = depth;
|
|
111
108
|
}
|
|
112
|
-
|
|
109
|
+
g.children().forEach(v => dfs(v, 1));
|
|
113
110
|
return depths;
|
|
114
111
|
}
|
|
115
112
|
|
|
116
113
|
function sumWeights(g) {
|
|
117
|
-
return
|
|
118
|
-
return acc + g.edge(e).weight;
|
|
119
|
-
}, 0);
|
|
114
|
+
return g.edges().reduce((acc, e) => acc + g.edge(e).weight, 0);
|
|
120
115
|
}
|
|
121
116
|
|
|
122
117
|
function cleanup(g) {
|
|
123
118
|
var graphLabel = g.graph();
|
|
124
119
|
g.removeNode(graphLabel.nestingRoot);
|
|
125
120
|
delete graphLabel.nestingRoot;
|
|
126
|
-
|
|
121
|
+
g.edges().forEach(e => {
|
|
127
122
|
var edge = g.edge(e);
|
|
128
123
|
if (edge.nestingEdge) {
|
|
129
124
|
g.removeEdge(e);
|
package/lib/normalize.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
util = require("./util");
|
|
3
|
+
var util = require("./util");
|
|
5
4
|
|
|
6
5
|
module.exports = {
|
|
7
6
|
run: run,
|
|
@@ -26,17 +25,17 @@ module.exports = {
|
|
|
26
25
|
*/
|
|
27
26
|
function run(g) {
|
|
28
27
|
g.graph().dummyChains = [];
|
|
29
|
-
|
|
28
|
+
g.edges().forEach(edge => normalizeEdge(g, edge));
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
function normalizeEdge(g, e) {
|
|
33
|
-
var v = e.v
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
var v = e.v;
|
|
33
|
+
var vRank = g.node(v).rank;
|
|
34
|
+
var w = e.w;
|
|
35
|
+
var wRank = g.node(w).rank;
|
|
36
|
+
var name = e.name;
|
|
37
|
+
var edgeLabel = g.edge(e);
|
|
38
|
+
var labelRank = edgeLabel.labelRank;
|
|
40
39
|
|
|
41
40
|
if (wRank === vRank + 1) return;
|
|
42
41
|
|
|
@@ -68,10 +67,10 @@ function normalizeEdge(g, e) {
|
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
function undo(g) {
|
|
71
|
-
|
|
72
|
-
var node = g.node(v)
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
g.graph().dummyChains.forEach(function(v) {
|
|
71
|
+
var node = g.node(v);
|
|
72
|
+
var origLabel = node.edgeLabel;
|
|
73
|
+
var w;
|
|
75
74
|
g.setEdge(node.edgeObj, origLabel);
|
|
76
75
|
while (node.dummy) {
|
|
77
76
|
w = g.successors(v)[0];
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
var _ = require("../lodash");
|
|
2
|
-
|
|
3
1
|
module.exports = addSubgraphConstraints;
|
|
4
2
|
|
|
5
3
|
function addSubgraphConstraints(g, cg, vs) {
|
|
6
4
|
var prev = {},
|
|
7
|
-
|
|
5
|
+
rootPrev;
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
vs.forEach(function(v) {
|
|
10
8
|
var child = g.parent(v),
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
parent,
|
|
10
|
+
prevChild;
|
|
13
11
|
while (child) {
|
|
14
12
|
parent = g.parent(child);
|
|
15
13
|
if (parent) {
|
|
@@ -33,14 +31,14 @@ function addSubgraphConstraints(g, cg, vs) {
|
|
|
33
31
|
if (children.length) {
|
|
34
32
|
var min = Number.POSITIVE_INFINITY,
|
|
35
33
|
subgraphs = [];
|
|
36
|
-
|
|
34
|
+
children.forEach(function(child) {
|
|
37
35
|
var childMin = dfs(child);
|
|
38
36
|
if (g.children(child).length) {
|
|
39
37
|
subgraphs.push({ v: child, order: childMin });
|
|
40
38
|
}
|
|
41
39
|
min = Math.min(min, childMin);
|
|
42
40
|
});
|
|
43
|
-
_.
|
|
41
|
+
_.sortBy(subgraphs, "order").reduce(function(prev, curr) {
|
|
44
42
|
cg.setEdge(prev.v, curr.v);
|
|
45
43
|
return curr;
|
|
46
44
|
});
|
package/lib/order/barycenter.js
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
var _ = require("../lodash");
|
|
2
|
-
|
|
3
1
|
module.exports = barycenter;
|
|
4
2
|
|
|
5
|
-
function barycenter(g, movable) {
|
|
6
|
-
return
|
|
3
|
+
function barycenter(g, movable = []) {
|
|
4
|
+
return movable.map(v => {
|
|
7
5
|
var inV = g.inEdges(v);
|
|
8
6
|
if (!inV.length) {
|
|
9
7
|
return { v: v };
|
|
10
8
|
} else {
|
|
11
|
-
var result =
|
|
9
|
+
var result = inV.reduce((acc, e) => {
|
|
12
10
|
var edge = g.edge(e),
|
|
13
|
-
|
|
11
|
+
nodeU = g.node(e.v);
|
|
14
12
|
return {
|
|
15
13
|
sum: acc.sum + (edge.weight * nodeU.order),
|
|
16
14
|
weight: acc.weight + edge.weight
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
var
|
|
2
|
-
|
|
1
|
+
var Graph = require("@dagrejs/graphlib").Graph;
|
|
2
|
+
var util = require("../util");
|
|
3
3
|
|
|
4
4
|
module.exports = buildLayerGraph;
|
|
5
5
|
|
|
@@ -35,26 +35,26 @@ module.exports = buildLayerGraph;
|
|
|
35
35
|
*/
|
|
36
36
|
function buildLayerGraph(g, rank, relationship) {
|
|
37
37
|
var root = createRootNode(g),
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
result = new Graph({ compound: true }).setGraph({ root: root })
|
|
39
|
+
.setDefaultNodeLabel(function(v) { return g.node(v); });
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
g.nodes().forEach(function(v) {
|
|
42
42
|
var node = g.node(v),
|
|
43
|
-
|
|
43
|
+
parent = g.parent(v);
|
|
44
44
|
|
|
45
45
|
if (node.rank === rank || node.minRank <= rank && rank <= node.maxRank) {
|
|
46
46
|
result.setNode(v);
|
|
47
47
|
result.setParent(v, parent || root);
|
|
48
48
|
|
|
49
49
|
// This assumes we have only short edges!
|
|
50
|
-
|
|
50
|
+
g[relationship](v).forEach(function(e) {
|
|
51
51
|
var u = e.v === v ? e.w : e.v,
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
edge = result.edge(u, v),
|
|
53
|
+
weight = edge !== undefined ? edge.weight : 0;
|
|
54
54
|
result.setEdge(u, v, { weight: g.edge(e).weight + weight });
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
if (
|
|
57
|
+
if (node.hasOwnProperty("minRank")) {
|
|
58
58
|
result.setNode(v, {
|
|
59
59
|
borderLeft: node.borderLeft[rank],
|
|
60
60
|
borderRight: node.borderRight[rank]
|
|
@@ -68,6 +68,6 @@ function buildLayerGraph(g, rank, relationship) {
|
|
|
68
68
|
|
|
69
69
|
function createRootNode(g) {
|
|
70
70
|
var v;
|
|
71
|
-
while (g.hasNode((v =
|
|
71
|
+
while (g.hasNode((v = util.uniqueId("_root"))));
|
|
72
72
|
return v;
|
|
73
73
|
}
|