@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/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;
|
package/lib/util.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
6
6
|
|
|
7
7
|
module.exports = {
|
|
8
8
|
addBorderNode,
|
|
@@ -30,7 +30,7 @@ module.exports = {
|
|
|
30
30
|
* Adds a dummy node to the graph and return v.
|
|
31
31
|
*/
|
|
32
32
|
function addDummyNode(g, type, attrs, name) {
|
|
33
|
-
|
|
33
|
+
let v;
|
|
34
34
|
do {
|
|
35
35
|
v = uniqueId(name);
|
|
36
36
|
} while (g.hasNode(v));
|
|
@@ -45,11 +45,11 @@ function addDummyNode(g, type, attrs, name) {
|
|
|
45
45
|
* associated with multi-edges.
|
|
46
46
|
*/
|
|
47
47
|
function simplify(g) {
|
|
48
|
-
|
|
48
|
+
let simplified = new Graph().setGraph(g.graph());
|
|
49
49
|
g.nodes().forEach(v => simplified.setNode(v, g.node(v)));
|
|
50
50
|
g.edges().forEach(e => {
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
let simpleLabel = simplified.edge(e.v, e.w) || { weight: 0, minlen: 1 };
|
|
52
|
+
let label = g.edge(e);
|
|
53
53
|
simplified.setEdge(e.v, e.w, {
|
|
54
54
|
weight: simpleLabel.weight + label.weight,
|
|
55
55
|
minlen: Math.max(simpleLabel.minlen, label.minlen)
|
|
@@ -59,7 +59,7 @@ function simplify(g) {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
function asNonCompoundGraph(g) {
|
|
62
|
-
|
|
62
|
+
let simplified = new Graph({ multigraph: g.isMultigraph() }).setGraph(g.graph());
|
|
63
63
|
g.nodes().forEach(v => {
|
|
64
64
|
if (!g.children(v).length) {
|
|
65
65
|
simplified.setNode(v, g.node(v));
|
|
@@ -72,8 +72,8 @@ function asNonCompoundGraph(g) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
function successorWeights(g) {
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
let weightMap = g.nodes().map(v => {
|
|
76
|
+
let sucs = {};
|
|
77
77
|
g.outEdges(v).forEach(e => {
|
|
78
78
|
sucs[e.w] = (sucs[e.w] || 0) + g.edge(e).weight;
|
|
79
79
|
});
|
|
@@ -83,8 +83,8 @@ function successorWeights(g) {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
function predecessorWeights(g) {
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
let weightMap = g.nodes().map(v => {
|
|
87
|
+
let preds = {};
|
|
88
88
|
g.inEdges(v).forEach(e => {
|
|
89
89
|
preds[e.v] = (preds[e.v] || 0) + g.edge(e).weight;
|
|
90
90
|
});
|
|
@@ -98,21 +98,21 @@ function predecessorWeights(g) {
|
|
|
98
98
|
* ({x, y, width, height}) if it were pointing at the rectangle's center.
|
|
99
99
|
*/
|
|
100
100
|
function intersectRect(rect, point) {
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
let x = rect.x;
|
|
102
|
+
let y = rect.y;
|
|
103
103
|
|
|
104
104
|
// Rectangle intersection algorithm from:
|
|
105
105
|
// http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
let dx = point.x - x;
|
|
107
|
+
let dy = point.y - y;
|
|
108
|
+
let w = rect.width / 2;
|
|
109
|
+
let h = rect.height / 2;
|
|
110
110
|
|
|
111
111
|
if (!dx && !dy) {
|
|
112
112
|
throw new Error("Not possible to find intersection inside of the rectangle");
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
let sx, sy;
|
|
116
116
|
if (Math.abs(dy) * w > Math.abs(dx) * h) {
|
|
117
117
|
// Intersection is top or bottom of rect.
|
|
118
118
|
if (dy < 0) {
|
|
@@ -137,10 +137,10 @@ function intersectRect(rect, point) {
|
|
|
137
137
|
* function will produce a matrix with the ids of each node.
|
|
138
138
|
*/
|
|
139
139
|
function buildLayerMatrix(g) {
|
|
140
|
-
|
|
140
|
+
let layering = range(maxRank(g) + 1).map(() => []);
|
|
141
141
|
g.nodes().forEach(v => {
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
let node = g.node(v);
|
|
143
|
+
let rank = node.rank;
|
|
144
144
|
if (rank !== undefined) {
|
|
145
145
|
layering[rank][node.order] = v;
|
|
146
146
|
}
|
|
@@ -153,8 +153,8 @@ function buildLayerMatrix(g) {
|
|
|
153
153
|
* rank(v) >= 0 and at least one node w has rank(w) = 0.
|
|
154
154
|
*/
|
|
155
155
|
function normalizeRanks(g) {
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
let min = Math.min(...g.nodes().map(v => {
|
|
157
|
+
let rank = g.node(v).rank;
|
|
158
158
|
if (rank === undefined) {
|
|
159
159
|
return Number.MAX_VALUE;
|
|
160
160
|
}
|
|
@@ -162,7 +162,7 @@ function normalizeRanks(g) {
|
|
|
162
162
|
return rank;
|
|
163
163
|
}));
|
|
164
164
|
g.nodes().forEach(v => {
|
|
165
|
-
|
|
165
|
+
let node = g.node(v);
|
|
166
166
|
if (node.hasOwnProperty("rank")) {
|
|
167
167
|
node.rank -= min;
|
|
168
168
|
}
|
|
@@ -171,19 +171,19 @@ function normalizeRanks(g) {
|
|
|
171
171
|
|
|
172
172
|
function removeEmptyRanks(g) {
|
|
173
173
|
// Ranks may not start at 0, so we need to offset them
|
|
174
|
-
|
|
174
|
+
let offset = Math.min(...g.nodes().map(v => g.node(v).rank));
|
|
175
175
|
|
|
176
|
-
|
|
176
|
+
let layers = [];
|
|
177
177
|
g.nodes().forEach(v => {
|
|
178
|
-
|
|
178
|
+
let rank = g.node(v).rank - offset;
|
|
179
179
|
if (!layers[rank]) {
|
|
180
180
|
layers[rank] = [];
|
|
181
181
|
}
|
|
182
182
|
layers[rank].push(v);
|
|
183
183
|
});
|
|
184
184
|
|
|
185
|
-
|
|
186
|
-
|
|
185
|
+
let delta = 0;
|
|
186
|
+
let nodeRankFactor = g.graph().nodeRankFactor;
|
|
187
187
|
Array.from(layers).forEach((vs, i) => {
|
|
188
188
|
if (vs === undefined && i % nodeRankFactor !== 0) {
|
|
189
189
|
--delta;
|
|
@@ -194,7 +194,7 @@ function removeEmptyRanks(g) {
|
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
function addBorderNode(g, prefix, rank, order) {
|
|
197
|
-
|
|
197
|
+
let node = {
|
|
198
198
|
width: 0,
|
|
199
199
|
height: 0
|
|
200
200
|
};
|
|
@@ -207,7 +207,7 @@ function addBorderNode(g, prefix, rank, order) {
|
|
|
207
207
|
|
|
208
208
|
function maxRank(g) {
|
|
209
209
|
return Math.max(...g.nodes().map(v => {
|
|
210
|
-
|
|
210
|
+
let rank = g.node(v).rank;
|
|
211
211
|
if (rank === undefined) {
|
|
212
212
|
return Number.MIN_VALUE;
|
|
213
213
|
}
|
|
@@ -222,7 +222,7 @@ function maxRank(g) {
|
|
|
222
222
|
* into `rhs.
|
|
223
223
|
*/
|
|
224
224
|
function partition(collection, fn) {
|
|
225
|
-
|
|
225
|
+
let result = { lhs: [], rhs: [] };
|
|
226
226
|
collection.forEach(value => {
|
|
227
227
|
if (fn(value)) {
|
|
228
228
|
result.lhs.push(value);
|
|
@@ -238,7 +238,7 @@ function partition(collection, fn) {
|
|
|
238
238
|
* time it takes to execute the function.
|
|
239
239
|
*/
|
|
240
240
|
function time(name, fn) {
|
|
241
|
-
|
|
241
|
+
let start = Date.now();
|
|
242
242
|
try {
|
|
243
243
|
return fn();
|
|
244
244
|
} finally {
|
package/lib/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
module.exports = "1.0.
|
|
1
|
+
module.exports = "1.0.4";
|