@dagrejs/dagre 1.0.4 → 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.
Files changed (58) hide show
  1. package/index.d.ts +10 -2
  2. package/lib/acyclic.js +10 -18
  3. package/lib/add-border-segments.js +19 -11
  4. package/lib/coordinate-system.js +5 -15
  5. package/lib/data/list.js +8 -7
  6. package/lib/debug.js +25 -14
  7. package/lib/greedy-fas.js +35 -30
  8. package/lib/index.js +38 -0
  9. package/lib/layout.js +105 -102
  10. package/lib/nesting-graph.js +18 -21
  11. package/lib/normalize.js +22 -18
  12. package/lib/order/add-subgraph-constraints.js +6 -2
  13. package/lib/order/barycenter.js +14 -6
  14. package/lib/order/build-layer-graph.js +19 -13
  15. package/lib/order/cross-count.js +13 -10
  16. package/lib/order/index.js +33 -24
  17. package/lib/order/init-order.js +8 -7
  18. package/lib/order/resolve-conflicts.js +9 -19
  19. package/lib/order/sort-subgraph.js +16 -22
  20. package/lib/order/sort.js +13 -12
  21. package/lib/parent-dummy-chains.js +17 -19
  22. package/lib/position/bk.js +42 -84
  23. package/lib/position/index.js +10 -9
  24. package/lib/rank/feasible-tree.js +14 -17
  25. package/lib/rank/index.js +25 -15
  26. package/lib/rank/network-simplex.js +18 -39
  27. package/lib/rank/util.js +6 -12
  28. package/lib/util.js +42 -57
  29. package/lib/version.js +8 -1
  30. package/mjs-lib/acyclic.js +62 -0
  31. package/mjs-lib/add-border-segments.js +35 -0
  32. package/mjs-lib/coordinate-system.js +65 -0
  33. package/mjs-lib/data/list.js +56 -0
  34. package/mjs-lib/debug.js +30 -0
  35. package/mjs-lib/greedy-fas.js +125 -0
  36. package/mjs-lib/index.js +9 -0
  37. package/mjs-lib/layout.js +405 -0
  38. package/mjs-lib/nesting-graph.js +120 -0
  39. package/mjs-lib/normalize.js +84 -0
  40. package/mjs-lib/order/add-subgraph-constraints.js +49 -0
  41. package/mjs-lib/order/barycenter.js +24 -0
  42. package/mjs-lib/order/build-layer-graph.js +71 -0
  43. package/mjs-lib/order/cross-count.js +64 -0
  44. package/mjs-lib/order/index.js +70 -0
  45. package/mjs-lib/order/init-order.js +34 -0
  46. package/mjs-lib/order/resolve-conflicts.js +116 -0
  47. package/mjs-lib/order/sort-subgraph.js +71 -0
  48. package/mjs-lib/order/sort.js +54 -0
  49. package/mjs-lib/parent-dummy-chains.js +82 -0
  50. package/mjs-lib/position/bk.js +409 -0
  51. package/mjs-lib/position/index.js +30 -0
  52. package/mjs-lib/rank/feasible-tree.js +93 -0
  53. package/mjs-lib/rank/index.js +46 -0
  54. package/mjs-lib/rank/network-simplex.js +233 -0
  55. package/mjs-lib/rank/util.js +58 -0
  56. package/mjs-lib/util.js +305 -0
  57. package/mjs-lib/version.js +1 -0
  58. package/package.json +14 -3
@@ -1,14 +1,16 @@
1
1
  "use strict";
2
2
 
3
- var feasibleTree = require("./feasible-tree");
4
- var slack = require("./util").slack;
5
- var initRank = require("./util").longestPath;
6
- var preorder = require("@dagrejs/graphlib").alg.preorder;
7
- var postorder = require("@dagrejs/graphlib").alg.postorder;
8
- var simplify = require("../util").simplify;
9
-
10
- module.exports = networkSimplex;
11
-
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = networkSimplex;
7
+ var _feasibleTree = _interopRequireDefault(require("./feasible-tree.js"));
8
+ var _util = require("./util.js");
9
+ var _graphlib = require("@dagrejs/graphlib");
10
+ var _util2 = require("../util.js");
11
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
+ var preorder = _graphlib.alg.preorder;
13
+ var postorder = _graphlib.alg.postorder;
12
14
  // Expose some internals for testing purposes
13
15
  networkSimplex.initLowLimValues = initLowLimValues;
14
16
  networkSimplex.initCutValues = initCutValues;
@@ -51,14 +53,13 @@ networkSimplex.exchangeEdges = exchangeEdges;
51
53
  * structure of the overall algorithm.
52
54
  */
53
55
  function networkSimplex(g) {
54
- g = simplify(g);
55
- initRank(g);
56
- var t = feasibleTree(g);
56
+ g = (0, _util2.simplify)(g);
57
+ (0, _util.longestPath)(g);
58
+ var t = (0, _feasibleTree.default)(g);
57
59
  initLowLimValues(t);
58
60
  initCutValues(t, g);
59
-
60
61
  var e, f;
61
- while ((e = leaveEdge(t))) {
62
+ while (e = leaveEdge(t)) {
62
63
  f = enterEdge(t, g, e);
63
64
  exchangeEdges(t, g, e, f);
64
65
  }
@@ -72,7 +73,6 @@ function initCutValues(t, g) {
72
73
  vs = vs.slice(0, vs.length - 1);
73
74
  vs.forEach(v => assignCutValue(t, g, v));
74
75
  }
75
-
76
76
  function assignCutValue(t, g, child) {
77
77
  var childLab = t.node(child);
78
78
  var parent = childLab.parent;
@@ -92,22 +92,17 @@ function calcCutValue(t, g, child) {
92
92
  var graphEdge = g.edge(child, parent);
93
93
  // The accumulated cut value for the edge between this node and its parent
94
94
  var cutValue = 0;
95
-
96
95
  if (!graphEdge) {
97
96
  childIsTail = false;
98
97
  graphEdge = g.edge(parent, child);
99
98
  }
100
-
101
99
  cutValue = graphEdge.weight;
102
-
103
100
  g.nodeEdges(child).forEach(e => {
104
101
  var isOutEdge = e.v === child,
105
102
  other = isOutEdge ? e.w : e.v;
106
-
107
103
  if (other !== parent) {
108
104
  var pointsToHead = isOutEdge === childIsTail,
109
105
  otherWeight = g.edge(e).weight;
110
-
111
106
  cutValue += pointsToHead ? otherWeight : -otherWeight;
112
107
  if (isTreeEdge(t, child, other)) {
113
108
  var otherCutValue = t.edge(child, other).cutvalue;
@@ -115,28 +110,23 @@ function calcCutValue(t, g, child) {
115
110
  }
116
111
  }
117
112
  });
118
-
119
113
  return cutValue;
120
114
  }
121
-
122
115
  function initLowLimValues(tree, root) {
123
116
  if (arguments.length < 2) {
124
117
  root = tree.nodes()[0];
125
118
  }
126
119
  dfsAssignLowLim(tree, {}, 1, root);
127
120
  }
128
-
129
121
  function dfsAssignLowLim(tree, visited, nextLim, v, parent) {
130
122
  var low = nextLim;
131
123
  var label = tree.node(v);
132
-
133
124
  visited[v] = true;
134
125
  tree.neighbors(v).forEach(w => {
135
126
  if (!visited.hasOwnProperty(w)) {
136
127
  nextLim = dfsAssignLowLim(tree, visited, nextLim, w, v);
137
128
  }
138
129
  });
139
-
140
130
  label.low = low;
141
131
  label.lim = nextLim++;
142
132
  if (parent) {
@@ -145,14 +135,11 @@ function dfsAssignLowLim(tree, visited, nextLim, v, parent) {
145
135
  // TODO should be able to remove this when we incrementally update low lim
146
136
  delete label.parent;
147
137
  }
148
-
149
138
  return nextLim;
150
139
  }
151
-
152
140
  function leaveEdge(tree) {
153
141
  return tree.edges().find(e => tree.edge(e).cutvalue < 0);
154
142
  }
155
-
156
143
  function enterEdge(t, g, edge) {
157
144
  var v = edge.v;
158
145
  var w = edge.w;
@@ -164,7 +151,6 @@ function enterEdge(t, g, edge) {
164
151
  v = edge.w;
165
152
  w = edge.v;
166
153
  }
167
-
168
154
  var vLabel = t.node(v);
169
155
  var wLabel = t.node(w);
170
156
  var tailLabel = vLabel;
@@ -176,21 +162,16 @@ function enterEdge(t, g, edge) {
176
162
  tailLabel = wLabel;
177
163
  flip = true;
178
164
  }
179
-
180
165
  var candidates = g.edges().filter(edge => {
181
- return flip === isDescendant(t, t.node(edge.v), tailLabel) &&
182
- flip !== isDescendant(t, t.node(edge.w), tailLabel);
166
+ return flip === isDescendant(t, t.node(edge.v), tailLabel) && flip !== isDescendant(t, t.node(edge.w), tailLabel);
183
167
  });
184
-
185
168
  return candidates.reduce((acc, edge) => {
186
- if (slack(g, edge) < slack(g, acc)) {
169
+ if ((0, _util.slack)(g, edge) < (0, _util.slack)(g, acc)) {
187
170
  return edge;
188
171
  }
189
-
190
172
  return acc;
191
173
  });
192
174
  }
193
-
194
175
  function exchangeEdges(t, g, e, f) {
195
176
  var v = e.v;
196
177
  var w = e.w;
@@ -200,7 +181,6 @@ function exchangeEdges(t, g, e, f) {
200
181
  initCutValues(t, g);
201
182
  updateRanks(t, g);
202
183
  }
203
-
204
184
  function updateRanks(t, g) {
205
185
  var root = t.nodes().find(v => !g.node(v).parent);
206
186
  var vs = preorder(t, root);
@@ -209,12 +189,10 @@ function updateRanks(t, g) {
209
189
  var parent = t.node(v).parent,
210
190
  edge = g.edge(v, parent),
211
191
  flipped = false;
212
-
213
192
  if (!edge) {
214
193
  edge = g.edge(parent, v);
215
194
  flipped = true;
216
195
  }
217
-
218
196
  g.node(v).rank = g.node(parent).rank + (flipped ? edge.minlen : -edge.minlen);
219
197
  });
220
198
  }
@@ -233,3 +211,4 @@ function isTreeEdge(tree, u, v) {
233
211
  function isDescendant(tree, vLabel, rootLabel) {
234
212
  return rootLabel.low <= vLabel.lim && vLabel.lim <= rootLabel.lim;
235
213
  }
214
+ module.exports = exports.default;
package/lib/rank/util.js CHANGED
@@ -1,10 +1,5 @@
1
1
  "use strict";
2
2
 
3
- module.exports = {
4
- longestPath: longestPath,
5
- slack: slack
6
- };
7
-
8
3
  /*
9
4
  * Initializes ranks for the input graph using the longest path algorithm. This
10
5
  * algorithm scales well and is fast in practice, it yields rather poor
@@ -26,31 +21,30 @@ module.exports = {
26
21
  *
27
22
  * 1. Each node will be assign an (unnormalized) "rank" property.
28
23
  */
24
+ Object.defineProperty(exports, "__esModule", {
25
+ value: true
26
+ });
27
+ exports.longestPath = longestPath;
28
+ exports.slack = slack;
29
29
  function longestPath(g) {
30
30
  var visited = {};
31
-
32
31
  function dfs(v) {
33
32
  var label = g.node(v);
34
33
  if (visited.hasOwnProperty(v)) {
35
34
  return label.rank;
36
35
  }
37
36
  visited[v] = true;
38
-
39
37
  var rank = Math.min(...g.outEdges(v).map(e => {
40
38
  if (e == null) {
41
39
  return Number.POSITIVE_INFINITY;
42
40
  }
43
-
44
41
  return dfs(e.w) - g.edge(e).minlen;
45
42
  }));
46
-
47
43
  if (rank === Number.POSITIVE_INFINITY) {
48
44
  rank = 0;
49
45
  }
50
-
51
- return (label.rank = rank);
46
+ return label.rank = rank;
52
47
  }
53
-
54
48
  g.sources().forEach(dfs);
55
49
  }
56
50
 
package/lib/util.js CHANGED
@@ -2,30 +2,29 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- let Graph = require("@dagrejs/graphlib").Graph;
6
-
7
- module.exports = {
8
- addBorderNode,
9
- addDummyNode,
10
- asNonCompoundGraph,
11
- buildLayerMatrix,
12
- intersectRect,
13
- mapValues,
14
- maxRank,
15
- normalizeRanks,
16
- notime,
17
- partition,
18
- pick,
19
- predecessorWeights,
20
- range,
21
- removeEmptyRanks,
22
- simplify,
23
- successorWeights,
24
- time,
25
- uniqueId,
26
- zipObject,
27
- };
28
-
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.addBorderNode = addBorderNode;
9
+ exports.addDummyNode = addDummyNode;
10
+ exports.asNonCompoundGraph = asNonCompoundGraph;
11
+ exports.buildLayerMatrix = buildLayerMatrix;
12
+ exports.intersectRect = intersectRect;
13
+ exports.mapValues = mapValues;
14
+ exports.maxRank = maxRank;
15
+ exports.normalizeRanks = normalizeRanks;
16
+ exports.notime = notime;
17
+ exports.partition = partition;
18
+ exports.pick = pick;
19
+ exports.predecessorWeights = predecessorWeights;
20
+ exports.range = range;
21
+ exports.removeEmptyRanks = removeEmptyRanks;
22
+ exports.simplify = simplify;
23
+ exports.successorWeights = successorWeights;
24
+ exports.time = time;
25
+ exports.uniqueId = uniqueId;
26
+ exports.zipObject = zipObject;
27
+ var _graphlib = require("@dagrejs/graphlib");
29
28
  /*
30
29
  * Adds a dummy node to the graph and return v.
31
30
  */
@@ -34,7 +33,6 @@ function addDummyNode(g, type, attrs, name) {
34
33
  do {
35
34
  v = uniqueId(name);
36
35
  } while (g.hasNode(v));
37
-
38
36
  attrs.dummy = type;
39
37
  g.setNode(v, attrs);
40
38
  return v;
@@ -45,10 +43,13 @@ function addDummyNode(g, type, attrs, name) {
45
43
  * associated with multi-edges.
46
44
  */
47
45
  function simplify(g) {
48
- let simplified = new Graph().setGraph(g.graph());
46
+ let simplified = new _graphlib.Graph().setGraph(g.graph());
49
47
  g.nodes().forEach(v => simplified.setNode(v, g.node(v)));
50
48
  g.edges().forEach(e => {
51
- let simpleLabel = simplified.edge(e.v, e.w) || { weight: 0, minlen: 1 };
49
+ let simpleLabel = simplified.edge(e.v, e.w) || {
50
+ weight: 0,
51
+ minlen: 1
52
+ };
52
53
  let label = g.edge(e);
53
54
  simplified.setEdge(e.v, e.w, {
54
55
  weight: simpleLabel.weight + label.weight,
@@ -57,9 +58,10 @@ function simplify(g) {
57
58
  });
58
59
  return simplified;
59
60
  }
60
-
61
61
  function asNonCompoundGraph(g) {
62
- let simplified = new Graph({ multigraph: g.isMultigraph() }).setGraph(g.graph());
62
+ let simplified = new _graphlib.Graph({
63
+ multigraph: g.isMultigraph()
64
+ }).setGraph(g.graph());
63
65
  g.nodes().forEach(v => {
64
66
  if (!g.children(v).length) {
65
67
  simplified.setNode(v, g.node(v));
@@ -70,7 +72,6 @@ function asNonCompoundGraph(g) {
70
72
  });
71
73
  return simplified;
72
74
  }
73
-
74
75
  function successorWeights(g) {
75
76
  let weightMap = g.nodes().map(v => {
76
77
  let sucs = {};
@@ -81,7 +82,6 @@ function successorWeights(g) {
81
82
  });
82
83
  return zipObject(g.nodes(), weightMap);
83
84
  }
84
-
85
85
  function predecessorWeights(g) {
86
86
  let weightMap = g.nodes().map(v => {
87
87
  let preds = {};
@@ -107,11 +107,9 @@ function intersectRect(rect, point) {
107
107
  let dy = point.y - y;
108
108
  let w = rect.width / 2;
109
109
  let h = rect.height / 2;
110
-
111
110
  if (!dx && !dy) {
112
111
  throw new Error("Not possible to find intersection inside of the rectangle");
113
112
  }
114
-
115
113
  let sx, sy;
116
114
  if (Math.abs(dy) * w > Math.abs(dx) * h) {
117
115
  // Intersection is top or bottom of rect.
@@ -128,8 +126,10 @@ function intersectRect(rect, point) {
128
126
  sx = w;
129
127
  sy = w * dy / dx;
130
128
  }
131
-
132
- return { x: x + sx, y: y + sy };
129
+ return {
130
+ x: x + sx,
131
+ y: y + sy
132
+ };
133
133
  }
134
134
 
135
135
  /*
@@ -158,7 +158,6 @@ function normalizeRanks(g) {
158
158
  if (rank === undefined) {
159
159
  return Number.MAX_VALUE;
160
160
  }
161
-
162
161
  return rank;
163
162
  }));
164
163
  g.nodes().forEach(v => {
@@ -168,11 +167,9 @@ function normalizeRanks(g) {
168
167
  }
169
168
  });
170
169
  }
171
-
172
170
  function removeEmptyRanks(g) {
173
171
  // Ranks may not start at 0, so we need to offset them
174
172
  let offset = Math.min(...g.nodes().map(v => g.node(v).rank));
175
-
176
173
  let layers = [];
177
174
  g.nodes().forEach(v => {
178
175
  let rank = g.node(v).rank - offset;
@@ -181,7 +178,6 @@ function removeEmptyRanks(g) {
181
178
  }
182
179
  layers[rank].push(v);
183
180
  });
184
-
185
181
  let delta = 0;
186
182
  let nodeRankFactor = g.graph().nodeRankFactor;
187
183
  Array.from(layers).forEach((vs, i) => {
@@ -192,7 +188,6 @@ function removeEmptyRanks(g) {
192
188
  }
193
189
  });
194
190
  }
195
-
196
191
  function addBorderNode(g, prefix, rank, order) {
197
192
  let node = {
198
193
  width: 0,
@@ -204,14 +199,12 @@ function addBorderNode(g, prefix, rank, order) {
204
199
  }
205
200
  return addDummyNode(g, "border", node, prefix);
206
201
  }
207
-
208
202
  function maxRank(g) {
209
203
  return Math.max(...g.nodes().map(v => {
210
204
  let rank = g.node(v).rank;
211
205
  if (rank === undefined) {
212
206
  return Number.MIN_VALUE;
213
207
  }
214
-
215
208
  return rank;
216
209
  }));
217
210
  }
@@ -222,7 +215,10 @@ function maxRank(g) {
222
215
  * into `rhs.
223
216
  */
224
217
  function partition(collection, fn) {
225
- let result = { lhs: [], rhs: [] };
218
+ let result = {
219
+ lhs: [],
220
+ rhs: []
221
+ };
226
222
  collection.forEach(value => {
227
223
  if (fn(value)) {
228
224
  result.lhs.push(value);
@@ -245,36 +241,29 @@ function time(name, fn) {
245
241
  console.log(name + " time: " + (Date.now() - start) + "ms");
246
242
  }
247
243
  }
248
-
249
244
  function notime(name, fn) {
250
245
  return fn();
251
246
  }
252
-
253
247
  let idCounter = 0;
254
248
  function uniqueId(prefix) {
255
249
  var id = ++idCounter;
256
250
  return toString(prefix) + id;
257
251
  }
258
-
259
252
  function range(start, limit, step = 1) {
260
253
  if (limit == null) {
261
254
  limit = start;
262
255
  start = 0;
263
256
  }
264
-
265
- let endCon = (i) => i < limit;
257
+ let endCon = i => i < limit;
266
258
  if (step < 0) {
267
- endCon = (i) => limit < i;
259
+ endCon = i => limit < i;
268
260
  }
269
-
270
261
  const range = [];
271
262
  for (let i = start; endCon(i); i += step) {
272
263
  range.push(i);
273
264
  }
274
-
275
265
  return range;
276
266
  }
277
-
278
267
  function pick(source, keys) {
279
268
  const dest = {};
280
269
  for (const key of keys) {
@@ -282,22 +271,18 @@ function pick(source, keys) {
282
271
  dest[key] = source[key];
283
272
  }
284
273
  }
285
-
286
274
  return dest;
287
275
  }
288
-
289
276
  function mapValues(obj, funcOrProp) {
290
277
  let func = funcOrProp;
291
278
  if (typeof funcOrProp === 'string') {
292
- func = (val) => val[funcOrProp];
279
+ func = val => val[funcOrProp];
293
280
  }
294
-
295
281
  return Object.entries(obj).reduce((acc, [k, v]) => {
296
282
  acc[k] = func(v, k);
297
283
  return acc;
298
284
  }, {});
299
285
  }
300
-
301
286
  function zipObject(props, values) {
302
287
  return props.reduce((acc, key, i) => {
303
288
  acc[key] = values[i];
package/lib/version.js CHANGED
@@ -1 +1,8 @@
1
- module.exports = "1.0.4";
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _default = exports.default = "1.1.0";
8
+ module.exports = exports.default;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+
3
+ import { default as greedyFAS } from "./greedy-fas.js";
4
+ import { uniqueId as uniqueId } from "./util.js";
5
+
6
+ export function run(g) {
7
+ let fas = (g.graph().acyclicer === "greedy"
8
+ ? greedyFAS(g, weightFn(g))
9
+ : dfsFAS(g));
10
+ fas.forEach(e => {
11
+ let label = g.edge(e);
12
+ g.removeEdge(e);
13
+ label.forwardName = e.name;
14
+ label.reversed = true;
15
+ g.setEdge(e.w, e.v, label, uniqueId("rev"));
16
+ });
17
+
18
+ function weightFn(g) {
19
+ return e => {
20
+ return g.edge(e).weight;
21
+ };
22
+ }
23
+ }
24
+
25
+ function dfsFAS(g) {
26
+ let fas = [];
27
+ let stack = {};
28
+ let visited = {};
29
+
30
+ function dfs(v) {
31
+ if (visited.hasOwnProperty(v)) {
32
+ return;
33
+ }
34
+ visited[v] = true;
35
+ stack[v] = true;
36
+ g.outEdges(v).forEach(e => {
37
+ if (stack.hasOwnProperty(e.w)) {
38
+ fas.push(e);
39
+ } else {
40
+ dfs(e.w);
41
+ }
42
+ });
43
+ delete stack[v];
44
+ }
45
+
46
+ g.nodes().forEach(dfs);
47
+ return fas;
48
+ }
49
+
50
+ export function undo(g) {
51
+ g.edges().forEach(e => {
52
+ let label = g.edge(e);
53
+ if (label.reversed) {
54
+ g.removeEdge(e);
55
+
56
+ let forwardName = label.forwardName;
57
+ delete label.reversed;
58
+ delete label.forwardName;
59
+ g.setEdge(e.w, e.v, label, forwardName);
60
+ }
61
+ });
62
+ }
@@ -0,0 +1,35 @@
1
+ import * as util from "./util.js";
2
+
3
+ export default function addBorderSegments(g) {
4
+ function dfs(v) {
5
+ let children = g.children(v);
6
+ let node = g.node(v);
7
+ if (children.length) {
8
+ children.forEach(dfs);
9
+ }
10
+
11
+ if (node.hasOwnProperty("minRank")) {
12
+ node.borderLeft = [];
13
+ node.borderRight = [];
14
+ for (let rank = node.minRank, maxRank = node.maxRank + 1;
15
+ rank < maxRank;
16
+ ++rank) {
17
+ addBorderNode(g, "borderLeft", "_bl", v, node, rank);
18
+ addBorderNode(g, "borderRight", "_br", v, node, rank);
19
+ }
20
+ }
21
+ }
22
+
23
+ g.children().forEach(dfs);
24
+ }
25
+
26
+ function addBorderNode(g, prop, prefix, sg, sgNode, rank) {
27
+ let label = { width: 0, height: 0, rank: rank, borderType: prop };
28
+ let prev = sgNode[prop][rank - 1];
29
+ let curr = util.addDummyNode(g, "border", label, prefix);
30
+ sgNode[prop][rank] = curr;
31
+ g.setParent(curr, sg);
32
+ if (prev) {
33
+ g.setEdge(prev, curr, { weight: 1 });
34
+ }
35
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+
3
+ export function adjust(g) {
4
+ let rankDir = g.graph().rankdir.toLowerCase();
5
+ if (rankDir === "lr" || rankDir === "rl") {
6
+ swapWidthHeight(g);
7
+ }
8
+ }
9
+
10
+ export function undo(g) {
11
+ let rankDir = g.graph().rankdir.toLowerCase();
12
+ if (rankDir === "bt" || rankDir === "rl") {
13
+ reverseY(g);
14
+ }
15
+
16
+ if (rankDir === "lr" || rankDir === "rl") {
17
+ swapXY(g);
18
+ swapWidthHeight(g);
19
+ }
20
+ }
21
+
22
+ function swapWidthHeight(g) {
23
+ g.nodes().forEach(v => swapWidthHeightOne(g.node(v)));
24
+ g.edges().forEach(e => swapWidthHeightOne(g.edge(e)));
25
+ }
26
+
27
+ function swapWidthHeightOne(attrs) {
28
+ let w = attrs.width;
29
+ attrs.width = attrs.height;
30
+ attrs.height = w;
31
+ }
32
+
33
+ function reverseY(g) {
34
+ g.nodes().forEach(v => reverseYOne(g.node(v)));
35
+
36
+ g.edges().forEach(e => {
37
+ let edge = g.edge(e);
38
+ edge.points.forEach(reverseYOne);
39
+ if (edge.hasOwnProperty("y")) {
40
+ reverseYOne(edge);
41
+ }
42
+ });
43
+ }
44
+
45
+ function reverseYOne(attrs) {
46
+ attrs.y = -attrs.y;
47
+ }
48
+
49
+ function swapXY(g) {
50
+ g.nodes().forEach(v => swapXYOne(g.node(v)));
51
+
52
+ g.edges().forEach(e => {
53
+ let edge = g.edge(e);
54
+ edge.points.forEach(swapXYOne);
55
+ if (edge.hasOwnProperty("x")) {
56
+ swapXYOne(edge);
57
+ }
58
+ });
59
+ }
60
+
61
+ function swapXYOne(attrs) {
62
+ let x = attrs.x;
63
+ attrs.x = attrs.y;
64
+ attrs.y = x;
65
+ }
@@ -0,0 +1,56 @@
1
+ /*
2
+ * Simple doubly linked list implementation derived from Cormen, et al.,
3
+ * "Introduction to Algorithms".
4
+ */
5
+
6
+ export default class List {
7
+ constructor() {
8
+ let sentinel = {};
9
+ sentinel._next = sentinel._prev = sentinel;
10
+ this._sentinel = sentinel;
11
+ }
12
+
13
+ dequeue() {
14
+ let sentinel = this._sentinel;
15
+ let entry = sentinel._prev;
16
+ if (entry !== sentinel) {
17
+ unlink(entry);
18
+ return entry;
19
+ }
20
+ }
21
+
22
+ enqueue(entry) {
23
+ let sentinel = this._sentinel;
24
+ if (entry._prev && entry._next) {
25
+ unlink(entry);
26
+ }
27
+ entry._next = sentinel._next;
28
+ sentinel._next._prev = entry;
29
+ sentinel._next = entry;
30
+ entry._prev = sentinel;
31
+ }
32
+
33
+ toString() {
34
+ let strs = [];
35
+ let sentinel = this._sentinel;
36
+ let curr = sentinel._prev;
37
+ while (curr !== sentinel) {
38
+ strs.push(JSON.stringify(curr, filterOutLinks));
39
+ curr = curr._prev;
40
+ }
41
+ return "[" + strs.join(", ") + "]";
42
+ }
43
+ }
44
+
45
+ function unlink(entry) {
46
+ entry._prev._next = entry._next;
47
+ entry._next._prev = entry._prev;
48
+ delete entry._next;
49
+ delete entry._prev;
50
+ }
51
+
52
+ function filterOutLinks(k, v) {
53
+ if (k !== "_next" && k !== "_prev") {
54
+ return v;
55
+ }
56
+ }