@dagrejs/dagre 0.7.5 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
- _.each(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
- _.each(layer.slice(scanPos, i +1), function(scanNode) {
62
- _.each(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
- _.each(_.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
- _.each(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
- _.each(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
- _.each(layering, function(layer) {
176
- _.each(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
- _.each(layering, function(layer) {
180
+ layering.forEach(function(layer) {
184
181
  var prevIdx = -1;
185
- _.each(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
- _.each(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
- _.each(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
- _.each(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
- _.each(layering, function(layer) {
265
+ layering.forEach(function(layer) {
260
266
  var u;
261
- _.each(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,11 +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 _.min(xss, function(xs) {
281
- var min = _.min(xs, function(x, v) { return x - width(g, v) / 2; }),
282
- max = _.max(xs, function(x, v) { return x + width(g, v) / 2; });
283
- return max - min;
284
- });
286
+ return Object.values(xss).reduce((currentMinAndXs, xs) => {
287
+ var max = Number.NEGATIVE_INFINITY;
288
+ var min = Number.POSITIVE_INFINITY;
289
+
290
+ Object.entries(xs).forEach(([v, x]) => {
291
+ var halfWidth = width(g, v) / 2;
292
+
293
+ max = Math.max(x + halfWidth, max);
294
+ min = Math.min(x - halfWidth, min);
295
+ });
296
+
297
+ const newMin = max - min;
298
+ if (newMin < currentMinAndXs[0]) {
299
+ currentMinAndXs = [newMin, xs];
300
+ }
301
+ return currentMinAndXs;
302
+ }, [Number.POSITIVE_INFINITY, null])[1];
285
303
  }
286
304
 
287
305
  /*
@@ -292,64 +310,70 @@ function findSmallestWidthAlignment(g, xss) {
292
310
  * coordinate of the smallest width alignment.
293
311
  */
294
312
  function alignCoordinates(xss, alignTo) {
295
- var alignToMin = _.min(alignTo),
296
- alignToMax = _.max(alignTo);
313
+ var alignToVals = Object.values(alignTo),
314
+ alignToMin = Math.min(...alignToVals),
315
+ alignToMax = Math.max(...alignToVals);
297
316
 
298
- _.each(["u", "d"], function(vert) {
299
- _.each(["l", "r"], function(horiz) {
317
+ ["u", "d"].forEach(function(vert) {
318
+ ["l", "r"].forEach(function(horiz) {
300
319
  var alignment = vert + horiz,
301
- xs = xss[alignment],
302
- delta;
320
+ xs = xss[alignment];
321
+
303
322
  if (xs === alignTo) return;
304
323
 
305
- delta = horiz === "l" ? alignToMin - _.min(xs) : alignToMax - _.max(xs);
324
+ var xsVals = Object.values(xs);
325
+ let delta = alignToMin - Math.min(...xsVals);
326
+ if (horiz !== "l") {
327
+ delta = alignToMax - Math.max(...xsVals);
328
+ }
306
329
 
307
330
  if (delta) {
308
- xss[alignment] = _.mapValues(xs, function(x) { return x + delta; });
331
+ xss[alignment] = util.mapValues(xs, x => x + delta);
309
332
  }
310
333
  });
311
334
  });
312
335
  }
313
336
 
314
337
  function balance(xss, align) {
315
- return _.mapValues(xss.ul, function(ignore, v) {
338
+ return util.mapValues(xss.ul, function(num, v) {
316
339
  if (align) {
317
340
  return xss[align.toLowerCase()][v];
318
341
  } else {
319
- var xs = _.sortBy(_.pluck(xss, v));
342
+ var xs = Object.values(xss).map(xs => xs[v]).sort((a, b) => a - b);
320
343
  return (xs[1] + xs[2]) / 2;
321
344
  }
322
345
  });
323
346
  }
324
347
 
325
348
  function positionX(g) {
326
- var layering = util.buildLayerMatrix(g),
327
- conflicts = _.merge(findType1Conflicts(g, layering),
328
- findType2Conflicts(g, layering));
329
-
330
- var xss = {},
331
- adjustedLayering;
332
- _.each(["u", "d"], function(vert) {
333
- adjustedLayering = vert === "u" ? layering : _.values(layering).reverse();
334
- _.each(["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) {
335
359
  if (horiz === "r") {
336
- adjustedLayering = _.map(adjustedLayering, function(inner) {
337
- return _.values(inner).reverse();
360
+ adjustedLayering = adjustedLayering.map(inner => {
361
+ return Object.values(inner).reverse();
338
362
  });
339
363
  }
340
364
 
341
- var neighborFn = _.bind(vert === "u" ? g.predecessors : g.successors, g);
365
+ var neighborFn = (vert === "u" ? g.predecessors : g.successors).bind(g);
342
366
  var align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn);
343
367
  var xs = horizontalCompaction(g, adjustedLayering,
344
- align.root, align.align,
345
- horiz === "r");
368
+ align.root, align.align, horiz === "r");
346
369
  if (horiz === "r") {
347
- xs = _.mapValues(xs, function(x) { return -x; });
370
+ xs = util.mapValues(xs, x => -x);
348
371
  }
349
372
  xss[vert + horiz] = xs;
350
373
  });
351
374
  });
352
375
 
376
+
353
377
  var smallestWidth = findSmallestWidthAlignment(g, xss);
354
378
  alignCoordinates(xss, smallestWidth);
355
379
  return balance(xss, g.graph().align);
@@ -357,16 +381,16 @@ function positionX(g) {
357
381
 
358
382
  function sep(nodeSep, edgeSep, reverseSep) {
359
383
  return function(g, v, w) {
360
- var vLabel = g.node(v),
361
- wLabel = g.node(w),
362
- sum = 0,
363
- delta;
384
+ var vLabel = g.node(v);
385
+ var wLabel = g.node(w);
386
+ var sum = 0;
387
+ var delta;
364
388
 
365
389
  sum += vLabel.width / 2;
366
- if (_.has(vLabel, "labelpos")) {
390
+ if (vLabel.hasOwnProperty("labelpos")) {
367
391
  switch (vLabel.labelpos.toLowerCase()) {
368
- case "l": delta = -vLabel.width / 2; break;
369
- case "r": delta = vLabel.width / 2; break;
392
+ case "l": delta = -vLabel.width / 2; break;
393
+ case "r": delta = vLabel.width / 2; break;
370
394
  }
371
395
  }
372
396
  if (delta) {
@@ -378,10 +402,10 @@ function sep(nodeSep, edgeSep, reverseSep) {
378
402
  sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
379
403
 
380
404
  sum += wLabel.width / 2;
381
- if (_.has(wLabel, "labelpos")) {
405
+ if (wLabel.hasOwnProperty("labelpos")) {
382
406
  switch (wLabel.labelpos.toLowerCase()) {
383
- case "l": delta = wLabel.width / 2; break;
384
- case "r": delta = -wLabel.width / 2; break;
407
+ case "l": delta = wLabel.width / 2; break;
408
+ case "r": delta = -wLabel.width / 2; break;
385
409
  }
386
410
  }
387
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
- _.each(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
- _.each(layering, function(layer) {
23
- var maxHeight = _.max(_.map(layer, function(v) { return g.node(v).height; }));
24
- _.each(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
- _.each(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
- _.each(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 _.min(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
- _.each(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