@dagrejs/dagre 1.1.2 → 1.1.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 +1 -1
- package/dist/dagre.js +89 -58
- package/dist/dagre.min.js +31 -31
- package/lib/acyclic.js +2 -2
- package/lib/add-border-segments.js +1 -1
- package/lib/coordinate-system.js +2 -2
- package/lib/layout.js +8 -8
- package/lib/nesting-graph.js +2 -1
- package/lib/order/build-layer-graph.js +1 -1
- package/lib/order/init-order.js +2 -1
- package/lib/order/sort-subgraph.js +2 -2
- package/lib/order/sort.js +1 -1
- package/lib/position/bk.js +7 -7
- package/lib/rank/network-simplex.js +1 -1
- package/lib/rank/util.js +7 -3
- package/lib/util.js +32 -7
- package/lib/version.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# dagre - Graph layout for JavaScript
|
|
2
2
|
|
|
3
3
|
[](https://github.com/dagrejs/dagre/actions?query=workflow%3A%22Build+Status%22)
|
|
4
|
-
[](https://www.npmjs.com/package/dagre)
|
|
4
|
+
[](https://www.npmjs.com/package/@dagrejs/dagre)
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
Dagre is a JavaScript library that makes it easy to lay out directed graphs on the client-side.
|
package/dist/dagre.js
CHANGED
|
@@ -69,13 +69,13 @@ function dfsFAS(g) {
|
|
|
69
69
|
let visited = {};
|
|
70
70
|
|
|
71
71
|
function dfs(v) {
|
|
72
|
-
if (
|
|
72
|
+
if (Object.hasOwn(visited, v)) {
|
|
73
73
|
return;
|
|
74
74
|
}
|
|
75
75
|
visited[v] = true;
|
|
76
76
|
stack[v] = true;
|
|
77
77
|
g.outEdges(v).forEach(e => {
|
|
78
|
-
if (
|
|
78
|
+
if (Object.hasOwn(stack, e.w)) {
|
|
79
79
|
fas.push(e);
|
|
80
80
|
} else {
|
|
81
81
|
dfs(e.w);
|
|
@@ -115,7 +115,7 @@ function addBorderSegments(g) {
|
|
|
115
115
|
children.forEach(dfs);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
if (
|
|
118
|
+
if (Object.hasOwn(node, "minRank")) {
|
|
119
119
|
node.borderLeft = [];
|
|
120
120
|
node.borderRight = [];
|
|
121
121
|
for (let rank = node.minRank, maxRank = node.maxRank + 1;
|
|
@@ -185,7 +185,7 @@ function reverseY(g) {
|
|
|
185
185
|
g.edges().forEach(e => {
|
|
186
186
|
let edge = g.edge(e);
|
|
187
187
|
edge.points.forEach(reverseYOne);
|
|
188
|
-
if (
|
|
188
|
+
if (Object.hasOwn(edge, "y")) {
|
|
189
189
|
reverseYOne(edge);
|
|
190
190
|
}
|
|
191
191
|
});
|
|
@@ -201,7 +201,7 @@ function swapXY(g) {
|
|
|
201
201
|
g.edges().forEach(e => {
|
|
202
202
|
let edge = g.edge(e);
|
|
203
203
|
edge.points.forEach(swapXYOne);
|
|
204
|
-
if (
|
|
204
|
+
if (Object.hasOwn(edge, "x")) {
|
|
205
205
|
swapXYOne(edge);
|
|
206
206
|
}
|
|
207
207
|
});
|
|
@@ -456,12 +456,12 @@ function layout(g, opts) {
|
|
|
456
456
|
time("layout", () => {
|
|
457
457
|
let layoutGraph =
|
|
458
458
|
time(" buildLayoutGraph", () => buildLayoutGraph(g));
|
|
459
|
-
time(" runLayout", () => runLayout(layoutGraph, time));
|
|
459
|
+
time(" runLayout", () => runLayout(layoutGraph, time, opts));
|
|
460
460
|
time(" updateInputGraph", () => updateInputGraph(g, layoutGraph));
|
|
461
461
|
});
|
|
462
462
|
}
|
|
463
463
|
|
|
464
|
-
function runLayout(g, time) {
|
|
464
|
+
function runLayout(g, time, opts) {
|
|
465
465
|
time(" makeSpaceForEdgeLabels", () => makeSpaceForEdgeLabels(g));
|
|
466
466
|
time(" removeSelfEdges", () => removeSelfEdges(g));
|
|
467
467
|
time(" acyclic", () => acyclic.run(g));
|
|
@@ -476,7 +476,7 @@ function runLayout(g, time) {
|
|
|
476
476
|
time(" normalize.run", () => normalize.run(g));
|
|
477
477
|
time(" parentDummyChains", () => parentDummyChains(g));
|
|
478
478
|
time(" addBorderSegments", () => addBorderSegments(g));
|
|
479
|
-
time(" order", () => order(g));
|
|
479
|
+
time(" order", () => order(g, opts));
|
|
480
480
|
time(" insertSelfEdges", () => insertSelfEdges(g));
|
|
481
481
|
time(" adjustCoordinateSystem", () => coordinateSystem.adjust(g));
|
|
482
482
|
time(" position", () => position(g));
|
|
@@ -519,7 +519,7 @@ function updateInputGraph(inputGraph, layoutGraph) {
|
|
|
519
519
|
let layoutLabel = layoutGraph.edge(e);
|
|
520
520
|
|
|
521
521
|
inputLabel.points = layoutLabel.points;
|
|
522
|
-
if (
|
|
522
|
+
if (Object.hasOwn(layoutLabel, "x")) {
|
|
523
523
|
inputLabel.x = layoutLabel.x;
|
|
524
524
|
inputLabel.y = layoutLabel.y;
|
|
525
525
|
}
|
|
@@ -668,7 +668,7 @@ function translateGraph(g) {
|
|
|
668
668
|
g.nodes().forEach(v => getExtremes(g.node(v)));
|
|
669
669
|
g.edges().forEach(e => {
|
|
670
670
|
let edge = g.edge(e);
|
|
671
|
-
if (
|
|
671
|
+
if (Object.hasOwn(edge, "x")) {
|
|
672
672
|
getExtremes(edge);
|
|
673
673
|
}
|
|
674
674
|
});
|
|
@@ -688,8 +688,8 @@ function translateGraph(g) {
|
|
|
688
688
|
p.x -= minX;
|
|
689
689
|
p.y -= minY;
|
|
690
690
|
});
|
|
691
|
-
if (
|
|
692
|
-
if (
|
|
691
|
+
if (Object.hasOwn(edge, "x")) { edge.x -= minX; }
|
|
692
|
+
if (Object.hasOwn(edge, "y")) { edge.y -= minY; }
|
|
693
693
|
});
|
|
694
694
|
|
|
695
695
|
graphLabel.width = maxX - minX + marginX;
|
|
@@ -718,7 +718,7 @@ function assignNodeIntersects(g) {
|
|
|
718
718
|
function fixupEdgeLabelCoords(g) {
|
|
719
719
|
g.edges().forEach(e => {
|
|
720
720
|
let edge = g.edge(e);
|
|
721
|
-
if (
|
|
721
|
+
if (Object.hasOwn(edge, "x")) {
|
|
722
722
|
if (edge.labelpos === "l" || edge.labelpos === "r") {
|
|
723
723
|
edge.width -= edge.labeloffset;
|
|
724
724
|
}
|
|
@@ -873,7 +873,8 @@ module.exports = {
|
|
|
873
873
|
function run(g) {
|
|
874
874
|
let root = util.addDummyNode(g, "root", {}, "_root");
|
|
875
875
|
let depths = treeDepths(g);
|
|
876
|
-
let
|
|
876
|
+
let depthsArr = Object.values(depths);
|
|
877
|
+
let height = util.applyWithChunking(Math.max, depthsArr) - 1; // Note: depths is an Object not an array
|
|
877
878
|
let nodeSep = 2 * height + 1;
|
|
878
879
|
|
|
879
880
|
g.graph().nestingRoot = root;
|
|
@@ -1195,7 +1196,7 @@ function buildLayerGraph(g, rank, relationship) {
|
|
|
1195
1196
|
result.setEdge(u, v, { weight: g.edge(e).weight + weight });
|
|
1196
1197
|
});
|
|
1197
1198
|
|
|
1198
|
-
if (
|
|
1199
|
+
if (Object.hasOwn(node, "minRank")) {
|
|
1199
1200
|
result.setNode(v, {
|
|
1200
1201
|
borderLeft: node.borderLeft[rank],
|
|
1201
1202
|
borderRight: node.borderRight[rank]
|
|
@@ -1385,7 +1386,8 @@ module.exports = initOrder;
|
|
|
1385
1386
|
function initOrder(g) {
|
|
1386
1387
|
let visited = {};
|
|
1387
1388
|
let simpleNodes = g.nodes().filter(v => !g.children(v).length);
|
|
1388
|
-
let
|
|
1389
|
+
let simpleNodesRanks = simpleNodes.map(v => g.node(v).rank);
|
|
1390
|
+
let maxRank = util.applyWithChunking(Math.max, simpleNodesRanks);
|
|
1389
1391
|
let layers = util.range(maxRank + 1).map(() => []);
|
|
1390
1392
|
|
|
1391
1393
|
function dfs(v) {
|
|
@@ -1545,7 +1547,7 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
1545
1547
|
if (g.children(entry.v).length) {
|
|
1546
1548
|
let subgraphResult = sortSubgraph(g, entry.v, cg, biasRight);
|
|
1547
1549
|
subgraphs[entry.v] = subgraphResult;
|
|
1548
|
-
if (
|
|
1550
|
+
if (Object.hasOwn(subgraphResult, "barycenter")) {
|
|
1549
1551
|
mergeBarycenters(entry, subgraphResult);
|
|
1550
1552
|
}
|
|
1551
1553
|
}
|
|
@@ -1561,7 +1563,7 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
1561
1563
|
if (g.predecessors(bl).length) {
|
|
1562
1564
|
let blPred = g.node(g.predecessors(bl)[0]),
|
|
1563
1565
|
brPred = g.node(g.predecessors(br)[0]);
|
|
1564
|
-
if (!
|
|
1566
|
+
if (!Object.hasOwn(result, "barycenter")) {
|
|
1565
1567
|
result.barycenter = 0;
|
|
1566
1568
|
result.weight = 0;
|
|
1567
1569
|
}
|
|
@@ -1604,7 +1606,7 @@ module.exports = sort;
|
|
|
1604
1606
|
|
|
1605
1607
|
function sort(entries, biasRight) {
|
|
1606
1608
|
let parts = util.partition(entries, entry => {
|
|
1607
|
-
return
|
|
1609
|
+
return Object.hasOwn(entry, "barycenter");
|
|
1608
1610
|
});
|
|
1609
1611
|
let sortable = parts.lhs,
|
|
1610
1612
|
unsortable = parts.rhs.sort((a, b) => b.i - a.i),
|
|
@@ -1896,7 +1898,7 @@ function hasConflict(conflicts, v, w) {
|
|
|
1896
1898
|
v = w;
|
|
1897
1899
|
w = tmp;
|
|
1898
1900
|
}
|
|
1899
|
-
return !!conflicts[v] && conflicts[v]
|
|
1901
|
+
return !!conflicts[v] && Object.hasOwn(conflicts[v], w);
|
|
1900
1902
|
}
|
|
1901
1903
|
|
|
1902
1904
|
/*
|
|
@@ -2057,8 +2059,8 @@ function findSmallestWidthAlignment(g, xss) {
|
|
|
2057
2059
|
*/
|
|
2058
2060
|
function alignCoordinates(xss, alignTo) {
|
|
2059
2061
|
let alignToVals = Object.values(alignTo),
|
|
2060
|
-
alignToMin = Math.min
|
|
2061
|
-
alignToMax = Math.max
|
|
2062
|
+
alignToMin = util.applyWithChunking(Math.min, alignToVals),
|
|
2063
|
+
alignToMax = util.applyWithChunking(Math.max, alignToVals);
|
|
2062
2064
|
|
|
2063
2065
|
["u", "d"].forEach(vert => {
|
|
2064
2066
|
["l", "r"].forEach(horiz => {
|
|
@@ -2068,9 +2070,9 @@ function alignCoordinates(xss, alignTo) {
|
|
|
2068
2070
|
if (xs === alignTo) return;
|
|
2069
2071
|
|
|
2070
2072
|
let xsVals = Object.values(xs);
|
|
2071
|
-
let delta = alignToMin - Math.min
|
|
2073
|
+
let delta = alignToMin - util.applyWithChunking(Math.min, xsVals);
|
|
2072
2074
|
if (horiz !== "l") {
|
|
2073
|
-
delta = alignToMax - Math.max
|
|
2075
|
+
delta = alignToMax - util.applyWithChunking(Math.max,xsVals);
|
|
2074
2076
|
}
|
|
2075
2077
|
|
|
2076
2078
|
if (delta) {
|
|
@@ -2133,7 +2135,7 @@ function sep(nodeSep, edgeSep, reverseSep) {
|
|
|
2133
2135
|
let delta;
|
|
2134
2136
|
|
|
2135
2137
|
sum += vLabel.width / 2;
|
|
2136
|
-
if (
|
|
2138
|
+
if (Object.hasOwn(vLabel, "labelpos")) {
|
|
2137
2139
|
switch (vLabel.labelpos.toLowerCase()) {
|
|
2138
2140
|
case "l": delta = -vLabel.width / 2; break;
|
|
2139
2141
|
case "r": delta = vLabel.width / 2; break;
|
|
@@ -2148,7 +2150,7 @@ function sep(nodeSep, edgeSep, reverseSep) {
|
|
|
2148
2150
|
sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
|
|
2149
2151
|
|
|
2150
2152
|
sum += wLabel.width / 2;
|
|
2151
|
-
if (
|
|
2153
|
+
if (Object.hasOwn(wLabel, "labelpos")) {
|
|
2152
2154
|
switch (wLabel.labelpos.toLowerCase()) {
|
|
2153
2155
|
case "l": delta = wLabel.width / 2; break;
|
|
2154
2156
|
case "r": delta = -wLabel.width / 2; break;
|
|
@@ -2483,7 +2485,7 @@ function dfsAssignLowLim(tree, visited, nextLim, v, parent) {
|
|
|
2483
2485
|
|
|
2484
2486
|
visited[v] = true;
|
|
2485
2487
|
tree.neighbors(v).forEach(w => {
|
|
2486
|
-
if (!
|
|
2488
|
+
if (!Object.hasOwn(visited, w)) {
|
|
2487
2489
|
nextLim = dfsAssignLowLim(tree, visited, nextLim, w, v);
|
|
2488
2490
|
}
|
|
2489
2491
|
});
|
|
@@ -2588,6 +2590,8 @@ function isDescendant(tree, vLabel, rootLabel) {
|
|
|
2588
2590
|
},{"../util":27,"./feasible-tree":23,"./util":26,"@dagrejs/graphlib":29}],26:[function(require,module,exports){
|
|
2589
2591
|
"use strict";
|
|
2590
2592
|
|
|
2593
|
+
const { applyWithChunking } = require("../util");
|
|
2594
|
+
|
|
2591
2595
|
module.exports = {
|
|
2592
2596
|
longestPath: longestPath,
|
|
2593
2597
|
slack: slack
|
|
@@ -2619,18 +2623,20 @@ function longestPath(g) {
|
|
|
2619
2623
|
|
|
2620
2624
|
function dfs(v) {
|
|
2621
2625
|
var label = g.node(v);
|
|
2622
|
-
if (
|
|
2626
|
+
if (Object.hasOwn(visited, v)) {
|
|
2623
2627
|
return label.rank;
|
|
2624
2628
|
}
|
|
2625
2629
|
visited[v] = true;
|
|
2626
2630
|
|
|
2627
|
-
|
|
2631
|
+
let outEdgesMinLens = g.outEdges(v).map(e => {
|
|
2628
2632
|
if (e == null) {
|
|
2629
2633
|
return Number.POSITIVE_INFINITY;
|
|
2630
2634
|
}
|
|
2631
2635
|
|
|
2632
2636
|
return dfs(e.w) - g.edge(e).minlen;
|
|
2633
|
-
})
|
|
2637
|
+
});
|
|
2638
|
+
|
|
2639
|
+
var rank = applyWithChunking(Math.min, outEdgesMinLens);
|
|
2634
2640
|
|
|
2635
2641
|
if (rank === Number.POSITIVE_INFINITY) {
|
|
2636
2642
|
rank = 0;
|
|
@@ -2650,7 +2656,7 @@ function slack(g, e) {
|
|
|
2650
2656
|
return g.node(e.w).rank - g.node(e.v).rank - g.edge(e).minlen;
|
|
2651
2657
|
}
|
|
2652
2658
|
|
|
2653
|
-
},{}],27:[function(require,module,exports){
|
|
2659
|
+
},{"../util":27}],27:[function(require,module,exports){
|
|
2654
2660
|
/* eslint "no-console": off */
|
|
2655
2661
|
|
|
2656
2662
|
"use strict";
|
|
@@ -2660,6 +2666,7 @@ let Graph = require("@dagrejs/graphlib").Graph;
|
|
|
2660
2666
|
module.exports = {
|
|
2661
2667
|
addBorderNode,
|
|
2662
2668
|
addDummyNode,
|
|
2669
|
+
applyWithChunking,
|
|
2663
2670
|
asNonCompoundGraph,
|
|
2664
2671
|
buildLayerMatrix,
|
|
2665
2672
|
intersectRect,
|
|
@@ -2806,17 +2813,18 @@ function buildLayerMatrix(g) {
|
|
|
2806
2813
|
* rank(v) >= 0 and at least one node w has rank(w) = 0.
|
|
2807
2814
|
*/
|
|
2808
2815
|
function normalizeRanks(g) {
|
|
2809
|
-
let
|
|
2816
|
+
let nodeRanks = g.nodes().map(v => {
|
|
2810
2817
|
let rank = g.node(v).rank;
|
|
2811
2818
|
if (rank === undefined) {
|
|
2812
2819
|
return Number.MAX_VALUE;
|
|
2813
2820
|
}
|
|
2814
2821
|
|
|
2815
2822
|
return rank;
|
|
2816
|
-
})
|
|
2823
|
+
});
|
|
2824
|
+
let min = applyWithChunking(Math.min, nodeRanks);
|
|
2817
2825
|
g.nodes().forEach(v => {
|
|
2818
2826
|
let node = g.node(v);
|
|
2819
|
-
if (
|
|
2827
|
+
if (Object.hasOwn(node, "rank")) {
|
|
2820
2828
|
node.rank -= min;
|
|
2821
2829
|
}
|
|
2822
2830
|
});
|
|
@@ -2824,7 +2832,8 @@ function normalizeRanks(g) {
|
|
|
2824
2832
|
|
|
2825
2833
|
function removeEmptyRanks(g) {
|
|
2826
2834
|
// Ranks may not start at 0, so we need to offset them
|
|
2827
|
-
let
|
|
2835
|
+
let nodeRanks = g.nodes().map(v => g.node(v).rank);
|
|
2836
|
+
let offset = applyWithChunking(Math.min, nodeRanks);
|
|
2828
2837
|
|
|
2829
2838
|
let layers = [];
|
|
2830
2839
|
g.nodes().forEach(v => {
|
|
@@ -2858,15 +2867,37 @@ function addBorderNode(g, prefix, rank, order) {
|
|
|
2858
2867
|
return addDummyNode(g, "border", node, prefix);
|
|
2859
2868
|
}
|
|
2860
2869
|
|
|
2870
|
+
function splitToChunks(array, chunkSize = CHUNKING_THRESHOLD) {
|
|
2871
|
+
const chunks = [];
|
|
2872
|
+
for (let i = 0; i < array.length; i += chunkSize) {
|
|
2873
|
+
const chunk = array.slice(i, i + chunkSize);
|
|
2874
|
+
chunks.push(chunk);
|
|
2875
|
+
}
|
|
2876
|
+
return chunks;
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
const CHUNKING_THRESHOLD = 65535;
|
|
2880
|
+
|
|
2881
|
+
function applyWithChunking(fn, argsArray) {
|
|
2882
|
+
if(argsArray.length > CHUNKING_THRESHOLD) {
|
|
2883
|
+
const chunks = splitToChunks(argsArray);
|
|
2884
|
+
return fn.apply(null, chunks.map(chunk => fn.apply(null, chunk)));
|
|
2885
|
+
} else {
|
|
2886
|
+
return fn.apply(null, argsArray);
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2861
2890
|
function maxRank(g) {
|
|
2862
|
-
|
|
2891
|
+
const nodes = g.nodes();
|
|
2892
|
+
const nodeRanks = nodes.map(v => {
|
|
2863
2893
|
let rank = g.node(v).rank;
|
|
2864
2894
|
if (rank === undefined) {
|
|
2865
2895
|
return Number.MIN_VALUE;
|
|
2866
2896
|
}
|
|
2867
|
-
|
|
2868
2897
|
return rank;
|
|
2869
|
-
})
|
|
2898
|
+
});
|
|
2899
|
+
|
|
2900
|
+
return applyWithChunking(Math.max, nodeRanks);
|
|
2870
2901
|
}
|
|
2871
2902
|
|
|
2872
2903
|
/*
|
|
@@ -2959,7 +2990,7 @@ function zipObject(props, values) {
|
|
|
2959
2990
|
}
|
|
2960
2991
|
|
|
2961
2992
|
},{"@dagrejs/graphlib":29}],28:[function(require,module,exports){
|
|
2962
|
-
module.exports = "1.1.
|
|
2993
|
+
module.exports = "1.1.4";
|
|
2963
2994
|
|
|
2964
2995
|
},{}],29:[function(require,module,exports){
|
|
2965
2996
|
/**
|
|
@@ -3010,7 +3041,7 @@ function components(g) {
|
|
|
3010
3041
|
var cmpt;
|
|
3011
3042
|
|
|
3012
3043
|
function dfs(v) {
|
|
3013
|
-
if (
|
|
3044
|
+
if (Object.hasOwn(visited, v)) return;
|
|
3014
3045
|
visited[v] = true;
|
|
3015
3046
|
cmpt.push(v);
|
|
3016
3047
|
g.successors(v).forEach(dfs);
|
|
@@ -3067,7 +3098,7 @@ function postOrderDfs(v, navigation, visited, acc) {
|
|
|
3067
3098
|
if (curr[1]) {
|
|
3068
3099
|
acc.push(curr[0]);
|
|
3069
3100
|
} else {
|
|
3070
|
-
if (!
|
|
3101
|
+
if (!Object.hasOwn(visited, curr[0])) {
|
|
3071
3102
|
visited[curr[0]] = true;
|
|
3072
3103
|
stack.push([curr[0], true]);
|
|
3073
3104
|
forEachRight(navigation(curr[0]), w => stack.push([w, false]));
|
|
@@ -3080,7 +3111,7 @@ function preOrderDfs(v, navigation, visited, acc) {
|
|
|
3080
3111
|
var stack = [v];
|
|
3081
3112
|
while (stack.length > 0) {
|
|
3082
3113
|
var curr = stack.pop();
|
|
3083
|
-
if (!
|
|
3114
|
+
if (!Object.hasOwn(visited, curr)) {
|
|
3084
3115
|
visited[curr] = true;
|
|
3085
3116
|
acc.push(curr);
|
|
3086
3117
|
forEachRight(navigation(curr), w => stack.push(w));
|
|
@@ -3314,7 +3345,7 @@ function prim(g, weightFunc) {
|
|
|
3314
3345
|
var init = false;
|
|
3315
3346
|
while (pq.size() > 0) {
|
|
3316
3347
|
v = pq.removeMin();
|
|
3317
|
-
if (
|
|
3348
|
+
if (Object.hasOwn(parents, v)) {
|
|
3318
3349
|
result.setEdge(v, parents[v]);
|
|
3319
3350
|
} else if (init) {
|
|
3320
3351
|
throw new Error("Input graph is not connected: " + g);
|
|
@@ -3346,7 +3377,7 @@ function tarjan(g) {
|
|
|
3346
3377
|
stack.push(v);
|
|
3347
3378
|
|
|
3348
3379
|
g.successors(v).forEach(function(w) {
|
|
3349
|
-
if (!
|
|
3380
|
+
if (!Object.hasOwn(visited, w)) {
|
|
3350
3381
|
dfs(w);
|
|
3351
3382
|
entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink);
|
|
3352
3383
|
} else if (visited[w].onStack) {
|
|
@@ -3367,7 +3398,7 @@ function tarjan(g) {
|
|
|
3367
3398
|
}
|
|
3368
3399
|
|
|
3369
3400
|
g.nodes().forEach(function(v) {
|
|
3370
|
-
if (!
|
|
3401
|
+
if (!Object.hasOwn(visited, v)) {
|
|
3371
3402
|
dfs(v);
|
|
3372
3403
|
}
|
|
3373
3404
|
});
|
|
@@ -3382,11 +3413,11 @@ function topsort(g) {
|
|
|
3382
3413
|
var results = [];
|
|
3383
3414
|
|
|
3384
3415
|
function visit(node) {
|
|
3385
|
-
if (
|
|
3416
|
+
if (Object.hasOwn(stack, node)) {
|
|
3386
3417
|
throw new CycleException();
|
|
3387
3418
|
}
|
|
3388
3419
|
|
|
3389
|
-
if (!
|
|
3420
|
+
if (!Object.hasOwn(visited, node)) {
|
|
3390
3421
|
stack[node] = true;
|
|
3391
3422
|
visited[node] = true;
|
|
3392
3423
|
g.predecessors(node).forEach(visit);
|
|
@@ -3443,7 +3474,7 @@ class PriorityQueue {
|
|
|
3443
3474
|
* Returns `true` if **key** is in the queue and `false` if not.
|
|
3444
3475
|
*/
|
|
3445
3476
|
has(key) {
|
|
3446
|
-
return this._keyIndices
|
|
3477
|
+
return Object.hasOwn(this._keyIndices, key);
|
|
3447
3478
|
}
|
|
3448
3479
|
|
|
3449
3480
|
/**
|
|
@@ -3481,7 +3512,7 @@ class PriorityQueue {
|
|
|
3481
3512
|
add(key, priority) {
|
|
3482
3513
|
var keyIndices = this._keyIndices;
|
|
3483
3514
|
key = String(key);
|
|
3484
|
-
if (!
|
|
3515
|
+
if (!Object.hasOwn(keyIndices, key)) {
|
|
3485
3516
|
var arr = this._arr;
|
|
3486
3517
|
var index = arr.length;
|
|
3487
3518
|
keyIndices[key] = index;
|
|
@@ -3629,9 +3660,9 @@ class Graph {
|
|
|
3629
3660
|
|
|
3630
3661
|
constructor(opts) {
|
|
3631
3662
|
if (opts) {
|
|
3632
|
-
this._isDirected =
|
|
3633
|
-
this._isMultigraph =
|
|
3634
|
-
this._isCompound =
|
|
3663
|
+
this._isDirected = Object.hasOwn(opts, "directed") ? opts.directed : true;
|
|
3664
|
+
this._isMultigraph = Object.hasOwn(opts, "multigraph") ? opts.multigraph : false;
|
|
3665
|
+
this._isCompound = Object.hasOwn(opts, "compound") ? opts.compound : false;
|
|
3635
3666
|
}
|
|
3636
3667
|
|
|
3637
3668
|
if (this._isCompound) {
|
|
@@ -3760,7 +3791,7 @@ class Graph {
|
|
|
3760
3791
|
* Complexity: O(1).
|
|
3761
3792
|
*/
|
|
3762
3793
|
setNode(v, value) {
|
|
3763
|
-
if (this._nodes
|
|
3794
|
+
if (Object.hasOwn(this._nodes, v)) {
|
|
3764
3795
|
if (arguments.length > 1) {
|
|
3765
3796
|
this._nodes[v] = value;
|
|
3766
3797
|
}
|
|
@@ -3793,7 +3824,7 @@ class Graph {
|
|
|
3793
3824
|
* Detects whether graph has a node with specified name or not.
|
|
3794
3825
|
*/
|
|
3795
3826
|
hasNode(v) {
|
|
3796
|
-
return this._nodes
|
|
3827
|
+
return Object.hasOwn(this._nodes, v);
|
|
3797
3828
|
}
|
|
3798
3829
|
|
|
3799
3830
|
/**
|
|
@@ -3804,7 +3835,7 @@ class Graph {
|
|
|
3804
3835
|
*/
|
|
3805
3836
|
removeNode(v) {
|
|
3806
3837
|
var self = this;
|
|
3807
|
-
if (this._nodes
|
|
3838
|
+
if (Object.hasOwn(this._nodes, v)) {
|
|
3808
3839
|
var removeEdge = e => self.removeEdge(self._edgeObjs[e]);
|
|
3809
3840
|
delete this._nodes[v];
|
|
3810
3841
|
if (this._isCompound) {
|
|
@@ -4082,7 +4113,7 @@ class Graph {
|
|
|
4082
4113
|
}
|
|
4083
4114
|
|
|
4084
4115
|
var e = edgeArgsToId(this._isDirected, v, w, name);
|
|
4085
|
-
if (this._edgeLabels
|
|
4116
|
+
if (Object.hasOwn(this._edgeLabels, e)) {
|
|
4086
4117
|
if (valueSpecified) {
|
|
4087
4118
|
this._edgeLabels[e] = value;
|
|
4088
4119
|
}
|
|
@@ -4147,7 +4178,7 @@ class Graph {
|
|
|
4147
4178
|
var e = (arguments.length === 1
|
|
4148
4179
|
? edgeObjToId(this._isDirected, arguments[0])
|
|
4149
4180
|
: edgeArgsToId(this._isDirected, v, w, name));
|
|
4150
|
-
return this._edgeLabels
|
|
4181
|
+
return Object.hasOwn(this._edgeLabels, e);
|
|
4151
4182
|
}
|
|
4152
4183
|
|
|
4153
4184
|
/**
|
|
@@ -4353,7 +4384,7 @@ function read(json) {
|
|
|
4353
4384
|
}
|
|
4354
4385
|
|
|
4355
4386
|
},{"./graph":44}],47:[function(require,module,exports){
|
|
4356
|
-
module.exports = '2.2.
|
|
4387
|
+
module.exports = '2.2.4';
|
|
4357
4388
|
|
|
4358
4389
|
},{}]},{},[1])(1)
|
|
4359
4390
|
});
|
package/dist/dagre.min.js
CHANGED
|
@@ -20,7 +20,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
21
|
THE SOFTWARE.
|
|
22
22
|
*/
|
|
23
|
-
module.exports={graphlib:require("@dagrejs/graphlib"),layout:require("./lib/layout"),debug:require("./lib/debug"),util:{time:require("./lib/util").time,notime:require("./lib/util").notime},version:require("./lib/version")}},{"./lib/debug":6,"./lib/layout":8,"./lib/util":27,"./lib/version":28,"@dagrejs/graphlib":29}],2:[function(require,module,exports){"use strict";let greedyFAS=require("./greedy-fas");let uniqueId=require("./util").uniqueId;module.exports={run:run,undo:undo};function run(g){let fas=g.graph().acyclicer==="greedy"?greedyFAS(g,weightFn(g)):dfsFAS(g);fas.forEach(e=>{let label=g.edge(e);g.removeEdge(e);label.forwardName=e.name;label.reversed=true;g.setEdge(e.w,e.v,label,uniqueId("rev"))});function weightFn(g){return e=>{return g.edge(e).weight}}}function dfsFAS(g){let fas=[];let stack={};let visited={};function dfs(v){if(
|
|
23
|
+
module.exports={graphlib:require("@dagrejs/graphlib"),layout:require("./lib/layout"),debug:require("./lib/debug"),util:{time:require("./lib/util").time,notime:require("./lib/util").notime},version:require("./lib/version")}},{"./lib/debug":6,"./lib/layout":8,"./lib/util":27,"./lib/version":28,"@dagrejs/graphlib":29}],2:[function(require,module,exports){"use strict";let greedyFAS=require("./greedy-fas");let uniqueId=require("./util").uniqueId;module.exports={run:run,undo:undo};function run(g){let fas=g.graph().acyclicer==="greedy"?greedyFAS(g,weightFn(g)):dfsFAS(g);fas.forEach(e=>{let label=g.edge(e);g.removeEdge(e);label.forwardName=e.name;label.reversed=true;g.setEdge(e.w,e.v,label,uniqueId("rev"))});function weightFn(g){return e=>{return g.edge(e).weight}}}function dfsFAS(g){let fas=[];let stack={};let visited={};function dfs(v){if(Object.hasOwn(visited,v)){return}visited[v]=true;stack[v]=true;g.outEdges(v).forEach(e=>{if(Object.hasOwn(stack,e.w)){fas.push(e)}else{dfs(e.w)}});delete stack[v]}g.nodes().forEach(dfs);return fas}function undo(g){g.edges().forEach(e=>{let label=g.edge(e);if(label.reversed){g.removeEdge(e);let forwardName=label.forwardName;delete label.reversed;delete label.forwardName;g.setEdge(e.w,e.v,label,forwardName)}})}},{"./greedy-fas":7,"./util":27}],3:[function(require,module,exports){let util=require("./util");module.exports=addBorderSegments;function addBorderSegments(g){function dfs(v){let children=g.children(v);let node=g.node(v);if(children.length){children.forEach(dfs)}if(Object.hasOwn(node,"minRank")){node.borderLeft=[];node.borderRight=[];for(let rank=node.minRank,maxRank=node.maxRank+1;rank<maxRank;++rank){addBorderNode(g,"borderLeft","_bl",v,node,rank);addBorderNode(g,"borderRight","_br",v,node,rank)}}}g.children().forEach(dfs)}function addBorderNode(g,prop,prefix,sg,sgNode,rank){let label={width:0,height:0,rank:rank,borderType:prop};let prev=sgNode[prop][rank-1];let curr=util.addDummyNode(g,"border",label,prefix);sgNode[prop][rank]=curr;g.setParent(curr,sg);if(prev){g.setEdge(prev,curr,{weight:1})}}},{"./util":27}],4:[function(require,module,exports){"use strict";module.exports={adjust:adjust,undo:undo};function adjust(g){let rankDir=g.graph().rankdir.toLowerCase();if(rankDir==="lr"||rankDir==="rl"){swapWidthHeight(g)}}function undo(g){let rankDir=g.graph().rankdir.toLowerCase();if(rankDir==="bt"||rankDir==="rl"){reverseY(g)}if(rankDir==="lr"||rankDir==="rl"){swapXY(g);swapWidthHeight(g)}}function swapWidthHeight(g){g.nodes().forEach(v=>swapWidthHeightOne(g.node(v)));g.edges().forEach(e=>swapWidthHeightOne(g.edge(e)))}function swapWidthHeightOne(attrs){let w=attrs.width;attrs.width=attrs.height;attrs.height=w}function reverseY(g){g.nodes().forEach(v=>reverseYOne(g.node(v)));g.edges().forEach(e=>{let edge=g.edge(e);edge.points.forEach(reverseYOne);if(Object.hasOwn(edge,"y")){reverseYOne(edge)}})}function reverseYOne(attrs){attrs.y=-attrs.y}function swapXY(g){g.nodes().forEach(v=>swapXYOne(g.node(v)));g.edges().forEach(e=>{let edge=g.edge(e);edge.points.forEach(swapXYOne);if(Object.hasOwn(edge,"x")){swapXYOne(edge)}})}function swapXYOne(attrs){let x=attrs.x;attrs.x=attrs.y;attrs.y=x}},{}],5:[function(require,module,exports){
|
|
24
24
|
/*
|
|
25
25
|
* Simple doubly linked list implementation derived from Cormen, et al.,
|
|
26
26
|
* "Introduction to Algorithms".
|
|
@@ -38,13 +38,13 @@ class List{constructor(){let sentinel={};sentinel._next=sentinel._prev=sentinel;
|
|
|
38
38
|
return results.flatMap(e=>g.outEdges(e.v,e.w))}function doGreedyFAS(g,buckets,zeroIdx){let results=[];let sources=buckets[buckets.length-1];let sinks=buckets[0];let entry;while(g.nodeCount()){while(entry=sinks.dequeue()){removeNode(g,buckets,zeroIdx,entry)}while(entry=sources.dequeue()){removeNode(g,buckets,zeroIdx,entry)}if(g.nodeCount()){for(let i=buckets.length-2;i>0;--i){entry=buckets[i].dequeue();if(entry){results=results.concat(removeNode(g,buckets,zeroIdx,entry,true));break}}}}return results}function removeNode(g,buckets,zeroIdx,entry,collectPredecessors){let results=collectPredecessors?[]:undefined;g.inEdges(entry.v).forEach(edge=>{let weight=g.edge(edge);let uEntry=g.node(edge.v);if(collectPredecessors){results.push({v:edge.v,w:edge.w})}uEntry.out-=weight;assignBucket(buckets,zeroIdx,uEntry)});g.outEdges(entry.v).forEach(edge=>{let weight=g.edge(edge);let w=edge.w;let wEntry=g.node(w);wEntry["in"]-=weight;assignBucket(buckets,zeroIdx,wEntry)});g.removeNode(entry.v);return results}function buildState(g,weightFn){let fasGraph=new Graph;let maxIn=0;let maxOut=0;g.nodes().forEach(v=>{fasGraph.setNode(v,{v:v,in:0,out:0})});
|
|
39
39
|
// Aggregate weights on nodes, but also sum the weights across multi-edges
|
|
40
40
|
// into a single edge for the fasGraph.
|
|
41
|
-
g.edges().forEach(e=>{let prevWeight=fasGraph.edge(e.v,e.w)||0;let weight=weightFn(e);let edgeWeight=prevWeight+weight;fasGraph.setEdge(e.v,e.w,edgeWeight);maxOut=Math.max(maxOut,fasGraph.node(e.v).out+=weight);maxIn=Math.max(maxIn,fasGraph.node(e.w)["in"]+=weight)});let buckets=range(maxOut+maxIn+3).map(()=>new List);let zeroIdx=maxIn+1;fasGraph.nodes().forEach(v=>{assignBucket(buckets,zeroIdx,fasGraph.node(v))});return{graph:fasGraph,buckets:buckets,zeroIdx:zeroIdx}}function assignBucket(buckets,zeroIdx,entry){if(!entry.out){buckets[0].enqueue(entry)}else if(!entry["in"]){buckets[buckets.length-1].enqueue(entry)}else{buckets[entry.out-entry["in"]+zeroIdx].enqueue(entry)}}function range(limit){const range=[];for(let i=0;i<limit;i++){range.push(i)}return range}},{"./data/list":5,"@dagrejs/graphlib":29}],8:[function(require,module,exports){"use strict";let acyclic=require("./acyclic");let normalize=require("./normalize");let rank=require("./rank");let normalizeRanks=require("./util").normalizeRanks;let parentDummyChains=require("./parent-dummy-chains");let removeEmptyRanks=require("./util").removeEmptyRanks;let nestingGraph=require("./nesting-graph");let addBorderSegments=require("./add-border-segments");let coordinateSystem=require("./coordinate-system");let order=require("./order");let position=require("./position");let util=require("./util");let Graph=require("@dagrejs/graphlib").Graph;module.exports=layout;function layout(g,opts){let time=opts&&opts.debugTiming?util.time:util.notime;time("layout",()=>{let layoutGraph=time(" buildLayoutGraph",()=>buildLayoutGraph(g));time(" runLayout",()=>runLayout(layoutGraph,time));time(" updateInputGraph",()=>updateInputGraph(g,layoutGraph))})}function runLayout(g,time){time(" makeSpaceForEdgeLabels",()=>makeSpaceForEdgeLabels(g));time(" removeSelfEdges",()=>removeSelfEdges(g));time(" acyclic",()=>acyclic.run(g));time(" nestingGraph.run",()=>nestingGraph.run(g));time(" rank",()=>rank(util.asNonCompoundGraph(g)));time(" injectEdgeLabelProxies",()=>injectEdgeLabelProxies(g));time(" removeEmptyRanks",()=>removeEmptyRanks(g));time(" nestingGraph.cleanup",()=>nestingGraph.cleanup(g));time(" normalizeRanks",()=>normalizeRanks(g));time(" assignRankMinMax",()=>assignRankMinMax(g));time(" removeEdgeLabelProxies",()=>removeEdgeLabelProxies(g));time(" normalize.run",()=>normalize.run(g));time(" parentDummyChains",()=>parentDummyChains(g));time(" addBorderSegments",()=>addBorderSegments(g));time(" order",()=>order(g));time(" insertSelfEdges",()=>insertSelfEdges(g));time(" adjustCoordinateSystem",()=>coordinateSystem.adjust(g));time(" position",()=>position(g));time(" positionSelfEdges",()=>positionSelfEdges(g));time(" removeBorderNodes",()=>removeBorderNodes(g));time(" normalize.undo",()=>normalize.undo(g));time(" fixupEdgeLabelCoords",()=>fixupEdgeLabelCoords(g));time(" undoCoordinateSystem",()=>coordinateSystem.undo(g));time(" translateGraph",()=>translateGraph(g));time(" assignNodeIntersects",()=>assignNodeIntersects(g));time(" reversePoints",()=>reversePointsForReversedEdges(g));time(" acyclic.undo",()=>acyclic.undo(g))}
|
|
41
|
+
g.edges().forEach(e=>{let prevWeight=fasGraph.edge(e.v,e.w)||0;let weight=weightFn(e);let edgeWeight=prevWeight+weight;fasGraph.setEdge(e.v,e.w,edgeWeight);maxOut=Math.max(maxOut,fasGraph.node(e.v).out+=weight);maxIn=Math.max(maxIn,fasGraph.node(e.w)["in"]+=weight)});let buckets=range(maxOut+maxIn+3).map(()=>new List);let zeroIdx=maxIn+1;fasGraph.nodes().forEach(v=>{assignBucket(buckets,zeroIdx,fasGraph.node(v))});return{graph:fasGraph,buckets:buckets,zeroIdx:zeroIdx}}function assignBucket(buckets,zeroIdx,entry){if(!entry.out){buckets[0].enqueue(entry)}else if(!entry["in"]){buckets[buckets.length-1].enqueue(entry)}else{buckets[entry.out-entry["in"]+zeroIdx].enqueue(entry)}}function range(limit){const range=[];for(let i=0;i<limit;i++){range.push(i)}return range}},{"./data/list":5,"@dagrejs/graphlib":29}],8:[function(require,module,exports){"use strict";let acyclic=require("./acyclic");let normalize=require("./normalize");let rank=require("./rank");let normalizeRanks=require("./util").normalizeRanks;let parentDummyChains=require("./parent-dummy-chains");let removeEmptyRanks=require("./util").removeEmptyRanks;let nestingGraph=require("./nesting-graph");let addBorderSegments=require("./add-border-segments");let coordinateSystem=require("./coordinate-system");let order=require("./order");let position=require("./position");let util=require("./util");let Graph=require("@dagrejs/graphlib").Graph;module.exports=layout;function layout(g,opts){let time=opts&&opts.debugTiming?util.time:util.notime;time("layout",()=>{let layoutGraph=time(" buildLayoutGraph",()=>buildLayoutGraph(g));time(" runLayout",()=>runLayout(layoutGraph,time,opts));time(" updateInputGraph",()=>updateInputGraph(g,layoutGraph))})}function runLayout(g,time,opts){time(" makeSpaceForEdgeLabels",()=>makeSpaceForEdgeLabels(g));time(" removeSelfEdges",()=>removeSelfEdges(g));time(" acyclic",()=>acyclic.run(g));time(" nestingGraph.run",()=>nestingGraph.run(g));time(" rank",()=>rank(util.asNonCompoundGraph(g)));time(" injectEdgeLabelProxies",()=>injectEdgeLabelProxies(g));time(" removeEmptyRanks",()=>removeEmptyRanks(g));time(" nestingGraph.cleanup",()=>nestingGraph.cleanup(g));time(" normalizeRanks",()=>normalizeRanks(g));time(" assignRankMinMax",()=>assignRankMinMax(g));time(" removeEdgeLabelProxies",()=>removeEdgeLabelProxies(g));time(" normalize.run",()=>normalize.run(g));time(" parentDummyChains",()=>parentDummyChains(g));time(" addBorderSegments",()=>addBorderSegments(g));time(" order",()=>order(g,opts));time(" insertSelfEdges",()=>insertSelfEdges(g));time(" adjustCoordinateSystem",()=>coordinateSystem.adjust(g));time(" position",()=>position(g));time(" positionSelfEdges",()=>positionSelfEdges(g));time(" removeBorderNodes",()=>removeBorderNodes(g));time(" normalize.undo",()=>normalize.undo(g));time(" fixupEdgeLabelCoords",()=>fixupEdgeLabelCoords(g));time(" undoCoordinateSystem",()=>coordinateSystem.undo(g));time(" translateGraph",()=>translateGraph(g));time(" assignNodeIntersects",()=>assignNodeIntersects(g));time(" reversePoints",()=>reversePointsForReversedEdges(g));time(" acyclic.undo",()=>acyclic.undo(g))}
|
|
42
42
|
/*
|
|
43
43
|
* Copies final layout information from the layout graph back to the input
|
|
44
44
|
* graph. This process only copies whitelisted attributes from the layout graph
|
|
45
45
|
* to the input graph, so it serves as a good place to determine what
|
|
46
46
|
* attributes can influence layout.
|
|
47
|
-
*/function updateInputGraph(inputGraph,layoutGraph){inputGraph.nodes().forEach(v=>{let inputLabel=inputGraph.node(v);let layoutLabel=layoutGraph.node(v);if(inputLabel){inputLabel.x=layoutLabel.x;inputLabel.y=layoutLabel.y;inputLabel.rank=layoutLabel.rank;if(layoutGraph.children(v).length){inputLabel.width=layoutLabel.width;inputLabel.height=layoutLabel.height}}});inputGraph.edges().forEach(e=>{let inputLabel=inputGraph.edge(e);let layoutLabel=layoutGraph.edge(e);inputLabel.points=layoutLabel.points;if(
|
|
47
|
+
*/function updateInputGraph(inputGraph,layoutGraph){inputGraph.nodes().forEach(v=>{let inputLabel=inputGraph.node(v);let layoutLabel=layoutGraph.node(v);if(inputLabel){inputLabel.x=layoutLabel.x;inputLabel.y=layoutLabel.y;inputLabel.rank=layoutLabel.rank;if(layoutGraph.children(v).length){inputLabel.width=layoutLabel.width;inputLabel.height=layoutLabel.height}}});inputGraph.edges().forEach(e=>{let inputLabel=inputGraph.edge(e);let layoutLabel=layoutGraph.edge(e);inputLabel.points=layoutLabel.points;if(Object.hasOwn(layoutLabel,"x")){inputLabel.x=layoutLabel.x;inputLabel.y=layoutLabel.y}});inputGraph.graph().width=layoutGraph.graph().width;inputGraph.graph().height=layoutGraph.graph().height}let graphNumAttrs=["nodesep","edgesep","ranksep","marginx","marginy"];let graphDefaults={ranksep:50,edgesep:20,nodesep:50,rankdir:"tb"};let graphAttrs=["acyclicer","ranker","rankdir","align"];let nodeNumAttrs=["width","height"];let nodeDefaults={width:0,height:0};let edgeNumAttrs=["minlen","weight","width","height","labeloffset"];let edgeDefaults={minlen:1,weight:1,width:0,height:0,labeloffset:10,labelpos:"r"};let edgeAttrs=["labelpos"];
|
|
48
48
|
/*
|
|
49
49
|
* Constructs a new graph from the input graph, which can be used for layout.
|
|
50
50
|
* This process copies only whitelisted attributes from the input graph to the
|
|
@@ -64,7 +64,7 @@ g.edges().forEach(e=>{let prevWeight=fasGraph.edge(e.v,e.w)||0;let weight=weight
|
|
|
64
64
|
* label is going to, if it has one of non-zero width and height. We do this
|
|
65
65
|
* so that we can safely remove empty ranks while preserving balance for the
|
|
66
66
|
* label's position.
|
|
67
|
-
*/function injectEdgeLabelProxies(g){g.edges().forEach(e=>{let edge=g.edge(e);if(edge.width&&edge.height){let v=g.node(e.v);let w=g.node(e.w);let label={rank:(w.rank-v.rank)/2+v.rank,e:e};util.addDummyNode(g,"edge-proxy",label,"_ep")}})}function assignRankMinMax(g){let maxRank=0;g.nodes().forEach(v=>{let node=g.node(v);if(node.borderTop){node.minRank=g.node(node.borderTop).rank;node.maxRank=g.node(node.borderBottom).rank;maxRank=Math.max(maxRank,node.maxRank)}});g.graph().maxRank=maxRank}function removeEdgeLabelProxies(g){g.nodes().forEach(v=>{let node=g.node(v);if(node.dummy==="edge-proxy"){g.edge(node.e).labelRank=node.rank;g.removeNode(v)}})}function translateGraph(g){let minX=Number.POSITIVE_INFINITY;let maxX=0;let minY=Number.POSITIVE_INFINITY;let maxY=0;let graphLabel=g.graph();let marginX=graphLabel.marginx||0;let marginY=graphLabel.marginy||0;function getExtremes(attrs){let x=attrs.x;let y=attrs.y;let w=attrs.width;let h=attrs.height;minX=Math.min(minX,x-w/2);maxX=Math.max(maxX,x+w/2);minY=Math.min(minY,y-h/2);maxY=Math.max(maxY,y+h/2)}g.nodes().forEach(v=>getExtremes(g.node(v)));g.edges().forEach(e=>{let edge=g.edge(e);if(
|
|
67
|
+
*/function injectEdgeLabelProxies(g){g.edges().forEach(e=>{let edge=g.edge(e);if(edge.width&&edge.height){let v=g.node(e.v);let w=g.node(e.w);let label={rank:(w.rank-v.rank)/2+v.rank,e:e};util.addDummyNode(g,"edge-proxy",label,"_ep")}})}function assignRankMinMax(g){let maxRank=0;g.nodes().forEach(v=>{let node=g.node(v);if(node.borderTop){node.minRank=g.node(node.borderTop).rank;node.maxRank=g.node(node.borderBottom).rank;maxRank=Math.max(maxRank,node.maxRank)}});g.graph().maxRank=maxRank}function removeEdgeLabelProxies(g){g.nodes().forEach(v=>{let node=g.node(v);if(node.dummy==="edge-proxy"){g.edge(node.e).labelRank=node.rank;g.removeNode(v)}})}function translateGraph(g){let minX=Number.POSITIVE_INFINITY;let maxX=0;let minY=Number.POSITIVE_INFINITY;let maxY=0;let graphLabel=g.graph();let marginX=graphLabel.marginx||0;let marginY=graphLabel.marginy||0;function getExtremes(attrs){let x=attrs.x;let y=attrs.y;let w=attrs.width;let h=attrs.height;minX=Math.min(minX,x-w/2);maxX=Math.max(maxX,x+w/2);minY=Math.min(minY,y-h/2);maxY=Math.max(maxY,y+h/2)}g.nodes().forEach(v=>getExtremes(g.node(v)));g.edges().forEach(e=>{let edge=g.edge(e);if(Object.hasOwn(edge,"x")){getExtremes(edge)}});minX-=marginX;minY-=marginY;g.nodes().forEach(v=>{let node=g.node(v);node.x-=minX;node.y-=minY});g.edges().forEach(e=>{let edge=g.edge(e);edge.points.forEach(p=>{p.x-=minX;p.y-=minY});if(Object.hasOwn(edge,"x")){edge.x-=minX}if(Object.hasOwn(edge,"y")){edge.y-=minY}});graphLabel.width=maxX-minX+marginX;graphLabel.height=maxY-minY+marginY}function assignNodeIntersects(g){g.edges().forEach(e=>{let edge=g.edge(e);let nodeV=g.node(e.v);let nodeW=g.node(e.w);let p1,p2;if(!edge.points){edge.points=[];p1=nodeW;p2=nodeV}else{p1=edge.points[0];p2=edge.points[edge.points.length-1]}edge.points.unshift(util.intersectRect(nodeV,p1));edge.points.push(util.intersectRect(nodeW,p2))})}function fixupEdgeLabelCoords(g){g.edges().forEach(e=>{let edge=g.edge(e);if(Object.hasOwn(edge,"x")){if(edge.labelpos==="l"||edge.labelpos==="r"){edge.width-=edge.labeloffset}switch(edge.labelpos){case"l":edge.x-=edge.width/2+edge.labeloffset;break;case"r":edge.x+=edge.width/2+edge.labeloffset;break}}})}function reversePointsForReversedEdges(g){g.edges().forEach(e=>{let edge=g.edge(e);if(edge.reversed){edge.points.reverse()}})}function removeBorderNodes(g){g.nodes().forEach(v=>{if(g.children(v).length){let node=g.node(v);let t=g.node(node.borderTop);let b=g.node(node.borderBottom);let l=g.node(node.borderLeft[node.borderLeft.length-1]);let r=g.node(node.borderRight[node.borderRight.length-1]);node.width=Math.abs(r.x-l.x);node.height=Math.abs(b.y-t.y);node.x=l.x+node.width/2;node.y=t.y+node.height/2}});g.nodes().forEach(v=>{if(g.node(v).dummy==="border"){g.removeNode(v)}})}function removeSelfEdges(g){g.edges().forEach(e=>{if(e.v===e.w){var node=g.node(e.v);if(!node.selfEdges){node.selfEdges=[]}node.selfEdges.push({e:e,label:g.edge(e)});g.removeEdge(e)}})}function insertSelfEdges(g){var layers=util.buildLayerMatrix(g);layers.forEach(layer=>{var orderShift=0;layer.forEach((v,i)=>{var node=g.node(v);node.order=i+orderShift;(node.selfEdges||[]).forEach(selfEdge=>{util.addDummyNode(g,"selfedge",{width:selfEdge.label.width,height:selfEdge.label.height,rank:node.rank,order:i+ ++orderShift,e:selfEdge.e,label:selfEdge.label},"_se")});delete node.selfEdges})})}function positionSelfEdges(g){g.nodes().forEach(v=>{var node=g.node(v);if(node.dummy==="selfedge"){var selfNode=g.node(node.e.v);var x=selfNode.x+selfNode.width/2;var y=selfNode.y;var dx=node.x-x;var dy=selfNode.height/2;g.setEdge(node.e,node.label);g.removeNode(v);node.label.points=[{x:x+2*dx/3,y:y-dy},{x:x+5*dx/6,y:y-dy},{x:x+dx,y:y},{x:x+5*dx/6,y:y+dy},{x:x+2*dx/3,y:y+dy}];node.label.x=node.x;node.label.y=node.y}})}function selectNumberAttrs(obj,attrs){return util.mapValues(util.pick(obj,attrs),Number)}function canonicalize(attrs){var newAttrs={};if(attrs){Object.entries(attrs).forEach(([k,v])=>{if(typeof k==="string"){k=k.toLowerCase()}newAttrs[k]=v})}return newAttrs}},{"./acyclic":2,"./add-border-segments":3,"./coordinate-system":4,"./nesting-graph":9,"./normalize":10,"./order":15,"./parent-dummy-chains":20,"./position":22,"./rank":24,"./util":27,"@dagrejs/graphlib":29}],9:[function(require,module,exports){let util=require("./util");module.exports={run:run,cleanup:cleanup};
|
|
68
68
|
/*
|
|
69
69
|
* A nesting graph creates dummy nodes for the tops and bottoms of subgraphs,
|
|
70
70
|
* adds appropriate edges to ensure that all cluster nodes are placed between
|
|
@@ -87,7 +87,7 @@ g.edges().forEach(e=>{let prevWeight=fasGraph.edge(e.v,e.w)||0;let weight=weight
|
|
|
87
87
|
*
|
|
88
88
|
* The nesting graph idea comes from Sander, "Layout of Compound Directed
|
|
89
89
|
* Graphs."
|
|
90
|
-
*/function run(g){let root=util.addDummyNode(g,"root",{},"_root");let depths=treeDepths(g);let
|
|
90
|
+
*/function run(g){let root=util.addDummyNode(g,"root",{},"_root");let depths=treeDepths(g);let depthsArr=Object.values(depths);let height=util.applyWithChunking(Math.max,depthsArr)-1;// Note: depths is an Object not an array
|
|
91
91
|
let nodeSep=2*height+1;g.graph().nestingRoot=root;
|
|
92
92
|
// Multiply minlen by nodeSep to align nodes on non-border ranks.
|
|
93
93
|
g.edges().forEach(e=>g.edge(e).minlen*=nodeSep);
|
|
@@ -168,7 +168,7 @@ g.graph().nodeRankFactor=nodeSep}function dfs(g,root,nodeSep,weight,height,depth
|
|
|
168
168
|
* graph is not a multi-graph.
|
|
169
169
|
*/function buildLayerGraph(g,rank,relationship){let root=createRootNode(g),result=new Graph({compound:true}).setGraph({root:root}).setDefaultNodeLabel(v=>g.node(v));g.nodes().forEach(v=>{let node=g.node(v),parent=g.parent(v);if(node.rank===rank||node.minRank<=rank&&rank<=node.maxRank){result.setNode(v);result.setParent(v,parent||root);
|
|
170
170
|
// This assumes we have only short edges!
|
|
171
|
-
g[relationship](v).forEach(e=>{let u=e.v===v?e.w:e.v,edge=result.edge(u,v),weight=edge!==undefined?edge.weight:0;result.setEdge(u,v,{weight:g.edge(e).weight+weight})});if(
|
|
171
|
+
g[relationship](v).forEach(e=>{let u=e.v===v?e.w:e.v,edge=result.edge(u,v),weight=edge!==undefined?edge.weight:0;result.setEdge(u,v,{weight:g.edge(e).weight+weight})});if(Object.hasOwn(node,"minRank")){result.setNode(v,{borderLeft:node.borderLeft[rank],borderRight:node.borderRight[rank]})}}});return result}function createRootNode(g){var v;while(g.hasNode(v=util.uniqueId("_root")));return v}},{"../util":27,"@dagrejs/graphlib":29}],14:[function(require,module,exports){"use strict";let zipObject=require("../util").zipObject;module.exports=crossCount;
|
|
172
172
|
/*
|
|
173
173
|
* A function that takes a layering (an array of layers, each with an array of
|
|
174
174
|
* ordererd nodes) and a graph and returns a weighted crossing count.
|
|
@@ -218,7 +218,7 @@ let cc=0;southEntries.forEach(entry=>{let index=entry.pos+firstIndex;tree[index]
|
|
|
218
218
|
*
|
|
219
219
|
* Returns a layering matrix with an array per layer and each layer sorted by
|
|
220
220
|
* the order of its nodes.
|
|
221
|
-
*/function initOrder(g){let visited={};let simpleNodes=g.nodes().filter(v=>!g.children(v).length);let
|
|
221
|
+
*/function initOrder(g){let visited={};let simpleNodes=g.nodes().filter(v=>!g.children(v).length);let simpleNodesRanks=simpleNodes.map(v=>g.node(v).rank);let maxRank=util.applyWithChunking(Math.max,simpleNodesRanks);let layers=util.range(maxRank+1).map(()=>[]);function dfs(v){if(visited[v])return;visited[v]=true;let node=g.node(v);layers[node.rank].push(v);g.successors(v).forEach(dfs)}let orderedVs=simpleNodes.sort((a,b)=>g.node(a).rank-g.node(b).rank);orderedVs.forEach(dfs);return layers}},{"../util":27}],17:[function(require,module,exports){"use strict";let util=require("../util");module.exports=resolveConflicts;
|
|
222
222
|
/*
|
|
223
223
|
* Given a list of entries of the form {v, barycenter, weight} and a
|
|
224
224
|
* constraint graph this function will resolve any conflicts between the
|
|
@@ -243,7 +243,7 @@ let cc=0;southEntries.forEach(entry=>{let index=entry.pos+firstIndex;tree[index]
|
|
|
243
243
|
* ordered such that they do not violate constraints from the constraint
|
|
244
244
|
* graph. The property `i` is the lowest original index of any of the
|
|
245
245
|
* elements in `vs`.
|
|
246
|
-
*/function resolveConflicts(entries,cg){let mappedEntries={};entries.forEach((entry,i)=>{let tmp=mappedEntries[entry.v]={indegree:0,in:[],out:[],vs:[entry.v],i:i};if(entry.barycenter!==undefined){tmp.barycenter=entry.barycenter;tmp.weight=entry.weight}});cg.edges().forEach(e=>{let entryV=mappedEntries[e.v];let entryW=mappedEntries[e.w];if(entryV!==undefined&&entryW!==undefined){entryW.indegree++;entryV.out.push(mappedEntries[e.w])}});let sourceSet=Object.values(mappedEntries).filter(entry=>!entry.indegree);return doResolveConflicts(sourceSet)}function doResolveConflicts(sourceSet){let entries=[];function handleIn(vEntry){return uEntry=>{if(uEntry.merged){return}if(uEntry.barycenter===undefined||vEntry.barycenter===undefined||uEntry.barycenter>=vEntry.barycenter){mergeEntries(vEntry,uEntry)}}}function handleOut(vEntry){return wEntry=>{wEntry["in"].push(vEntry);if(--wEntry.indegree===0){sourceSet.push(wEntry)}}}while(sourceSet.length){let entry=sourceSet.pop();entries.push(entry);entry["in"].reverse().forEach(handleIn(entry));entry.out.forEach(handleOut(entry))}return entries.filter(entry=>!entry.merged).map(entry=>{return util.pick(entry,["vs","i","barycenter","weight"])})}function mergeEntries(target,source){let sum=0;let weight=0;if(target.weight){sum+=target.barycenter*target.weight;weight+=target.weight}if(source.weight){sum+=source.barycenter*source.weight;weight+=source.weight}target.vs=source.vs.concat(target.vs);target.barycenter=sum/weight;target.weight=weight;target.i=Math.min(source.i,target.i);source.merged=true}},{"../util":27}],18:[function(require,module,exports){let barycenter=require("./barycenter");let resolveConflicts=require("./resolve-conflicts");let sort=require("./sort");module.exports=sortSubgraph;function sortSubgraph(g,v,cg,biasRight){let movable=g.children(v);let node=g.node(v);let bl=node?node.borderLeft:undefined;let br=node?node.borderRight:undefined;let subgraphs={};if(bl){movable=movable.filter(w=>w!==bl&&w!==br)}let barycenters=barycenter(g,movable);barycenters.forEach(entry=>{if(g.children(entry.v).length){let subgraphResult=sortSubgraph(g,entry.v,cg,biasRight);subgraphs[entry.v]=subgraphResult;if(
|
|
246
|
+
*/function resolveConflicts(entries,cg){let mappedEntries={};entries.forEach((entry,i)=>{let tmp=mappedEntries[entry.v]={indegree:0,in:[],out:[],vs:[entry.v],i:i};if(entry.barycenter!==undefined){tmp.barycenter=entry.barycenter;tmp.weight=entry.weight}});cg.edges().forEach(e=>{let entryV=mappedEntries[e.v];let entryW=mappedEntries[e.w];if(entryV!==undefined&&entryW!==undefined){entryW.indegree++;entryV.out.push(mappedEntries[e.w])}});let sourceSet=Object.values(mappedEntries).filter(entry=>!entry.indegree);return doResolveConflicts(sourceSet)}function doResolveConflicts(sourceSet){let entries=[];function handleIn(vEntry){return uEntry=>{if(uEntry.merged){return}if(uEntry.barycenter===undefined||vEntry.barycenter===undefined||uEntry.barycenter>=vEntry.barycenter){mergeEntries(vEntry,uEntry)}}}function handleOut(vEntry){return wEntry=>{wEntry["in"].push(vEntry);if(--wEntry.indegree===0){sourceSet.push(wEntry)}}}while(sourceSet.length){let entry=sourceSet.pop();entries.push(entry);entry["in"].reverse().forEach(handleIn(entry));entry.out.forEach(handleOut(entry))}return entries.filter(entry=>!entry.merged).map(entry=>{return util.pick(entry,["vs","i","barycenter","weight"])})}function mergeEntries(target,source){let sum=0;let weight=0;if(target.weight){sum+=target.barycenter*target.weight;weight+=target.weight}if(source.weight){sum+=source.barycenter*source.weight;weight+=source.weight}target.vs=source.vs.concat(target.vs);target.barycenter=sum/weight;target.weight=weight;target.i=Math.min(source.i,target.i);source.merged=true}},{"../util":27}],18:[function(require,module,exports){let barycenter=require("./barycenter");let resolveConflicts=require("./resolve-conflicts");let sort=require("./sort");module.exports=sortSubgraph;function sortSubgraph(g,v,cg,biasRight){let movable=g.children(v);let node=g.node(v);let bl=node?node.borderLeft:undefined;let br=node?node.borderRight:undefined;let subgraphs={};if(bl){movable=movable.filter(w=>w!==bl&&w!==br)}let barycenters=barycenter(g,movable);barycenters.forEach(entry=>{if(g.children(entry.v).length){let subgraphResult=sortSubgraph(g,entry.v,cg,biasRight);subgraphs[entry.v]=subgraphResult;if(Object.hasOwn(subgraphResult,"barycenter")){mergeBarycenters(entry,subgraphResult)}}});let entries=resolveConflicts(barycenters,cg);expandSubgraphs(entries,subgraphs);let result=sort(entries,biasRight);if(bl){result.vs=[bl,result.vs,br].flat(true);if(g.predecessors(bl).length){let blPred=g.node(g.predecessors(bl)[0]),brPred=g.node(g.predecessors(br)[0]);if(!Object.hasOwn(result,"barycenter")){result.barycenter=0;result.weight=0}result.barycenter=(result.barycenter*result.weight+blPred.order+brPred.order)/(result.weight+2);result.weight+=2}}return result}function expandSubgraphs(entries,subgraphs){entries.forEach(entry=>{entry.vs=entry.vs.flatMap(v=>{if(subgraphs[v]){return subgraphs[v].vs}return v})})}function mergeBarycenters(target,other){if(target.barycenter!==undefined){target.barycenter=(target.barycenter*target.weight+other.barycenter*other.weight)/(target.weight+other.weight);target.weight+=other.weight}else{target.barycenter=other.barycenter;target.weight=other.weight}}},{"./barycenter":12,"./resolve-conflicts":17,"./sort":19}],19:[function(require,module,exports){let util=require("../util");module.exports=sort;function sort(entries,biasRight){let parts=util.partition(entries,entry=>{return Object.hasOwn(entry,"barycenter")});let sortable=parts.lhs,unsortable=parts.rhs.sort((a,b)=>b.i-a.i),vs=[],sum=0,weight=0,vsIndex=0;sortable.sort(compareWithBias(!!biasRight));vsIndex=consumeUnsortable(vs,unsortable,vsIndex);sortable.forEach(entry=>{vsIndex+=entry.vs.length;vs.push(entry.vs);sum+=entry.barycenter*entry.weight;weight+=entry.weight;vsIndex=consumeUnsortable(vs,unsortable,vsIndex)});let result={vs:vs.flat(true)};if(weight){result.barycenter=sum/weight;result.weight=weight}return result}function consumeUnsortable(vs,unsortable,index){let last;while(unsortable.length&&(last=unsortable[unsortable.length-1]).i<=index){unsortable.pop();vs.push(last.vs);index++}return index}function compareWithBias(bias){return(entryV,entryW)=>{if(entryV.barycenter<entryW.barycenter){return-1}else if(entryV.barycenter>entryW.barycenter){return 1}return!bias?entryV.i-entryW.i:entryW.i-entryV.i}}},{"../util":27}],20:[function(require,module,exports){module.exports=parentDummyChains;function parentDummyChains(g){let postorderNums=postorder(g);g.graph().dummyChains.forEach(v=>{let node=g.node(v);let edgeObj=node.edgeObj;let pathData=findPath(g,postorderNums,edgeObj.v,edgeObj.w);let path=pathData.path;let lca=pathData.lca;let pathIdx=0;let pathV=path[pathIdx];let ascending=true;while(v!==edgeObj.w){node=g.node(v);if(ascending){while((pathV=path[pathIdx])!==lca&&g.node(pathV).maxRank<node.rank){pathIdx++}if(pathV===lca){ascending=false}}if(!ascending){while(pathIdx<path.length-1&&g.node(pathV=path[pathIdx+1]).minRank<=node.rank){pathIdx++}pathV=path[pathIdx]}g.setParent(v,pathV);v=g.successors(v)[0]}})}
|
|
247
247
|
// Find a path from v to w through the lowest common ancestor (LCA). Return the
|
|
248
248
|
// full path and the LCA.
|
|
249
249
|
function findPath(g,postorderNums,v,w){let vPath=[];let wPath=[];let low=Math.min(postorderNums[v].low,postorderNums[w].low);let lim=Math.max(postorderNums[v].lim,postorderNums[w].lim);let parent;let lca;
|
|
@@ -277,7 +277,7 @@ parent=w;while((parent=g.parent(parent))!==lca){wPath.push(parent)}return{path:v
|
|
|
277
277
|
k0=0,
|
|
278
278
|
// Tracks the last node in this layer scanned for crossings with a type-1
|
|
279
279
|
// segment.
|
|
280
|
-
scanPos=0,prevLayerLength=prevLayer.length,lastNode=layer[layer.length-1];layer.forEach((v,i)=>{let w=findOtherInnerSegmentNode(g,v),k1=w?g.node(w).order:prevLayerLength;if(w||v===lastNode){layer.slice(scanPos,i+1).forEach(scanNode=>{g.predecessors(scanNode).forEach(u=>{let uLabel=g.node(u),uPos=uLabel.order;if((uPos<k0||k1<uPos)&&!(uLabel.dummy&&g.node(scanNode).dummy)){addConflict(conflicts,u,scanNode)}})});scanPos=i+1;k0=k1}});return layer}layering.length&&layering.reduce(visitLayer);return conflicts}function findType2Conflicts(g,layering){let conflicts={};function scan(south,southPos,southEnd,prevNorthBorder,nextNorthBorder){let v;util.range(southPos,southEnd).forEach(i=>{v=south[i];if(g.node(v).dummy){g.predecessors(v).forEach(u=>{let uNode=g.node(u);if(uNode.dummy&&(uNode.order<prevNorthBorder||uNode.order>nextNorthBorder)){addConflict(conflicts,u,v)}})}})}function visitLayer(north,south){let prevNorthPos=-1,nextNorthPos,southPos=0;south.forEach((v,southLookahead)=>{if(g.node(v).dummy==="border"){let predecessors=g.predecessors(v);if(predecessors.length){nextNorthPos=g.node(predecessors[0]).order;scan(south,southPos,southLookahead,prevNorthPos,nextNorthPos);southPos=southLookahead;prevNorthPos=nextNorthPos}}scan(south,southPos,south.length,nextNorthPos,north.length)});return south}layering.length&&layering.reduce(visitLayer);return conflicts}function findOtherInnerSegmentNode(g,v){if(g.node(v).dummy){return g.predecessors(v).find(u=>g.node(u).dummy)}}function addConflict(conflicts,v,w){if(v>w){let tmp=v;v=w;w=tmp}let conflictsV=conflicts[v];if(!conflictsV){conflicts[v]=conflictsV={}}conflictsV[w]=true}function hasConflict(conflicts,v,w){if(v>w){let tmp=v;v=w;w=tmp}return!!conflicts[v]&&conflicts[v]
|
|
280
|
+
scanPos=0,prevLayerLength=prevLayer.length,lastNode=layer[layer.length-1];layer.forEach((v,i)=>{let w=findOtherInnerSegmentNode(g,v),k1=w?g.node(w).order:prevLayerLength;if(w||v===lastNode){layer.slice(scanPos,i+1).forEach(scanNode=>{g.predecessors(scanNode).forEach(u=>{let uLabel=g.node(u),uPos=uLabel.order;if((uPos<k0||k1<uPos)&&!(uLabel.dummy&&g.node(scanNode).dummy)){addConflict(conflicts,u,scanNode)}})});scanPos=i+1;k0=k1}});return layer}layering.length&&layering.reduce(visitLayer);return conflicts}function findType2Conflicts(g,layering){let conflicts={};function scan(south,southPos,southEnd,prevNorthBorder,nextNorthBorder){let v;util.range(southPos,southEnd).forEach(i=>{v=south[i];if(g.node(v).dummy){g.predecessors(v).forEach(u=>{let uNode=g.node(u);if(uNode.dummy&&(uNode.order<prevNorthBorder||uNode.order>nextNorthBorder)){addConflict(conflicts,u,v)}})}})}function visitLayer(north,south){let prevNorthPos=-1,nextNorthPos,southPos=0;south.forEach((v,southLookahead)=>{if(g.node(v).dummy==="border"){let predecessors=g.predecessors(v);if(predecessors.length){nextNorthPos=g.node(predecessors[0]).order;scan(south,southPos,southLookahead,prevNorthPos,nextNorthPos);southPos=southLookahead;prevNorthPos=nextNorthPos}}scan(south,southPos,south.length,nextNorthPos,north.length)});return south}layering.length&&layering.reduce(visitLayer);return conflicts}function findOtherInnerSegmentNode(g,v){if(g.node(v).dummy){return g.predecessors(v).find(u=>g.node(u).dummy)}}function addConflict(conflicts,v,w){if(v>w){let tmp=v;v=w;w=tmp}let conflictsV=conflicts[v];if(!conflictsV){conflicts[v]=conflictsV={}}conflictsV[w]=true}function hasConflict(conflicts,v,w){if(v>w){let tmp=v;v=w;w=tmp}return!!conflicts[v]&&Object.hasOwn(conflicts[v],w)}
|
|
281
281
|
/*
|
|
282
282
|
* Try to align nodes into vertical "blocks" where possible. This algorithm
|
|
283
283
|
* attempts to align a node with one of its median neighbors. If the edge
|
|
@@ -311,7 +311,7 @@ Object.keys(align).forEach(v=>xs[v]=xs[root[v]]);return xs}function buildBlockGr
|
|
|
311
311
|
* the minimum coordinate of the smallest width alignment and right-biased
|
|
312
312
|
* alignments have their maximum coordinate at the same point as the maximum
|
|
313
313
|
* coordinate of the smallest width alignment.
|
|
314
|
-
*/function alignCoordinates(xss,alignTo){let alignToVals=Object.values(alignTo),alignToMin=Math.min
|
|
314
|
+
*/function alignCoordinates(xss,alignTo){let alignToVals=Object.values(alignTo),alignToMin=util.applyWithChunking(Math.min,alignToVals),alignToMax=util.applyWithChunking(Math.max,alignToVals);["u","d"].forEach(vert=>{["l","r"].forEach(horiz=>{let alignment=vert+horiz,xs=xss[alignment];if(xs===alignTo)return;let xsVals=Object.values(xs);let delta=alignToMin-util.applyWithChunking(Math.min,xsVals);if(horiz!=="l"){delta=alignToMax-util.applyWithChunking(Math.max,xsVals)}if(delta){xss[alignment]=util.mapValues(xs,x=>x+delta)}})})}function balance(xss,align){return util.mapValues(xss.ul,(num,v)=>{if(align){return xss[align.toLowerCase()][v]}else{let xs=Object.values(xss).map(xs=>xs[v]).sort((a,b)=>a-b);return(xs[1]+xs[2])/2}})}function positionX(g){let layering=util.buildLayerMatrix(g);let conflicts=Object.assign(findType1Conflicts(g,layering),findType2Conflicts(g,layering));let xss={};let adjustedLayering;["u","d"].forEach(vert=>{adjustedLayering=vert==="u"?layering:Object.values(layering).reverse();["l","r"].forEach(horiz=>{if(horiz==="r"){adjustedLayering=adjustedLayering.map(inner=>{return Object.values(inner).reverse()})}let neighborFn=(vert==="u"?g.predecessors:g.successors).bind(g);let align=verticalAlignment(g,adjustedLayering,conflicts,neighborFn);let xs=horizontalCompaction(g,adjustedLayering,align.root,align.align,horiz==="r");if(horiz==="r"){xs=util.mapValues(xs,x=>-x)}xss[vert+horiz]=xs})});let smallestWidth=findSmallestWidthAlignment(g,xss);alignCoordinates(xss,smallestWidth);return balance(xss,g.graph().align)}function sep(nodeSep,edgeSep,reverseSep){return(g,v,w)=>{let vLabel=g.node(v);let wLabel=g.node(w);let sum=0;let delta;sum+=vLabel.width/2;if(Object.hasOwn(vLabel,"labelpos")){switch(vLabel.labelpos.toLowerCase()){case"l":delta=-vLabel.width/2;break;case"r":delta=vLabel.width/2;break}}if(delta){sum+=reverseSep?delta:-delta}delta=0;sum+=(vLabel.dummy?edgeSep:nodeSep)/2;sum+=(wLabel.dummy?edgeSep:nodeSep)/2;sum+=wLabel.width/2;if(Object.hasOwn(wLabel,"labelpos")){switch(wLabel.labelpos.toLowerCase()){case"l":delta=wLabel.width/2;break;case"r":delta=-wLabel.width/2;break}}if(delta){sum+=reverseSep?delta:-delta}delta=0;return sum}}function width(g,v){return g.node(v).width}},{"../util":27,"@dagrejs/graphlib":29}],22:[function(require,module,exports){"use strict";let util=require("../util");let positionX=require("./bk").positionX;module.exports=position;function position(g){g=util.asNonCompoundGraph(g);positionY(g);Object.entries(positionX(g)).forEach(([v,x])=>g.node(v).x=x)}function positionY(g){let layering=util.buildLayerMatrix(g);let rankSep=g.graph().ranksep;let prevY=0;layering.forEach(layer=>{const maxHeight=layer.reduce((acc,v)=>{const height=g.node(v).height;if(acc>height){return acc}else{return height}},0);layer.forEach(v=>g.node(v).y=prevY+maxHeight/2);prevY+=maxHeight+rankSep})}},{"../util":27,"./bk":21}],23:[function(require,module,exports){"use strict";var Graph=require("@dagrejs/graphlib").Graph;var slack=require("./util").slack;module.exports=feasibleTree;
|
|
315
315
|
/*
|
|
316
316
|
* Constructs a spanning tree with tight edges and adjusted the input node's
|
|
317
317
|
* ranks to achieve this. A tight edge is one that is has a length that matches
|
|
@@ -415,7 +415,7 @@ var childIsTail=true;
|
|
|
415
415
|
// The graph's view of the tree edge we're inspecting
|
|
416
416
|
var graphEdge=g.edge(child,parent);
|
|
417
417
|
// The accumulated cut value for the edge between this node and its parent
|
|
418
|
-
var cutValue=0;if(!graphEdge){childIsTail=false;graphEdge=g.edge(parent,child)}cutValue=graphEdge.weight;g.nodeEdges(child).forEach(e=>{var isOutEdge=e.v===child,other=isOutEdge?e.w:e.v;if(other!==parent){var pointsToHead=isOutEdge===childIsTail,otherWeight=g.edge(e).weight;cutValue+=pointsToHead?otherWeight:-otherWeight;if(isTreeEdge(t,child,other)){var otherCutValue=t.edge(child,other).cutvalue;cutValue+=pointsToHead?-otherCutValue:otherCutValue}}});return cutValue}function initLowLimValues(tree,root){if(arguments.length<2){root=tree.nodes()[0]}dfsAssignLowLim(tree,{},1,root)}function dfsAssignLowLim(tree,visited,nextLim,v,parent){var low=nextLim;var label=tree.node(v);visited[v]=true;tree.neighbors(v).forEach(w=>{if(!
|
|
418
|
+
var cutValue=0;if(!graphEdge){childIsTail=false;graphEdge=g.edge(parent,child)}cutValue=graphEdge.weight;g.nodeEdges(child).forEach(e=>{var isOutEdge=e.v===child,other=isOutEdge?e.w:e.v;if(other!==parent){var pointsToHead=isOutEdge===childIsTail,otherWeight=g.edge(e).weight;cutValue+=pointsToHead?otherWeight:-otherWeight;if(isTreeEdge(t,child,other)){var otherCutValue=t.edge(child,other).cutvalue;cutValue+=pointsToHead?-otherCutValue:otherCutValue}}});return cutValue}function initLowLimValues(tree,root){if(arguments.length<2){root=tree.nodes()[0]}dfsAssignLowLim(tree,{},1,root)}function dfsAssignLowLim(tree,visited,nextLim,v,parent){var low=nextLim;var label=tree.node(v);visited[v]=true;tree.neighbors(v).forEach(w=>{if(!Object.hasOwn(visited,w)){nextLim=dfsAssignLowLim(tree,visited,nextLim,w,v)}});label.low=low;label.lim=nextLim++;if(parent){label.parent=parent}else{
|
|
419
419
|
// TODO should be able to remove this when we incrementally update low lim
|
|
420
420
|
delete label.parent}return nextLim}function leaveEdge(tree){return tree.edges().find(e=>tree.edge(e).cutvalue<0)}function enterEdge(t,g,edge){var v=edge.v;var w=edge.w;
|
|
421
421
|
// For the rest of this function we assume that v is the tail and w is the
|
|
@@ -431,7 +431,7 @@ if(vLabel.lim>wLabel.lim){tailLabel=wLabel;flip=true}var candidates=g.edges().fi
|
|
|
431
431
|
/*
|
|
432
432
|
* Returns true if the specified node is descendant of the root node per the
|
|
433
433
|
* assigned low and lim attributes in the tree.
|
|
434
|
-
*/function isDescendant(tree,vLabel,rootLabel){return rootLabel.low<=vLabel.lim&&vLabel.lim<=rootLabel.lim}},{"../util":27,"./feasible-tree":23,"./util":26,"@dagrejs/graphlib":29}],26:[function(require,module,exports){"use strict";module.exports={longestPath:longestPath,slack:slack};
|
|
434
|
+
*/function isDescendant(tree,vLabel,rootLabel){return rootLabel.low<=vLabel.lim&&vLabel.lim<=rootLabel.lim}},{"../util":27,"./feasible-tree":23,"./util":26,"@dagrejs/graphlib":29}],26:[function(require,module,exports){"use strict";const{applyWithChunking}=require("../util");module.exports={longestPath:longestPath,slack:slack};
|
|
435
435
|
/*
|
|
436
436
|
* Initializes ranks for the input graph using the longest path algorithm. This
|
|
437
437
|
* algorithm scales well and is fast in practice, it yields rather poor
|
|
@@ -452,13 +452,13 @@ if(vLabel.lim>wLabel.lim){tailLabel=wLabel;flip=true}var candidates=g.edges().fi
|
|
|
452
452
|
* Post-conditions:
|
|
453
453
|
*
|
|
454
454
|
* 1. Each node will be assign an (unnormalized) "rank" property.
|
|
455
|
-
*/function longestPath(g){var visited={};function dfs(v){var label=g.node(v);if(
|
|
455
|
+
*/function longestPath(g){var visited={};function dfs(v){var label=g.node(v);if(Object.hasOwn(visited,v)){return label.rank}visited[v]=true;let outEdgesMinLens=g.outEdges(v).map(e=>{if(e==null){return Number.POSITIVE_INFINITY}return dfs(e.w)-g.edge(e).minlen});var rank=applyWithChunking(Math.min,outEdgesMinLens);if(rank===Number.POSITIVE_INFINITY){rank=0}return label.rank=rank}g.sources().forEach(dfs)}
|
|
456
456
|
/*
|
|
457
457
|
* Returns the amount of slack for the given edge. The slack is defined as the
|
|
458
458
|
* difference between the length of the edge and its minimum length.
|
|
459
|
-
*/function slack(g,e){return g.node(e.w).rank-g.node(e.v).rank-g.edge(e).minlen}},{}],27:[function(require,module,exports){
|
|
459
|
+
*/function slack(g,e){return g.node(e.w).rank-g.node(e.v).rank-g.edge(e).minlen}},{"../util":27}],27:[function(require,module,exports){
|
|
460
460
|
/* eslint "no-console": off */
|
|
461
|
-
"use strict";let Graph=require("@dagrejs/graphlib").Graph;module.exports={addBorderNode:addBorderNode,addDummyNode:addDummyNode,asNonCompoundGraph:asNonCompoundGraph,buildLayerMatrix:buildLayerMatrix,intersectRect:intersectRect,mapValues:mapValues,maxRank:maxRank,normalizeRanks:normalizeRanks,notime:notime,partition:partition,pick:pick,predecessorWeights:predecessorWeights,range:range,removeEmptyRanks:removeEmptyRanks,simplify:simplify,successorWeights:successorWeights,time:time,uniqueId:uniqueId,zipObject:zipObject};
|
|
461
|
+
"use strict";let Graph=require("@dagrejs/graphlib").Graph;module.exports={addBorderNode:addBorderNode,addDummyNode:addDummyNode,applyWithChunking:applyWithChunking,asNonCompoundGraph:asNonCompoundGraph,buildLayerMatrix:buildLayerMatrix,intersectRect:intersectRect,mapValues:mapValues,maxRank:maxRank,normalizeRanks:normalizeRanks,notime:notime,partition:partition,pick:pick,predecessorWeights:predecessorWeights,range:range,removeEmptyRanks:removeEmptyRanks,simplify:simplify,successorWeights:successorWeights,time:time,uniqueId:uniqueId,zipObject:zipObject};
|
|
462
462
|
/*
|
|
463
463
|
* Adds a dummy node to the graph and return v.
|
|
464
464
|
*/function addDummyNode(g,type,attrs,name){let v;do{v=uniqueId(name)}while(g.hasNode(v));attrs.dummy=type;g.setNode(v,attrs);return v}
|
|
@@ -484,9 +484,9 @@ if(dx<0){w=-w}sx=w;sy=w*dy/dx}return{x:x+sx,y:y+sy}}
|
|
|
484
484
|
/*
|
|
485
485
|
* Adjusts the ranks for all nodes in the graph such that all nodes v have
|
|
486
486
|
* rank(v) >= 0 and at least one node w has rank(w) = 0.
|
|
487
|
-
*/function normalizeRanks(g){let
|
|
487
|
+
*/function normalizeRanks(g){let nodeRanks=g.nodes().map(v=>{let rank=g.node(v).rank;if(rank===undefined){return Number.MAX_VALUE}return rank});let min=applyWithChunking(Math.min,nodeRanks);g.nodes().forEach(v=>{let node=g.node(v);if(Object.hasOwn(node,"rank")){node.rank-=min}})}function removeEmptyRanks(g){
|
|
488
488
|
// Ranks may not start at 0, so we need to offset them
|
|
489
|
-
let
|
|
489
|
+
let nodeRanks=g.nodes().map(v=>g.node(v).rank);let offset=applyWithChunking(Math.min,nodeRanks);let layers=[];g.nodes().forEach(v=>{let rank=g.node(v).rank-offset;if(!layers[rank]){layers[rank]=[]}layers[rank].push(v)});let delta=0;let nodeRankFactor=g.graph().nodeRankFactor;Array.from(layers).forEach((vs,i)=>{if(vs===undefined&&i%nodeRankFactor!==0){--delta}else if(vs!==undefined&&delta){vs.forEach(v=>g.node(v).rank+=delta)}})}function addBorderNode(g,prefix,rank,order){let node={width:0,height:0};if(arguments.length>=4){node.rank=rank;node.order=order}return addDummyNode(g,"border",node,prefix)}function splitToChunks(array,chunkSize=CHUNKING_THRESHOLD){const chunks=[];for(let i=0;i<array.length;i+=chunkSize){const chunk=array.slice(i,i+chunkSize);chunks.push(chunk)}return chunks}const CHUNKING_THRESHOLD=65535;function applyWithChunking(fn,argsArray){if(argsArray.length>CHUNKING_THRESHOLD){const chunks=splitToChunks(argsArray);return fn.apply(null,chunks.map(chunk=>fn.apply(null,chunk)))}else{return fn.apply(null,argsArray)}}function maxRank(g){const nodes=g.nodes();const nodeRanks=nodes.map(v=>{let rank=g.node(v).rank;if(rank===undefined){return Number.MIN_VALUE}return rank});return applyWithChunking(Math.max,nodeRanks)}
|
|
490
490
|
/*
|
|
491
491
|
* Partition a collection into two groups: `lhs` and `rhs`. If the supplied
|
|
492
492
|
* function returns true for an entry it goes into `lhs`. Otherwise it goes
|
|
@@ -495,7 +495,7 @@ let offset=Math.min(...g.nodes().map(v=>g.node(v).rank));let layers=[];g.nodes()
|
|
|
495
495
|
/*
|
|
496
496
|
* Returns a new function that wraps `fn` with a timer. The wrapper logs the
|
|
497
497
|
* time it takes to execute the function.
|
|
498
|
-
*/function time(name,fn){let start=Date.now();try{return fn()}finally{console.log(name+" time: "+(Date.now()-start)+"ms")}}function notime(name,fn){return fn()}let idCounter=0;function uniqueId(prefix){var id=++idCounter;return toString(prefix)+id}function range(start,limit,step=1){if(limit==null){limit=start;start=0}let endCon=i=>i<limit;if(step<0){endCon=i=>limit<i}const range=[];for(let i=start;endCon(i);i+=step){range.push(i)}return range}function pick(source,keys){const dest={};for(const key of keys){if(source[key]!==undefined){dest[key]=source[key]}}return dest}function mapValues(obj,funcOrProp){let func=funcOrProp;if(typeof funcOrProp==="string"){func=val=>val[funcOrProp]}return Object.entries(obj).reduce((acc,[k,v])=>{acc[k]=func(v,k);return acc},{})}function zipObject(props,values){return props.reduce((acc,key,i)=>{acc[key]=values[i];return acc},{})}},{"@dagrejs/graphlib":29}],28:[function(require,module,exports){module.exports="1.1.
|
|
498
|
+
*/function time(name,fn){let start=Date.now();try{return fn()}finally{console.log(name+" time: "+(Date.now()-start)+"ms")}}function notime(name,fn){return fn()}let idCounter=0;function uniqueId(prefix){var id=++idCounter;return toString(prefix)+id}function range(start,limit,step=1){if(limit==null){limit=start;start=0}let endCon=i=>i<limit;if(step<0){endCon=i=>limit<i}const range=[];for(let i=start;endCon(i);i+=step){range.push(i)}return range}function pick(source,keys){const dest={};for(const key of keys){if(source[key]!==undefined){dest[key]=source[key]}}return dest}function mapValues(obj,funcOrProp){let func=funcOrProp;if(typeof funcOrProp==="string"){func=val=>val[funcOrProp]}return Object.entries(obj).reduce((acc,[k,v])=>{acc[k]=func(v,k);return acc},{})}function zipObject(props,values){return props.reduce((acc,key,i)=>{acc[key]=values[i];return acc},{})}},{"@dagrejs/graphlib":29}],28:[function(require,module,exports){module.exports="1.1.4"},{}],29:[function(require,module,exports){
|
|
499
499
|
/**
|
|
500
500
|
* Copyright (c) 2014, Chris Pettitt
|
|
501
501
|
* All rights reserved.
|
|
@@ -525,7 +525,7 @@ let offset=Math.min(...g.nodes().map(v=>g.node(v).rank));let layers=[];g.nodes()
|
|
|
525
525
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
526
526
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
527
527
|
*/
|
|
528
|
-
var lib=require("./lib");module.exports={Graph:lib.Graph,json:require("./lib/json"),alg:require("./lib/alg"),version:lib.version}},{"./lib":45,"./lib/alg":36,"./lib/json":46}],30:[function(require,module,exports){module.exports=components;function components(g){var visited={};var cmpts=[];var cmpt;function dfs(v){if(
|
|
528
|
+
var lib=require("./lib");module.exports={Graph:lib.Graph,json:require("./lib/json"),alg:require("./lib/alg"),version:lib.version}},{"./lib":45,"./lib/alg":36,"./lib/json":46}],30:[function(require,module,exports){module.exports=components;function components(g){var visited={};var cmpts=[];var cmpt;function dfs(v){if(Object.hasOwn(visited,v))return;visited[v]=true;cmpt.push(v);g.successors(v).forEach(dfs);g.predecessors(v).forEach(dfs)}g.nodes().forEach(function(v){cmpt=[];dfs(v);if(cmpt.length){cmpts.push(cmpt)}});return cmpts}},{}],31:[function(require,module,exports){module.exports=dfs;
|
|
529
529
|
/*
|
|
530
530
|
* A helper that preforms a pre- or post-order traversal on the input graph
|
|
531
531
|
* and returns the nodes in the order they were visited. If the graph is
|
|
@@ -533,10 +533,10 @@ var lib=require("./lib");module.exports={Graph:lib.Graph,json:require("./lib/jso
|
|
|
533
533
|
* is directed then this algorithm will navigate using successors.
|
|
534
534
|
*
|
|
535
535
|
* If the order is not "post", it will be treated as "pre".
|
|
536
|
-
*/function dfs(g,vs,order){if(!Array.isArray(vs)){vs=[vs]}var navigation=g.isDirected()?v=>g.successors(v):v=>g.neighbors(v);var orderFunc=order==="post"?postOrderDfs:preOrderDfs;var acc=[];var visited={};vs.forEach(v=>{if(!g.hasNode(v)){throw new Error("Graph does not have node: "+v)}orderFunc(v,navigation,visited,acc)});return acc}function postOrderDfs(v,navigation,visited,acc){var stack=[[v,false]];while(stack.length>0){var curr=stack.pop();if(curr[1]){acc.push(curr[0])}else{if(!
|
|
536
|
+
*/function dfs(g,vs,order){if(!Array.isArray(vs)){vs=[vs]}var navigation=g.isDirected()?v=>g.successors(v):v=>g.neighbors(v);var orderFunc=order==="post"?postOrderDfs:preOrderDfs;var acc=[];var visited={};vs.forEach(v=>{if(!g.hasNode(v)){throw new Error("Graph does not have node: "+v)}orderFunc(v,navigation,visited,acc)});return acc}function postOrderDfs(v,navigation,visited,acc){var stack=[[v,false]];while(stack.length>0){var curr=stack.pop();if(curr[1]){acc.push(curr[0])}else{if(!Object.hasOwn(visited,curr[0])){visited[curr[0]]=true;stack.push([curr[0],true]);forEachRight(navigation(curr[0]),w=>stack.push([w,false]))}}}}function preOrderDfs(v,navigation,visited,acc){var stack=[v];while(stack.length>0){var curr=stack.pop();if(!Object.hasOwn(visited,curr)){visited[curr]=true;acc.push(curr);forEachRight(navigation(curr),w=>stack.push(w))}}}function forEachRight(array,iteratee){var length=array.length;while(length--){iteratee(array[length],length,array)}return array}},{}],32:[function(require,module,exports){var dijkstra=require("./dijkstra");module.exports=dijkstraAll;function dijkstraAll(g,weightFunc,edgeFunc){return g.nodes().reduce(function(acc,v){acc[v]=dijkstra(g,v,weightFunc,edgeFunc);return acc},{})}},{"./dijkstra":33}],33:[function(require,module,exports){var PriorityQueue=require("../data/priority-queue");module.exports=dijkstra;var DEFAULT_WEIGHT_FUNC=()=>1;function dijkstra(g,source,weightFn,edgeFn){return runDijkstra(g,String(source),weightFn||DEFAULT_WEIGHT_FUNC,edgeFn||function(v){return g.outEdges(v)})}function runDijkstra(g,source,weightFn,edgeFn){var results={};var pq=new PriorityQueue;var v,vEntry;var updateNeighbors=function(edge){var w=edge.v!==v?edge.v:edge.w;var wEntry=results[w];var weight=weightFn(edge);var distance=vEntry.distance+weight;if(weight<0){throw new Error("dijkstra does not allow negative edge weights. "+"Bad edge: "+edge+" Weight: "+weight)}if(distance<wEntry.distance){wEntry.distance=distance;wEntry.predecessor=v;pq.decrease(w,distance)}};g.nodes().forEach(function(v){var distance=v===source?0:Number.POSITIVE_INFINITY;results[v]={distance:distance};pq.add(v,distance)});while(pq.size()>0){v=pq.removeMin();vEntry=results[v];if(vEntry.distance===Number.POSITIVE_INFINITY){break}edgeFn(v).forEach(updateNeighbors)}return results}},{"../data/priority-queue":43}],34:[function(require,module,exports){var tarjan=require("./tarjan");module.exports=findCycles;function findCycles(g){return tarjan(g).filter(function(cmpt){return cmpt.length>1||cmpt.length===1&&g.hasEdge(cmpt[0],cmpt[0])})}},{"./tarjan":41}],35:[function(require,module,exports){module.exports=floydWarshall;var DEFAULT_WEIGHT_FUNC=()=>1;function floydWarshall(g,weightFn,edgeFn){return runFloydWarshall(g,weightFn||DEFAULT_WEIGHT_FUNC,edgeFn||function(v){return g.outEdges(v)})}function runFloydWarshall(g,weightFn,edgeFn){var results={};var nodes=g.nodes();nodes.forEach(function(v){results[v]={};results[v][v]={distance:0};nodes.forEach(function(w){if(v!==w){results[v][w]={distance:Number.POSITIVE_INFINITY}}});edgeFn(v).forEach(function(edge){var w=edge.v===v?edge.w:edge.v;var d=weightFn(edge);results[v][w]={distance:d,predecessor:v}})});nodes.forEach(function(k){var rowK=results[k];nodes.forEach(function(i){var rowI=results[i];nodes.forEach(function(j){var ik=rowI[k];var kj=rowK[j];var ij=rowI[j];var altDistance=ik.distance+kj.distance;if(altDistance<ij.distance){ij.distance=altDistance;ij.predecessor=kj.predecessor}})})});return results}},{}],36:[function(require,module,exports){module.exports={components:require("./components"),dijkstra:require("./dijkstra"),dijkstraAll:require("./dijkstra-all"),findCycles:require("./find-cycles"),floydWarshall:require("./floyd-warshall"),isAcyclic:require("./is-acyclic"),postorder:require("./postorder"),preorder:require("./preorder"),prim:require("./prim"),tarjan:require("./tarjan"),topsort:require("./topsort")}},{"./components":30,"./dijkstra":33,"./dijkstra-all":32,"./find-cycles":34,"./floyd-warshall":35,"./is-acyclic":37,"./postorder":38,"./preorder":39,"./prim":40,"./tarjan":41,"./topsort":42}],37:[function(require,module,exports){var topsort=require("./topsort");module.exports=isAcyclic;function isAcyclic(g){try{topsort(g)}catch(e){if(e instanceof topsort.CycleException){return false}throw e}return true}},{"./topsort":42}],38:[function(require,module,exports){var dfs=require("./dfs");module.exports=postorder;function postorder(g,vs){return dfs(g,vs,"post")}},{"./dfs":31}],39:[function(require,module,exports){var dfs=require("./dfs");module.exports=preorder;function preorder(g,vs){return dfs(g,vs,"pre")}},{"./dfs":31}],40:[function(require,module,exports){var Graph=require("../graph");var PriorityQueue=require("../data/priority-queue");module.exports=prim;function prim(g,weightFunc){var result=new Graph;var parents={};var pq=new PriorityQueue;var v;function updateNeighbors(edge){var w=edge.v===v?edge.w:edge.v;var pri=pq.priority(w);if(pri!==undefined){var edgeWeight=weightFunc(edge);if(edgeWeight<pri){parents[w]=v;pq.decrease(w,edgeWeight)}}}if(g.nodeCount()===0){return result}g.nodes().forEach(function(v){pq.add(v,Number.POSITIVE_INFINITY);result.setNode(v)});
|
|
537
537
|
// Start from an arbitrary node
|
|
538
|
-
pq.decrease(g.nodes()[0],0);var init=false;while(pq.size()>0){v=pq.removeMin();if(
|
|
539
|
-
var results=[];function dfs(v){var entry=visited[v]={onStack:true,lowlink:index,index:index++};stack.push(v);g.successors(v).forEach(function(w){if(!
|
|
538
|
+
pq.decrease(g.nodes()[0],0);var init=false;while(pq.size()>0){v=pq.removeMin();if(Object.hasOwn(parents,v)){result.setEdge(v,parents[v])}else if(init){throw new Error("Input graph is not connected: "+g)}else{init=true}g.nodeEdges(v).forEach(updateNeighbors)}return result}},{"../data/priority-queue":43,"../graph":44}],41:[function(require,module,exports){module.exports=tarjan;function tarjan(g){var index=0;var stack=[];var visited={};// node id -> { onStack, lowlink, index }
|
|
539
|
+
var results=[];function dfs(v){var entry=visited[v]={onStack:true,lowlink:index,index:index++};stack.push(v);g.successors(v).forEach(function(w){if(!Object.hasOwn(visited,w)){dfs(w);entry.lowlink=Math.min(entry.lowlink,visited[w].lowlink)}else if(visited[w].onStack){entry.lowlink=Math.min(entry.lowlink,visited[w].index)}});if(entry.lowlink===entry.index){var cmpt=[];var w;do{w=stack.pop();visited[w].onStack=false;cmpt.push(w)}while(v!==w);results.push(cmpt)}}g.nodes().forEach(function(v){if(!Object.hasOwn(visited,v)){dfs(v)}});return results}},{}],42:[function(require,module,exports){function topsort(g){var visited={};var stack={};var results=[];function visit(node){if(Object.hasOwn(stack,node)){throw new CycleException}if(!Object.hasOwn(visited,node)){stack[node]=true;visited[node]=true;g.predecessors(node).forEach(visit);delete stack[node];results.push(node)}}g.sinks().forEach(visit);if(Object.keys(visited).length!==g.nodeCount()){throw new CycleException}return results}class CycleException extends Error{constructor(){super(...arguments)}}module.exports=topsort;topsort.CycleException=CycleException},{}],43:[function(require,module,exports){
|
|
540
540
|
/**
|
|
541
541
|
* A min-priority queue data structure. This algorithm is derived from Cormen,
|
|
542
542
|
* et al., "Introduction to Algorithms". The basic idea of a min-priority
|
|
@@ -553,7 +553,7 @@ class PriorityQueue{_arr=[];_keyIndices={};
|
|
|
553
553
|
*/keys(){return this._arr.map(function(x){return x.key})}
|
|
554
554
|
/**
|
|
555
555
|
* Returns `true` if **key** is in the queue and `false` if not.
|
|
556
|
-
*/has(key){return this._keyIndices
|
|
556
|
+
*/has(key){return Object.hasOwn(this._keyIndices,key)}
|
|
557
557
|
/**
|
|
558
558
|
* Returns the priority for **key**. If **key** is not present in the queue
|
|
559
559
|
* then this function returns `undefined`. Takes `O(1)` time.
|
|
@@ -571,7 +571,7 @@ class PriorityQueue{_arr=[];_keyIndices={};
|
|
|
571
571
|
*
|
|
572
572
|
* @param {Object} key the key to add
|
|
573
573
|
* @param {Number} priority the initial priority for the key
|
|
574
|
-
*/add(key,priority){var keyIndices=this._keyIndices;key=String(key);if(!
|
|
574
|
+
*/add(key,priority){var keyIndices=this._keyIndices;key=String(key);if(!Object.hasOwn(keyIndices,key)){var arr=this._arr;var index=arr.length;keyIndices[key]=index;arr.push({key:key,priority:priority});this._decrease(index);return true}return false}
|
|
575
575
|
/**
|
|
576
576
|
* Removes and returns the smallest key in the queue. Takes `O(log n)` time.
|
|
577
577
|
*/removeMin(){this._swap(0,this._arr.length-1);var min=this._arr.pop();delete this._keyIndices[min.key];this._heapify(0);return min.key}
|
|
@@ -613,7 +613,7 @@ _edgeObjs={};
|
|
|
613
613
|
// e -> label
|
|
614
614
|
_edgeLabels={};
|
|
615
615
|
/* Number of nodes in the graph. Should only be changed by the implementation. */_nodeCount=0;
|
|
616
|
-
/* Number of edges in the graph. Should only be changed by the implementation. */_edgeCount=0;_parent;_children;constructor(opts){if(opts){this._isDirected=
|
|
616
|
+
/* Number of edges in the graph. Should only be changed by the implementation. */_edgeCount=0;_parent;_children;constructor(opts){if(opts){this._isDirected=Object.hasOwn(opts,"directed")?opts.directed:true;this._isMultigraph=Object.hasOwn(opts,"multigraph")?opts.multigraph:false;this._isCompound=Object.hasOwn(opts,"compound")?opts.compound:false}if(this._isCompound){
|
|
617
617
|
// v -> parent
|
|
618
618
|
this._parent={};
|
|
619
619
|
// v -> children
|
|
@@ -668,20 +668,20 @@ this._children={};this._children[GRAPH_NODE]={}}}
|
|
|
668
668
|
* it is set as the value for the node. If label is not supplied and the node was
|
|
669
669
|
* created by this call then the default node label will be assigned.
|
|
670
670
|
* Complexity: O(1).
|
|
671
|
-
*/setNode(v,value){if(this._nodes
|
|
671
|
+
*/setNode(v,value){if(Object.hasOwn(this._nodes,v)){if(arguments.length>1){this._nodes[v]=value}return this}this._nodes[v]=arguments.length>1?value:this._defaultNodeLabelFn(v);if(this._isCompound){this._parent[v]=GRAPH_NODE;this._children[v]={};this._children[GRAPH_NODE][v]=true}this._in[v]={};this._preds[v]={};this._out[v]={};this._sucs[v]={};++this._nodeCount;return this}
|
|
672
672
|
/**
|
|
673
673
|
* Gets the label of node with specified name.
|
|
674
674
|
* Complexity: O(|V|).
|
|
675
675
|
*/node(v){return this._nodes[v]}
|
|
676
676
|
/**
|
|
677
677
|
* Detects whether graph has a node with specified name or not.
|
|
678
|
-
*/hasNode(v){return this._nodes
|
|
678
|
+
*/hasNode(v){return Object.hasOwn(this._nodes,v)}
|
|
679
679
|
/**
|
|
680
680
|
* Remove the node with the name from the graph or do nothing if the node is not in
|
|
681
681
|
* the graph. If the node was removed this function also removes any incident
|
|
682
682
|
* edges.
|
|
683
683
|
* Complexity: O(1).
|
|
684
|
-
*/removeNode(v){var self=this;if(this._nodes
|
|
684
|
+
*/removeNode(v){var self=this;if(Object.hasOwn(this._nodes,v)){var removeEdge=e=>self.removeEdge(self._edgeObjs[e]);delete this._nodes[v];if(this._isCompound){this._removeFromParentsChildList(v);delete this._parent[v];this.children(v).forEach(function(child){self.setParent(child)});delete this._children[v]}Object.keys(this._in[v]).forEach(removeEdge);delete this._in[v];delete this._preds[v];Object.keys(this._out[v]).forEach(removeEdge);delete this._out[v];delete this._sucs[v];--this._nodeCount}return this}
|
|
685
685
|
/**
|
|
686
686
|
* Sets node p as a parent for node v if it is defined, or removes the
|
|
687
687
|
* parent for v if p is undefined. Method throws an exception in case of
|
|
@@ -746,7 +746,7 @@ parent+="";for(var ancestor=parent;ancestor!==undefined;ancestor=this.parent(anc
|
|
|
746
746
|
* name. If label is supplied it is set as the value for the edge. If label is not
|
|
747
747
|
* supplied and the edge was created by this call then the default edge label will
|
|
748
748
|
* be assigned. The name parameter is only useful with multigraphs.
|
|
749
|
-
*/setEdge(){var v,w,name,value;var valueSpecified=false;var arg0=arguments[0];if(typeof arg0==="object"&&arg0!==null&&"v"in arg0){v=arg0.v;w=arg0.w;name=arg0.name;if(arguments.length===2){value=arguments[1];valueSpecified=true}}else{v=arg0;w=arguments[1];name=arguments[3];if(arguments.length>2){value=arguments[2];valueSpecified=true}}v=""+v;w=""+w;if(name!==undefined){name=""+name}var e=edgeArgsToId(this._isDirected,v,w,name);if(this._edgeLabels
|
|
749
|
+
*/setEdge(){var v,w,name,value;var valueSpecified=false;var arg0=arguments[0];if(typeof arg0==="object"&&arg0!==null&&"v"in arg0){v=arg0.v;w=arg0.w;name=arg0.name;if(arguments.length===2){value=arguments[1];valueSpecified=true}}else{v=arg0;w=arguments[1];name=arguments[3];if(arguments.length>2){value=arguments[2];valueSpecified=true}}v=""+v;w=""+w;if(name!==undefined){name=""+name}var e=edgeArgsToId(this._isDirected,v,w,name);if(Object.hasOwn(this._edgeLabels,e)){if(valueSpecified){this._edgeLabels[e]=value}return this}if(name!==undefined&&!this._isMultigraph){throw new Error("Cannot set a named edge when isMultigraph = false")}
|
|
750
750
|
// It didn't exist, so we need to create it.
|
|
751
751
|
// First ensure the nodes exist.
|
|
752
752
|
this.setNode(v);this.setNode(w);this._edgeLabels[e]=valueSpecified?value:this._defaultEdgeLabelFn(v,w,name);var edgeObj=edgeArgsToObj(this._isDirected,v,w,name);
|
|
@@ -763,7 +763,7 @@ v=edgeObj.v;w=edgeObj.w;Object.freeze(edgeObj);this._edgeObjs[e]=edgeObj;increme
|
|
|
763
763
|
/**
|
|
764
764
|
* Detects whether the graph contains specified edge or not. No subgraphs are considered.
|
|
765
765
|
* Complexity: O(1).
|
|
766
|
-
*/hasEdge(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return this._edgeLabels
|
|
766
|
+
*/hasEdge(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return Object.hasOwn(this._edgeLabels,e)}
|
|
767
767
|
/**
|
|
768
768
|
* Removes the specified edge from the graph. No subgraphs are considered.
|
|
769
769
|
* Complexity: O(1).
|
|
@@ -798,4 +798,4 @@ module.exports={Graph:require("./graph"),version:require("./version")}},{"./grap
|
|
|
798
798
|
* // ['a', 'b']
|
|
799
799
|
* g2.edges()
|
|
800
800
|
* // [ { v: 'a', w: 'b' } ]
|
|
801
|
-
*/function read(json){var g=new Graph(json.options).setGraph(json.value);json.nodes.forEach(function(entry){g.setNode(entry.v,entry.value);if(entry.parent){g.setParent(entry.v,entry.parent)}});json.edges.forEach(function(entry){g.setEdge({v:entry.v,w:entry.w,name:entry.name},entry.value)});return g}},{"./graph":44}],47:[function(require,module,exports){module.exports="2.2.
|
|
801
|
+
*/function read(json){var g=new Graph(json.options).setGraph(json.value);json.nodes.forEach(function(entry){g.setNode(entry.v,entry.value);if(entry.parent){g.setParent(entry.v,entry.parent)}});json.edges.forEach(function(entry){g.setEdge({v:entry.v,w:entry.w,name:entry.name},entry.value)});return g}},{"./graph":44}],47:[function(require,module,exports){module.exports="2.2.4"},{}]},{},[1])(1)});
|
package/lib/acyclic.js
CHANGED
|
@@ -33,13 +33,13 @@ function dfsFAS(g) {
|
|
|
33
33
|
let visited = {};
|
|
34
34
|
|
|
35
35
|
function dfs(v) {
|
|
36
|
-
if (
|
|
36
|
+
if (Object.hasOwn(visited, v)) {
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
visited[v] = true;
|
|
40
40
|
stack[v] = true;
|
|
41
41
|
g.outEdges(v).forEach(e => {
|
|
42
|
-
if (
|
|
42
|
+
if (Object.hasOwn(stack, e.w)) {
|
|
43
43
|
fas.push(e);
|
|
44
44
|
} else {
|
|
45
45
|
dfs(e.w);
|
package/lib/coordinate-system.js
CHANGED
|
@@ -41,7 +41,7 @@ function reverseY(g) {
|
|
|
41
41
|
g.edges().forEach(e => {
|
|
42
42
|
let edge = g.edge(e);
|
|
43
43
|
edge.points.forEach(reverseYOne);
|
|
44
|
-
if (
|
|
44
|
+
if (Object.hasOwn(edge, "y")) {
|
|
45
45
|
reverseYOne(edge);
|
|
46
46
|
}
|
|
47
47
|
});
|
|
@@ -57,7 +57,7 @@ function swapXY(g) {
|
|
|
57
57
|
g.edges().forEach(e => {
|
|
58
58
|
let edge = g.edge(e);
|
|
59
59
|
edge.points.forEach(swapXYOne);
|
|
60
|
-
if (
|
|
60
|
+
if (Object.hasOwn(edge, "x")) {
|
|
61
61
|
swapXYOne(edge);
|
|
62
62
|
}
|
|
63
63
|
});
|
package/lib/layout.js
CHANGED
|
@@ -21,12 +21,12 @@ function layout(g, opts) {
|
|
|
21
21
|
time("layout", () => {
|
|
22
22
|
let layoutGraph =
|
|
23
23
|
time(" buildLayoutGraph", () => buildLayoutGraph(g));
|
|
24
|
-
time(" runLayout", () => runLayout(layoutGraph, time));
|
|
24
|
+
time(" runLayout", () => runLayout(layoutGraph, time, opts));
|
|
25
25
|
time(" updateInputGraph", () => updateInputGraph(g, layoutGraph));
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
function runLayout(g, time) {
|
|
29
|
+
function runLayout(g, time, opts) {
|
|
30
30
|
time(" makeSpaceForEdgeLabels", () => makeSpaceForEdgeLabels(g));
|
|
31
31
|
time(" removeSelfEdges", () => removeSelfEdges(g));
|
|
32
32
|
time(" acyclic", () => acyclic.run(g));
|
|
@@ -41,7 +41,7 @@ function runLayout(g, time) {
|
|
|
41
41
|
time(" normalize.run", () => normalize.run(g));
|
|
42
42
|
time(" parentDummyChains", () => parentDummyChains(g));
|
|
43
43
|
time(" addBorderSegments", () => addBorderSegments(g));
|
|
44
|
-
time(" order", () => order(g));
|
|
44
|
+
time(" order", () => order(g, opts));
|
|
45
45
|
time(" insertSelfEdges", () => insertSelfEdges(g));
|
|
46
46
|
time(" adjustCoordinateSystem", () => coordinateSystem.adjust(g));
|
|
47
47
|
time(" position", () => position(g));
|
|
@@ -84,7 +84,7 @@ function updateInputGraph(inputGraph, layoutGraph) {
|
|
|
84
84
|
let layoutLabel = layoutGraph.edge(e);
|
|
85
85
|
|
|
86
86
|
inputLabel.points = layoutLabel.points;
|
|
87
|
-
if (
|
|
87
|
+
if (Object.hasOwn(layoutLabel, "x")) {
|
|
88
88
|
inputLabel.x = layoutLabel.x;
|
|
89
89
|
inputLabel.y = layoutLabel.y;
|
|
90
90
|
}
|
|
@@ -233,7 +233,7 @@ function translateGraph(g) {
|
|
|
233
233
|
g.nodes().forEach(v => getExtremes(g.node(v)));
|
|
234
234
|
g.edges().forEach(e => {
|
|
235
235
|
let edge = g.edge(e);
|
|
236
|
-
if (
|
|
236
|
+
if (Object.hasOwn(edge, "x")) {
|
|
237
237
|
getExtremes(edge);
|
|
238
238
|
}
|
|
239
239
|
});
|
|
@@ -253,8 +253,8 @@ function translateGraph(g) {
|
|
|
253
253
|
p.x -= minX;
|
|
254
254
|
p.y -= minY;
|
|
255
255
|
});
|
|
256
|
-
if (
|
|
257
|
-
if (
|
|
256
|
+
if (Object.hasOwn(edge, "x")) { edge.x -= minX; }
|
|
257
|
+
if (Object.hasOwn(edge, "y")) { edge.y -= minY; }
|
|
258
258
|
});
|
|
259
259
|
|
|
260
260
|
graphLabel.width = maxX - minX + marginX;
|
|
@@ -283,7 +283,7 @@ function assignNodeIntersects(g) {
|
|
|
283
283
|
function fixupEdgeLabelCoords(g) {
|
|
284
284
|
g.edges().forEach(e => {
|
|
285
285
|
let edge = g.edge(e);
|
|
286
|
-
if (
|
|
286
|
+
if (Object.hasOwn(edge, "x")) {
|
|
287
287
|
if (edge.labelpos === "l" || edge.labelpos === "r") {
|
|
288
288
|
edge.width -= edge.labeloffset;
|
|
289
289
|
}
|
package/lib/nesting-graph.js
CHANGED
|
@@ -31,7 +31,8 @@ module.exports = {
|
|
|
31
31
|
function run(g) {
|
|
32
32
|
let root = util.addDummyNode(g, "root", {}, "_root");
|
|
33
33
|
let depths = treeDepths(g);
|
|
34
|
-
let
|
|
34
|
+
let depthsArr = Object.values(depths);
|
|
35
|
+
let height = util.applyWithChunking(Math.max, depthsArr) - 1; // Note: depths is an Object not an array
|
|
35
36
|
let nodeSep = 2 * height + 1;
|
|
36
37
|
|
|
37
38
|
g.graph().nestingRoot = root;
|
|
@@ -54,7 +54,7 @@ function buildLayerGraph(g, rank, relationship) {
|
|
|
54
54
|
result.setEdge(u, v, { weight: g.edge(e).weight + weight });
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
if (
|
|
57
|
+
if (Object.hasOwn(node, "minRank")) {
|
|
58
58
|
result.setNode(v, {
|
|
59
59
|
borderLeft: node.borderLeft[rank],
|
|
60
60
|
borderRight: node.borderRight[rank]
|
package/lib/order/init-order.js
CHANGED
|
@@ -18,7 +18,8 @@ module.exports = initOrder;
|
|
|
18
18
|
function initOrder(g) {
|
|
19
19
|
let visited = {};
|
|
20
20
|
let simpleNodes = g.nodes().filter(v => !g.children(v).length);
|
|
21
|
-
let
|
|
21
|
+
let simpleNodesRanks = simpleNodes.map(v => g.node(v).rank);
|
|
22
|
+
let maxRank = util.applyWithChunking(Math.max, simpleNodesRanks);
|
|
22
23
|
let layers = util.range(maxRank + 1).map(() => []);
|
|
23
24
|
|
|
24
25
|
function dfs(v) {
|
|
@@ -20,7 +20,7 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
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
|
-
if (
|
|
23
|
+
if (Object.hasOwn(subgraphResult, "barycenter")) {
|
|
24
24
|
mergeBarycenters(entry, subgraphResult);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -36,7 +36,7 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
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
|
-
if (!
|
|
39
|
+
if (!Object.hasOwn(result, "barycenter")) {
|
|
40
40
|
result.barycenter = 0;
|
|
41
41
|
result.weight = 0;
|
|
42
42
|
}
|
package/lib/order/sort.js
CHANGED
|
@@ -4,7 +4,7 @@ module.exports = sort;
|
|
|
4
4
|
|
|
5
5
|
function sort(entries, biasRight) {
|
|
6
6
|
let parts = util.partition(entries, entry => {
|
|
7
|
-
return
|
|
7
|
+
return Object.hasOwn(entry, "barycenter");
|
|
8
8
|
});
|
|
9
9
|
let sortable = parts.lhs,
|
|
10
10
|
unsortable = parts.rhs.sort((a, b) => b.i - a.i),
|
package/lib/position/bk.js
CHANGED
|
@@ -152,7 +152,7 @@ function hasConflict(conflicts, v, w) {
|
|
|
152
152
|
v = w;
|
|
153
153
|
w = tmp;
|
|
154
154
|
}
|
|
155
|
-
return !!conflicts[v] && conflicts[v]
|
|
155
|
+
return !!conflicts[v] && Object.hasOwn(conflicts[v], w);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
/*
|
|
@@ -313,8 +313,8 @@ function findSmallestWidthAlignment(g, xss) {
|
|
|
313
313
|
*/
|
|
314
314
|
function alignCoordinates(xss, alignTo) {
|
|
315
315
|
let alignToVals = Object.values(alignTo),
|
|
316
|
-
alignToMin = Math.min
|
|
317
|
-
alignToMax = Math.max
|
|
316
|
+
alignToMin = util.applyWithChunking(Math.min, alignToVals),
|
|
317
|
+
alignToMax = util.applyWithChunking(Math.max, alignToVals);
|
|
318
318
|
|
|
319
319
|
["u", "d"].forEach(vert => {
|
|
320
320
|
["l", "r"].forEach(horiz => {
|
|
@@ -324,9 +324,9 @@ function alignCoordinates(xss, alignTo) {
|
|
|
324
324
|
if (xs === alignTo) return;
|
|
325
325
|
|
|
326
326
|
let xsVals = Object.values(xs);
|
|
327
|
-
let delta = alignToMin - Math.min
|
|
327
|
+
let delta = alignToMin - util.applyWithChunking(Math.min, xsVals);
|
|
328
328
|
if (horiz !== "l") {
|
|
329
|
-
delta = alignToMax - Math.max
|
|
329
|
+
delta = alignToMax - util.applyWithChunking(Math.max,xsVals);
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
if (delta) {
|
|
@@ -389,7 +389,7 @@ function sep(nodeSep, edgeSep, reverseSep) {
|
|
|
389
389
|
let delta;
|
|
390
390
|
|
|
391
391
|
sum += vLabel.width / 2;
|
|
392
|
-
if (
|
|
392
|
+
if (Object.hasOwn(vLabel, "labelpos")) {
|
|
393
393
|
switch (vLabel.labelpos.toLowerCase()) {
|
|
394
394
|
case "l": delta = -vLabel.width / 2; break;
|
|
395
395
|
case "r": delta = vLabel.width / 2; break;
|
|
@@ -404,7 +404,7 @@ function sep(nodeSep, edgeSep, reverseSep) {
|
|
|
404
404
|
sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
|
|
405
405
|
|
|
406
406
|
sum += wLabel.width / 2;
|
|
407
|
-
if (
|
|
407
|
+
if (Object.hasOwn(wLabel, "labelpos")) {
|
|
408
408
|
switch (wLabel.labelpos.toLowerCase()) {
|
|
409
409
|
case "l": delta = wLabel.width / 2; break;
|
|
410
410
|
case "r": delta = -wLabel.width / 2; break;
|
|
@@ -132,7 +132,7 @@ function dfsAssignLowLim(tree, visited, nextLim, v, parent) {
|
|
|
132
132
|
|
|
133
133
|
visited[v] = true;
|
|
134
134
|
tree.neighbors(v).forEach(w => {
|
|
135
|
-
if (!
|
|
135
|
+
if (!Object.hasOwn(visited, w)) {
|
|
136
136
|
nextLim = dfsAssignLowLim(tree, visited, nextLim, w, v);
|
|
137
137
|
}
|
|
138
138
|
});
|
package/lib/rank/util.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
const { applyWithChunking } = require("../util");
|
|
4
|
+
|
|
3
5
|
module.exports = {
|
|
4
6
|
longestPath: longestPath,
|
|
5
7
|
slack: slack
|
|
@@ -31,18 +33,20 @@ function longestPath(g) {
|
|
|
31
33
|
|
|
32
34
|
function dfs(v) {
|
|
33
35
|
var label = g.node(v);
|
|
34
|
-
if (
|
|
36
|
+
if (Object.hasOwn(visited, v)) {
|
|
35
37
|
return label.rank;
|
|
36
38
|
}
|
|
37
39
|
visited[v] = true;
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
let outEdgesMinLens = g.outEdges(v).map(e => {
|
|
40
42
|
if (e == null) {
|
|
41
43
|
return Number.POSITIVE_INFINITY;
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
return dfs(e.w) - g.edge(e).minlen;
|
|
45
|
-
})
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
var rank = applyWithChunking(Math.min, outEdgesMinLens);
|
|
46
50
|
|
|
47
51
|
if (rank === Number.POSITIVE_INFINITY) {
|
|
48
52
|
rank = 0;
|
package/lib/util.js
CHANGED
|
@@ -7,6 +7,7 @@ let Graph = require("@dagrejs/graphlib").Graph;
|
|
|
7
7
|
module.exports = {
|
|
8
8
|
addBorderNode,
|
|
9
9
|
addDummyNode,
|
|
10
|
+
applyWithChunking,
|
|
10
11
|
asNonCompoundGraph,
|
|
11
12
|
buildLayerMatrix,
|
|
12
13
|
intersectRect,
|
|
@@ -153,17 +154,18 @@ function buildLayerMatrix(g) {
|
|
|
153
154
|
* rank(v) >= 0 and at least one node w has rank(w) = 0.
|
|
154
155
|
*/
|
|
155
156
|
function normalizeRanks(g) {
|
|
156
|
-
let
|
|
157
|
+
let nodeRanks = g.nodes().map(v => {
|
|
157
158
|
let rank = g.node(v).rank;
|
|
158
159
|
if (rank === undefined) {
|
|
159
160
|
return Number.MAX_VALUE;
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
return rank;
|
|
163
|
-
})
|
|
164
|
+
});
|
|
165
|
+
let min = applyWithChunking(Math.min, nodeRanks);
|
|
164
166
|
g.nodes().forEach(v => {
|
|
165
167
|
let node = g.node(v);
|
|
166
|
-
if (
|
|
168
|
+
if (Object.hasOwn(node, "rank")) {
|
|
167
169
|
node.rank -= min;
|
|
168
170
|
}
|
|
169
171
|
});
|
|
@@ -171,7 +173,8 @@ function normalizeRanks(g) {
|
|
|
171
173
|
|
|
172
174
|
function removeEmptyRanks(g) {
|
|
173
175
|
// Ranks may not start at 0, so we need to offset them
|
|
174
|
-
let
|
|
176
|
+
let nodeRanks = g.nodes().map(v => g.node(v).rank);
|
|
177
|
+
let offset = applyWithChunking(Math.min, nodeRanks);
|
|
175
178
|
|
|
176
179
|
let layers = [];
|
|
177
180
|
g.nodes().forEach(v => {
|
|
@@ -205,15 +208,37 @@ function addBorderNode(g, prefix, rank, order) {
|
|
|
205
208
|
return addDummyNode(g, "border", node, prefix);
|
|
206
209
|
}
|
|
207
210
|
|
|
211
|
+
function splitToChunks(array, chunkSize = CHUNKING_THRESHOLD) {
|
|
212
|
+
const chunks = [];
|
|
213
|
+
for (let i = 0; i < array.length; i += chunkSize) {
|
|
214
|
+
const chunk = array.slice(i, i + chunkSize);
|
|
215
|
+
chunks.push(chunk);
|
|
216
|
+
}
|
|
217
|
+
return chunks;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const CHUNKING_THRESHOLD = 65535;
|
|
221
|
+
|
|
222
|
+
function applyWithChunking(fn, argsArray) {
|
|
223
|
+
if(argsArray.length > CHUNKING_THRESHOLD) {
|
|
224
|
+
const chunks = splitToChunks(argsArray);
|
|
225
|
+
return fn.apply(null, chunks.map(chunk => fn.apply(null, chunk)));
|
|
226
|
+
} else {
|
|
227
|
+
return fn.apply(null, argsArray);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
208
231
|
function maxRank(g) {
|
|
209
|
-
|
|
232
|
+
const nodes = g.nodes();
|
|
233
|
+
const nodeRanks = nodes.map(v => {
|
|
210
234
|
let rank = g.node(v).rank;
|
|
211
235
|
if (rank === undefined) {
|
|
212
236
|
return Number.MIN_VALUE;
|
|
213
237
|
}
|
|
214
|
-
|
|
215
238
|
return rank;
|
|
216
|
-
})
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
return applyWithChunking(Math.max, nodeRanks);
|
|
217
242
|
}
|
|
218
243
|
|
|
219
244
|
/*
|
package/lib/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
module.exports = "1.1.
|
|
1
|
+
module.exports = "1.1.4";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dagrejs/dagre",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "Graph layout for JavaScript",
|
|
5
5
|
"author": "Chris Pettitt <cpettitt@gmail.com>",
|
|
6
6
|
"contributors": [
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"layout"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@dagrejs/graphlib": "2.2.
|
|
27
|
+
"@dagrejs/graphlib": "2.2.4"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"benchmark": "2.1.4",
|