@dagrejs/dagre 1.1.3 → 1.1.5
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/README.md +1 -1
- package/dist/dagre.js +97 -60
- package/dist/dagre.min.js +32 -32
- package/index.d.ts +4 -4
- package/lib/acyclic.js +2 -2
- package/lib/add-border-segments.js +1 -1
- package/lib/coordinate-system.js +2 -2
- package/lib/layout.js +6 -6
- package/lib/nesting-graph.js +2 -1
- package/lib/order/build-layer-graph.js +1 -1
- package/lib/order/init-order.js +2 -1
- package/lib/order/sort-subgraph.js +2 -2
- package/lib/order/sort.js +1 -1
- package/lib/position/bk.js +7 -7
- package/lib/rank/index.js +6 -0
- package/lib/rank/network-simplex.js +1 -1
- package/lib/rank/util.js +7 -3
- package/lib/util.js +36 -11
- package/lib/version.js +1 -1
- package/package.json +2 -2
package/dist/dagre.min.js
CHANGED
|
@@ -20,7 +20,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
21
|
THE SOFTWARE.
|
|
22
22
|
*/
|
|
23
|
-
module.exports={graphlib:require("@dagrejs/graphlib"),layout:require("./lib/layout"),debug:require("./lib/debug"),util:{time:require("./lib/util").time,notime:require("./lib/util").notime},version:require("./lib/version")}},{"./lib/debug":6,"./lib/layout":8,"./lib/util":27,"./lib/version":28,"@dagrejs/graphlib":29}],2:[function(require,module,exports){"use strict";let greedyFAS=require("./greedy-fas");let uniqueId=require("./util").uniqueId;module.exports={run:run,undo:undo};function run(g){let fas=g.graph().acyclicer==="greedy"?greedyFAS(g,weightFn(g)):dfsFAS(g);fas.forEach(e=>{let label=g.edge(e);g.removeEdge(e);label.forwardName=e.name;label.reversed=true;g.setEdge(e.w,e.v,label,uniqueId("rev"))});function weightFn(g){return e=>{return g.edge(e).weight}}}function dfsFAS(g){let fas=[];let stack={};let visited={};function dfs(v){if(
|
|
23
|
+
module.exports={graphlib:require("@dagrejs/graphlib"),layout:require("./lib/layout"),debug:require("./lib/debug"),util:{time:require("./lib/util").time,notime:require("./lib/util").notime},version:require("./lib/version")}},{"./lib/debug":6,"./lib/layout":8,"./lib/util":27,"./lib/version":28,"@dagrejs/graphlib":29}],2:[function(require,module,exports){"use strict";let greedyFAS=require("./greedy-fas");let uniqueId=require("./util").uniqueId;module.exports={run:run,undo:undo};function run(g){let fas=g.graph().acyclicer==="greedy"?greedyFAS(g,weightFn(g)):dfsFAS(g);fas.forEach(e=>{let label=g.edge(e);g.removeEdge(e);label.forwardName=e.name;label.reversed=true;g.setEdge(e.w,e.v,label,uniqueId("rev"))});function weightFn(g){return e=>{return g.edge(e).weight}}}function dfsFAS(g){let fas=[];let stack={};let visited={};function dfs(v){if(Object.hasOwn(visited,v)){return}visited[v]=true;stack[v]=true;g.outEdges(v).forEach(e=>{if(Object.hasOwn(stack,e.w)){fas.push(e)}else{dfs(e.w)}});delete stack[v]}g.nodes().forEach(dfs);return fas}function undo(g){g.edges().forEach(e=>{let label=g.edge(e);if(label.reversed){g.removeEdge(e);let forwardName=label.forwardName;delete label.reversed;delete label.forwardName;g.setEdge(e.w,e.v,label,forwardName)}})}},{"./greedy-fas":7,"./util":27}],3:[function(require,module,exports){let util=require("./util");module.exports=addBorderSegments;function addBorderSegments(g){function dfs(v){let children=g.children(v);let node=g.node(v);if(children.length){children.forEach(dfs)}if(Object.hasOwn(node,"minRank")){node.borderLeft=[];node.borderRight=[];for(let rank=node.minRank,maxRank=node.maxRank+1;rank<maxRank;++rank){addBorderNode(g,"borderLeft","_bl",v,node,rank);addBorderNode(g,"borderRight","_br",v,node,rank)}}}g.children().forEach(dfs)}function addBorderNode(g,prop,prefix,sg,sgNode,rank){let label={width:0,height:0,rank:rank,borderType:prop};let prev=sgNode[prop][rank-1];let curr=util.addDummyNode(g,"border",label,prefix);sgNode[prop][rank]=curr;g.setParent(curr,sg);if(prev){g.setEdge(prev,curr,{weight:1})}}},{"./util":27}],4:[function(require,module,exports){"use strict";module.exports={adjust:adjust,undo:undo};function adjust(g){let rankDir=g.graph().rankdir.toLowerCase();if(rankDir==="lr"||rankDir==="rl"){swapWidthHeight(g)}}function undo(g){let rankDir=g.graph().rankdir.toLowerCase();if(rankDir==="bt"||rankDir==="rl"){reverseY(g)}if(rankDir==="lr"||rankDir==="rl"){swapXY(g);swapWidthHeight(g)}}function swapWidthHeight(g){g.nodes().forEach(v=>swapWidthHeightOne(g.node(v)));g.edges().forEach(e=>swapWidthHeightOne(g.edge(e)))}function swapWidthHeightOne(attrs){let w=attrs.width;attrs.width=attrs.height;attrs.height=w}function reverseY(g){g.nodes().forEach(v=>reverseYOne(g.node(v)));g.edges().forEach(e=>{let edge=g.edge(e);edge.points.forEach(reverseYOne);if(Object.hasOwn(edge,"y")){reverseYOne(edge)}})}function reverseYOne(attrs){attrs.y=-attrs.y}function swapXY(g){g.nodes().forEach(v=>swapXYOne(g.node(v)));g.edges().forEach(e=>{let edge=g.edge(e);edge.points.forEach(swapXYOne);if(Object.hasOwn(edge,"x")){swapXYOne(edge)}})}function swapXYOne(attrs){let x=attrs.x;attrs.x=attrs.y;attrs.y=x}},{}],5:[function(require,module,exports){
|
|
24
24
|
/*
|
|
25
25
|
* Simple doubly linked list implementation derived from Cormen, et al.,
|
|
26
26
|
* "Introduction to Algorithms".
|
|
@@ -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(
|
|
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
|
|
@@ -64,7 +64,7 @@ g.edges().forEach(e=>{let prevWeight=fasGraph.edge(e.v,e.w)||0;let weight=weight
|
|
|
64
64
|
* label is going to, if it has one of non-zero width and height. We do this
|
|
65
65
|
* so that we can safely remove empty ranks while preserving balance for the
|
|
66
66
|
* label's position.
|
|
67
|
-
*/function injectEdgeLabelProxies(g){g.edges().forEach(e=>{let edge=g.edge(e);if(edge.width&&edge.height){let v=g.node(e.v);let w=g.node(e.w);let label={rank:(w.rank-v.rank)/2+v.rank,e:e};util.addDummyNode(g,"edge-proxy",label,"_ep")}})}function assignRankMinMax(g){let maxRank=0;g.nodes().forEach(v=>{let node=g.node(v);if(node.borderTop){node.minRank=g.node(node.borderTop).rank;node.maxRank=g.node(node.borderBottom).rank;maxRank=Math.max(maxRank,node.maxRank)}});g.graph().maxRank=maxRank}function removeEdgeLabelProxies(g){g.nodes().forEach(v=>{let node=g.node(v);if(node.dummy==="edge-proxy"){g.edge(node.e).labelRank=node.rank;g.removeNode(v)}})}function translateGraph(g){let minX=Number.POSITIVE_INFINITY;let maxX=0;let minY=Number.POSITIVE_INFINITY;let maxY=0;let graphLabel=g.graph();let marginX=graphLabel.marginx||0;let marginY=graphLabel.marginy||0;function getExtremes(attrs){let x=attrs.x;let y=attrs.y;let w=attrs.width;let h=attrs.height;minX=Math.min(minX,x-w/2);maxX=Math.max(maxX,x+w/2);minY=Math.min(minY,y-h/2);maxY=Math.max(maxY,y+h/2)}g.nodes().forEach(v=>getExtremes(g.node(v)));g.edges().forEach(e=>{let edge=g.edge(e);if(
|
|
67
|
+
*/function injectEdgeLabelProxies(g){g.edges().forEach(e=>{let edge=g.edge(e);if(edge.width&&edge.height){let v=g.node(e.v);let w=g.node(e.w);let label={rank:(w.rank-v.rank)/2+v.rank,e:e};util.addDummyNode(g,"edge-proxy",label,"_ep")}})}function assignRankMinMax(g){let maxRank=0;g.nodes().forEach(v=>{let node=g.node(v);if(node.borderTop){node.minRank=g.node(node.borderTop).rank;node.maxRank=g.node(node.borderBottom).rank;maxRank=Math.max(maxRank,node.maxRank)}});g.graph().maxRank=maxRank}function removeEdgeLabelProxies(g){g.nodes().forEach(v=>{let node=g.node(v);if(node.dummy==="edge-proxy"){g.edge(node.e).labelRank=node.rank;g.removeNode(v)}})}function translateGraph(g){let minX=Number.POSITIVE_INFINITY;let maxX=0;let minY=Number.POSITIVE_INFINITY;let maxY=0;let graphLabel=g.graph();let marginX=graphLabel.marginx||0;let marginY=graphLabel.marginy||0;function getExtremes(attrs){let x=attrs.x;let y=attrs.y;let w=attrs.width;let h=attrs.height;minX=Math.min(minX,x-w/2);maxX=Math.max(maxX,x+w/2);minY=Math.min(minY,y-h/2);maxY=Math.max(maxY,y+h/2)}g.nodes().forEach(v=>getExtremes(g.node(v)));g.edges().forEach(e=>{let edge=g.edge(e);if(Object.hasOwn(edge,"x")){getExtremes(edge)}});minX-=marginX;minY-=marginY;g.nodes().forEach(v=>{let node=g.node(v);node.x-=minX;node.y-=minY});g.edges().forEach(e=>{let edge=g.edge(e);edge.points.forEach(p=>{p.x-=minX;p.y-=minY});if(Object.hasOwn(edge,"x")){edge.x-=minX}if(Object.hasOwn(edge,"y")){edge.y-=minY}});graphLabel.width=maxX-minX+marginX;graphLabel.height=maxY-minY+marginY}function assignNodeIntersects(g){g.edges().forEach(e=>{let edge=g.edge(e);let nodeV=g.node(e.v);let nodeW=g.node(e.w);let p1,p2;if(!edge.points){edge.points=[];p1=nodeW;p2=nodeV}else{p1=edge.points[0];p2=edge.points[edge.points.length-1]}edge.points.unshift(util.intersectRect(nodeV,p1));edge.points.push(util.intersectRect(nodeW,p2))})}function fixupEdgeLabelCoords(g){g.edges().forEach(e=>{let edge=g.edge(e);if(Object.hasOwn(edge,"x")){if(edge.labelpos==="l"||edge.labelpos==="r"){edge.width-=edge.labeloffset}switch(edge.labelpos){case"l":edge.x-=edge.width/2+edge.labeloffset;break;case"r":edge.x+=edge.width/2+edge.labeloffset;break}}})}function reversePointsForReversedEdges(g){g.edges().forEach(e=>{let edge=g.edge(e);if(edge.reversed){edge.points.reverse()}})}function removeBorderNodes(g){g.nodes().forEach(v=>{if(g.children(v).length){let node=g.node(v);let t=g.node(node.borderTop);let b=g.node(node.borderBottom);let l=g.node(node.borderLeft[node.borderLeft.length-1]);let r=g.node(node.borderRight[node.borderRight.length-1]);node.width=Math.abs(r.x-l.x);node.height=Math.abs(b.y-t.y);node.x=l.x+node.width/2;node.y=t.y+node.height/2}});g.nodes().forEach(v=>{if(g.node(v).dummy==="border"){g.removeNode(v)}})}function removeSelfEdges(g){g.edges().forEach(e=>{if(e.v===e.w){var node=g.node(e.v);if(!node.selfEdges){node.selfEdges=[]}node.selfEdges.push({e:e,label:g.edge(e)});g.removeEdge(e)}})}function insertSelfEdges(g){var layers=util.buildLayerMatrix(g);layers.forEach(layer=>{var orderShift=0;layer.forEach((v,i)=>{var node=g.node(v);node.order=i+orderShift;(node.selfEdges||[]).forEach(selfEdge=>{util.addDummyNode(g,"selfedge",{width:selfEdge.label.width,height:selfEdge.label.height,rank:node.rank,order:i+ ++orderShift,e:selfEdge.e,label:selfEdge.label},"_se")});delete node.selfEdges})})}function positionSelfEdges(g){g.nodes().forEach(v=>{var node=g.node(v);if(node.dummy==="selfedge"){var selfNode=g.node(node.e.v);var x=selfNode.x+selfNode.width/2;var y=selfNode.y;var dx=node.x-x;var dy=selfNode.height/2;g.setEdge(node.e,node.label);g.removeNode(v);node.label.points=[{x:x+2*dx/3,y:y-dy},{x:x+5*dx/6,y:y-dy},{x:x+dx,y:y},{x:x+5*dx/6,y:y+dy},{x:x+2*dx/3,y:y+dy}];node.label.x=node.x;node.label.y=node.y}})}function selectNumberAttrs(obj,attrs){return util.mapValues(util.pick(obj,attrs),Number)}function canonicalize(attrs){var newAttrs={};if(attrs){Object.entries(attrs).forEach(([k,v])=>{if(typeof k==="string"){k=k.toLowerCase()}newAttrs[k]=v})}return newAttrs}},{"./acyclic":2,"./add-border-segments":3,"./coordinate-system":4,"./nesting-graph":9,"./normalize":10,"./order":15,"./parent-dummy-chains":20,"./position":22,"./rank":24,"./util":27,"@dagrejs/graphlib":29}],9:[function(require,module,exports){let util=require("./util");module.exports={run:run,cleanup:cleanup};
|
|
68
68
|
/*
|
|
69
69
|
* A nesting graph creates dummy nodes for the tops and bottoms of subgraphs,
|
|
70
70
|
* adds appropriate edges to ensure that all cluster nodes are placed between
|
|
@@ -87,7 +87,7 @@ g.edges().forEach(e=>{let prevWeight=fasGraph.edge(e.v,e.w)||0;let weight=weight
|
|
|
87
87
|
*
|
|
88
88
|
* The nesting graph idea comes from Sander, "Layout of Compound Directed
|
|
89
89
|
* Graphs."
|
|
90
|
-
*/function run(g){let root=util.addDummyNode(g,"root",{},"_root");let depths=treeDepths(g);let
|
|
90
|
+
*/function run(g){let root=util.addDummyNode(g,"root",{},"_root");let depths=treeDepths(g);let depthsArr=Object.values(depths);let height=util.applyWithChunking(Math.max,depthsArr)-1;// Note: depths is an Object not an array
|
|
91
91
|
let nodeSep=2*height+1;g.graph().nestingRoot=root;
|
|
92
92
|
// Multiply minlen by nodeSep to align nodes on non-border ranks.
|
|
93
93
|
g.edges().forEach(e=>g.edge(e).minlen*=nodeSep);
|
|
@@ -168,7 +168,7 @@ g.graph().nodeRankFactor=nodeSep}function dfs(g,root,nodeSep,weight,height,depth
|
|
|
168
168
|
* graph is not a multi-graph.
|
|
169
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);
|
|
170
170
|
// This assumes we have only short edges!
|
|
171
|
-
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(
|
|
171
|
+
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
172
|
/*
|
|
173
173
|
* A function that takes a layering (an array of layers, each with an array of
|
|
174
174
|
* ordererd nodes) and a graph and returns a weighted crossing count.
|
|
@@ -218,7 +218,7 @@ let cc=0;southEntries.forEach(entry=>{let index=entry.pos+firstIndex;tree[index]
|
|
|
218
218
|
*
|
|
219
219
|
* Returns a layering matrix with an array per layer and each layer sorted by
|
|
220
220
|
* the order of its nodes.
|
|
221
|
-
*/function initOrder(g){let visited={};let simpleNodes=g.nodes().filter(v=>!g.children(v).length);let
|
|
221
|
+
*/function initOrder(g){let visited={};let simpleNodes=g.nodes().filter(v=>!g.children(v).length);let simpleNodesRanks=simpleNodes.map(v=>g.node(v).rank);let maxRank=util.applyWithChunking(Math.max,simpleNodesRanks);let layers=util.range(maxRank+1).map(()=>[]);function dfs(v){if(visited[v])return;visited[v]=true;let node=g.node(v);layers[node.rank].push(v);g.successors(v).forEach(dfs)}let orderedVs=simpleNodes.sort((a,b)=>g.node(a).rank-g.node(b).rank);orderedVs.forEach(dfs);return layers}},{"../util":27}],17:[function(require,module,exports){"use strict";let util=require("../util");module.exports=resolveConflicts;
|
|
222
222
|
/*
|
|
223
223
|
* Given a list of entries of the form {v, barycenter, weight} and a
|
|
224
224
|
* constraint graph this function will resolve any conflicts between the
|
|
@@ -243,7 +243,7 @@ let cc=0;southEntries.forEach(entry=>{let index=entry.pos+firstIndex;tree[index]
|
|
|
243
243
|
* ordered such that they do not violate constraints from the constraint
|
|
244
244
|
* graph. The property `i` is the lowest original index of any of the
|
|
245
245
|
* elements in `vs`.
|
|
246
|
-
*/function resolveConflicts(entries,cg){let mappedEntries={};entries.forEach((entry,i)=>{let tmp=mappedEntries[entry.v]={indegree:0,in:[],out:[],vs:[entry.v],i:i};if(entry.barycenter!==undefined){tmp.barycenter=entry.barycenter;tmp.weight=entry.weight}});cg.edges().forEach(e=>{let entryV=mappedEntries[e.v];let entryW=mappedEntries[e.w];if(entryV!==undefined&&entryW!==undefined){entryW.indegree++;entryV.out.push(mappedEntries[e.w])}});let sourceSet=Object.values(mappedEntries).filter(entry=>!entry.indegree);return doResolveConflicts(sourceSet)}function doResolveConflicts(sourceSet){let entries=[];function handleIn(vEntry){return uEntry=>{if(uEntry.merged){return}if(uEntry.barycenter===undefined||vEntry.barycenter===undefined||uEntry.barycenter>=vEntry.barycenter){mergeEntries(vEntry,uEntry)}}}function handleOut(vEntry){return wEntry=>{wEntry["in"].push(vEntry);if(--wEntry.indegree===0){sourceSet.push(wEntry)}}}while(sourceSet.length){let entry=sourceSet.pop();entries.push(entry);entry["in"].reverse().forEach(handleIn(entry));entry.out.forEach(handleOut(entry))}return entries.filter(entry=>!entry.merged).map(entry=>{return util.pick(entry,["vs","i","barycenter","weight"])})}function mergeEntries(target,source){let sum=0;let weight=0;if(target.weight){sum+=target.barycenter*target.weight;weight+=target.weight}if(source.weight){sum+=source.barycenter*source.weight;weight+=source.weight}target.vs=source.vs.concat(target.vs);target.barycenter=sum/weight;target.weight=weight;target.i=Math.min(source.i,target.i);source.merged=true}},{"../util":27}],18:[function(require,module,exports){let barycenter=require("./barycenter");let resolveConflicts=require("./resolve-conflicts");let sort=require("./sort");module.exports=sortSubgraph;function sortSubgraph(g,v,cg,biasRight){let movable=g.children(v);let node=g.node(v);let bl=node?node.borderLeft:undefined;let br=node?node.borderRight:undefined;let subgraphs={};if(bl){movable=movable.filter(w=>w!==bl&&w!==br)}let barycenters=barycenter(g,movable);barycenters.forEach(entry=>{if(g.children(entry.v).length){let subgraphResult=sortSubgraph(g,entry.v,cg,biasRight);subgraphs[entry.v]=subgraphResult;if(
|
|
246
|
+
*/function resolveConflicts(entries,cg){let mappedEntries={};entries.forEach((entry,i)=>{let tmp=mappedEntries[entry.v]={indegree:0,in:[],out:[],vs:[entry.v],i:i};if(entry.barycenter!==undefined){tmp.barycenter=entry.barycenter;tmp.weight=entry.weight}});cg.edges().forEach(e=>{let entryV=mappedEntries[e.v];let entryW=mappedEntries[e.w];if(entryV!==undefined&&entryW!==undefined){entryW.indegree++;entryV.out.push(mappedEntries[e.w])}});let sourceSet=Object.values(mappedEntries).filter(entry=>!entry.indegree);return doResolveConflicts(sourceSet)}function doResolveConflicts(sourceSet){let entries=[];function handleIn(vEntry){return uEntry=>{if(uEntry.merged){return}if(uEntry.barycenter===undefined||vEntry.barycenter===undefined||uEntry.barycenter>=vEntry.barycenter){mergeEntries(vEntry,uEntry)}}}function handleOut(vEntry){return wEntry=>{wEntry["in"].push(vEntry);if(--wEntry.indegree===0){sourceSet.push(wEntry)}}}while(sourceSet.length){let entry=sourceSet.pop();entries.push(entry);entry["in"].reverse().forEach(handleIn(entry));entry.out.forEach(handleOut(entry))}return entries.filter(entry=>!entry.merged).map(entry=>{return util.pick(entry,["vs","i","barycenter","weight"])})}function mergeEntries(target,source){let sum=0;let weight=0;if(target.weight){sum+=target.barycenter*target.weight;weight+=target.weight}if(source.weight){sum+=source.barycenter*source.weight;weight+=source.weight}target.vs=source.vs.concat(target.vs);target.barycenter=sum/weight;target.weight=weight;target.i=Math.min(source.i,target.i);source.merged=true}},{"../util":27}],18:[function(require,module,exports){let barycenter=require("./barycenter");let resolveConflicts=require("./resolve-conflicts");let sort=require("./sort");module.exports=sortSubgraph;function sortSubgraph(g,v,cg,biasRight){let movable=g.children(v);let node=g.node(v);let bl=node?node.borderLeft:undefined;let br=node?node.borderRight:undefined;let subgraphs={};if(bl){movable=movable.filter(w=>w!==bl&&w!==br)}let barycenters=barycenter(g,movable);barycenters.forEach(entry=>{if(g.children(entry.v).length){let subgraphResult=sortSubgraph(g,entry.v,cg,biasRight);subgraphs[entry.v]=subgraphResult;if(Object.hasOwn(subgraphResult,"barycenter")){mergeBarycenters(entry,subgraphResult)}}});let entries=resolveConflicts(barycenters,cg);expandSubgraphs(entries,subgraphs);let result=sort(entries,biasRight);if(bl){result.vs=[bl,result.vs,br].flat(true);if(g.predecessors(bl).length){let blPred=g.node(g.predecessors(bl)[0]),brPred=g.node(g.predecessors(br)[0]);if(!Object.hasOwn(result,"barycenter")){result.barycenter=0;result.weight=0}result.barycenter=(result.barycenter*result.weight+blPred.order+brPred.order)/(result.weight+2);result.weight+=2}}return result}function expandSubgraphs(entries,subgraphs){entries.forEach(entry=>{entry.vs=entry.vs.flatMap(v=>{if(subgraphs[v]){return subgraphs[v].vs}return v})})}function mergeBarycenters(target,other){if(target.barycenter!==undefined){target.barycenter=(target.barycenter*target.weight+other.barycenter*other.weight)/(target.weight+other.weight);target.weight+=other.weight}else{target.barycenter=other.barycenter;target.weight=other.weight}}},{"./barycenter":12,"./resolve-conflicts":17,"./sort":19}],19:[function(require,module,exports){let util=require("../util");module.exports=sort;function sort(entries,biasRight){let parts=util.partition(entries,entry=>{return Object.hasOwn(entry,"barycenter")});let sortable=parts.lhs,unsortable=parts.rhs.sort((a,b)=>b.i-a.i),vs=[],sum=0,weight=0,vsIndex=0;sortable.sort(compareWithBias(!!biasRight));vsIndex=consumeUnsortable(vs,unsortable,vsIndex);sortable.forEach(entry=>{vsIndex+=entry.vs.length;vs.push(entry.vs);sum+=entry.barycenter*entry.weight;weight+=entry.weight;vsIndex=consumeUnsortable(vs,unsortable,vsIndex)});let result={vs:vs.flat(true)};if(weight){result.barycenter=sum/weight;result.weight=weight}return result}function consumeUnsortable(vs,unsortable,index){let last;while(unsortable.length&&(last=unsortable[unsortable.length-1]).i<=index){unsortable.pop();vs.push(last.vs);index++}return index}function compareWithBias(bias){return(entryV,entryW)=>{if(entryV.barycenter<entryW.barycenter){return-1}else if(entryV.barycenter>entryW.barycenter){return 1}return!bias?entryV.i-entryW.i:entryW.i-entryV.i}}},{"../util":27}],20:[function(require,module,exports){module.exports=parentDummyChains;function parentDummyChains(g){let postorderNums=postorder(g);g.graph().dummyChains.forEach(v=>{let node=g.node(v);let edgeObj=node.edgeObj;let pathData=findPath(g,postorderNums,edgeObj.v,edgeObj.w);let path=pathData.path;let lca=pathData.lca;let pathIdx=0;let pathV=path[pathIdx];let ascending=true;while(v!==edgeObj.w){node=g.node(v);if(ascending){while((pathV=path[pathIdx])!==lca&&g.node(pathV).maxRank<node.rank){pathIdx++}if(pathV===lca){ascending=false}}if(!ascending){while(pathIdx<path.length-1&&g.node(pathV=path[pathIdx+1]).minRank<=node.rank){pathIdx++}pathV=path[pathIdx]}g.setParent(v,pathV);v=g.successors(v)[0]}})}
|
|
247
247
|
// Find a path from v to w through the lowest common ancestor (LCA). Return the
|
|
248
248
|
// full path and the LCA.
|
|
249
249
|
function findPath(g,postorderNums,v,w){let vPath=[];let wPath=[];let low=Math.min(postorderNums[v].low,postorderNums[w].low);let lim=Math.max(postorderNums[v].lim,postorderNums[w].lim);let parent;let lca;
|
|
@@ -277,7 +277,7 @@ parent=w;while((parent=g.parent(parent))!==lca){wPath.push(parent)}return{path:v
|
|
|
277
277
|
k0=0,
|
|
278
278
|
// Tracks the last node in this layer scanned for crossings with a type-1
|
|
279
279
|
// segment.
|
|
280
|
-
scanPos=0,prevLayerLength=prevLayer.length,lastNode=layer[layer.length-1];layer.forEach((v,i)=>{let w=findOtherInnerSegmentNode(g,v),k1=w?g.node(w).order:prevLayerLength;if(w||v===lastNode){layer.slice(scanPos,i+1).forEach(scanNode=>{g.predecessors(scanNode).forEach(u=>{let uLabel=g.node(u),uPos=uLabel.order;if((uPos<k0||k1<uPos)&&!(uLabel.dummy&&g.node(scanNode).dummy)){addConflict(conflicts,u,scanNode)}})});scanPos=i+1;k0=k1}});return layer}layering.length&&layering.reduce(visitLayer);return conflicts}function findType2Conflicts(g,layering){let conflicts={};function scan(south,southPos,southEnd,prevNorthBorder,nextNorthBorder){let v;util.range(southPos,southEnd).forEach(i=>{v=south[i];if(g.node(v).dummy){g.predecessors(v).forEach(u=>{let uNode=g.node(u);if(uNode.dummy&&(uNode.order<prevNorthBorder||uNode.order>nextNorthBorder)){addConflict(conflicts,u,v)}})}})}function visitLayer(north,south){let prevNorthPos=-1,nextNorthPos,southPos=0;south.forEach((v,southLookahead)=>{if(g.node(v).dummy==="border"){let predecessors=g.predecessors(v);if(predecessors.length){nextNorthPos=g.node(predecessors[0]).order;scan(south,southPos,southLookahead,prevNorthPos,nextNorthPos);southPos=southLookahead;prevNorthPos=nextNorthPos}}scan(south,southPos,south.length,nextNorthPos,north.length)});return south}layering.length&&layering.reduce(visitLayer);return conflicts}function findOtherInnerSegmentNode(g,v){if(g.node(v).dummy){return g.predecessors(v).find(u=>g.node(u).dummy)}}function addConflict(conflicts,v,w){if(v>w){let tmp=v;v=w;w=tmp}let conflictsV=conflicts[v];if(!conflictsV){conflicts[v]=conflictsV={}}conflictsV[w]=true}function hasConflict(conflicts,v,w){if(v>w){let tmp=v;v=w;w=tmp}return!!conflicts[v]&&conflicts[v]
|
|
280
|
+
scanPos=0,prevLayerLength=prevLayer.length,lastNode=layer[layer.length-1];layer.forEach((v,i)=>{let w=findOtherInnerSegmentNode(g,v),k1=w?g.node(w).order:prevLayerLength;if(w||v===lastNode){layer.slice(scanPos,i+1).forEach(scanNode=>{g.predecessors(scanNode).forEach(u=>{let uLabel=g.node(u),uPos=uLabel.order;if((uPos<k0||k1<uPos)&&!(uLabel.dummy&&g.node(scanNode).dummy)){addConflict(conflicts,u,scanNode)}})});scanPos=i+1;k0=k1}});return layer}layering.length&&layering.reduce(visitLayer);return conflicts}function findType2Conflicts(g,layering){let conflicts={};function scan(south,southPos,southEnd,prevNorthBorder,nextNorthBorder){let v;util.range(southPos,southEnd).forEach(i=>{v=south[i];if(g.node(v).dummy){g.predecessors(v).forEach(u=>{let uNode=g.node(u);if(uNode.dummy&&(uNode.order<prevNorthBorder||uNode.order>nextNorthBorder)){addConflict(conflicts,u,v)}})}})}function visitLayer(north,south){let prevNorthPos=-1,nextNorthPos,southPos=0;south.forEach((v,southLookahead)=>{if(g.node(v).dummy==="border"){let predecessors=g.predecessors(v);if(predecessors.length){nextNorthPos=g.node(predecessors[0]).order;scan(south,southPos,southLookahead,prevNorthPos,nextNorthPos);southPos=southLookahead;prevNorthPos=nextNorthPos}}scan(south,southPos,south.length,nextNorthPos,north.length)});return south}layering.length&&layering.reduce(visitLayer);return conflicts}function findOtherInnerSegmentNode(g,v){if(g.node(v).dummy){return g.predecessors(v).find(u=>g.node(u).dummy)}}function addConflict(conflicts,v,w){if(v>w){let tmp=v;v=w;w=tmp}let conflictsV=conflicts[v];if(!conflictsV){conflicts[v]=conflictsV={}}conflictsV[w]=true}function hasConflict(conflicts,v,w){if(v>w){let tmp=v;v=w;w=tmp}return!!conflicts[v]&&Object.hasOwn(conflicts[v],w)}
|
|
281
281
|
/*
|
|
282
282
|
* Try to align nodes into vertical "blocks" where possible. This algorithm
|
|
283
283
|
* attempts to align a node with one of its median neighbors. If the edge
|
|
@@ -311,7 +311,7 @@ Object.keys(align).forEach(v=>xs[v]=xs[root[v]]);return xs}function buildBlockGr
|
|
|
311
311
|
* the minimum coordinate of the smallest width alignment and right-biased
|
|
312
312
|
* alignments have their maximum coordinate at the same point as the maximum
|
|
313
313
|
* coordinate of the smallest width alignment.
|
|
314
|
-
*/function alignCoordinates(xss,alignTo){let alignToVals=Object.values(alignTo),alignToMin=Math.min
|
|
314
|
+
*/function alignCoordinates(xss,alignTo){let alignToVals=Object.values(alignTo),alignToMin=util.applyWithChunking(Math.min,alignToVals),alignToMax=util.applyWithChunking(Math.max,alignToVals);["u","d"].forEach(vert=>{["l","r"].forEach(horiz=>{let alignment=vert+horiz,xs=xss[alignment];if(xs===alignTo)return;let xsVals=Object.values(xs);let delta=alignToMin-util.applyWithChunking(Math.min,xsVals);if(horiz!=="l"){delta=alignToMax-util.applyWithChunking(Math.max,xsVals)}if(delta){xss[alignment]=util.mapValues(xs,x=>x+delta)}})})}function balance(xss,align){return util.mapValues(xss.ul,(num,v)=>{if(align){return xss[align.toLowerCase()][v]}else{let xs=Object.values(xss).map(xs=>xs[v]).sort((a,b)=>a-b);return(xs[1]+xs[2])/2}})}function positionX(g){let layering=util.buildLayerMatrix(g);let conflicts=Object.assign(findType1Conflicts(g,layering),findType2Conflicts(g,layering));let xss={};let adjustedLayering;["u","d"].forEach(vert=>{adjustedLayering=vert==="u"?layering:Object.values(layering).reverse();["l","r"].forEach(horiz=>{if(horiz==="r"){adjustedLayering=adjustedLayering.map(inner=>{return Object.values(inner).reverse()})}let neighborFn=(vert==="u"?g.predecessors:g.successors).bind(g);let align=verticalAlignment(g,adjustedLayering,conflicts,neighborFn);let xs=horizontalCompaction(g,adjustedLayering,align.root,align.align,horiz==="r");if(horiz==="r"){xs=util.mapValues(xs,x=>-x)}xss[vert+horiz]=xs})});let smallestWidth=findSmallestWidthAlignment(g,xss);alignCoordinates(xss,smallestWidth);return balance(xss,g.graph().align)}function sep(nodeSep,edgeSep,reverseSep){return(g,v,w)=>{let vLabel=g.node(v);let wLabel=g.node(w);let sum=0;let delta;sum+=vLabel.width/2;if(Object.hasOwn(vLabel,"labelpos")){switch(vLabel.labelpos.toLowerCase()){case"l":delta=-vLabel.width/2;break;case"r":delta=vLabel.width/2;break}}if(delta){sum+=reverseSep?delta:-delta}delta=0;sum+=(vLabel.dummy?edgeSep:nodeSep)/2;sum+=(wLabel.dummy?edgeSep:nodeSep)/2;sum+=wLabel.width/2;if(Object.hasOwn(wLabel,"labelpos")){switch(wLabel.labelpos.toLowerCase()){case"l":delta=wLabel.width/2;break;case"r":delta=-wLabel.width/2;break}}if(delta){sum+=reverseSep?delta:-delta}delta=0;return sum}}function width(g,v){return g.node(v).width}},{"../util":27,"@dagrejs/graphlib":29}],22:[function(require,module,exports){"use strict";let util=require("../util");let positionX=require("./bk").positionX;module.exports=position;function position(g){g=util.asNonCompoundGraph(g);positionY(g);Object.entries(positionX(g)).forEach(([v,x])=>g.node(v).x=x)}function positionY(g){let layering=util.buildLayerMatrix(g);let rankSep=g.graph().ranksep;let prevY=0;layering.forEach(layer=>{const maxHeight=layer.reduce((acc,v)=>{const height=g.node(v).height;if(acc>height){return acc}else{return height}},0);layer.forEach(v=>g.node(v).y=prevY+maxHeight/2);prevY+=maxHeight+rankSep})}},{"../util":27,"./bk":21}],23:[function(require,module,exports){"use strict";var Graph=require("@dagrejs/graphlib").Graph;var slack=require("./util").slack;module.exports=feasibleTree;
|
|
315
315
|
/*
|
|
316
316
|
* Constructs a spanning tree with tight edges and adjusted the input node's
|
|
317
317
|
* ranks to achieve this. A tight edge is one that is has a length that matches
|
|
@@ -365,7 +365,7 @@ var start=g.nodes()[0];var size=g.nodeCount();t.setNode(start,{});var edge,delta
|
|
|
365
365
|
* 1. Graph nodes will have a "rank" attribute based on the results of the
|
|
366
366
|
* algorithm. Ranks can start at any index (including negative), we'll
|
|
367
367
|
* 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)}}
|
|
368
|
+
*/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
369
|
// A fast and simple ranker, but results are far from optimal.
|
|
370
370
|
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
371
|
// Expose some internals for testing purposes
|
|
@@ -415,7 +415,7 @@ var childIsTail=true;
|
|
|
415
415
|
// The graph's view of the tree edge we're inspecting
|
|
416
416
|
var graphEdge=g.edge(child,parent);
|
|
417
417
|
// The accumulated cut value for the edge between this node and its parent
|
|
418
|
-
var cutValue=0;if(!graphEdge){childIsTail=false;graphEdge=g.edge(parent,child)}cutValue=graphEdge.weight;g.nodeEdges(child).forEach(e=>{var isOutEdge=e.v===child,other=isOutEdge?e.w:e.v;if(other!==parent){var pointsToHead=isOutEdge===childIsTail,otherWeight=g.edge(e).weight;cutValue+=pointsToHead?otherWeight:-otherWeight;if(isTreeEdge(t,child,other)){var otherCutValue=t.edge(child,other).cutvalue;cutValue+=pointsToHead?-otherCutValue:otherCutValue}}});return cutValue}function initLowLimValues(tree,root){if(arguments.length<2){root=tree.nodes()[0]}dfsAssignLowLim(tree,{},1,root)}function dfsAssignLowLim(tree,visited,nextLim,v,parent){var low=nextLim;var label=tree.node(v);visited[v]=true;tree.neighbors(v).forEach(w=>{if(!
|
|
418
|
+
var cutValue=0;if(!graphEdge){childIsTail=false;graphEdge=g.edge(parent,child)}cutValue=graphEdge.weight;g.nodeEdges(child).forEach(e=>{var isOutEdge=e.v===child,other=isOutEdge?e.w:e.v;if(other!==parent){var pointsToHead=isOutEdge===childIsTail,otherWeight=g.edge(e).weight;cutValue+=pointsToHead?otherWeight:-otherWeight;if(isTreeEdge(t,child,other)){var otherCutValue=t.edge(child,other).cutvalue;cutValue+=pointsToHead?-otherCutValue:otherCutValue}}});return cutValue}function initLowLimValues(tree,root){if(arguments.length<2){root=tree.nodes()[0]}dfsAssignLowLim(tree,{},1,root)}function dfsAssignLowLim(tree,visited,nextLim,v,parent){var low=nextLim;var label=tree.node(v);visited[v]=true;tree.neighbors(v).forEach(w=>{if(!Object.hasOwn(visited,w)){nextLim=dfsAssignLowLim(tree,visited,nextLim,w,v)}});label.low=low;label.lim=nextLim++;if(parent){label.parent=parent}else{
|
|
419
419
|
// TODO should be able to remove this when we incrementally update low lim
|
|
420
420
|
delete label.parent}return nextLim}function leaveEdge(tree){return tree.edges().find(e=>tree.edge(e).cutvalue<0)}function enterEdge(t,g,edge){var v=edge.v;var w=edge.w;
|
|
421
421
|
// For the rest of this function we assume that v is the tail and w is the
|
|
@@ -431,7 +431,7 @@ if(vLabel.lim>wLabel.lim){tailLabel=wLabel;flip=true}var candidates=g.edges().fi
|
|
|
431
431
|
/*
|
|
432
432
|
* Returns true if the specified node is descendant of the root node per the
|
|
433
433
|
* assigned low and lim attributes in the tree.
|
|
434
|
-
*/function isDescendant(tree,vLabel,rootLabel){return rootLabel.low<=vLabel.lim&&vLabel.lim<=rootLabel.lim}},{"../util":27,"./feasible-tree":23,"./util":26,"@dagrejs/graphlib":29}],26:[function(require,module,exports){"use strict";module.exports={longestPath:longestPath,slack:slack};
|
|
434
|
+
*/function isDescendant(tree,vLabel,rootLabel){return rootLabel.low<=vLabel.lim&&vLabel.lim<=rootLabel.lim}},{"../util":27,"./feasible-tree":23,"./util":26,"@dagrejs/graphlib":29}],26:[function(require,module,exports){"use strict";const{applyWithChunking}=require("../util");module.exports={longestPath:longestPath,slack:slack};
|
|
435
435
|
/*
|
|
436
436
|
* Initializes ranks for the input graph using the longest path algorithm. This
|
|
437
437
|
* algorithm scales well and is fast in practice, it yields rather poor
|
|
@@ -452,16 +452,16 @@ if(vLabel.lim>wLabel.lim){tailLabel=wLabel;flip=true}var candidates=g.edges().fi
|
|
|
452
452
|
* Post-conditions:
|
|
453
453
|
*
|
|
454
454
|
* 1. Each node will be assign an (unnormalized) "rank" property.
|
|
455
|
-
*/function longestPath(g){var visited={};function dfs(v){var label=g.node(v);if(
|
|
455
|
+
*/function longestPath(g){var visited={};function dfs(v){var label=g.node(v);if(Object.hasOwn(visited,v)){return label.rank}visited[v]=true;let outEdgesMinLens=g.outEdges(v).map(e=>{if(e==null){return Number.POSITIVE_INFINITY}return dfs(e.w)-g.edge(e).minlen});var rank=applyWithChunking(Math.min,outEdgesMinLens);if(rank===Number.POSITIVE_INFINITY){rank=0}return label.rank=rank}g.sources().forEach(dfs)}
|
|
456
456
|
/*
|
|
457
457
|
* Returns the amount of slack for the given edge. The slack is defined as the
|
|
458
458
|
* difference between the length of the edge and its minimum length.
|
|
459
|
-
*/function slack(g,e){return g.node(e.w).rank-g.node(e.v).rank-g.edge(e).minlen}},{}],27:[function(require,module,exports){
|
|
459
|
+
*/function slack(g,e){return g.node(e.w).rank-g.node(e.v).rank-g.edge(e).minlen}},{"../util":27}],27:[function(require,module,exports){
|
|
460
460
|
/* eslint "no-console": off */
|
|
461
|
-
"use strict";let Graph=require("@dagrejs/graphlib").Graph;module.exports={addBorderNode:addBorderNode,addDummyNode:addDummyNode,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};
|
|
461
|
+
"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
462
|
/*
|
|
463
463
|
* Adds a dummy node to the graph and return v.
|
|
464
|
-
*/function addDummyNode(g,type,attrs,name){
|
|
464
|
+
*/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
465
|
/*
|
|
466
466
|
* Returns a new graph with only simple edges. Handles aggregation of data
|
|
467
467
|
* associated with multi-edges.
|
|
@@ -484,9 +484,9 @@ if(dx<0){w=-w}sx=w;sy=w*dy/dx}return{x:x+sx,y:y+sy}}
|
|
|
484
484
|
/*
|
|
485
485
|
* Adjusts the ranks for all nodes in the graph such that all nodes v have
|
|
486
486
|
* rank(v) >= 0 and at least one node w has rank(w) = 0.
|
|
487
|
-
*/function normalizeRanks(g){let
|
|
487
|
+
*/function normalizeRanks(g){let nodeRanks=g.nodes().map(v=>{let rank=g.node(v).rank;if(rank===undefined){return Number.MAX_VALUE}return rank});let min=applyWithChunking(Math.min,nodeRanks);g.nodes().forEach(v=>{let node=g.node(v);if(Object.hasOwn(node,"rank")){node.rank-=min}})}function removeEmptyRanks(g){
|
|
488
488
|
// Ranks may not start at 0, so we need to offset them
|
|
489
|
-
let
|
|
489
|
+
let nodeRanks=g.nodes().map(v=>g.node(v).rank);let offset=applyWithChunking(Math.min,nodeRanks);let layers=[];g.nodes().forEach(v=>{let rank=g.node(v).rank-offset;if(!layers[rank]){layers[rank]=[]}layers[rank].push(v)});let delta=0;let nodeRankFactor=g.graph().nodeRankFactor;Array.from(layers).forEach((vs,i)=>{if(vs===undefined&&i%nodeRankFactor!==0){--delta}else if(vs!==undefined&&delta){vs.forEach(v=>g.node(v).rank+=delta)}})}function addBorderNode(g,prefix,rank,order){let node={width:0,height:0};if(arguments.length>=4){node.rank=rank;node.order=order}return addDummyNode(g,"border",node,prefix)}function splitToChunks(array,chunkSize=CHUNKING_THRESHOLD){const chunks=[];for(let i=0;i<array.length;i+=chunkSize){const chunk=array.slice(i,i+chunkSize);chunks.push(chunk)}return chunks}const CHUNKING_THRESHOLD=65535;function applyWithChunking(fn,argsArray){if(argsArray.length>CHUNKING_THRESHOLD){const chunks=splitToChunks(argsArray);return fn.apply(null,chunks.map(chunk=>fn.apply(null,chunk)))}else{return fn.apply(null,argsArray)}}function maxRank(g){const nodes=g.nodes();const nodeRanks=nodes.map(v=>{let rank=g.node(v).rank;if(rank===undefined){return Number.MIN_VALUE}return rank});return applyWithChunking(Math.max,nodeRanks)}
|
|
490
490
|
/*
|
|
491
491
|
* Partition a collection into two groups: `lhs` and `rhs`. If the supplied
|
|
492
492
|
* function returns true for an entry it goes into `lhs`. Otherwise it goes
|
|
@@ -495,7 +495,7 @@ let offset=Math.min(...g.nodes().map(v=>g.node(v).rank));let layers=[];g.nodes()
|
|
|
495
495
|
/*
|
|
496
496
|
* Returns a new function that wraps `fn` with a timer. The wrapper logs the
|
|
497
497
|
* 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
|
|
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 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.5"},{}],29:[function(require,module,exports){
|
|
499
499
|
/**
|
|
500
500
|
* Copyright (c) 2014, Chris Pettitt
|
|
501
501
|
* All rights reserved.
|
|
@@ -525,7 +525,7 @@ let offset=Math.min(...g.nodes().map(v=>g.node(v).rank));let layers=[];g.nodes()
|
|
|
525
525
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
526
526
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
527
527
|
*/
|
|
528
|
-
var lib=require("./lib");module.exports={Graph:lib.Graph,json:require("./lib/json"),alg:require("./lib/alg"),version:lib.version}},{"./lib":45,"./lib/alg":36,"./lib/json":46}],30:[function(require,module,exports){module.exports=components;function components(g){var visited={};var cmpts=[];var cmpt;function dfs(v){if(
|
|
528
|
+
var lib=require("./lib");module.exports={Graph:lib.Graph,json:require("./lib/json"),alg:require("./lib/alg"),version:lib.version}},{"./lib":45,"./lib/alg":36,"./lib/json":46}],30:[function(require,module,exports){module.exports=components;function components(g){var visited={};var cmpts=[];var cmpt;function dfs(v){if(Object.hasOwn(visited,v))return;visited[v]=true;cmpt.push(v);g.successors(v).forEach(dfs);g.predecessors(v).forEach(dfs)}g.nodes().forEach(function(v){cmpt=[];dfs(v);if(cmpt.length){cmpts.push(cmpt)}});return cmpts}},{}],31:[function(require,module,exports){module.exports=dfs;
|
|
529
529
|
/*
|
|
530
530
|
* A helper that preforms a pre- or post-order traversal on the input graph
|
|
531
531
|
* and returns the nodes in the order they were visited. If the graph is
|
|
@@ -533,10 +533,10 @@ var lib=require("./lib");module.exports={Graph:lib.Graph,json:require("./lib/jso
|
|
|
533
533
|
* is directed then this algorithm will navigate using successors.
|
|
534
534
|
*
|
|
535
535
|
* If the order is not "post", it will be treated as "pre".
|
|
536
|
-
*/function dfs(g,vs,order){if(!Array.isArray(vs)){vs=[vs]}var navigation=g.isDirected()?v=>g.successors(v):v=>g.neighbors(v);var orderFunc=order==="post"?postOrderDfs:preOrderDfs;var acc=[];var visited={};vs.forEach(v=>{if(!g.hasNode(v)){throw new Error("Graph does not have node: "+v)}orderFunc(v,navigation,visited,acc)});return acc}function postOrderDfs(v,navigation,visited,acc){var stack=[[v,false]];while(stack.length>0){var curr=stack.pop();if(curr[1]){acc.push(curr[0])}else{if(!
|
|
536
|
+
*/function dfs(g,vs,order){if(!Array.isArray(vs)){vs=[vs]}var navigation=g.isDirected()?v=>g.successors(v):v=>g.neighbors(v);var orderFunc=order==="post"?postOrderDfs:preOrderDfs;var acc=[];var visited={};vs.forEach(v=>{if(!g.hasNode(v)){throw new Error("Graph does not have node: "+v)}orderFunc(v,navigation,visited,acc)});return acc}function postOrderDfs(v,navigation,visited,acc){var stack=[[v,false]];while(stack.length>0){var curr=stack.pop();if(curr[1]){acc.push(curr[0])}else{if(!Object.hasOwn(visited,curr[0])){visited[curr[0]]=true;stack.push([curr[0],true]);forEachRight(navigation(curr[0]),w=>stack.push([w,false]))}}}}function preOrderDfs(v,navigation,visited,acc){var stack=[v];while(stack.length>0){var curr=stack.pop();if(!Object.hasOwn(visited,curr)){visited[curr]=true;acc.push(curr);forEachRight(navigation(curr),w=>stack.push(w))}}}function forEachRight(array,iteratee){var length=array.length;while(length--){iteratee(array[length],length,array)}return array}},{}],32:[function(require,module,exports){var dijkstra=require("./dijkstra");module.exports=dijkstraAll;function dijkstraAll(g,weightFunc,edgeFunc){return g.nodes().reduce(function(acc,v){acc[v]=dijkstra(g,v,weightFunc,edgeFunc);return acc},{})}},{"./dijkstra":33}],33:[function(require,module,exports){var PriorityQueue=require("../data/priority-queue");module.exports=dijkstra;var DEFAULT_WEIGHT_FUNC=()=>1;function dijkstra(g,source,weightFn,edgeFn){return runDijkstra(g,String(source),weightFn||DEFAULT_WEIGHT_FUNC,edgeFn||function(v){return g.outEdges(v)})}function runDijkstra(g,source,weightFn,edgeFn){var results={};var pq=new PriorityQueue;var v,vEntry;var updateNeighbors=function(edge){var w=edge.v!==v?edge.v:edge.w;var wEntry=results[w];var weight=weightFn(edge);var distance=vEntry.distance+weight;if(weight<0){throw new Error("dijkstra does not allow negative edge weights. "+"Bad edge: "+edge+" Weight: "+weight)}if(distance<wEntry.distance){wEntry.distance=distance;wEntry.predecessor=v;pq.decrease(w,distance)}};g.nodes().forEach(function(v){var distance=v===source?0:Number.POSITIVE_INFINITY;results[v]={distance:distance};pq.add(v,distance)});while(pq.size()>0){v=pq.removeMin();vEntry=results[v];if(vEntry.distance===Number.POSITIVE_INFINITY){break}edgeFn(v).forEach(updateNeighbors)}return results}},{"../data/priority-queue":43}],34:[function(require,module,exports){var tarjan=require("./tarjan");module.exports=findCycles;function findCycles(g){return tarjan(g).filter(function(cmpt){return cmpt.length>1||cmpt.length===1&&g.hasEdge(cmpt[0],cmpt[0])})}},{"./tarjan":41}],35:[function(require,module,exports){module.exports=floydWarshall;var DEFAULT_WEIGHT_FUNC=()=>1;function floydWarshall(g,weightFn,edgeFn){return runFloydWarshall(g,weightFn||DEFAULT_WEIGHT_FUNC,edgeFn||function(v){return g.outEdges(v)})}function runFloydWarshall(g,weightFn,edgeFn){var results={};var nodes=g.nodes();nodes.forEach(function(v){results[v]={};results[v][v]={distance:0};nodes.forEach(function(w){if(v!==w){results[v][w]={distance:Number.POSITIVE_INFINITY}}});edgeFn(v).forEach(function(edge){var w=edge.v===v?edge.w:edge.v;var d=weightFn(edge);results[v][w]={distance:d,predecessor:v}})});nodes.forEach(function(k){var rowK=results[k];nodes.forEach(function(i){var rowI=results[i];nodes.forEach(function(j){var ik=rowI[k];var kj=rowK[j];var ij=rowI[j];var altDistance=ik.distance+kj.distance;if(altDistance<ij.distance){ij.distance=altDistance;ij.predecessor=kj.predecessor}})})});return results}},{}],36:[function(require,module,exports){module.exports={components:require("./components"),dijkstra:require("./dijkstra"),dijkstraAll:require("./dijkstra-all"),findCycles:require("./find-cycles"),floydWarshall:require("./floyd-warshall"),isAcyclic:require("./is-acyclic"),postorder:require("./postorder"),preorder:require("./preorder"),prim:require("./prim"),tarjan:require("./tarjan"),topsort:require("./topsort")}},{"./components":30,"./dijkstra":33,"./dijkstra-all":32,"./find-cycles":34,"./floyd-warshall":35,"./is-acyclic":37,"./postorder":38,"./preorder":39,"./prim":40,"./tarjan":41,"./topsort":42}],37:[function(require,module,exports){var topsort=require("./topsort");module.exports=isAcyclic;function isAcyclic(g){try{topsort(g)}catch(e){if(e instanceof topsort.CycleException){return false}throw e}return true}},{"./topsort":42}],38:[function(require,module,exports){var dfs=require("./dfs");module.exports=postorder;function postorder(g,vs){return dfs(g,vs,"post")}},{"./dfs":31}],39:[function(require,module,exports){var dfs=require("./dfs");module.exports=preorder;function preorder(g,vs){return dfs(g,vs,"pre")}},{"./dfs":31}],40:[function(require,module,exports){var Graph=require("../graph");var PriorityQueue=require("../data/priority-queue");module.exports=prim;function prim(g,weightFunc){var result=new Graph;var parents={};var pq=new PriorityQueue;var v;function updateNeighbors(edge){var w=edge.v===v?edge.w:edge.v;var pri=pq.priority(w);if(pri!==undefined){var edgeWeight=weightFunc(edge);if(edgeWeight<pri){parents[w]=v;pq.decrease(w,edgeWeight)}}}if(g.nodeCount()===0){return result}g.nodes().forEach(function(v){pq.add(v,Number.POSITIVE_INFINITY);result.setNode(v)});
|
|
537
537
|
// Start from an arbitrary node
|
|
538
|
-
pq.decrease(g.nodes()[0],0);var init=false;while(pq.size()>0){v=pq.removeMin();if(
|
|
539
|
-
var results=[];function dfs(v){var entry=visited[v]={onStack:true,lowlink:index,index:index++};stack.push(v);g.successors(v).forEach(function(w){if(!
|
|
538
|
+
pq.decrease(g.nodes()[0],0);var init=false;while(pq.size()>0){v=pq.removeMin();if(Object.hasOwn(parents,v)){result.setEdge(v,parents[v])}else if(init){throw new Error("Input graph is not connected: "+g)}else{init=true}g.nodeEdges(v).forEach(updateNeighbors)}return result}},{"../data/priority-queue":43,"../graph":44}],41:[function(require,module,exports){module.exports=tarjan;function tarjan(g){var index=0;var stack=[];var visited={};// node id -> { onStack, lowlink, index }
|
|
539
|
+
var results=[];function dfs(v){var entry=visited[v]={onStack:true,lowlink:index,index:index++};stack.push(v);g.successors(v).forEach(function(w){if(!Object.hasOwn(visited,w)){dfs(w);entry.lowlink=Math.min(entry.lowlink,visited[w].lowlink)}else if(visited[w].onStack){entry.lowlink=Math.min(entry.lowlink,visited[w].index)}});if(entry.lowlink===entry.index){var cmpt=[];var w;do{w=stack.pop();visited[w].onStack=false;cmpt.push(w)}while(v!==w);results.push(cmpt)}}g.nodes().forEach(function(v){if(!Object.hasOwn(visited,v)){dfs(v)}});return results}},{}],42:[function(require,module,exports){function topsort(g){var visited={};var stack={};var results=[];function visit(node){if(Object.hasOwn(stack,node)){throw new CycleException}if(!Object.hasOwn(visited,node)){stack[node]=true;visited[node]=true;g.predecessors(node).forEach(visit);delete stack[node];results.push(node)}}g.sinks().forEach(visit);if(Object.keys(visited).length!==g.nodeCount()){throw new CycleException}return results}class CycleException extends Error{constructor(){super(...arguments)}}module.exports=topsort;topsort.CycleException=CycleException},{}],43:[function(require,module,exports){
|
|
540
540
|
/**
|
|
541
541
|
* A min-priority queue data structure. This algorithm is derived from Cormen,
|
|
542
542
|
* et al., "Introduction to Algorithms". The basic idea of a min-priority
|
|
@@ -553,7 +553,7 @@ class PriorityQueue{_arr=[];_keyIndices={};
|
|
|
553
553
|
*/keys(){return this._arr.map(function(x){return x.key})}
|
|
554
554
|
/**
|
|
555
555
|
* Returns `true` if **key** is in the queue and `false` if not.
|
|
556
|
-
*/has(key){return this._keyIndices
|
|
556
|
+
*/has(key){return Object.hasOwn(this._keyIndices,key)}
|
|
557
557
|
/**
|
|
558
558
|
* Returns the priority for **key**. If **key** is not present in the queue
|
|
559
559
|
* then this function returns `undefined`. Takes `O(1)` time.
|
|
@@ -571,7 +571,7 @@ class PriorityQueue{_arr=[];_keyIndices={};
|
|
|
571
571
|
*
|
|
572
572
|
* @param {Object} key the key to add
|
|
573
573
|
* @param {Number} priority the initial priority for the key
|
|
574
|
-
*/add(key,priority){var keyIndices=this._keyIndices;key=String(key);if(!
|
|
574
|
+
*/add(key,priority){var keyIndices=this._keyIndices;key=String(key);if(!Object.hasOwn(keyIndices,key)){var arr=this._arr;var index=arr.length;keyIndices[key]=index;arr.push({key:key,priority:priority});this._decrease(index);return true}return false}
|
|
575
575
|
/**
|
|
576
576
|
* Removes and returns the smallest key in the queue. Takes `O(log n)` time.
|
|
577
577
|
*/removeMin(){this._swap(0,this._arr.length-1);var min=this._arr.pop();delete this._keyIndices[min.key];this._heapify(0);return min.key}
|
|
@@ -613,7 +613,7 @@ _edgeObjs={};
|
|
|
613
613
|
// e -> label
|
|
614
614
|
_edgeLabels={};
|
|
615
615
|
/* Number of nodes in the graph. Should only be changed by the implementation. */_nodeCount=0;
|
|
616
|
-
/* Number of edges in the graph. Should only be changed by the implementation. */_edgeCount=0;_parent;_children;constructor(opts){if(opts){this._isDirected=
|
|
616
|
+
/* Number of edges in the graph. Should only be changed by the implementation. */_edgeCount=0;_parent;_children;constructor(opts){if(opts){this._isDirected=Object.hasOwn(opts,"directed")?opts.directed:true;this._isMultigraph=Object.hasOwn(opts,"multigraph")?opts.multigraph:false;this._isCompound=Object.hasOwn(opts,"compound")?opts.compound:false}if(this._isCompound){
|
|
617
617
|
// v -> parent
|
|
618
618
|
this._parent={};
|
|
619
619
|
// v -> children
|
|
@@ -668,20 +668,20 @@ this._children={};this._children[GRAPH_NODE]={}}}
|
|
|
668
668
|
* it is set as the value for the node. If label is not supplied and the node was
|
|
669
669
|
* created by this call then the default node label will be assigned.
|
|
670
670
|
* Complexity: O(1).
|
|
671
|
-
*/setNode(v,value){if(this._nodes
|
|
671
|
+
*/setNode(v,value){if(Object.hasOwn(this._nodes,v)){if(arguments.length>1){this._nodes[v]=value}return this}this._nodes[v]=arguments.length>1?value:this._defaultNodeLabelFn(v);if(this._isCompound){this._parent[v]=GRAPH_NODE;this._children[v]={};this._children[GRAPH_NODE][v]=true}this._in[v]={};this._preds[v]={};this._out[v]={};this._sucs[v]={};++this._nodeCount;return this}
|
|
672
672
|
/**
|
|
673
673
|
* Gets the label of node with specified name.
|
|
674
674
|
* Complexity: O(|V|).
|
|
675
675
|
*/node(v){return this._nodes[v]}
|
|
676
676
|
/**
|
|
677
677
|
* Detects whether graph has a node with specified name or not.
|
|
678
|
-
*/hasNode(v){return this._nodes
|
|
678
|
+
*/hasNode(v){return Object.hasOwn(this._nodes,v)}
|
|
679
679
|
/**
|
|
680
680
|
* Remove the node with the name from the graph or do nothing if the node is not in
|
|
681
681
|
* the graph. If the node was removed this function also removes any incident
|
|
682
682
|
* edges.
|
|
683
683
|
* Complexity: O(1).
|
|
684
|
-
*/removeNode(v){var self=this;if(this._nodes
|
|
684
|
+
*/removeNode(v){var self=this;if(Object.hasOwn(this._nodes,v)){var removeEdge=e=>self.removeEdge(self._edgeObjs[e]);delete this._nodes[v];if(this._isCompound){this._removeFromParentsChildList(v);delete this._parent[v];this.children(v).forEach(function(child){self.setParent(child)});delete this._children[v]}Object.keys(this._in[v]).forEach(removeEdge);delete this._in[v];delete this._preds[v];Object.keys(this._out[v]).forEach(removeEdge);delete this._out[v];delete this._sucs[v];--this._nodeCount}return this}
|
|
685
685
|
/**
|
|
686
686
|
* Sets node p as a parent for node v if it is defined, or removes the
|
|
687
687
|
* parent for v if p is undefined. Method throws an exception in case of
|
|
@@ -746,7 +746,7 @@ parent+="";for(var ancestor=parent;ancestor!==undefined;ancestor=this.parent(anc
|
|
|
746
746
|
* name. If label is supplied it is set as the value for the edge. If label is not
|
|
747
747
|
* supplied and the edge was created by this call then the default edge label will
|
|
748
748
|
* be assigned. The name parameter is only useful with multigraphs.
|
|
749
|
-
*/setEdge(){var v,w,name,value;var valueSpecified=false;var arg0=arguments[0];if(typeof arg0==="object"&&arg0!==null&&"v"in arg0){v=arg0.v;w=arg0.w;name=arg0.name;if(arguments.length===2){value=arguments[1];valueSpecified=true}}else{v=arg0;w=arguments[1];name=arguments[3];if(arguments.length>2){value=arguments[2];valueSpecified=true}}v=""+v;w=""+w;if(name!==undefined){name=""+name}var e=edgeArgsToId(this._isDirected,v,w,name);if(this._edgeLabels
|
|
749
|
+
*/setEdge(){var v,w,name,value;var valueSpecified=false;var arg0=arguments[0];if(typeof arg0==="object"&&arg0!==null&&"v"in arg0){v=arg0.v;w=arg0.w;name=arg0.name;if(arguments.length===2){value=arguments[1];valueSpecified=true}}else{v=arg0;w=arguments[1];name=arguments[3];if(arguments.length>2){value=arguments[2];valueSpecified=true}}v=""+v;w=""+w;if(name!==undefined){name=""+name}var e=edgeArgsToId(this._isDirected,v,w,name);if(Object.hasOwn(this._edgeLabels,e)){if(valueSpecified){this._edgeLabels[e]=value}return this}if(name!==undefined&&!this._isMultigraph){throw new Error("Cannot set a named edge when isMultigraph = false")}
|
|
750
750
|
// It didn't exist, so we need to create it.
|
|
751
751
|
// First ensure the nodes exist.
|
|
752
752
|
this.setNode(v);this.setNode(w);this._edgeLabels[e]=valueSpecified?value:this._defaultEdgeLabelFn(v,w,name);var edgeObj=edgeArgsToObj(this._isDirected,v,w,name);
|
|
@@ -763,7 +763,7 @@ v=edgeObj.v;w=edgeObj.w;Object.freeze(edgeObj);this._edgeObjs[e]=edgeObj;increme
|
|
|
763
763
|
/**
|
|
764
764
|
* Detects whether the graph contains specified edge or not. No subgraphs are considered.
|
|
765
765
|
* Complexity: O(1).
|
|
766
|
-
*/hasEdge(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return this._edgeLabels
|
|
766
|
+
*/hasEdge(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return Object.hasOwn(this._edgeLabels,e)}
|
|
767
767
|
/**
|
|
768
768
|
* Removes the specified edge from the graph. No subgraphs are considered.
|
|
769
769
|
* Complexity: O(1).
|
|
@@ -798,4 +798,4 @@ module.exports={Graph:require("./graph"),version:require("./version")}},{"./grap
|
|
|
798
798
|
* // ['a', 'b']
|
|
799
799
|
* g2.edges()
|
|
800
800
|
* // [ { v: 'a', w: 'b' } ]
|
|
801
|
-
*/function read(json){var g=new Graph(json.options).setGraph(json.value);json.nodes.forEach(function(entry){g.setNode(entry.v,entry.value);if(entry.parent){g.setParent(entry.v,entry.parent)}});json.edges.forEach(function(entry){g.setEdge({v:entry.v,w:entry.w,name:entry.name},entry.value)});return g}},{"./graph":44}],47:[function(require,module,exports){module.exports="2.2.
|
|
801
|
+
*/function read(json){var g=new Graph(json.options).setGraph(json.value);json.nodes.forEach(function(entry){g.setNode(entry.v,entry.value);if(entry.parent){g.setParent(entry.v,entry.parent)}});json.edges.forEach(function(entry){g.setEdge({v:entry.v,w:entry.w,name:entry.name},entry.value)});return g}},{"./graph":44}],47:[function(require,module,exports){module.exports="2.2.4"},{}]},{},[1])(1)});
|
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 {
|
package/lib/acyclic.js
CHANGED
|
@@ -33,13 +33,13 @@ function dfsFAS(g) {
|
|
|
33
33
|
let visited = {};
|
|
34
34
|
|
|
35
35
|
function dfs(v) {
|
|
36
|
-
if (
|
|
36
|
+
if (Object.hasOwn(visited, v)) {
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
visited[v] = true;
|
|
40
40
|
stack[v] = true;
|
|
41
41
|
g.outEdges(v).forEach(e => {
|
|
42
|
-
if (
|
|
42
|
+
if (Object.hasOwn(stack, e.w)) {
|
|
43
43
|
fas.push(e);
|
|
44
44
|
} else {
|
|
45
45
|
dfs(e.w);
|
package/lib/coordinate-system.js
CHANGED
|
@@ -41,7 +41,7 @@ function reverseY(g) {
|
|
|
41
41
|
g.edges().forEach(e => {
|
|
42
42
|
let edge = g.edge(e);
|
|
43
43
|
edge.points.forEach(reverseYOne);
|
|
44
|
-
if (
|
|
44
|
+
if (Object.hasOwn(edge, "y")) {
|
|
45
45
|
reverseYOne(edge);
|
|
46
46
|
}
|
|
47
47
|
});
|
|
@@ -57,7 +57,7 @@ function swapXY(g) {
|
|
|
57
57
|
g.edges().forEach(e => {
|
|
58
58
|
let edge = g.edge(e);
|
|
59
59
|
edge.points.forEach(swapXYOne);
|
|
60
|
-
if (
|
|
60
|
+
if (Object.hasOwn(edge, "x")) {
|
|
61
61
|
swapXYOne(edge);
|
|
62
62
|
}
|
|
63
63
|
});
|
package/lib/layout.js
CHANGED
|
@@ -84,7 +84,7 @@ function updateInputGraph(inputGraph, layoutGraph) {
|
|
|
84
84
|
let layoutLabel = layoutGraph.edge(e);
|
|
85
85
|
|
|
86
86
|
inputLabel.points = layoutLabel.points;
|
|
87
|
-
if (
|
|
87
|
+
if (Object.hasOwn(layoutLabel, "x")) {
|
|
88
88
|
inputLabel.x = layoutLabel.x;
|
|
89
89
|
inputLabel.y = layoutLabel.y;
|
|
90
90
|
}
|
|
@@ -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 = {
|
|
@@ -233,7 +233,7 @@ function translateGraph(g) {
|
|
|
233
233
|
g.nodes().forEach(v => getExtremes(g.node(v)));
|
|
234
234
|
g.edges().forEach(e => {
|
|
235
235
|
let edge = g.edge(e);
|
|
236
|
-
if (
|
|
236
|
+
if (Object.hasOwn(edge, "x")) {
|
|
237
237
|
getExtremes(edge);
|
|
238
238
|
}
|
|
239
239
|
});
|
|
@@ -253,8 +253,8 @@ function translateGraph(g) {
|
|
|
253
253
|
p.x -= minX;
|
|
254
254
|
p.y -= minY;
|
|
255
255
|
});
|
|
256
|
-
if (
|
|
257
|
-
if (
|
|
256
|
+
if (Object.hasOwn(edge, "x")) { edge.x -= minX; }
|
|
257
|
+
if (Object.hasOwn(edge, "y")) { edge.y -= minY; }
|
|
258
258
|
});
|
|
259
259
|
|
|
260
260
|
graphLabel.width = maxX - minX + marginX;
|
|
@@ -283,7 +283,7 @@ function assignNodeIntersects(g) {
|
|
|
283
283
|
function fixupEdgeLabelCoords(g) {
|
|
284
284
|
g.edges().forEach(e => {
|
|
285
285
|
let edge = g.edge(e);
|
|
286
|
-
if (
|
|
286
|
+
if (Object.hasOwn(edge, "x")) {
|
|
287
287
|
if (edge.labelpos === "l" || edge.labelpos === "r") {
|
|
288
288
|
edge.width -= edge.labeloffset;
|
|
289
289
|
}
|
package/lib/nesting-graph.js
CHANGED
|
@@ -31,7 +31,8 @@ module.exports = {
|
|
|
31
31
|
function run(g) {
|
|
32
32
|
let root = util.addDummyNode(g, "root", {}, "_root");
|
|
33
33
|
let depths = treeDepths(g);
|
|
34
|
-
let
|
|
34
|
+
let depthsArr = Object.values(depths);
|
|
35
|
+
let height = util.applyWithChunking(Math.max, depthsArr) - 1; // Note: depths is an Object not an array
|
|
35
36
|
let nodeSep = 2 * height + 1;
|
|
36
37
|
|
|
37
38
|
g.graph().nestingRoot = root;
|
|
@@ -54,7 +54,7 @@ function buildLayerGraph(g, rank, relationship) {
|
|
|
54
54
|
result.setEdge(u, v, { weight: g.edge(e).weight + weight });
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
if (
|
|
57
|
+
if (Object.hasOwn(node, "minRank")) {
|
|
58
58
|
result.setNode(v, {
|
|
59
59
|
borderLeft: node.borderLeft[rank],
|
|
60
60
|
borderRight: node.borderRight[rank]
|
package/lib/order/init-order.js
CHANGED
|
@@ -18,7 +18,8 @@ module.exports = initOrder;
|
|
|
18
18
|
function initOrder(g) {
|
|
19
19
|
let visited = {};
|
|
20
20
|
let simpleNodes = g.nodes().filter(v => !g.children(v).length);
|
|
21
|
-
let
|
|
21
|
+
let simpleNodesRanks = simpleNodes.map(v => g.node(v).rank);
|
|
22
|
+
let maxRank = util.applyWithChunking(Math.max, simpleNodesRanks);
|
|
22
23
|
let layers = util.range(maxRank + 1).map(() => []);
|
|
23
24
|
|
|
24
25
|
function dfs(v) {
|
|
@@ -20,7 +20,7 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
20
20
|
if (g.children(entry.v).length) {
|
|
21
21
|
let subgraphResult = sortSubgraph(g, entry.v, cg, biasRight);
|
|
22
22
|
subgraphs[entry.v] = subgraphResult;
|
|
23
|
-
if (
|
|
23
|
+
if (Object.hasOwn(subgraphResult, "barycenter")) {
|
|
24
24
|
mergeBarycenters(entry, subgraphResult);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -36,7 +36,7 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
36
36
|
if (g.predecessors(bl).length) {
|
|
37
37
|
let blPred = g.node(g.predecessors(bl)[0]),
|
|
38
38
|
brPred = g.node(g.predecessors(br)[0]);
|
|
39
|
-
if (!
|
|
39
|
+
if (!Object.hasOwn(result, "barycenter")) {
|
|
40
40
|
result.barycenter = 0;
|
|
41
41
|
result.weight = 0;
|
|
42
42
|
}
|
package/lib/order/sort.js
CHANGED
|
@@ -4,7 +4,7 @@ module.exports = sort;
|
|
|
4
4
|
|
|
5
5
|
function sort(entries, biasRight) {
|
|
6
6
|
let parts = util.partition(entries, entry => {
|
|
7
|
-
return
|
|
7
|
+
return Object.hasOwn(entry, "barycenter");
|
|
8
8
|
});
|
|
9
9
|
let sortable = parts.lhs,
|
|
10
10
|
unsortable = parts.rhs.sort((a, b) => b.i - a.i),
|