@dagrejs/dagre 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -7
- package/dist/dagre.js +443 -445
- package/dist/dagre.min.js +52 -52
- package/index.d.ts +18 -3
- package/lib/acyclic.js +20 -28
- package/lib/add-border-segments.js +23 -15
- package/lib/coordinate-system.js +13 -23
- package/lib/data/list.js +40 -37
- package/lib/debug.js +31 -22
- package/lib/greedy-fas.js +60 -55
- package/lib/index.js +38 -0
- package/lib/layout.js +158 -155
- package/lib/nesting-graph.js +35 -40
- package/lib/normalize.js +34 -30
- package/lib/order/add-subgraph-constraints.js +9 -5
- package/lib/order/barycenter.js +17 -9
- package/lib/order/build-layer-graph.js +24 -18
- package/lib/order/cross-count.js +22 -19
- package/lib/order/index.js +37 -28
- package/lib/order/init-order.js +14 -13
- package/lib/order/resolve-conflicts.js +20 -30
- package/lib/order/sort-subgraph.js +25 -31
- package/lib/order/sort.js +18 -17
- package/lib/parent-dummy-chains.js +36 -38
- package/lib/position/bk.js +103 -145
- package/lib/position/index.js +14 -13
- package/lib/rank/feasible-tree.js +15 -18
- package/lib/rank/index.js +25 -15
- package/lib/rank/network-simplex.js +22 -43
- package/lib/rank/util.js +6 -12
- package/lib/util.js +69 -84
- package/lib/version.js +8 -1
- package/mjs-lib/acyclic.js +62 -0
- package/mjs-lib/add-border-segments.js +35 -0
- package/mjs-lib/coordinate-system.js +65 -0
- package/mjs-lib/data/list.js +56 -0
- package/mjs-lib/debug.js +30 -0
- package/mjs-lib/greedy-fas.js +125 -0
- package/mjs-lib/index.js +9 -0
- package/mjs-lib/layout.js +405 -0
- package/mjs-lib/nesting-graph.js +120 -0
- package/mjs-lib/normalize.js +84 -0
- package/mjs-lib/order/add-subgraph-constraints.js +49 -0
- package/mjs-lib/order/barycenter.js +24 -0
- package/mjs-lib/order/build-layer-graph.js +71 -0
- package/mjs-lib/order/cross-count.js +64 -0
- package/mjs-lib/order/index.js +70 -0
- package/mjs-lib/order/init-order.js +34 -0
- package/mjs-lib/order/resolve-conflicts.js +116 -0
- package/mjs-lib/order/sort-subgraph.js +71 -0
- package/mjs-lib/order/sort.js +54 -0
- package/mjs-lib/parent-dummy-chains.js +82 -0
- package/mjs-lib/position/bk.js +409 -0
- package/mjs-lib/position/index.js +30 -0
- package/mjs-lib/rank/feasible-tree.js +93 -0
- package/mjs-lib/rank/index.js +46 -0
- package/mjs-lib/rank/network-simplex.js +233 -0
- package/mjs-lib/rank/util.js +58 -0
- package/mjs-lib/util.js +305 -0
- package/mjs-lib/version.js +1 -0
- package/package.json +14 -3
package/lib/layout.js
CHANGED
|
@@ -1,59 +1,61 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
var
|
|
12
|
-
var
|
|
13
|
-
var
|
|
14
|
-
var
|
|
15
|
-
var
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = layout;
|
|
7
|
+
var acyclic = _interopRequireWildcard(require("./acyclic.js"));
|
|
8
|
+
var normalize = _interopRequireWildcard(require("./normalize.js"));
|
|
9
|
+
var _index = _interopRequireDefault(require("./rank/index.js"));
|
|
10
|
+
var _parentDummyChains = _interopRequireDefault(require("./parent-dummy-chains.js"));
|
|
11
|
+
var nestingGraph = _interopRequireWildcard(require("./nesting-graph.js"));
|
|
12
|
+
var _addBorderSegments = _interopRequireDefault(require("./add-border-segments.js"));
|
|
13
|
+
var coordinateSystem = _interopRequireWildcard(require("./coordinate-system.js"));
|
|
14
|
+
var _index2 = _interopRequireDefault(require("./order/index.js"));
|
|
15
|
+
var _index3 = _interopRequireDefault(require("./position/index.js"));
|
|
16
|
+
var util = _interopRequireWildcard(require("./util.js"));
|
|
17
|
+
var _graphlib = require("@dagrejs/graphlib");
|
|
18
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
20
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
21
|
+
const removeEmptyRanks = util.removeEmptyRanks;
|
|
22
|
+
const normalizeRanks = util.normalizeRanks;
|
|
19
23
|
function layout(g, opts) {
|
|
20
|
-
|
|
21
|
-
time("layout",
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
time("
|
|
25
|
-
time(" updateInputGraph", function() { updateInputGraph(g, layoutGraph); });
|
|
24
|
+
let time = opts && opts.debugTiming ? util.time : util.notime;
|
|
25
|
+
time("layout", () => {
|
|
26
|
+
let layoutGraph = time(" buildLayoutGraph", () => buildLayoutGraph(g));
|
|
27
|
+
time(" runLayout", () => runLayout(layoutGraph, time));
|
|
28
|
+
time(" updateInputGraph", () => updateInputGraph(g, layoutGraph));
|
|
26
29
|
});
|
|
27
30
|
}
|
|
28
|
-
|
|
29
31
|
function runLayout(g, time) {
|
|
30
|
-
time(" makeSpaceForEdgeLabels",
|
|
31
|
-
time(" removeSelfEdges",
|
|
32
|
-
time(" acyclic",
|
|
33
|
-
time(" nestingGraph.run",
|
|
34
|
-
time(" rank",
|
|
35
|
-
time(" injectEdgeLabelProxies",
|
|
36
|
-
time(" removeEmptyRanks",
|
|
37
|
-
time(" nestingGraph.cleanup",
|
|
38
|
-
time(" normalizeRanks",
|
|
39
|
-
time(" assignRankMinMax",
|
|
40
|
-
time(" removeEdgeLabelProxies",
|
|
41
|
-
time(" normalize.run",
|
|
42
|
-
time(" parentDummyChains",
|
|
43
|
-
time(" addBorderSegments",
|
|
44
|
-
time(" order",
|
|
45
|
-
time(" insertSelfEdges",
|
|
46
|
-
time(" adjustCoordinateSystem",
|
|
47
|
-
time(" position",
|
|
48
|
-
time(" positionSelfEdges",
|
|
49
|
-
time(" removeBorderNodes",
|
|
50
|
-
time(" normalize.undo",
|
|
51
|
-
time(" fixupEdgeLabelCoords",
|
|
52
|
-
time(" undoCoordinateSystem",
|
|
53
|
-
time(" translateGraph",
|
|
54
|
-
time(" assignNodeIntersects",
|
|
55
|
-
time(" reversePoints",
|
|
56
|
-
time(" acyclic.undo",
|
|
32
|
+
time(" makeSpaceForEdgeLabels", () => makeSpaceForEdgeLabels(g));
|
|
33
|
+
time(" removeSelfEdges", () => removeSelfEdges(g));
|
|
34
|
+
time(" acyclic", () => acyclic.run(g));
|
|
35
|
+
time(" nestingGraph.run", () => nestingGraph.run(g));
|
|
36
|
+
time(" rank", () => (0, _index.default)(util.asNonCompoundGraph(g)));
|
|
37
|
+
time(" injectEdgeLabelProxies", () => injectEdgeLabelProxies(g));
|
|
38
|
+
time(" removeEmptyRanks", () => removeEmptyRanks(g));
|
|
39
|
+
time(" nestingGraph.cleanup", () => nestingGraph.cleanup(g));
|
|
40
|
+
time(" normalizeRanks", () => normalizeRanks(g));
|
|
41
|
+
time(" assignRankMinMax", () => assignRankMinMax(g));
|
|
42
|
+
time(" removeEdgeLabelProxies", () => removeEdgeLabelProxies(g));
|
|
43
|
+
time(" normalize.run", () => normalize.run(g));
|
|
44
|
+
time(" parentDummyChains", () => (0, _parentDummyChains.default)(g));
|
|
45
|
+
time(" addBorderSegments", () => (0, _addBorderSegments.default)(g));
|
|
46
|
+
time(" order", () => (0, _index2.default)(g));
|
|
47
|
+
time(" insertSelfEdges", () => insertSelfEdges(g));
|
|
48
|
+
time(" adjustCoordinateSystem", () => coordinateSystem.adjust(g));
|
|
49
|
+
time(" position", () => (0, _index3.default)(g));
|
|
50
|
+
time(" positionSelfEdges", () => positionSelfEdges(g));
|
|
51
|
+
time(" removeBorderNodes", () => removeBorderNodes(g));
|
|
52
|
+
time(" normalize.undo", () => normalize.undo(g));
|
|
53
|
+
time(" fixupEdgeLabelCoords", () => fixupEdgeLabelCoords(g));
|
|
54
|
+
time(" undoCoordinateSystem", () => coordinateSystem.undo(g));
|
|
55
|
+
time(" translateGraph", () => translateGraph(g));
|
|
56
|
+
time(" assignNodeIntersects", () => assignNodeIntersects(g));
|
|
57
|
+
time(" reversePoints", () => reversePointsForReversedEdges(g));
|
|
58
|
+
time(" acyclic.undo", () => acyclic.undo(g));
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
/*
|
|
@@ -64,47 +66,53 @@ function runLayout(g, time) {
|
|
|
64
66
|
*/
|
|
65
67
|
function updateInputGraph(inputGraph, layoutGraph) {
|
|
66
68
|
inputGraph.nodes().forEach(v => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
let inputLabel = inputGraph.node(v);
|
|
70
|
+
let layoutLabel = layoutGraph.node(v);
|
|
70
71
|
if (inputLabel) {
|
|
71
72
|
inputLabel.x = layoutLabel.x;
|
|
72
73
|
inputLabel.y = layoutLabel.y;
|
|
73
74
|
inputLabel.rank = layoutLabel.rank;
|
|
74
|
-
|
|
75
75
|
if (layoutGraph.children(v).length) {
|
|
76
76
|
inputLabel.width = layoutLabel.width;
|
|
77
77
|
inputLabel.height = layoutLabel.height;
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
});
|
|
81
|
-
|
|
82
81
|
inputGraph.edges().forEach(e => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
let inputLabel = inputGraph.edge(e);
|
|
83
|
+
let layoutLabel = layoutGraph.edge(e);
|
|
86
84
|
inputLabel.points = layoutLabel.points;
|
|
87
85
|
if (layoutLabel.hasOwnProperty("x")) {
|
|
88
86
|
inputLabel.x = layoutLabel.x;
|
|
89
87
|
inputLabel.y = layoutLabel.y;
|
|
90
88
|
}
|
|
91
89
|
});
|
|
92
|
-
|
|
93
90
|
inputGraph.graph().width = layoutGraph.graph().width;
|
|
94
91
|
inputGraph.graph().height = layoutGraph.graph().height;
|
|
95
92
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
var edgeNumAttrs = ["minlen", "weight", "width", "height", "labeloffset"];
|
|
103
|
-
var edgeDefaults = {
|
|
104
|
-
minlen: 1, weight: 1, width: 0, height: 0,
|
|
105
|
-
labeloffset: 10, labelpos: "r"
|
|
93
|
+
let graphNumAttrs = ["nodesep", "edgesep", "ranksep", "marginx", "marginy"];
|
|
94
|
+
let graphDefaults = {
|
|
95
|
+
ranksep: 50,
|
|
96
|
+
edgesep: 20,
|
|
97
|
+
nodesep: 50,
|
|
98
|
+
rankdir: "tb"
|
|
106
99
|
};
|
|
107
|
-
|
|
100
|
+
let graphAttrs = ["acyclicer", "ranker", "rankdir", "align"];
|
|
101
|
+
let nodeNumAttrs = ["width", "height"];
|
|
102
|
+
let nodeDefaults = {
|
|
103
|
+
width: 0,
|
|
104
|
+
height: 0
|
|
105
|
+
};
|
|
106
|
+
let edgeNumAttrs = ["minlen", "weight", "width", "height", "labeloffset"];
|
|
107
|
+
let edgeDefaults = {
|
|
108
|
+
minlen: 1,
|
|
109
|
+
weight: 1,
|
|
110
|
+
width: 0,
|
|
111
|
+
height: 0,
|
|
112
|
+
labeloffset: 10,
|
|
113
|
+
labelpos: "r"
|
|
114
|
+
};
|
|
115
|
+
let edgeAttrs = ["labelpos"];
|
|
108
116
|
|
|
109
117
|
/*
|
|
110
118
|
* Constructs a new graph from the input graph, which can be used for layout.
|
|
@@ -113,35 +121,27 @@ var edgeAttrs = ["labelpos"];
|
|
|
113
121
|
* attributes can influence layout.
|
|
114
122
|
*/
|
|
115
123
|
function buildLayoutGraph(inputGraph) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
util.pick(graph, graphAttrs)));
|
|
123
|
-
|
|
124
|
+
let g = new _graphlib.Graph({
|
|
125
|
+
multigraph: true,
|
|
126
|
+
compound: true
|
|
127
|
+
});
|
|
128
|
+
let graph = canonicalize(inputGraph.graph());
|
|
129
|
+
g.setGraph(Object.assign({}, graphDefaults, selectNumberAttrs(graph, graphNumAttrs), util.pick(graph, graphAttrs)));
|
|
124
130
|
inputGraph.nodes().forEach(v => {
|
|
125
|
-
|
|
131
|
+
let node = canonicalize(inputGraph.node(v));
|
|
126
132
|
const newNode = selectNumberAttrs(node, nodeNumAttrs);
|
|
127
133
|
Object.keys(nodeDefaults).forEach(k => {
|
|
128
134
|
if (newNode[k] === undefined) {
|
|
129
135
|
newNode[k] = nodeDefaults[k];
|
|
130
136
|
}
|
|
131
137
|
});
|
|
132
|
-
|
|
133
138
|
g.setNode(v, newNode);
|
|
134
139
|
g.setParent(v, inputGraph.parent(v));
|
|
135
140
|
});
|
|
136
|
-
|
|
137
141
|
inputGraph.edges().forEach(e => {
|
|
138
|
-
|
|
139
|
-
g.setEdge(e, Object.assign({},
|
|
140
|
-
edgeDefaults,
|
|
141
|
-
selectNumberAttrs(edge, edgeNumAttrs),
|
|
142
|
-
util.pick(edge, edgeAttrs)));
|
|
142
|
+
let edge = canonicalize(inputGraph.edge(e));
|
|
143
|
+
g.setEdge(e, Object.assign({}, edgeDefaults, selectNumberAttrs(edge, edgeNumAttrs), util.pick(edge, edgeAttrs)));
|
|
143
144
|
});
|
|
144
|
-
|
|
145
145
|
return g;
|
|
146
146
|
}
|
|
147
147
|
|
|
@@ -154,10 +154,10 @@ function buildLayoutGraph(inputGraph) {
|
|
|
154
154
|
* away from the edge itself a bit.
|
|
155
155
|
*/
|
|
156
156
|
function makeSpaceForEdgeLabels(g) {
|
|
157
|
-
|
|
157
|
+
let graph = g.graph();
|
|
158
158
|
graph.ranksep /= 2;
|
|
159
159
|
g.edges().forEach(e => {
|
|
160
|
-
|
|
160
|
+
let edge = g.edge(e);
|
|
161
161
|
edge.minlen *= 2;
|
|
162
162
|
if (edge.labelpos.toLowerCase() !== "c") {
|
|
163
163
|
if (graph.rankdir === "TB" || graph.rankdir === "BT") {
|
|
@@ -177,20 +177,22 @@ function makeSpaceForEdgeLabels(g) {
|
|
|
177
177
|
*/
|
|
178
178
|
function injectEdgeLabelProxies(g) {
|
|
179
179
|
g.edges().forEach(e => {
|
|
180
|
-
|
|
180
|
+
let edge = g.edge(e);
|
|
181
181
|
if (edge.width && edge.height) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
182
|
+
let v = g.node(e.v);
|
|
183
|
+
let w = g.node(e.w);
|
|
184
|
+
let label = {
|
|
185
|
+
rank: (w.rank - v.rank) / 2 + v.rank,
|
|
186
|
+
e: e
|
|
187
|
+
};
|
|
185
188
|
util.addDummyNode(g, "edge-proxy", label, "_ep");
|
|
186
189
|
}
|
|
187
190
|
});
|
|
188
191
|
}
|
|
189
|
-
|
|
190
192
|
function assignRankMinMax(g) {
|
|
191
|
-
|
|
193
|
+
let maxRank = 0;
|
|
192
194
|
g.nodes().forEach(v => {
|
|
193
|
-
|
|
195
|
+
let node = g.node(v);
|
|
194
196
|
if (node.borderTop) {
|
|
195
197
|
node.minRank = g.node(node.borderTop).rank;
|
|
196
198
|
node.maxRank = g.node(node.borderBottom).rank;
|
|
@@ -199,74 +201,69 @@ function assignRankMinMax(g) {
|
|
|
199
201
|
});
|
|
200
202
|
g.graph().maxRank = maxRank;
|
|
201
203
|
}
|
|
202
|
-
|
|
203
204
|
function removeEdgeLabelProxies(g) {
|
|
204
205
|
g.nodes().forEach(v => {
|
|
205
|
-
|
|
206
|
+
let node = g.node(v);
|
|
206
207
|
if (node.dummy === "edge-proxy") {
|
|
207
208
|
g.edge(node.e).labelRank = node.rank;
|
|
208
209
|
g.removeNode(v);
|
|
209
210
|
}
|
|
210
211
|
});
|
|
211
212
|
}
|
|
212
|
-
|
|
213
213
|
function translateGraph(g) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
214
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
215
|
+
let maxX = 0;
|
|
216
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
217
|
+
let maxY = 0;
|
|
218
|
+
let graphLabel = g.graph();
|
|
219
|
+
let marginX = graphLabel.marginx || 0;
|
|
220
|
+
let marginY = graphLabel.marginy || 0;
|
|
222
221
|
function getExtremes(attrs) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
222
|
+
let x = attrs.x;
|
|
223
|
+
let y = attrs.y;
|
|
224
|
+
let w = attrs.width;
|
|
225
|
+
let h = attrs.height;
|
|
227
226
|
minX = Math.min(minX, x - w / 2);
|
|
228
227
|
maxX = Math.max(maxX, x + w / 2);
|
|
229
228
|
minY = Math.min(minY, y - h / 2);
|
|
230
229
|
maxY = Math.max(maxY, y + h / 2);
|
|
231
230
|
}
|
|
232
|
-
|
|
233
231
|
g.nodes().forEach(v => getExtremes(g.node(v)));
|
|
234
232
|
g.edges().forEach(e => {
|
|
235
|
-
|
|
233
|
+
let edge = g.edge(e);
|
|
236
234
|
if (edge.hasOwnProperty("x")) {
|
|
237
235
|
getExtremes(edge);
|
|
238
236
|
}
|
|
239
237
|
});
|
|
240
|
-
|
|
241
238
|
minX -= marginX;
|
|
242
239
|
minY -= marginY;
|
|
243
|
-
|
|
244
240
|
g.nodes().forEach(v => {
|
|
245
|
-
|
|
241
|
+
let node = g.node(v);
|
|
246
242
|
node.x -= minX;
|
|
247
243
|
node.y -= minY;
|
|
248
244
|
});
|
|
249
|
-
|
|
250
245
|
g.edges().forEach(e => {
|
|
251
|
-
|
|
246
|
+
let edge = g.edge(e);
|
|
252
247
|
edge.points.forEach(p => {
|
|
253
248
|
p.x -= minX;
|
|
254
249
|
p.y -= minY;
|
|
255
250
|
});
|
|
256
|
-
if (edge.hasOwnProperty("x")) {
|
|
257
|
-
|
|
251
|
+
if (edge.hasOwnProperty("x")) {
|
|
252
|
+
edge.x -= minX;
|
|
253
|
+
}
|
|
254
|
+
if (edge.hasOwnProperty("y")) {
|
|
255
|
+
edge.y -= minY;
|
|
256
|
+
}
|
|
258
257
|
});
|
|
259
|
-
|
|
260
258
|
graphLabel.width = maxX - minX + marginX;
|
|
261
259
|
graphLabel.height = maxY - minY + marginY;
|
|
262
260
|
}
|
|
263
|
-
|
|
264
261
|
function assignNodeIntersects(g) {
|
|
265
262
|
g.edges().forEach(e => {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
263
|
+
let edge = g.edge(e);
|
|
264
|
+
let nodeV = g.node(e.v);
|
|
265
|
+
let nodeW = g.node(e.w);
|
|
266
|
+
let p1, p2;
|
|
270
267
|
if (!edge.points) {
|
|
271
268
|
edge.points = [];
|
|
272
269
|
p1 = nodeW;
|
|
@@ -279,54 +276,52 @@ function assignNodeIntersects(g) {
|
|
|
279
276
|
edge.points.push(util.intersectRect(nodeW, p2));
|
|
280
277
|
});
|
|
281
278
|
}
|
|
282
|
-
|
|
283
279
|
function fixupEdgeLabelCoords(g) {
|
|
284
280
|
g.edges().forEach(e => {
|
|
285
|
-
|
|
281
|
+
let edge = g.edge(e);
|
|
286
282
|
if (edge.hasOwnProperty("x")) {
|
|
287
283
|
if (edge.labelpos === "l" || edge.labelpos === "r") {
|
|
288
284
|
edge.width -= edge.labeloffset;
|
|
289
285
|
}
|
|
290
286
|
switch (edge.labelpos) {
|
|
291
|
-
|
|
292
|
-
|
|
287
|
+
case "l":
|
|
288
|
+
edge.x -= edge.width / 2 + edge.labeloffset;
|
|
289
|
+
break;
|
|
290
|
+
case "r":
|
|
291
|
+
edge.x += edge.width / 2 + edge.labeloffset;
|
|
292
|
+
break;
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
});
|
|
296
296
|
}
|
|
297
|
-
|
|
298
297
|
function reversePointsForReversedEdges(g) {
|
|
299
298
|
g.edges().forEach(e => {
|
|
300
|
-
|
|
299
|
+
let edge = g.edge(e);
|
|
301
300
|
if (edge.reversed) {
|
|
302
301
|
edge.points.reverse();
|
|
303
302
|
}
|
|
304
303
|
});
|
|
305
304
|
}
|
|
306
|
-
|
|
307
305
|
function removeBorderNodes(g) {
|
|
308
306
|
g.nodes().forEach(v => {
|
|
309
307
|
if (g.children(v).length) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
308
|
+
let node = g.node(v);
|
|
309
|
+
let t = g.node(node.borderTop);
|
|
310
|
+
let b = g.node(node.borderBottom);
|
|
311
|
+
let l = g.node(node.borderLeft[node.borderLeft.length - 1]);
|
|
312
|
+
let r = g.node(node.borderRight[node.borderRight.length - 1]);
|
|
316
313
|
node.width = Math.abs(r.x - l.x);
|
|
317
314
|
node.height = Math.abs(b.y - t.y);
|
|
318
315
|
node.x = l.x + node.width / 2;
|
|
319
316
|
node.y = t.y + node.height / 2;
|
|
320
317
|
}
|
|
321
318
|
});
|
|
322
|
-
|
|
323
319
|
g.nodes().forEach(v => {
|
|
324
320
|
if (g.node(v).dummy === "border") {
|
|
325
321
|
g.removeNode(v);
|
|
326
322
|
}
|
|
327
323
|
});
|
|
328
324
|
}
|
|
329
|
-
|
|
330
325
|
function removeSelfEdges(g) {
|
|
331
326
|
g.edges().forEach(e => {
|
|
332
327
|
if (e.v === e.w) {
|
|
@@ -334,12 +329,14 @@ function removeSelfEdges(g) {
|
|
|
334
329
|
if (!node.selfEdges) {
|
|
335
330
|
node.selfEdges = [];
|
|
336
331
|
}
|
|
337
|
-
node.selfEdges.push({
|
|
332
|
+
node.selfEdges.push({
|
|
333
|
+
e: e,
|
|
334
|
+
label: g.edge(e)
|
|
335
|
+
});
|
|
338
336
|
g.removeEdge(e);
|
|
339
337
|
}
|
|
340
338
|
});
|
|
341
339
|
}
|
|
342
|
-
|
|
343
340
|
function insertSelfEdges(g) {
|
|
344
341
|
var layers = util.buildLayerMatrix(g);
|
|
345
342
|
layers.forEach(layer => {
|
|
@@ -352,7 +349,7 @@ function insertSelfEdges(g) {
|
|
|
352
349
|
width: selfEdge.label.width,
|
|
353
350
|
height: selfEdge.label.height,
|
|
354
351
|
rank: node.rank,
|
|
355
|
-
order: i +
|
|
352
|
+
order: i + ++orderShift,
|
|
356
353
|
e: selfEdge.e,
|
|
357
354
|
label: selfEdge.label
|
|
358
355
|
}, "_se");
|
|
@@ -361,7 +358,6 @@ function insertSelfEdges(g) {
|
|
|
361
358
|
});
|
|
362
359
|
});
|
|
363
360
|
}
|
|
364
|
-
|
|
365
361
|
function positionSelfEdges(g) {
|
|
366
362
|
g.nodes().forEach(v => {
|
|
367
363
|
var node = g.node(v);
|
|
@@ -373,23 +369,30 @@ function positionSelfEdges(g) {
|
|
|
373
369
|
var dy = selfNode.height / 2;
|
|
374
370
|
g.setEdge(node.e, node.label);
|
|
375
371
|
g.removeNode(v);
|
|
376
|
-
node.label.points = [
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
372
|
+
node.label.points = [{
|
|
373
|
+
x: x + 2 * dx / 3,
|
|
374
|
+
y: y - dy
|
|
375
|
+
}, {
|
|
376
|
+
x: x + 5 * dx / 6,
|
|
377
|
+
y: y - dy
|
|
378
|
+
}, {
|
|
379
|
+
x: x + dx,
|
|
380
|
+
y: y
|
|
381
|
+
}, {
|
|
382
|
+
x: x + 5 * dx / 6,
|
|
383
|
+
y: y + dy
|
|
384
|
+
}, {
|
|
385
|
+
x: x + 2 * dx / 3,
|
|
386
|
+
y: y + dy
|
|
387
|
+
}];
|
|
383
388
|
node.label.x = node.x;
|
|
384
389
|
node.label.y = node.y;
|
|
385
390
|
}
|
|
386
391
|
});
|
|
387
392
|
}
|
|
388
|
-
|
|
389
393
|
function selectNumberAttrs(obj, attrs) {
|
|
390
394
|
return util.mapValues(util.pick(obj, attrs), Number);
|
|
391
395
|
}
|
|
392
|
-
|
|
393
396
|
function canonicalize(attrs) {
|
|
394
397
|
var newAttrs = {};
|
|
395
398
|
if (attrs) {
|
|
@@ -397,9 +400,9 @@ function canonicalize(attrs) {
|
|
|
397
400
|
if (typeof k === "string") {
|
|
398
401
|
k = k.toLowerCase();
|
|
399
402
|
}
|
|
400
|
-
|
|
401
403
|
newAttrs[k] = v;
|
|
402
404
|
});
|
|
403
405
|
}
|
|
404
406
|
return newAttrs;
|
|
405
407
|
}
|
|
408
|
+
module.exports = exports.default;
|
package/lib/nesting-graph.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.cleanup = cleanup;
|
|
7
|
+
exports.run = run;
|
|
8
|
+
var util = _interopRequireWildcard(require("./util.js"));
|
|
9
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
10
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
8
11
|
/*
|
|
9
12
|
* A nesting graph creates dummy nodes for the tops and bottoms of subgraphs,
|
|
10
13
|
* adds appropriate edges to ensure that all cluster nodes are placed between
|
|
11
|
-
* these
|
|
14
|
+
* these boundaries, and ensures that the graph is connected.
|
|
12
15
|
*
|
|
13
16
|
* In addition we ensure, through the use of the minlen property, that nodes
|
|
14
17
|
* and subgraph border nodes to not end up on the same rank.
|
|
@@ -29,74 +32,68 @@ module.exports = {
|
|
|
29
32
|
* Graphs."
|
|
30
33
|
*/
|
|
31
34
|
function run(g) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
let root = util.addDummyNode(g, "root", {}, "_root");
|
|
36
|
+
let depths = treeDepths(g);
|
|
37
|
+
let height = Math.max(...Object.values(depths)) - 1; // Note: depths is an Object not an array
|
|
38
|
+
let nodeSep = 2 * height + 1;
|
|
37
39
|
g.graph().nestingRoot = root;
|
|
38
40
|
|
|
39
41
|
// Multiply minlen by nodeSep to align nodes on non-border ranks.
|
|
40
42
|
g.edges().forEach(e => g.edge(e).minlen *= nodeSep);
|
|
41
43
|
|
|
42
44
|
// Calculate a weight that is sufficient to keep subgraphs vertically compact
|
|
43
|
-
|
|
45
|
+
let weight = sumWeights(g) + 1;
|
|
44
46
|
|
|
45
47
|
// Create border nodes and link them up
|
|
46
|
-
g.children().forEach(
|
|
47
|
-
dfs(g, root, nodeSep, weight, height, depths, child);
|
|
48
|
-
});
|
|
48
|
+
g.children().forEach(child => dfs(g, root, nodeSep, weight, height, depths, child));
|
|
49
49
|
|
|
50
50
|
// Save the multiplier for node layers for later removal of empty border
|
|
51
51
|
// layers.
|
|
52
52
|
g.graph().nodeRankFactor = nodeSep;
|
|
53
53
|
}
|
|
54
|
-
|
|
55
54
|
function dfs(g, root, nodeSep, weight, height, depths, v) {
|
|
56
|
-
|
|
55
|
+
let children = g.children(v);
|
|
57
56
|
if (!children.length) {
|
|
58
57
|
if (v !== root) {
|
|
59
|
-
g.setEdge(root, v, {
|
|
58
|
+
g.setEdge(root, v, {
|
|
59
|
+
weight: 0,
|
|
60
|
+
minlen: nodeSep
|
|
61
|
+
});
|
|
60
62
|
}
|
|
61
63
|
return;
|
|
62
64
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
var label = g.node(v);
|
|
67
|
-
|
|
65
|
+
let top = util.addBorderNode(g, "_bt");
|
|
66
|
+
let bottom = util.addBorderNode(g, "_bb");
|
|
67
|
+
let label = g.node(v);
|
|
68
68
|
g.setParent(top, v);
|
|
69
69
|
label.borderTop = top;
|
|
70
70
|
g.setParent(bottom, v);
|
|
71
71
|
label.borderBottom = bottom;
|
|
72
|
-
|
|
73
|
-
children.forEach(function(child) {
|
|
72
|
+
children.forEach(child => {
|
|
74
73
|
dfs(g, root, nodeSep, weight, height, depths, child);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
var minlen = childTop !== childBottom ? 1 : height - depths[v] + 1;
|
|
81
|
-
|
|
74
|
+
let childNode = g.node(child);
|
|
75
|
+
let childTop = childNode.borderTop ? childNode.borderTop : child;
|
|
76
|
+
let childBottom = childNode.borderBottom ? childNode.borderBottom : child;
|
|
77
|
+
let thisWeight = childNode.borderTop ? weight : 2 * weight;
|
|
78
|
+
let minlen = childTop !== childBottom ? 1 : height - depths[v] + 1;
|
|
82
79
|
g.setEdge(top, childTop, {
|
|
83
80
|
weight: thisWeight,
|
|
84
81
|
minlen: minlen,
|
|
85
82
|
nestingEdge: true
|
|
86
83
|
});
|
|
87
|
-
|
|
88
84
|
g.setEdge(childBottom, bottom, {
|
|
89
85
|
weight: thisWeight,
|
|
90
86
|
minlen: minlen,
|
|
91
87
|
nestingEdge: true
|
|
92
88
|
});
|
|
93
89
|
});
|
|
94
|
-
|
|
95
90
|
if (!g.parent(v)) {
|
|
96
|
-
g.setEdge(root, top, {
|
|
91
|
+
g.setEdge(root, top, {
|
|
92
|
+
weight: 0,
|
|
93
|
+
minlen: height + depths[v]
|
|
94
|
+
});
|
|
97
95
|
}
|
|
98
96
|
}
|
|
99
|
-
|
|
100
97
|
function treeDepths(g) {
|
|
101
98
|
var depths = {};
|
|
102
99
|
function dfs(v, depth) {
|
|
@@ -109,11 +106,9 @@ function treeDepths(g) {
|
|
|
109
106
|
g.children().forEach(v => dfs(v, 1));
|
|
110
107
|
return depths;
|
|
111
108
|
}
|
|
112
|
-
|
|
113
109
|
function sumWeights(g) {
|
|
114
110
|
return g.edges().reduce((acc, e) => acc + g.edge(e).weight, 0);
|
|
115
111
|
}
|
|
116
|
-
|
|
117
112
|
function cleanup(g) {
|
|
118
113
|
var graphLabel = g.graph();
|
|
119
114
|
g.removeNode(graphLabel.nestingRoot);
|