@dagrejs/dagre 0.8.0 → 1.0.1

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.
@@ -1,8 +1,7 @@
1
1
  "use strict";
2
2
 
3
- var _ = require("../lodash"),
4
- Graph = require("../graphlib").Graph,
5
- util = require("../util");
3
+ var Graph = require("@dagrejs/graphlib").Graph;
4
+ var util = require("../util");
6
5
 
7
6
  /*
8
7
  * This module provides coordinate assignment based on Brandes and Köpf, "Fast
@@ -51,17 +50,17 @@ function findType1Conflicts(g, layering) {
51
50
  // segment.
52
51
  scanPos = 0,
53
52
  prevLayerLength = prevLayer.length,
54
- lastNode = _.last(layer);
53
+ lastNode = layer[layer.length - 1];
55
54
 
56
- _.forEach(layer, function(v, i) {
55
+ layer.forEach(function(v, i) {
57
56
  var w = findOtherInnerSegmentNode(g, v),
58
- k1 = w ? g.node(w).order : prevLayerLength;
57
+ k1 = w ? g.node(w).order : prevLayerLength;
59
58
 
60
59
  if (w || v === lastNode) {
61
- _.forEach(layer.slice(scanPos, i +1), function(scanNode) {
62
- _.forEach(g.predecessors(scanNode), function(u) {
60
+ layer.slice(scanPos, i+1).forEach(function(scanNode) {
61
+ g.predecessors(scanNode).forEach(function(u) {
63
62
  var uLabel = g.node(u),
64
- uPos = uLabel.order;
63
+ uPos = uLabel.order;
65
64
  if ((uPos < k0 || k1 < uPos) &&
66
65
  !(uLabel.dummy && g.node(scanNode).dummy)) {
67
66
  addConflict(conflicts, u, scanNode);
@@ -76,7 +75,7 @@ function findType1Conflicts(g, layering) {
76
75
  return layer;
77
76
  }
78
77
 
79
- _.reduce(layering, visitLayer);
78
+ layering.reduce(visitLayer);
80
79
  return conflicts;
81
80
  }
82
81
 
@@ -85,10 +84,10 @@ function findType2Conflicts(g, layering) {
85
84
 
86
85
  function scan(south, southPos, southEnd, prevNorthBorder, nextNorthBorder) {
87
86
  var v;
88
- _.forEach(_.range(southPos, southEnd), function(i) {
87
+ util.range(southPos, southEnd).forEach(function(i) {
89
88
  v = south[i];
90
89
  if (g.node(v).dummy) {
91
- _.forEach(g.predecessors(v), function(u) {
90
+ g.predecessors(v).forEach(function(u) {
92
91
  var uNode = g.node(u);
93
92
  if (uNode.dummy &&
94
93
  (uNode.order < prevNorthBorder || uNode.order > nextNorthBorder)) {
@@ -102,10 +101,10 @@ function findType2Conflicts(g, layering) {
102
101
 
103
102
  function visitLayer(north, south) {
104
103
  var prevNorthPos = -1,
105
- nextNorthPos,
106
- southPos = 0;
104
+ nextNorthPos,
105
+ southPos = 0;
107
106
 
108
- _.forEach(south, function(v, southLookahead) {
107
+ south.forEach(function(v, southLookahead) {
109
108
  if (g.node(v).dummy === "border") {
110
109
  var predecessors = g.predecessors(v);
111
110
  if (predecessors.length) {
@@ -121,15 +120,13 @@ function findType2Conflicts(g, layering) {
121
120
  return south;
122
121
  }
123
122
 
124
- _.reduce(layering, visitLayer);
123
+ layering.reduce(visitLayer);
125
124
  return conflicts;
126
125
  }
127
126
 
128
127
  function findOtherInnerSegmentNode(g, v) {
129
128
  if (g.node(v).dummy) {
130
- return _.find(g.predecessors(v), function(u) {
131
- return g.node(u).dummy;
132
- });
129
+ return g.predecessors(v).find(u => g.node(u).dummy);
133
130
  }
134
131
  }
135
132
 
@@ -153,7 +150,7 @@ function hasConflict(conflicts, v, w) {
153
150
  v = w;
154
151
  w = tmp;
155
152
  }
156
- return _.has(conflicts[v], w);
153
+ return !!conflicts[v] && conflicts[v].hasOwnProperty(w);
157
154
  }
158
155
 
159
156
  /*
@@ -166,26 +163,26 @@ function hasConflict(conflicts, v, w) {
166
163
  */
167
164
  function verticalAlignment(g, layering, conflicts, neighborFn) {
168
165
  var root = {},
169
- align = {},
170
- pos = {};
166
+ align = {},
167
+ pos = {};
171
168
 
172
169
  // We cache the position here based on the layering because the graph and
173
170
  // layering may be out of sync. The layering matrix is manipulated to
174
171
  // generate different extreme alignments.
175
- _.forEach(layering, function(layer) {
176
- _.forEach(layer, function(v, order) {
172
+ layering.forEach(function(layer) {
173
+ layer.forEach(function(v, order) {
177
174
  root[v] = v;
178
175
  align[v] = v;
179
176
  pos[v] = order;
180
177
  });
181
178
  });
182
179
 
183
- _.forEach(layering, function(layer) {
180
+ layering.forEach(function(layer) {
184
181
  var prevIdx = -1;
185
- _.forEach(layer, function(v) {
182
+ layer.forEach(function(v) {
186
183
  var ws = neighborFn(v);
187
184
  if (ws.length) {
188
- ws = _.sortBy(ws, function(w) { return pos[w]; });
185
+ ws = ws.sort((a, b) => pos[a] - pos[b]);
189
186
  var mp = (ws.length - 1) / 2;
190
187
  for (var i = Math.floor(mp), il = Math.ceil(mp); i <= il; ++i) {
191
188
  var w = ws[i];
@@ -211,41 +208,50 @@ function horizontalCompaction(g, layering, root, align, reverseSep) {
211
208
  // coordinates. The second sweep removes unused space by moving blocks to the
212
209
  // greatest coordinates without violating separation.
213
210
  var xs = {},
214
- blockG = buildBlockGraph(g, layering, root, reverseSep);
215
-
216
- // First pass, assign smallest coordinates via DFS
217
- var visited = {};
218
- function pass1(v) {
219
- if (!_.has(visited, v)) {
220
- visited[v] = true;
221
- xs[v] = _.reduce(blockG.inEdges(v), function(max, e) {
222
- pass1(e.v);
223
- return Math.max(max, xs[e.v] + blockG.edge(e));
224
- }, 0);
211
+ blockG = buildBlockGraph(g, layering, root, reverseSep),
212
+ borderType = reverseSep ? "borderLeft" : "borderRight";
213
+
214
+ function iterate(setXsFunc, nextNodesFunc) {
215
+ var stack = blockG.nodes();
216
+ var elem = stack.pop();
217
+ var visited = {};
218
+ while (elem) {
219
+ if (visited[elem]) {
220
+ setXsFunc(elem);
221
+ } else {
222
+ visited[elem] = true;
223
+ stack.push(elem);
224
+ stack = stack.concat(nextNodesFunc(elem));
225
+ }
226
+
227
+ elem = stack.pop();
225
228
  }
226
229
  }
227
- _.forEach(blockG.nodes(), pass1);
228
-
229
- var borderType = reverseSep ? "borderLeft" : "borderRight";
230
- function pass2(v) {
231
- if (visited[v] !== 2) {
232
- visited[v]++;
233
- var node = g.node(v);
234
- var min = _.reduce(blockG.outEdges(v), function(min, e) {
235
- pass2(e.w);
236
- return Math.min(min, xs[e.w] - blockG.edge(e));
237
- }, Number.POSITIVE_INFINITY);
238
- if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
239
- xs[v] = Math.max(xs[v], min);
240
- }
230
+
231
+ // First pass, assign smallest coordinates
232
+ function pass1(elem) {
233
+ xs[elem] = blockG.inEdges(elem).reduce(function(acc, e) {
234
+ return Math.max(acc, xs[e.v] + blockG.edge(e));
235
+ }, 0);
236
+ }
237
+
238
+ // Second pass, assign greatest coordinates
239
+ function pass2(elem) {
240
+ var min = blockG.outEdges(elem).reduce(function(acc, e) {
241
+ return Math.min(acc, xs[e.w] - blockG.edge(e));
242
+ }, Number.POSITIVE_INFINITY);
243
+
244
+ var node = g.node(elem);
245
+ if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
246
+ xs[elem] = Math.max(xs[elem], min);
241
247
  }
242
248
  }
243
- _.forEach(blockG.nodes(), pass2);
249
+
250
+ iterate(pass1, blockG.predecessors.bind(blockG));
251
+ iterate(pass2, blockG.successors.bind(blockG));
244
252
 
245
253
  // Assign x coordinates to all nodes
246
- _.forEach(align, function(v) {
247
- xs[v] = xs[root[v]];
248
- });
254
+ Object.keys(align).forEach(v => xs[v] = xs[root[v]]);
249
255
 
250
256
  return xs;
251
257
  }
@@ -253,17 +259,17 @@ function horizontalCompaction(g, layering, root, align, reverseSep) {
253
259
 
254
260
  function buildBlockGraph(g, layering, root, reverseSep) {
255
261
  var blockGraph = new Graph(),
256
- graphLabel = g.graph(),
257
- sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
262
+ graphLabel = g.graph(),
263
+ sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
258
264
 
259
- _.forEach(layering, function(layer) {
265
+ layering.forEach(function(layer) {
260
266
  var u;
261
- _.forEach(layer, function(v) {
267
+ layer.forEach(function(v) {
262
268
  var vRoot = root[v];
263
269
  blockGraph.setNode(vRoot);
264
270
  if (u) {
265
271
  var uRoot = root[u],
266
- prevMax = blockGraph.edge(uRoot, vRoot);
272
+ prevMax = blockGraph.edge(uRoot, vRoot);
267
273
  blockGraph.setEdge(uRoot, vRoot, Math.max(sepFn(g, v, u), prevMax || 0));
268
274
  }
269
275
  u = v;
@@ -277,19 +283,23 @@ function buildBlockGraph(g, layering, root, reverseSep) {
277
283
  * Returns the alignment that has the smallest width of the given alignments.
278
284
  */
279
285
  function findSmallestWidthAlignment(g, xss) {
280
- return _.minBy(_.values(xss), function (xs) {
286
+ return Object.values(xss).reduce((currentMinAndXs, xs) => {
281
287
  var max = Number.NEGATIVE_INFINITY;
282
288
  var min = Number.POSITIVE_INFINITY;
283
289
 
284
- _.forIn(xs, function (x, v) {
290
+ Object.entries(xs).forEach(([v, x]) => {
285
291
  var halfWidth = width(g, v) / 2;
286
292
 
287
293
  max = Math.max(x + halfWidth, max);
288
294
  min = Math.min(x - halfWidth, min);
289
295
  });
290
296
 
291
- return max - min;
292
- });
297
+ const newMin = max - min;
298
+ if (newMin < currentMinAndXs[0]) {
299
+ currentMinAndXs = [newMin, xs];
300
+ }
301
+ return currentMinAndXs;
302
+ }, [Number.POSITIVE_INFINITY, null])[1];
293
303
  }
294
304
 
295
305
  /*
@@ -300,66 +310,70 @@ function findSmallestWidthAlignment(g, xss) {
300
310
  * coordinate of the smallest width alignment.
301
311
  */
302
312
  function alignCoordinates(xss, alignTo) {
303
- var alignToVals = _.values(alignTo),
304
- alignToMin = _.min(alignToVals),
305
- alignToMax = _.max(alignToVals);
313
+ var alignToVals = Object.values(alignTo),
314
+ alignToMin = Math.min(...alignToVals),
315
+ alignToMax = Math.max(...alignToVals);
306
316
 
307
- _.forEach(["u", "d"], function(vert) {
308
- _.forEach(["l", "r"], function(horiz) {
317
+ ["u", "d"].forEach(function(vert) {
318
+ ["l", "r"].forEach(function(horiz) {
309
319
  var alignment = vert + horiz,
310
- xs = xss[alignment],
311
- delta;
320
+ xs = xss[alignment];
321
+
312
322
  if (xs === alignTo) return;
313
323
 
314
- var xsVals = _.values(xs);
315
- delta = horiz === "l" ? alignToMin - _.min(xsVals) : alignToMax - _.max(xsVals);
324
+ var xsVals = Object.values(xs);
325
+ let delta = alignToMin - Math.min(...xsVals);
326
+ if (horiz !== "l") {
327
+ delta = alignToMax - Math.max(...xsVals);
328
+ }
316
329
 
317
330
  if (delta) {
318
- xss[alignment] = _.mapValues(xs, function(x) { return x + delta; });
331
+ xss[alignment] = util.mapValues(xs, x => x + delta);
319
332
  }
320
333
  });
321
334
  });
322
335
  }
323
336
 
324
337
  function balance(xss, align) {
325
- return _.mapValues(xss.ul, function(ignore, v) {
338
+ return util.mapValues(xss.ul, function(num, v) {
326
339
  if (align) {
327
340
  return xss[align.toLowerCase()][v];
328
341
  } else {
329
- var xs = _.sortBy(_.map(xss, v));
342
+ var xs = Object.values(xss).map(xs => xs[v]).sort((a, b) => a - b);
330
343
  return (xs[1] + xs[2]) / 2;
331
344
  }
332
345
  });
333
346
  }
334
347
 
335
348
  function positionX(g) {
336
- var layering = util.buildLayerMatrix(g),
337
- conflicts = _.merge(findType1Conflicts(g, layering),
338
- findType2Conflicts(g, layering));
339
-
340
- var xss = {},
341
- adjustedLayering;
342
- _.forEach(["u", "d"], function(vert) {
343
- adjustedLayering = vert === "u" ? layering : _.values(layering).reverse();
344
- _.forEach(["l", "r"], function(horiz) {
349
+ var layering = util.buildLayerMatrix(g);
350
+ var conflicts = Object.assign(
351
+ findType1Conflicts(g, layering),
352
+ findType2Conflicts(g, layering));
353
+
354
+ var xss = {};
355
+ var adjustedLayering;
356
+ ["u", "d"].forEach(function(vert) {
357
+ adjustedLayering = vert === "u" ? layering : Object.values(layering).reverse();
358
+ ["l", "r"].forEach(function(horiz) {
345
359
  if (horiz === "r") {
346
- adjustedLayering = _.map(adjustedLayering, function(inner) {
347
- return _.values(inner).reverse();
360
+ adjustedLayering = adjustedLayering.map(inner => {
361
+ return Object.values(inner).reverse();
348
362
  });
349
363
  }
350
364
 
351
- var neighborFn = _.bind(vert === "u" ? g.predecessors : g.successors, g);
365
+ var neighborFn = (vert === "u" ? g.predecessors : g.successors).bind(g);
352
366
  var align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn);
353
367
  var xs = horizontalCompaction(g, adjustedLayering,
354
- align.root, align.align,
355
- horiz === "r");
368
+ align.root, align.align, horiz === "r");
356
369
  if (horiz === "r") {
357
- xs = _.mapValues(xs, function(x) { return -x; });
370
+ xs = util.mapValues(xs, x => -x);
358
371
  }
359
372
  xss[vert + horiz] = xs;
360
373
  });
361
374
  });
362
375
 
376
+
363
377
  var smallestWidth = findSmallestWidthAlignment(g, xss);
364
378
  alignCoordinates(xss, smallestWidth);
365
379
  return balance(xss, g.graph().align);
@@ -367,16 +381,16 @@ function positionX(g) {
367
381
 
368
382
  function sep(nodeSep, edgeSep, reverseSep) {
369
383
  return function(g, v, w) {
370
- var vLabel = g.node(v),
371
- wLabel = g.node(w),
372
- sum = 0,
373
- delta;
384
+ var vLabel = g.node(v);
385
+ var wLabel = g.node(w);
386
+ var sum = 0;
387
+ var delta;
374
388
 
375
389
  sum += vLabel.width / 2;
376
- if (_.has(vLabel, "labelpos")) {
390
+ if (vLabel.hasOwnProperty("labelpos")) {
377
391
  switch (vLabel.labelpos.toLowerCase()) {
378
- case "l": delta = -vLabel.width / 2; break;
379
- case "r": delta = vLabel.width / 2; break;
392
+ case "l": delta = -vLabel.width / 2; break;
393
+ case "r": delta = vLabel.width / 2; break;
380
394
  }
381
395
  }
382
396
  if (delta) {
@@ -388,10 +402,10 @@ function sep(nodeSep, edgeSep, reverseSep) {
388
402
  sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
389
403
 
390
404
  sum += wLabel.width / 2;
391
- if (_.has(wLabel, "labelpos")) {
405
+ if (wLabel.hasOwnProperty("labelpos")) {
392
406
  switch (wLabel.labelpos.toLowerCase()) {
393
- case "l": delta = wLabel.width / 2; break;
394
- case "r": delta = -wLabel.width / 2; break;
407
+ case "l": delta = wLabel.width / 2; break;
408
+ case "r": delta = -wLabel.width / 2; break;
395
409
  }
396
410
  }
397
411
  if (delta) {
@@ -1,8 +1,7 @@
1
1
  "use strict";
2
2
 
3
- var _ = require("../lodash"),
4
- util = require("../util"),
5
- positionX = require("./bk").positionX;
3
+ var util = require("../util");
4
+ var positionX = require("./bk").positionX;
6
5
 
7
6
  module.exports = position;
8
7
 
@@ -10,20 +9,23 @@ function position(g) {
10
9
  g = util.asNonCompoundGraph(g);
11
10
 
12
11
  positionY(g);
13
- _.forEach(positionX(g), function(x, v) {
14
- g.node(v).x = x;
15
- });
12
+ Object.entries(positionX(g)).forEach(([v, x]) => g.node(v).x = x);
16
13
  }
17
14
 
18
15
  function positionY(g) {
19
- var layering = util.buildLayerMatrix(g),
20
- rankSep = g.graph().ranksep,
21
- prevY = 0;
22
- _.forEach(layering, function(layer) {
23
- var maxHeight = _.max(_.map(layer, function(v) { return g.node(v).height; }));
24
- _.forEach(layer, function(v) {
25
- g.node(v).y = prevY + maxHeight / 2;
26
- });
16
+ var layering = util.buildLayerMatrix(g);
17
+ var rankSep = g.graph().ranksep;
18
+ var prevY = 0;
19
+ layering.forEach(function(layer) {
20
+ const maxHeight = layer.reduce((acc, v) => {
21
+ const height = g.node(v).height;
22
+ if (acc > height) {
23
+ return acc;
24
+ } else {
25
+ return height;
26
+ }
27
+ }, 0);
28
+ layer.forEach(v => g.node(v).y = prevY + maxHeight / 2);
27
29
  prevY += maxHeight + rankSep;
28
30
  });
29
31
  }
@@ -1,8 +1,7 @@
1
1
  "use strict";
2
2
 
3
- var _ = require("../lodash"),
4
- Graph = require("../graphlib").Graph,
5
- slack = require("./util").slack;
3
+ var Graph = require("@dagrejs/graphlib").Graph;
4
+ var slack = require("./util").slack;
6
5
 
7
6
  module.exports = feasibleTree;
8
7
 
@@ -35,8 +34,8 @@ function feasibleTree(g) {
35
34
  var t = new Graph({ directed: false });
36
35
 
37
36
  // Choose arbitrary node from which to start our tree
38
- var start = g.nodes()[0],
39
- size = g.nodeCount();
37
+ var start = g.nodes()[0];
38
+ var size = g.nodeCount();
40
39
  t.setNode(start, {});
41
40
 
42
41
  var edge, delta;
@@ -55,9 +54,9 @@ function feasibleTree(g) {
55
54
  */
56
55
  function tightTree(t, g) {
57
56
  function dfs(v) {
58
- _.forEach(g.nodeEdges(v), function(e) {
57
+ g.nodeEdges(v).forEach(function(e) {
59
58
  var edgeV = e.v,
60
- w = (v === edgeV) ? e.w : edgeV;
59
+ w = (v === edgeV) ? e.w : edgeV;
61
60
  if (!t.hasNode(w) && !slack(g, e)) {
62
61
  t.setNode(w, {});
63
62
  t.setEdge(v, w, {});
@@ -66,7 +65,7 @@ function tightTree(t, g) {
66
65
  });
67
66
  }
68
67
 
69
- _.forEach(t.nodes(), dfs);
68
+ t.nodes().forEach(dfs);
70
69
  return t.nodeCount();
71
70
  }
72
71
 
@@ -75,15 +74,22 @@ function tightTree(t, g) {
75
74
  * it.
76
75
  */
77
76
  function findMinSlackEdge(t, g) {
78
- return _.minBy(g.edges(), function(e) {
79
- if (t.hasNode(e.v) !== t.hasNode(e.w)) {
80
- return slack(g, e);
77
+ const edges = g.edges();
78
+
79
+ return edges.reduce((acc, edge) => {
80
+ let edgeSlack = Number.POSITIVE_INFINITY;
81
+ if (t.hasNode(edge.v) !== t.hasNode(edge.w)) {
82
+ edgeSlack = slack(g, edge);
83
+ }
84
+
85
+ if (edgeSlack < acc[0]) {
86
+ return [edgeSlack, edge];
81
87
  }
82
- });
88
+
89
+ return acc;
90
+ }, [Number.POSITIVE_INFINITY, null])[1];
83
91
  }
84
92
 
85
93
  function shiftRanks(t, g, delta) {
86
- _.forEach(t.nodes(), function(v) {
87
- g.node(v).rank += delta;
88
- });
94
+ t.nodes().forEach(v => g.node(v).rank += delta);
89
95
  }
package/lib/rank/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
 
3
- var rankUtil = require("./util"),
4
- longestPath = rankUtil.longestPath,
5
- feasibleTree = require("./feasible-tree"),
6
- networkSimplex = require("./network-simplex");
3
+ var rankUtil = require("./util");
4
+ var longestPath = rankUtil.longestPath;
5
+ var feasibleTree = require("./feasible-tree");
6
+ var networkSimplex = require("./network-simplex");
7
7
 
8
8
  module.exports = rank;
9
9
 
@@ -28,10 +28,10 @@ module.exports = rank;
28
28
  */
29
29
  function rank(g) {
30
30
  switch(g.graph().ranker) {
31
- case "network-simplex": networkSimplexRanker(g); break;
32
- case "tight-tree": tightTreeRanker(g); break;
33
- case "longest-path": longestPathRanker(g); break;
34
- default: networkSimplexRanker(g);
31
+ case "network-simplex": networkSimplexRanker(g); break;
32
+ case "tight-tree": tightTreeRanker(g); break;
33
+ case "longest-path": longestPathRanker(g); break;
34
+ default: networkSimplexRanker(g);
35
35
  }
36
36
  }
37
37