@dagrejs/dagre 1.1.4 → 1.1.8

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/dist/dagre.js CHANGED
@@ -532,7 +532,7 @@ function updateInputGraph(inputGraph, layoutGraph) {
532
532
  let graphNumAttrs = ["nodesep", "edgesep", "ranksep", "marginx", "marginy"];
533
533
  let graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: "tb" };
534
534
  let graphAttrs = ["acyclicer", "ranker", "rankdir", "align"];
535
- let nodeNumAttrs = ["width", "height"];
535
+ let nodeNumAttrs = ["width", "height", "rank"];
536
536
  let nodeDefaults = { width: 0, height: 0 };
537
537
  let edgeNumAttrs = ["minlen", "weight", "width", "height", "labeloffset"];
538
538
  let edgeDefaults = {
@@ -1161,6 +1161,8 @@ module.exports = buildLayerGraph;
1161
1161
  * 2. Base nodes in the input graph have a rank attribute
1162
1162
  * 3. Subgraph nodes in the input graph has minRank and maxRank attributes
1163
1163
  * 4. Edges have an assigned weight
1164
+ * 5. If `nodesWithRank` is not undefined, it must contains only the nodes
1165
+ * which belong to `g` and belong to `rank`.
1164
1166
  *
1165
1167
  * Post-conditions:
1166
1168
  *
@@ -1175,12 +1177,16 @@ module.exports = buildLayerGraph;
1175
1177
  * 5. The weights for copied edges are aggregated as need, since the output
1176
1178
  * graph is not a multi-graph.
1177
1179
  */
1178
- function buildLayerGraph(g, rank, relationship) {
1180
+ function buildLayerGraph(g, rank, relationship, nodesWithRank) {
1181
+ if (!nodesWithRank) {
1182
+ nodesWithRank = g.nodes();
1183
+ }
1179
1184
  let root = createRootNode(g),
1180
- result = new Graph({ compound: true }).setGraph({ root: root })
1181
- .setDefaultNodeLabel(v => g.node(v));
1185
+ result = new Graph({ compound: true })
1186
+ .setGraph({ root: root })
1187
+ .setDefaultNodeLabel((v) => g.node(v));
1182
1188
 
1183
- g.nodes().forEach(v => {
1189
+ nodesWithRank.forEach((v) => {
1184
1190
  let node = g.node(v),
1185
1191
  parent = g.parent(v);
1186
1192
 
@@ -1346,8 +1352,38 @@ function order(g, opts) {
1346
1352
  }
1347
1353
 
1348
1354
  function buildLayerGraphs(g, ranks, relationship) {
1349
- return ranks.map(function(rank) {
1350
- return buildLayerGraph(g, rank, relationship);
1355
+ // Build an index mapping from rank to the nodes with that rank.
1356
+ // This helps to avoid a quadratic search for all nodes with the same rank as
1357
+ // the current node.
1358
+ const nodesByRank = new Map();
1359
+ const addNodeToRank = (rank, node) => {
1360
+ if (!nodesByRank.has(rank)) {
1361
+ nodesByRank.set(rank, []);
1362
+ }
1363
+ nodesByRank.get(rank).push(node);
1364
+ };
1365
+
1366
+ // Visit the nodes in their original order in the graph, and add each
1367
+ // node to the ranks(s) that it belongs to.
1368
+ for (const v of g.nodes()) {
1369
+ const node = g.node(v);
1370
+ if (typeof node.rank === "number") {
1371
+ addNodeToRank(node.rank, v);
1372
+ }
1373
+ // If there is a range of ranks, add it to each, but skip the `node.rank` which
1374
+ // has already had the node added.
1375
+ if (typeof node.minRank === "number" && typeof node.maxRank === "number") {
1376
+ for (let r = node.minRank; r <= node.maxRank; r++) {
1377
+ if (r !== node.rank) {
1378
+ // Don't add this node to its `node.rank` twice.
1379
+ addNodeToRank(r, v);
1380
+ }
1381
+ }
1382
+ }
1383
+ }
1384
+
1385
+ return ranks.map(function (rank) {
1386
+ return buildLayerGraph(g, rank, relationship, nodesByRank.get(rank) || []);
1351
1387
  });
1352
1388
  }
1353
1389
 
@@ -2330,10 +2366,16 @@ module.exports = rank;
2330
2366
  * fix them up later.
2331
2367
  */
2332
2368
  function rank(g) {
2369
+ var ranker = g.graph().ranker;
2370
+ if (ranker instanceof Function) {
2371
+ return ranker(g);
2372
+ }
2373
+
2333
2374
  switch(g.graph().ranker) {
2334
2375
  case "network-simplex": networkSimplexRanker(g); break;
2335
2376
  case "tight-tree": tightTreeRanker(g); break;
2336
2377
  case "longest-path": longestPathRanker(g); break;
2378
+ case "none": break;
2337
2379
  default: networkSimplexRanker(g);
2338
2380
  }
2339
2381
  }
@@ -2690,10 +2732,10 @@ module.exports = {
2690
2732
  * Adds a dummy node to the graph and return v.
2691
2733
  */
2692
2734
  function addDummyNode(g, type, attrs, name) {
2693
- let v;
2694
- do {
2735
+ var v = name;
2736
+ while (g.hasNode(v)) {
2695
2737
  v = uniqueId(name);
2696
- } while (g.hasNode(v));
2738
+ }
2697
2739
 
2698
2740
  attrs.dummy = type;
2699
2741
  g.setNode(v, attrs);
@@ -2937,7 +2979,7 @@ function notime(name, fn) {
2937
2979
  let idCounter = 0;
2938
2980
  function uniqueId(prefix) {
2939
2981
  var id = ++idCounter;
2940
- return toString(prefix) + id;
2982
+ return prefix + ("" + id);
2941
2983
  }
2942
2984
 
2943
2985
  function range(start, limit, step = 1) {
@@ -2990,7 +3032,7 @@ function zipObject(props, values) {
2990
3032
  }
2991
3033
 
2992
3034
  },{"@dagrejs/graphlib":29}],28:[function(require,module,exports){
2993
- module.exports = "1.1.4";
3035
+ module.exports = "1.1.8";
2994
3036
 
2995
3037
  },{}],29:[function(require,module,exports){
2996
3038
  /**
package/dist/dagre.min.js CHANGED
@@ -44,7 +44,7 @@ g.edges().forEach(e=>{let prevWeight=fasGraph.edge(e.v,e.w)||0;let weight=weight
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(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"];
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","rank"];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
@@ -153,6 +153,8 @@ g.graph().nodeRankFactor=nodeSep}function dfs(g,root,nodeSep,weight,height,depth
153
153
  * 2. Base nodes in the input graph have a rank attribute
154
154
  * 3. Subgraph nodes in the input graph has minRank and maxRank attributes
155
155
  * 4. Edges have an assigned weight
156
+ * 5. If `nodesWithRank` is not undefined, it must contains only the nodes
157
+ * which belong to `g` and belong to `rank`.
156
158
  *
157
159
  * Post-conditions:
158
160
  *
@@ -166,7 +168,7 @@ g.graph().nodeRankFactor=nodeSep}function dfs(g,root,nodeSep,weight,height,depth
166
168
  * parameter, are added to the output graph.
167
169
  * 5. The weights for copied edges are aggregated as need, since the output
168
170
  * graph is not a multi-graph.
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);
171
+ */function buildLayerGraph(g,rank,relationship,nodesWithRank){if(!nodesWithRank){nodesWithRank=g.nodes()}let root=createRootNode(g),result=new Graph({compound:true}).setGraph({root:root}).setDefaultNodeLabel(v=>g.node(v));nodesWithRank.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
172
  // This assumes we have only short edges!
171
173
  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
174
  /*
@@ -207,7 +209,19 @@ let cc=0;southEntries.forEach(entry=>{let index=entry.pos+firstIndex;tree[index]
207
209
  *
208
210
  * 1. Graph nodes will have an "order" attribute based on the results of the
209
211
  * algorithm.
210
- */function order(g,opts){if(opts&&typeof opts.customOrder==="function"){opts.customOrder(g,order);return}let maxRank=util.maxRank(g),downLayerGraphs=buildLayerGraphs(g,util.range(1,maxRank+1),"inEdges"),upLayerGraphs=buildLayerGraphs(g,util.range(maxRank-1,-1,-1),"outEdges");let layering=initOrder(g);assignOrder(g,layering);if(opts&&opts.disableOptimalOrderHeuristic){return}let bestCC=Number.POSITIVE_INFINITY,best;for(let i=0,lastBest=0;lastBest<4;++i,++lastBest){sweepLayerGraphs(i%2?downLayerGraphs:upLayerGraphs,i%4>=2);layering=util.buildLayerMatrix(g);let cc=crossCount(g,layering);if(cc<bestCC){lastBest=0;best=Object.assign({},layering);bestCC=cc}}assignOrder(g,best)}function buildLayerGraphs(g,ranks,relationship){return ranks.map(function(rank){return buildLayerGraph(g,rank,relationship)})}function sweepLayerGraphs(layerGraphs,biasRight){let cg=new Graph;layerGraphs.forEach(function(lg){let root=lg.graph().root;let sorted=sortSubgraph(lg,root,cg,biasRight);sorted.vs.forEach((v,i)=>lg.node(v).order=i);addSubgraphConstraints(lg,cg,sorted.vs)})}function assignOrder(g,layering){Object.values(layering).forEach(layer=>layer.forEach((v,i)=>g.node(v).order=i))}},{"../util":27,"./add-subgraph-constraints":11,"./build-layer-graph":13,"./cross-count":14,"./init-order":16,"./sort-subgraph":18,"@dagrejs/graphlib":29}],16:[function(require,module,exports){"use strict";let util=require("../util");module.exports=initOrder;
212
+ */function order(g,opts){if(opts&&typeof opts.customOrder==="function"){opts.customOrder(g,order);return}let maxRank=util.maxRank(g),downLayerGraphs=buildLayerGraphs(g,util.range(1,maxRank+1),"inEdges"),upLayerGraphs=buildLayerGraphs(g,util.range(maxRank-1,-1,-1),"outEdges");let layering=initOrder(g);assignOrder(g,layering);if(opts&&opts.disableOptimalOrderHeuristic){return}let bestCC=Number.POSITIVE_INFINITY,best;for(let i=0,lastBest=0;lastBest<4;++i,++lastBest){sweepLayerGraphs(i%2?downLayerGraphs:upLayerGraphs,i%4>=2);layering=util.buildLayerMatrix(g);let cc=crossCount(g,layering);if(cc<bestCC){lastBest=0;best=Object.assign({},layering);bestCC=cc}}assignOrder(g,best)}function buildLayerGraphs(g,ranks,relationship){
213
+ // Build an index mapping from rank to the nodes with that rank.
214
+ // This helps to avoid a quadratic search for all nodes with the same rank as
215
+ // the current node.
216
+ const nodesByRank=new Map;const addNodeToRank=(rank,node)=>{if(!nodesByRank.has(rank)){nodesByRank.set(rank,[])}nodesByRank.get(rank).push(node)};
217
+ // Visit the nodes in their original order in the graph, and add each
218
+ // node to the ranks(s) that it belongs to.
219
+ for(const v of g.nodes()){const node=g.node(v);if(typeof node.rank==="number"){addNodeToRank(node.rank,v)}
220
+ // If there is a range of ranks, add it to each, but skip the `node.rank` which
221
+ // has already had the node added.
222
+ if(typeof node.minRank==="number"&&typeof node.maxRank==="number"){for(let r=node.minRank;r<=node.maxRank;r++){if(r!==node.rank){
223
+ // Don't add this node to its `node.rank` twice.
224
+ addNodeToRank(r,v)}}}}return ranks.map(function(rank){return buildLayerGraph(g,rank,relationship,nodesByRank.get(rank)||[])})}function sweepLayerGraphs(layerGraphs,biasRight){let cg=new Graph;layerGraphs.forEach(function(lg){let root=lg.graph().root;let sorted=sortSubgraph(lg,root,cg,biasRight);sorted.vs.forEach((v,i)=>lg.node(v).order=i);addSubgraphConstraints(lg,cg,sorted.vs)})}function assignOrder(g,layering){Object.values(layering).forEach(layer=>layer.forEach((v,i)=>g.node(v).order=i))}},{"../util":27,"./add-subgraph-constraints":11,"./build-layer-graph":13,"./cross-count":14,"./init-order":16,"./sort-subgraph":18,"@dagrejs/graphlib":29}],16:[function(require,module,exports){"use strict";let util=require("../util");module.exports=initOrder;
211
225
  /*
212
226
  * Assigns an initial order value for each node by performing a DFS search
213
227
  * starting from nodes in the first rank. Nodes are assigned an order in their
@@ -365,7 +379,7 @@ var start=g.nodes()[0];var size=g.nodeCount();t.setNode(start,{});var edge,delta
365
379
  * 1. Graph nodes will have a "rank" attribute based on the results of the
366
380
  * algorithm. Ranks can start at any index (including negative), we'll
367
381
  * fix them up later.
368
- */function rank(g){switch(g.graph().ranker){case"network-simplex":networkSimplexRanker(g);break;case"tight-tree":tightTreeRanker(g);break;case"longest-path":longestPathRanker(g);break;default:networkSimplexRanker(g)}}
382
+ */function rank(g){var ranker=g.graph().ranker;if(ranker instanceof Function){return ranker(g)}switch(g.graph().ranker){case"network-simplex":networkSimplexRanker(g);break;case"tight-tree":tightTreeRanker(g);break;case"longest-path":longestPathRanker(g);break;case"none":break;default:networkSimplexRanker(g)}}
369
383
  // A fast and simple ranker, but results are far from optimal.
370
384
  var longestPathRanker=longestPath;function tightTreeRanker(g){longestPath(g);feasibleTree(g)}function networkSimplexRanker(g){networkSimplex(g)}},{"./feasible-tree":23,"./network-simplex":25,"./util":26}],25:[function(require,module,exports){"use strict";var feasibleTree=require("./feasible-tree");var slack=require("./util").slack;var initRank=require("./util").longestPath;var preorder=require("@dagrejs/graphlib").alg.preorder;var postorder=require("@dagrejs/graphlib").alg.postorder;var simplify=require("../util").simplify;module.exports=networkSimplex;
371
385
  // Expose some internals for testing purposes
@@ -461,7 +475,7 @@ if(vLabel.lim>wLabel.lim){tailLabel=wLabel;flip=true}var candidates=g.edges().fi
461
475
  "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
476
  /*
463
477
  * Adds a dummy node to the graph and return v.
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}
478
+ */function addDummyNode(g,type,attrs,name){var v=name;while(g.hasNode(v)){v=uniqueId(name)}attrs.dummy=type;g.setNode(v,attrs);return v}
465
479
  /*
466
480
  * Returns a new graph with only simple edges. Handles aggregation of data
467
481
  * associated with multi-edges.
@@ -495,7 +509,7 @@ let nodeRanks=g.nodes().map(v=>g.node(v).rank);let offset=applyWithChunking(Math
495
509
  /*
496
510
  * Returns a new function that wraps `fn` with a timer. The wrapper logs the
497
511
  * 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.4"},{}],29:[function(require,module,exports){
512
+ */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 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.8"},{}],29:[function(require,module,exports){
499
513
  /**
500
514
  * Copyright (c) 2014, Chris Pettitt
501
515
  * All rights reserved.
package/index.d.ts CHANGED
@@ -29,14 +29,14 @@ declare module '@dagrejs/dagre' {
29
29
  setEdge(params: Edge, value?: string | { [key: string]: any }): Graph<T>;
30
30
  setEdge(sourceId: string, targetId: string, value?: string | Label, name?: string): Graph<T>;
31
31
 
32
- children(parentName: string): string | undefined;
32
+ children(parentName: string): string[];
33
33
  hasNode(name: string): boolean;
34
- neighbors(name: string): Array<Node<T>> | undefined;
34
+ neighbors(name: string): string[] | undefined;
35
35
  node(id: string | Label): Node<T>;
36
36
  nodeCount(): number;
37
37
  nodes(): string[];
38
38
  parent(childName: string): string | undefined;
39
- predecessors(name: string): Array<Node<T>> | undefined;
39
+ predecessors(name: string): string[] | undefined;
40
40
  removeNode(name: string): Graph<T>;
41
41
  filterNodes(callback: (nodeId: string) => boolean): Graph<T>;
42
42
  setDefaultNodeLabel(callback: string | ((nodeId: string) => string | Label)): Graph<T>;
@@ -44,7 +44,7 @@ declare module '@dagrejs/dagre' {
44
44
  setParent(childName: string, parentName: string): void;
45
45
  sinks(): Array<Node<T>>;
46
46
  sources(): Array<Node<T>>;
47
- successors(name: string): Array<Node<T>> | undefined;
47
+ successors(name: string): string[] | undefined;
48
48
  }
49
49
 
50
50
  namespace json {
@@ -57,7 +57,7 @@ declare module '@dagrejs/dagre' {
57
57
  function dijkstra(graph: Graph, source: string, weightFn?: WeightFn, edgeFn?: EdgeFn): any;
58
58
  function dijkstraAll(graph: Graph, weightFn?: WeightFn, edgeFn?: EdgeFn): any;
59
59
  function findCycles(graph: Graph): string[][];
60
- function floydWarchall(graph: Graph, weightFn?: WeightFn, edgeFn?: EdgeFn): any;
60
+ function floydWarshall(graph: Graph, weightFn?: WeightFn, edgeFn?: EdgeFn): any;
61
61
  function isAcyclic(graph: Graph): boolean;
62
62
  function postorder(graph: Graph, nodeNames: string | string[]): string[];
63
63
  function preorder(graph: Graph, nodeNames: string | string[]): string[];
package/lib/layout.js CHANGED
@@ -97,7 +97,7 @@ function updateInputGraph(inputGraph, layoutGraph) {
97
97
  let graphNumAttrs = ["nodesep", "edgesep", "ranksep", "marginx", "marginy"];
98
98
  let graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: "tb" };
99
99
  let graphAttrs = ["acyclicer", "ranker", "rankdir", "align"];
100
- let nodeNumAttrs = ["width", "height"];
100
+ let nodeNumAttrs = ["width", "height", "rank"];
101
101
  let nodeDefaults = { width: 0, height: 0 };
102
102
  let edgeNumAttrs = ["minlen", "weight", "width", "height", "labeloffset"];
103
103
  let edgeDefaults = {
@@ -19,6 +19,8 @@ module.exports = buildLayerGraph;
19
19
  * 2. Base nodes in the input graph have a rank attribute
20
20
  * 3. Subgraph nodes in the input graph has minRank and maxRank attributes
21
21
  * 4. Edges have an assigned weight
22
+ * 5. If `nodesWithRank` is not undefined, it must contains only the nodes
23
+ * which belong to `g` and belong to `rank`.
22
24
  *
23
25
  * Post-conditions:
24
26
  *
@@ -33,12 +35,16 @@ module.exports = buildLayerGraph;
33
35
  * 5. The weights for copied edges are aggregated as need, since the output
34
36
  * graph is not a multi-graph.
35
37
  */
36
- function buildLayerGraph(g, rank, relationship) {
38
+ function buildLayerGraph(g, rank, relationship, nodesWithRank) {
39
+ if (!nodesWithRank) {
40
+ nodesWithRank = g.nodes();
41
+ }
37
42
  let root = createRootNode(g),
38
- result = new Graph({ compound: true }).setGraph({ root: root })
39
- .setDefaultNodeLabel(v => g.node(v));
43
+ result = new Graph({ compound: true })
44
+ .setGraph({ root: root })
45
+ .setDefaultNodeLabel((v) => g.node(v));
40
46
 
41
- g.nodes().forEach(v => {
47
+ nodesWithRank.forEach((v) => {
42
48
  let node = g.node(v),
43
49
  parent = g.parent(v);
44
50
 
@@ -61,8 +61,38 @@ function order(g, opts) {
61
61
  }
62
62
 
63
63
  function buildLayerGraphs(g, ranks, relationship) {
64
- return ranks.map(function(rank) {
65
- return buildLayerGraph(g, rank, relationship);
64
+ // Build an index mapping from rank to the nodes with that rank.
65
+ // This helps to avoid a quadratic search for all nodes with the same rank as
66
+ // the current node.
67
+ const nodesByRank = new Map();
68
+ const addNodeToRank = (rank, node) => {
69
+ if (!nodesByRank.has(rank)) {
70
+ nodesByRank.set(rank, []);
71
+ }
72
+ nodesByRank.get(rank).push(node);
73
+ };
74
+
75
+ // Visit the nodes in their original order in the graph, and add each
76
+ // node to the ranks(s) that it belongs to.
77
+ for (const v of g.nodes()) {
78
+ const node = g.node(v);
79
+ if (typeof node.rank === "number") {
80
+ addNodeToRank(node.rank, v);
81
+ }
82
+ // If there is a range of ranks, add it to each, but skip the `node.rank` which
83
+ // has already had the node added.
84
+ if (typeof node.minRank === "number" && typeof node.maxRank === "number") {
85
+ for (let r = node.minRank; r <= node.maxRank; r++) {
86
+ if (r !== node.rank) {
87
+ // Don't add this node to its `node.rank` twice.
88
+ addNodeToRank(r, v);
89
+ }
90
+ }
91
+ }
92
+ }
93
+
94
+ return ranks.map(function (rank) {
95
+ return buildLayerGraph(g, rank, relationship, nodesByRank.get(rank) || []);
66
96
  });
67
97
  }
68
98
 
package/lib/rank/index.js CHANGED
@@ -27,10 +27,16 @@ module.exports = rank;
27
27
  * fix them up later.
28
28
  */
29
29
  function rank(g) {
30
+ var ranker = g.graph().ranker;
31
+ if (ranker instanceof Function) {
32
+ return ranker(g);
33
+ }
34
+
30
35
  switch(g.graph().ranker) {
31
36
  case "network-simplex": networkSimplexRanker(g); break;
32
37
  case "tight-tree": tightTreeRanker(g); break;
33
38
  case "longest-path": longestPathRanker(g); break;
39
+ case "none": break;
34
40
  default: networkSimplexRanker(g);
35
41
  }
36
42
  }
package/lib/util.js CHANGED
@@ -31,10 +31,10 @@ module.exports = {
31
31
  * Adds a dummy node to the graph and return v.
32
32
  */
33
33
  function addDummyNode(g, type, attrs, name) {
34
- let v;
35
- do {
34
+ var v = name;
35
+ while (g.hasNode(v)) {
36
36
  v = uniqueId(name);
37
- } while (g.hasNode(v));
37
+ }
38
38
 
39
39
  attrs.dummy = type;
40
40
  g.setNode(v, attrs);
@@ -278,7 +278,7 @@ function notime(name, fn) {
278
278
  let idCounter = 0;
279
279
  function uniqueId(prefix) {
280
280
  var id = ++idCounter;
281
- return toString(prefix) + id;
281
+ return prefix + ("" + id);
282
282
  }
283
283
 
284
284
  function range(start, limit, step = 1) {
package/lib/version.js CHANGED
@@ -1 +1 @@
1
- module.exports = "1.1.4";
1
+ module.exports = "1.1.8";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dagrejs/dagre",
3
- "version": "1.1.4",
3
+ "version": "1.1.8",
4
4
  "description": "Graph layout for JavaScript",
5
5
  "author": "Chris Pettitt <cpettitt@gmail.com>",
6
6
  "contributors": [