@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 +54 -12
- package/dist/dagre.min.js +20 -6
- package/index.d.ts +5 -5
- package/lib/layout.js +1 -1
- package/lib/order/build-layer-graph.js +10 -4
- package/lib/order/index.js +32 -2
- package/lib/rank/index.js +6 -0
- package/lib/util.js +4 -4
- package/lib/version.js +1 -1
- package/package.json +1 -1
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 })
|
|
1181
|
-
.
|
|
1185
|
+
result = new Graph({ compound: true })
|
|
1186
|
+
.setGraph({ root: root })
|
|
1187
|
+
.setDefaultNodeLabel((v) => g.node(v));
|
|
1182
1188
|
|
|
1183
|
-
|
|
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
|
-
|
|
1350
|
-
|
|
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
|
-
|
|
2694
|
-
|
|
2735
|
+
var v = name;
|
|
2736
|
+
while (g.hasNode(v)) {
|
|
2695
2737
|
v = uniqueId(name);
|
|
2696
|
-
}
|
|
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
|
|
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.
|
|
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));
|
|
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){
|
|
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){
|
|
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
|
|
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
|
|
32
|
+
children(parentName: string): string[];
|
|
33
33
|
hasNode(name: string): boolean;
|
|
34
|
-
neighbors(name: string):
|
|
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):
|
|
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):
|
|
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
|
|
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 })
|
|
39
|
-
.
|
|
43
|
+
result = new Graph({ compound: true })
|
|
44
|
+
.setGraph({ root: root })
|
|
45
|
+
.setDefaultNodeLabel((v) => g.node(v));
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
nodesWithRank.forEach((v) => {
|
|
42
48
|
let node = g.node(v),
|
|
43
49
|
parent = g.parent(v);
|
|
44
50
|
|
package/lib/order/index.js
CHANGED
|
@@ -61,8 +61,38 @@ function order(g, opts) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
function buildLayerGraphs(g, ranks, relationship) {
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
35
|
-
|
|
34
|
+
var v = name;
|
|
35
|
+
while (g.hasNode(v)) {
|
|
36
36
|
v = uniqueId(name);
|
|
37
|
-
}
|
|
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
|
|
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.
|
|
1
|
+
module.exports = "1.1.8";
|