1 line
40 KiB
JavaScript
1 line
40 KiB
JavaScript
var dagre=dagre||{};dagre.layout=(graph,layout)=>{const time=(name,callback)=>{const result=callback();return result};const buildLayoutGraph=graph=>{const g=new dagre.Graph({compound:true});g.layout=Object.assign({},{ranksep:50,edgesep:20,nodesep:50,rankdir:"tb"},layout);g.state=Object.assign({},graph.state);for(const node of graph.nodes.values()){const v=node.v;const label=node.label;g.setNode(v,{width:label.width||0,height:label.height||0});g.setParent(v,graph.parent(v))}for(const e of graph.edges.values()){const edge=e.label;g.setEdge(e.v,e.w,{minlen:edge.minlen||1,weight:edge.weight||1,width:edge.width||0,height:edge.height||0,labeloffset:edge.labeloffset||10,labelpos:edge.labelpos||"r"})}return g};const runLayout=(g,time)=>{let uniqueIdCounter=0;const uniqueId=prefix=>{const id=++uniqueIdCounter;return prefix+id};const flat=list=>{if(Array.isArray(list)&&list.every(item=>!Array.isArray(item))){return list}const target=[];for(const item of list){if(!Array.isArray(item)){target.push(item);continue}for(const entry of item){target.push(entry)}}return target};const addDummyNode=(g,type,label,name)=>{let v;do{v=uniqueId(name)}while(g.hasNode(v));label.dummy=type;g.setNode(v,label);return v};const asNonCompoundGraph=g=>{const graph=new dagre.Graph({});graph.layout=g.layout;graph.state=g.state;for(const node of g.nodes.values()){const v=node.v;if(g.children(v).length===0){graph.setNode(v,node.label)}}for(const e of g.edges.values()){graph.setEdge(e.v,e.w,e.label)}return graph};const maxRank=g=>{let rank=Number.NEGATIVE_INFINITY;for(const node of g.nodes.values()){const x=node.label.rank;if(x!==undefined&&x>rank){rank=x}}return rank===Number.NEGATIVE_INFINITY?undefined:rank};const buildLayerMatrix=g=>{const rank=maxRank(g);const length=rank===undefined?0:rank+1;const layering=Array.from(new Array(length),()=>[]);for(const node of g.nodes.values()){const label=node.label;const rank=label.rank;if(rank!==undefined){layering[rank][label.order]=node.v}}return layering};const makeSpaceForEdgeLabels=g=>{g.layout.ranksep/=2;const rankdir=g.layout.rankdir;for(const e of g.edges.values()){const edge=e.label;edge.minlen*=2;if(edge.labelpos.toLowerCase()!=="c"){if(rankdir==="TB"||rankdir==="BT"){edge.width+=edge.labeloffset}else{edge.height+=edge.labeloffset}}}};const removeSelfEdges=g=>{for(const e of g.edges.values()){if(e.v===e.w){const label=e.vNode.label;if(!label.selfEdges){label.selfEdges=[]}label.selfEdges.push({e:e,label:e.label});g.removeEdge(e)}}};const acyclic_run=g=>{const edges=[];const visited=new Set;const path=new Set;const stack=Array.from(g.nodes.keys()).reverse();while(stack.length>0){const v=stack.pop();if(!Array.isArray(v)){if(!visited.has(v)){visited.add(v);path.add(v);stack.push([v]);const out=g.node(v).out;for(let i=out.length-1;i>=0;i--){const e=out[i];if(path.has(e.w)){edges.push(e)}stack.push(e.w)}}}else{path.delete(v[0])}}for(const e of edges){const label=e.label;g.removeEdge(e);label.forwardName=e.name;label.reversed=true;g.setEdge(e.w,e.v,label,uniqueId("rev"))}};const acyclic_undo=g=>{for(const e of g.edges.values()){const edge=e.label;if(edge.reversed){edge.points.reverse();g.removeEdge(e);const forwardName=edge.forwardName;delete edge.reversed;delete edge.forwardName;g.setEdge(e.w,e.v,edge,forwardName)}}};const slack=(g,e)=>{return e.wNode.label.rank-e.vNode.label.rank-e.label.minlen};const rank=g=>{const feasibleTree=g=>{const t=new dagre.Graph({directed:false});const start=g.nodes.keys().next().value;const size=g.nodes.size;t.setNode(start,{});const tightTree=(t,g)=>{const stack=Array.from(t.nodes.keys()).reverse();while(stack.length>0){const v=stack.pop();const node=g.node(v);for(const e of node.in.concat(node.out)){const edgeV=e.v;const w=v===edgeV?e.w:edgeV;if(!t.hasNode(w)&&!slack(g,e)){t.setNode(w,{});t.setEdge(v,w,{});stack.push(w)}}}return t.nodes.size};while(tightTree(t,g)<size){let minKey=Number.MAX_SAFE_INTEGER;let edge=undefined;for(const e of g.edges.values()){if(t.hasNode(e.v)!==t.hasNode(e.w)){const key=slack(g,e);if(key<minKey){minKey=key;edge=e}}}const delta=t.hasNode(edge.v)?slack(g,edge):-slack(g,edge);for(const v of t.nodes.keys()){g.node(v).label.rank+=delta}}return t};const longestPath=g=>{const visited=new Set;const stack=[Array.from(g.nodes.values()).filter(node=>node.in.length===0).reverse()];while(stack.length>0){const current=stack[stack.length-1];if(Array.isArray(current)){const node=current.pop();if(current.length===0){stack.pop()}if(!visited.has(node)){visited.add(node);const children=node.out.map(e=>e.wNode);if(children.length>0){stack.push(node);stack.push(children.reverse())}else{node.label.rank=0}}}else{stack.pop();let rank=Number.MAX_SAFE_INTEGER;for(const e of current.out){rank=Math.min(rank,e.wNode.label.rank-e.label.minlen)}current.label.rank=rank}}};const networkSimplex=g=>{const simplify=g=>{const graph=new dagre.Graph;graph.layout=g.layout;graph.state=g.state;for(const node of g.nodes.values()){graph.setNode(node.v,node.label)}for(const e of g.edges.values()){const simpleEdge=graph.edge(e.v,e.w);const simpleLabel=simpleEdge?simpleEdge.label:{weight:0,minlen:1};const label=e.label;graph.setEdge(e.v,e.w,{weight:simpleLabel.weight+label.weight,minlen:Math.max(simpleLabel.minlen,label.minlen)})}return graph};const initLowLimValues=(tree,root)=>{const dfs=(tree,visited,nextLim,v,parent)=>{const low=nextLim;const label=tree.node(v).label;visited.add(v);for(const w of tree.neighbors(v)){if(!visited.has(w)){nextLim=dfs(tree,visited,nextLim,w,v)}}label.low=low;label.lim=nextLim++;if(parent){label.parent=parent}else{delete label.parent}return nextLim};root=tree.nodes.keys().next().value;const visited=new Set;dfs(tree,visited,1,root)};const initCutValues=(t,g)=>{const vs=[];const visited=new Set;const stack=[Array.from(t.nodes.keys()).reverse()];while(stack.length>0){const current=stack[stack.length-1];if(Array.isArray(current)){const v=current.pop();if(current.length===0){stack.pop()}if(!visited.has(v)){visited.add(v);const children=t.neighbors(v);if(children.length>0){stack.push(v);stack.push(children.reverse())}else{vs.push(v)}}}else{vs.push(stack.pop())}}for(const v of vs.slice(0,vs.length-1)){const childLabel=t.node(v).label;const parent=childLabel.parent;const edge=g.edge(v,parent);const childIsTail=edge?true:false;const graphEdge=edge?edge.label:g.edge(parent,v).label;let cutValue=graphEdge.weight;const node=g.node(v);for(const e of node.in.concat(node.out)){const isOutEdge=e.v===v;const other=isOutEdge?e.w:e.v;if(other!==parent){const pointsToHead=isOutEdge===childIsTail;cutValue+=pointsToHead?e.label.weight:-e.label.weight;const edge=t.edge(v,other);if(edge){const otherCutValue=edge.label.cutvalue;cutValue+=pointsToHead?-otherCutValue:otherCutValue}}}t.edge(v,parent).label.cutvalue=cutValue}};const leaveEdge=tree=>{return Array.from(tree.edges.values()).find(e=>e.label.cutvalue<0)};const enterEdge=(t,g,edge)=>{let v=edge.v;let w=edge.w;if(!g.edge(v,w)){v=edge.w;w=edge.v}const vLabel=t.node(v).label;const wLabel=t.node(w).label;let tailLabel=vLabel;let flip=false;if(vLabel.lim>wLabel.lim){tailLabel=wLabel;flip=true}const isDescendant=(vLabel,rootLabel)=>{return rootLabel.low<=vLabel.lim&&vLabel.lim<=rootLabel.lim};let minKey=Number.POSITIVE_INFINITY;let minValue=undefined;for(const edge of g.edges.values()){if(flip===isDescendant(t.node(edge.v).label,tailLabel)&&flip!==isDescendant(t.node(edge.w).label,tailLabel)){const key=slack(g,edge);if(key<minKey){minKey=key;minValue=edge}}}return minValue};const exchangeEdges=(t,g,e,f)=>{t.removeEdge(e);t.setEdge(f.v,f.w,{});initLowLimValues(t);initCutValues(t,g);const root=Array.from(t.nodes.keys()).find(v=>!g.node(v).label.parent);const stack=[root];const visited=new Set;while(stack.length>0){const v=stack.pop();if(!visited.has(v)){visited.add(v);const neighbors=t.neighbors(v);for(let i=neighbors.length-1;i>=0;i--){stack.push(neighbors[i])}}}const vs=Array.from(visited);for(const v of vs.slice(1)){const parent=t.node(v).label.parent;let edge=g.edge(v,parent);let flipped=false;if(!edge){edge=g.edge(parent,v);flipped=true}g.node(v).label.rank=g.node(parent).label.rank+(flipped?edge.label.minlen:-edge.label.minlen)}};g=simplify(g);longestPath(g);const t=feasibleTree(g);initLowLimValues(t);initCutValues(t,g);let e;let f;while(e=leaveEdge(t)){f=enterEdge(t,g,e);exchangeEdges(t,g,e,f)}};switch(g.layout.ranker){case"tight-tree":longestPath(g);feasibleTree(g);break;case"longest-path":longestPath(g);break;default:networkSimplex(g);break}};const injectEdgeLabelProxies=g=>{for(const e of g.edges.values()){const edge=e.label;if(edge.width&&edge.height){const v=e.vNode.label;const w=e.wNode.label;addDummyNode(g,"edge-proxy",{rank:(w.rank-v.rank)/2+v.rank,e:e},"_ep")}}};const removeEmptyRanks=g=>{if(g.nodes.size>0){let minRank=Number.MAX_SAFE_INTEGER;let maxRank=Number.MIN_SAFE_INTEGER;const nodes=Array.from(g.nodes.values());for(const node of nodes){const label=node.label;if(label.rank!==undefined){minRank=Math.min(minRank,label.rank);maxRank=Math.max(maxRank,label.rank)}}const size=maxRank-minRank;if(size>0){const layers=new Array(size);for(const node of nodes){const label=node.label;if(label.rank!==undefined){const rank=label.rank-minRank;if(!layers[rank]){layers[rank]=[]}layers[rank].push(node.v)}}let delta=0;const nodeRankFactor=g.state.nodeRankFactor;for(let i=0;i<layers.length;i++){const vs=layers[i];if(vs===undefined&&i%nodeRankFactor!==0){delta--}else if(delta&&vs){for(const v of vs){g.node(v).label.rank+=delta}}}}}};const nestingGraph_run=g=>{const root=addDummyNode(g,"root",{},"_root");const treeDepths=g=>{const depths={};const dfs=(v,depth)=>{const children=g.children(v);if(children&&children.length>0){for(const child of children){dfs(child,depth+1)}}depths[v]=depth};for(const v of g.children()){dfs(v,1)}return depths};const dfs=(g,root,nodeSep,weight,height,depths,v)=>{const children=g.children(v);if(!children.length){if(v!==root){g.setEdge(root,v,{weight:0,minlen:nodeSep})}return}const top=addDummyNode(g,"border",{width:0,height:0},"_bt");const bottom=addDummyNode(g,"border",{width:0,height:0},"_bb");const label=g.node(v).label;g.setParent(top,v);label.borderTop=top;g.setParent(bottom,v);label.borderBottom=bottom;for(const child of children){dfs(g,root,nodeSep,weight,height,depths,child);const childNode=g.node(child).label;const childTop=childNode.borderTop?childNode.borderTop:child;const childBottom=childNode.borderBottom?childNode.borderBottom:child;const thisWeight=childNode.borderTop?weight:2*weight;const minlen=childTop!==childBottom?1:height-depths[v]+1;g.setEdge(top,childTop,{weight:thisWeight,minlen:minlen,nestingEdge:true});g.setEdge(childBottom,bottom,{weight:thisWeight,minlen:minlen,nestingEdge:true})}if(!g.parent(v)){g.setEdge(root,top,{weight:0,minlen:height+depths[v]})}};const depths=treeDepths(g);const height=Math.max(...Object.values(depths))-1;const nodeSep=2*height+1;g.state.nestingRoot=root;for(const e of g.edges.values()){e.label.minlen*=nodeSep}const weight=Array.from(g.edges.values()).reduce((acc,e)=>acc+e.label.weight,0)+1;for(const child of g.children()){dfs(g,root,nodeSep,weight,height,depths,child)}g.state.nodeRankFactor=nodeSep};const nestingGraph_cleanup=g=>{g.removeNode(g.state.nestingRoot);delete g.state.nestingRoot;for(const e of g.edges.values()){if(e.label.nestingEdge){g.removeEdge(e)}}};const assignRankMinMax=g=>{let min=Number.POSITIVE_INFINITY;for(const node of g.nodes.values()){const rank=node.label.rank;if(rank!==undefined&&rank<min){min=rank}}for(const node of g.nodes.values()){const label=node.label;if(label.rank!==undefined){label.rank-=min}}let maxRank=0;for(const node of g.nodes.values()){const label=node.label;if(label.borderTop){label.minRank=g.node(label.borderTop).label.rank;label.maxRank=g.node(label.borderBottom).label.rank;maxRank=Math.max(maxRank,label.maxRank)}}g.state.maxRank=maxRank};const normalize=g=>{g.state.dummyChains=[];for(const e of g.edges.values()){let v=e.v;const w=e.w;const name=e.name;const edgeLabel=e.label;const labelRank=edgeLabel.labelRank;let vRank=g.node(v).label.rank;const wRank=g.node(w).label.rank;if(wRank!==vRank+1){g.removeEdge(e);let first=true;vRank++;while(vRank<wRank){edgeLabel.points=[];delete e.key;const attrs={width:0,height:0,edgeLabel:edgeLabel,edgeObj:e,rank:vRank};const dummy=addDummyNode(g,"edge",attrs,"_d");if(vRank===labelRank){attrs.width=edgeLabel.width;attrs.height=edgeLabel.height;attrs.dummy="edge-label";attrs.labelpos=edgeLabel.labelpos}g.setEdge(v,dummy,{weight:edgeLabel.weight},name);if(first){g.state.dummyChains.push(dummy);first=false}v=dummy;vRank++}g.setEdge(v,w,{weight:edgeLabel.weight},name)}}};const denormalize=g=>{for(let v of g.state.dummyChains){let label=g.node(v).label;const edgeLabel=label.edgeLabel;const e=label.edgeObj;g.setEdge(e.v,e.w,edgeLabel,e.name);while(label.dummy){const w=g.successors(v)[0];g.removeNode(v);edgeLabel.points.push({x:label.x,y:label.y});if(label.dummy==="edge-label"){edgeLabel.x=label.x;edgeLabel.y=label.y;edgeLabel.width=label.width;edgeLabel.height=label.height}v=w;label=g.node(v).label}}};const removeEdgeLabelProxies=g=>{for(const node of g.nodes.values()){const label=node.label;if(label.dummy==="edge-proxy"){label.e.label.labelRank=label.rank;g.removeNode(node.v)}}};const parentDummyChains=g=>{const findPath=(g,postorderNums,v,w)=>{const low=Math.min(postorderNums[v].low,postorderNums[w].low);const lim=Math.max(postorderNums[v].lim,postorderNums[w].lim);let parent=v;const vPath=[];do{parent=g.parent(parent);vPath.push(parent)}while(parent&&(postorderNums[parent].low>low||lim>postorderNums[parent].lim));const lca=parent;parent=w;const wPath=[];while((parent=g.parent(parent))!==lca){wPath.push(parent)}return{path:vPath.concat(wPath.reverse()),lca:lca}};const postorder=g=>{const result={};let lim=0;const dfs=v=>{const low=lim;for(const u of g.children(v)){dfs(u)}result[v]={low:low,lim:lim++}};for(const v of g.children()){dfs(v)}return result};const postorderNums=postorder(g);for(let v of g.state.dummyChains||[]){const node=g.node(v).label;const edgeObj=node.edgeObj;const pathData=findPath(g,postorderNums,edgeObj.v,edgeObj.w);const path=pathData.path;const lca=pathData.lca;let pathIdx=0;let pathV=path[pathIdx];let ascending=true;while(v!==edgeObj.w){const node=g.node(v).label;if(ascending){while((pathV=path[pathIdx])!==lca&&g.node(pathV).label.maxRank<node.rank){pathIdx++}if(pathV===lca){ascending=false}}if(!ascending){while(pathIdx<path.length-1&&g.node(path[pathIdx+1]).label.minRank<=node.rank){pathIdx++}pathV=path[pathIdx]}g.setParent(v,pathV);v=g.successors(v)[0]}}};const addBorderSegments=g=>{const addBorderNode=(g,prop,prefix,sg,sgNode,rank)=>{const label={width:0,height:0,rank:rank,borderType:prop};const prev=sgNode[prop][rank-1];const curr=addDummyNode(g,"border",label,prefix);sgNode[prop][rank]=curr;g.setParent(curr,sg);if(prev){g.setEdge(prev,curr,{weight:1})}};const queue=g.children();while(queue.length>0){const v=queue.shift();const node=g.node(v).label;if("minRank"in node){node.borderLeft=[];node.borderRight=[];const maxRank=node.maxRank+1;for(let rank=node.minRank;rank<maxRank;rank++){addBorderNode(g,"borderLeft","_bl",v,node,rank);addBorderNode(g,"borderRight","_br",v,node,rank)}}const children=g.children(v);if(children.length){for(const v of children){queue.push(v)}}}};const order=g=>{const sortSubgraph=(g,v,cg,biasRight)=>{const resolveConflicts=(entries,cg)=>{const mappedEntries=new Map;for(let i=0;i<entries.length;i++){const entry=entries[i];const tmp={indegree:0,in:[],out:[],vs:[entry.v],i:i};if(entry.barycenter!==undefined){tmp.barycenter=entry.barycenter;tmp.weight=entry.weight}mappedEntries.set(entry.v,tmp)}for(const e of cg.edges.values()){const entryV=mappedEntries.get(e.v);const entryW=mappedEntries.get(e.w);if(entryV&&entryW){entryW.indegree++;entryV.out.push(entryW)}}const sourceSet=Array.from(mappedEntries.values()).filter(entry=>!entry.indegree);const results=[];function handleIn(vEntry){return function(uEntry){if(uEntry.merged){return}if(uEntry.barycenter===undefined||vEntry.barycenter===undefined||uEntry.barycenter>=vEntry.barycenter){let sum=0;let weight=0;if(vEntry.weight){sum+=vEntry.barycenter*vEntry.weight;weight+=vEntry.weight}if(uEntry.weight){sum+=uEntry.barycenter*uEntry.weight;weight+=uEntry.weight}vEntry.vs=uEntry.vs.concat(vEntry.vs);vEntry.barycenter=sum/weight;vEntry.weight=weight;vEntry.i=Math.min(uEntry.i,vEntry.i);uEntry.merged=true}}}function handleOut(vEntry){return function(wEntry){wEntry.in.push(vEntry);if(--wEntry.indegree===0){sourceSet.push(wEntry)}}}while(sourceSet.length){const entry=sourceSet.pop();results.push(entry);entry.in.reverse().forEach(handleIn(entry));entry.out.forEach(handleOut(entry))}return results.filter(entry=>!entry.merged).map(entry=>{const value={vs:entry.vs,i:entry.i};if(entry.barycenter!==undefined){value.barycenter=entry.barycenter}if(entry.weight!==undefined){value.weight=entry.weight}return value})};const barycenter=(g,movable)=>{return(movable||[]).map(v=>{const inV=g.node(v).in;if(!inV.length){return{v:v}}const result=inV.reduce((acc,e)=>{const edge=e.label;const nodeU=e.vNode.label;return{sum:acc.sum+edge.weight*nodeU.order,weight:acc.weight+edge.weight}},{sum:0,weight:0});return{v:v,barycenter:result.sum/result.weight,weight:result.weight}})};const sort=(entries,biasRight)=>{const 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};const compareWithBias=bias=>{return function(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}};const parts={lhs:[],rhs:[]};for(const value of entries){if("barycenter"in value){parts.lhs.push(value)}else{parts.rhs.push(value)}}const sortable=parts.lhs;const unsortable=parts.rhs.sort((a,b)=>-a.i+b.i);const vs=[];let sum=0;let weight=0;let vsIndex=0;sortable.sort(compareWithBias(!!biasRight));vsIndex=consumeUnsortable(vs,unsortable,vsIndex);for(const entry of sortable){vsIndex+=entry.vs.length;vs.push(entry.vs);sum+=entry.barycenter*entry.weight;weight+=entry.weight;vsIndex=consumeUnsortable(vs,unsortable,vsIndex)}const result={vs:flat(vs)};if(weight){result.barycenter=sum/weight;result.weight=weight}return result};const node=g.node(v);const bl=node&&node.label?node.label.borderLeft:undefined;const br=node&&node.label?node.label.borderRight:undefined;const subgraphs={};const movable=bl?g.children(v).filter(w=>w!==bl&&w!==br):g.children(v);const barycenters=barycenter(g,movable);for(const entry of barycenters){if(g.children(entry.v).length){const result=sortSubgraph(g,entry.v,cg,biasRight);subgraphs[entry.v]=result;if("barycenter"in result){if(entry.barycenter!==undefined){entry.barycenter=(entry.barycenter*entry.weight+result.barycenter*result.weight)/(entry.weight+result.weight);entry.weight+=result.weight}else{entry.barycenter=result.barycenter;entry.weight=result.weight}}}}const entries=resolveConflicts(barycenters,cg);for(const entry of entries){entry.vs=flat(entry.vs.map(v=>subgraphs[v]?subgraphs[v].vs:v))}const result=sort(entries,biasRight);if(bl){result.vs=flat([bl,result.vs,br]);if(g.predecessors(bl).length){const blPred=g.node(g.predecessors(bl)[0]).label;const brPred=g.node(g.predecessors(br)[0]).label;if(!("barycenter"in result)){result.barycenter=0;result.weight=0}result.barycenter=(result.barycenter*result.weight+blPred.order+brPred.order)/(result.weight+2);result.weight+=2}}return result};const sweepLayerGraphs=(layerGraphs,biasRight)=>{const cg=new dagre.Graph;for(const lg of layerGraphs){const root=lg.state.root;const sorted=sortSubgraph(lg,root,cg,biasRight);const vs=sorted.vs;const length=vs.length;for(let i=0;i<length;i++){lg.node(vs[i]).label.order=i}const prev={};let rootPrev;let exit=false;for(const v of vs){let child=lg.parent(v);let prevChild;while(child){const parent=lg.parent(child);if(parent){prevChild=prev[parent];prev[parent]=child}else{prevChild=rootPrev;rootPrev=child}if(prevChild&&prevChild!==child){cg.setEdge(prevChild,child,null);exit=true;break}child=parent}if(exit){break}}}};const crossCount=(g,layering)=>{let count=0;for(let i=1;i<layering.length;i++){const northLayer=layering[i-1];const southLayer=layering[i];const southPos={};for(let i=0;i<southLayer.length;i++){southPos[southLayer[i]]=i}const southEntries=[];for(const v of northLayer){const entries=[];for(const e of g.node(v).out){entries.push({pos:southPos[e.w],weight:e.label.weight})}entries.sort((a,b)=>a.pos-b.pos);for(const entry of entries){southEntries.push(entry)}}let firstIndex=1;while(firstIndex<southLayer.length){firstIndex<<=1}const treeSize=2*firstIndex-1;firstIndex-=1;const tree=Array.from(new Array(treeSize),()=>0);for(const entry of southEntries){let index=entry.pos+firstIndex;tree[index]+=entry.weight;let weightSum=0;while(index>0){if(index%2){weightSum+=tree[index+1]}index=index-1>>1;tree[index]+=entry.weight}count+=entry.weight*weightSum}}return count};const initOrder=g=>{const visited=new Set;const nodes=Array.from(g.nodes.values()).filter(node=>g.children(node.v).length===0);let maxRank=undefined;for(const node of nodes){const rank=node.label.rank;if(maxRank===undefined||rank!==undefined&&rank>maxRank){maxRank=rank}}if(maxRank!==undefined){const layers=Array.from(new Array(maxRank+1),()=>[]);const queue=nodes.sort((a,b)=>a.label.rank-b.label.rank).map(node=>node.v).reverse();while(queue.length>0){const v=queue.shift();if(!visited.has(v)){visited.add(v);const rank=g.node(v).label.rank;layers[rank].push(v);for(const w of g.successors(v)){queue.push(w)}}}return layers}return[]};const buildLayerGraph=(g,nodes,rank,relationship)=>{let root;while(g.hasNode(root=uniqueId("_root"))){}const graph=new dagre.Graph({compound:true});graph.state={root:root};graph.setDefaultNodeLabel(v=>{const node=g.node(v);return node?node.label:undefined});const length=nodes.length;let i=0;while(i<length){const node=nodes[i++];const label=node.label;if(label.rank===rank||"minRank"in label&&"maxRank"in label&&label.minRank<=rank&&rank<=label.maxRank){const v=node.v;graph.setNode(v);const parent=g.parent(v);graph.setParent(v,parent||root);if(relationship){for(const e of node.in){graph.setEdge(e.v,v,{weight:e.label.weight})}}else{for(const e of node.out){graph.setEdge(e.w,v,{weight:e.label.weight})}}if("minRank"in label){graph.setNode(v,{borderLeft:label.borderLeft[rank],borderRight:label.borderRight[rank]})}}}return graph};let layering=initOrder(g);const assignOrder=(g,layering)=>{for(const layer of layering){for(let i=0;i<layer.length;i++){g.node(layer[i]).label.order=i}}};assignOrder(g,layering);const rank=maxRank(g)||0;const downLayerGraphs=new Array(rank);const upLayerGraphs=new Array(rank);const nodes=Array.from(g.nodes.values());for(let i=0;i<rank;i++){downLayerGraphs[i]=buildLayerGraph(g,nodes,i+1,true);upLayerGraphs[i]=buildLayerGraph(g,nodes,rank-i-1,false)}let bestCC=Number.POSITIVE_INFINITY;let best;for(let i=0,lastBest=0;lastBest<4;++i,++lastBest){sweepLayerGraphs(i%2?downLayerGraphs:upLayerGraphs,i%4>=2);layering=buildLayerMatrix(g);const cc=crossCount(g,layering);if(cc<bestCC){lastBest=0;const length=layering.length;best=new Array(length);for(let j=0;j<length;j++){best[j]=layering[j].slice()}bestCC=cc}}assignOrder(g,best)};const insertSelfEdges=g=>{const layers=buildLayerMatrix(g);for(const layer of layers){let orderShift=0;layer.forEach(function(v,i){const label=g.node(v).label;label.order=i+orderShift;if(label.selfEdges){for(const selfEdge of label.selfEdges){addDummyNode(g,"selfedge",{width:selfEdge.label.width,height:selfEdge.label.height,rank:label.rank,order:i+ ++orderShift,e:selfEdge.e,label:selfEdge.label},"_se")}delete label.selfEdges}})}};const coordinateSystem_swapWidthHeight=g=>{for(const node of g.nodes.values()){const label=node.label;const w=label.width;label.width=label.height;label.height=w}for(const e of g.edges.values()){const label=e.label;const w=label.width;label.width=label.height;label.height=w}};const coordinateSystem_adjust=g=>{const rankDir=g.layout.rankdir.toLowerCase();if(rankDir==="lr"||rankDir==="rl"){coordinateSystem_swapWidthHeight(g)}};const coordinateSystem_undo=g=>{const rankDir=g.layout.rankdir.toLowerCase();if(rankDir==="bt"||rankDir==="rl"){for(const node of g.nodes.values()){node.label.y=-node.label.y}for(const e of g.edges.values()){const edge=e.label;for(const attr of edge.points){attr.y=-attr.y}if("y"in edge){edge.y=-edge.y}}}if(rankDir==="lr"||rankDir==="rl"){const swapXYOne=attrs=>{const x=attrs.x;attrs.x=attrs.y;attrs.y=x};for(const node of g.nodes.values()){swapXYOne(node.label)}for(const e of g.edges.values()){const edge=e.label;for(const e of edge.points){swapXYOne(e)}if(edge.x!==undefined){swapXYOne(edge)}}coordinateSystem_swapWidthHeight(g)}};const position=g=>{const addConflict=(conflicts,v,w)=>{if(v>w){const tmp=v;v=w;w=tmp}let conflictsV=conflicts[v];if(!conflictsV){conflicts[v]=conflictsV={}}conflictsV[w]=true};const hasConflict=(conflicts,v,w)=>{if(v>w){const tmp=v;v=w;w=tmp}return conflicts[v]&&w in conflicts[v]};const buildBlockGraph=(g,layering,root,reverseSep)=>{const nodeSep=g.layout.nodesep;const edgeSep=g.layout.edgesep;const blockGraph=new dagre.Graph;for(const layer of layering){let u;for(const v of layer){const vRoot=root[v];blockGraph.setNode(vRoot,{});if(u){const uRoot=root[u];const vLabel=g.node(v).label;const wLabel=g.node(u).label;let sum=0;let delta;sum+=vLabel.width/2;if("labelpos"in vLabel){switch(vLabel.labelpos){case"l":delta=-vLabel.width/2;break;case"r":delta=vLabel.width/2;break;default:throw new dagre.Error("Unsupported label position '"+vLabel.labelpos+"'.")}}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("labelpos"in wLabel){switch(wLabel.labelpos){case"l":delta=wLabel.width/2;break;case"r":delta=-wLabel.width/2;break;default:throw new dagre.Error("Unsupported label position '"+wLabel.labelpos+"'.")}}if(delta){sum+=reverseSep?delta:-delta}const edge=blockGraph.edge(uRoot,vRoot);const max=Math.max(sum,edge?edge.label:0);if(edge){edge.label=max}else{blockGraph.setEdge(uRoot,vRoot,max)}}u=v}}return blockGraph};const verticalAlignment=(layering,conflicts,neighborFn)=>{const root={};const align={};const pos={};for(const layer of layering){let order=0;for(const v of layer){root[v]=v;align[v]=v;pos[v]=order;order++}}for(const layer of layering){let prevIdx=-1;for(const v of layer){let ws=neighborFn(v);if(ws.length>0){ws=ws.sort((a,b)=>pos[a]-pos[b]);const mp=(ws.length-1)/2;const il=Math.ceil(mp);for(let i=Math.floor(mp);i<=il;i++){const w=ws[i];if(align[v]===v&&prevIdx<pos[w]&&!hasConflict(conflicts,v,w)){align[w]=v;align[v]=root[v]=root[w];prevIdx=pos[w]}}}}}return{root:root,align:align}};const horizontalCompaction=(g,layering,root,align,reverseSep)=>{const blockG=buildBlockGraph(g,layering,root,reverseSep);const borderType=reverseSep?"borderLeft":"borderRight";const xs={};if(blockG.nodes.size>0){const stack=Array.from(blockG.nodes.keys());const visited=new Set;while(stack.length>0){const v=stack.pop();if(visited.has(v)){let max=0;for(const e of blockG.node(v).in){max=Math.max(max,xs[e.v]+e.label)}xs[v]=max}else{visited.add(v);stack.push(v);for(const w of blockG.predecessors(v)){stack.push(w)}}}}if(blockG.nodes.size>0){const stack=Array.from(blockG.nodes.keys());const visited=new Set;while(stack.length>0){const v=stack.pop();if(visited.has(v)){let min=Number.POSITIVE_INFINITY;for(const e of blockG.node(v).out){min=Math.min(min,xs[e.w]-e.label)}const label=g.node(v).label;if(min!==Number.POSITIVE_INFINITY&&label.borderType!==borderType){xs[v]=Math.max(xs[v],min)}}else{visited.add(v);stack.push(v);for(const w of blockG.successors(v)){stack.push(w)}}}}for(const v of Object.values(align)){xs[v]=xs[root[v]]}return xs};const findType1Conflicts=(g,layering)=>{const conflicts={};if(layering.length>0){let prev=layering[0];for(let k=1;k<layering.length;k++){const layer=layering[k];let k0=0;let scanPos=0;const prevLayerLength=prev.length;const lastNode=layer[layer.length-1];for(let i=0;i<layer.length;i++){const v=layer[i];const w=g.node(v).label.dummy?g.predecessors(v).find(u=>g.node(u).label.dummy):null;if(w||v===lastNode){const k1=w?g.node(w).label.order:prevLayerLength;for(const scanNode of layer.slice(scanPos,i+1)){for(const u of g.predecessors(scanNode)){const uLabel=g.node(u).label;const uPos=uLabel.order;if((uPos<k0||k1<uPos)&&!(uLabel.dummy&&g.node(scanNode).label.dummy)){addConflict(conflicts,u,scanNode)}}}scanPos=i+1;k0=k1}}prev=layer}}return conflicts};const findType2Conflicts=(g,layering)=>{const conflicts={};const scan=(south,southPos,southEnd,prevNorthBorder,nextNorthBorder)=>{let v;for(let i=southPos;i<southEnd;i++){v=south[i];if(g.node(v).labeldummy){for(const u of g.predecessors(v)){const uNode=g.node(u).label;if(uNode.dummy&&(uNode.order<prevNorthBorder||uNode.order>nextNorthBorder)){addConflict(conflicts,u,v)}}}}};if(layering.length>0){let north=layering[0];for(let i=1;i<layering.length;i++){const south=layering[i];let prevNorthPos=-1;let nextNorthPos;let southPos=0;south.forEach(function(v,southLookahead){if(g.node(v).label.dummy==="border"){const predecessors=g.predecessors(v);if(predecessors.length){nextNorthPos=g.node(predecessors[0]).label.order;scan(south,southPos,southLookahead,prevNorthPos,nextNorthPos);southPos=southLookahead;prevNorthPos=nextNorthPos}}scan(south,southPos,south.length,nextNorthPos,north.length)});north=south}}return conflicts};g=asNonCompoundGraph(g);const layering=buildLayerMatrix(g);const ranksep=g.layout.ranksep;let y=0;for(const layer of layering){const maxHeight=layer.reduce((a,v)=>Math.max(a,g.node(v).label.height),0);for(const v of layer){g.node(v).label.y=y+maxHeight/2}y+=maxHeight+ranksep}const conflicts=Object.assign(findType1Conflicts(g,layering),findType2Conflicts(g,layering));const xss={};for(const vertical of["u","d"]){let adjustedLayering=vertical==="u"?layering:Object.values(layering).reverse();for(const horizontal of["l","r"]){if(horizontal==="r"){adjustedLayering=adjustedLayering.map(layer=>Object.values(layer).reverse())}const neighborFn=(vertical==="u"?g.predecessors:g.successors).bind(g);const align=verticalAlignment(adjustedLayering,conflicts,neighborFn);const xs=horizontalCompaction(g,adjustedLayering,align.root,align.align,horizontal==="r");if(horizontal==="r"){for(const entry of Object.entries(xs)){xs[entry[0]]=-entry[1]}}xss[vertical+horizontal]=xs}}let minWidth=Number.POSITIVE_INFINITY;let minValue=undefined;for(const xs of Object.values(xss)){let max=Number.NEGATIVE_INFINITY;let min=Number.POSITIVE_INFINITY;for(const[v,x]of Object.entries(xs)){const halfWidth=g.node(v).label.width/2;max=Math.max(x+halfWidth,max);min=Math.min(x-halfWidth,min)}const width=max-min;if(width<minWidth){minWidth=width;minValue=xs}}const alignTo=minValue;const range=values=>{let min=Number.POSITIVE_INFINITY;let max=Number.NEGATIVE_INFINITY;for(const value of values){if(value<min){min=value}if(value>max){max=value}}return[min,max]};const alignToRange=range(Object.values(alignTo));for(const vertical of["u","d"]){for(const horizontal of["l","r"]){const alignment=vertical+horizontal;const xs=xss[alignment];let delta;if(xs!==alignTo){const vsValsRange=range(Object.values(xs));delta=horizontal==="l"?alignToRange[0]-vsValsRange[0]:alignToRange[1]-vsValsRange[1];if(delta){const list={};for(const key of Object.keys(xs)){list[key]=xs[key]+delta}xss[alignment]=list}}}}const align=g.layout.align;if(align){const xs=xss[align.toLowerCase()];for(const v of Object.keys(xss.ul)){g.node(v).label.x=xs[v]}}else{for(const v of Object.keys(xss.ul)){const xs=[xss.ul[v],xss.ur[v],xss.dl[v],xss.dr[v]].sort((a,b)=>a-b);g.node(v).label.x=(xs[1]+xs[2])/2}}};const positionSelfEdges=g=>{for(const node of g.nodes.values()){const label=node.label;if(label.dummy==="selfedge"){const v=node.v;const selfNode=g.node(label.e.v).label;const x=selfNode.x+selfNode.width/2;const y=selfNode.y;const dx=label.x-x;const dy=selfNode.height/2;g.setEdge(label.e.v,label.e.w,label.label);g.removeNode(v);label.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}];label.label.x=label.x;label.label.y=label.y}}};const removeBorderNodes=g=>{for(const node of g.nodes.values()){const v=node.v;if(g.children(v).length){const label=node.label;const t=g.node(label.borderTop).label;const b=g.node(label.borderBottom).label;const l=g.node(label.borderLeft[label.borderLeft.length-1]).label;const r=g.node(label.borderRight[label.borderRight.length-1]).label;label.width=Math.abs(r.x-l.x);label.height=Math.abs(b.y-t.y);label.x=l.x+label.width/2;label.y=t.y+label.height/2}}for(const node of g.nodes.values()){if(node.label.dummy==="border"){g.removeNode(node.v)}}};const fixupEdgeLabelCoords=g=>{for(const e of g.edges.values()){const edge=e.label;if("x"in edge){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;default:throw new dagre.Error("Unsupported label position '"+edge.labelpos+"'.")}}}};const translateGraph=g=>{let minX=Number.POSITIVE_INFINITY;let maxX=0;let minY=Number.POSITIVE_INFINITY;let maxY=0;const getExtremes=attrs=>{const x=attrs.x;const y=attrs.y;const w=attrs.width;const 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)};for(const node of g.nodes.values()){getExtremes(node.label)}for(const e of g.edges.values()){const edge=e.label;if("x"in edge){getExtremes(edge)}}for(const node of g.nodes.values()){node.label.x-=minX;node.label.y-=minY}for(const e of g.edges.values()){const edge=e.label;for(const p of edge.points){p.x-=minX;p.y-=minY}if("x"in edge){edge.x-=minX}if("y"in edge){edge.y-=minY}}g.state.width=maxX-minX;g.state.height=maxY-minY};const assignNodeIntersects=g=>{const intersectRect=(rect,point)=>{const x=rect.x;const y=rect.y;const dx=point.x-x;const dy=point.y-y;if(dx===0&&dy===0){throw new Error("Not possible to find intersection inside of the rectangle")}let w=rect.width/2;let h=rect.height/2;if(Math.abs(dy)*w>Math.abs(dx)*h){h=dy<0?-h:h;return{x:x+h*dx/dy,y:y+h}}w=dx<0?-w:w;return{x:x+w,y:y+w*dy/dx}};for(const e of g.edges.values()){const edge=e.label;const vNode=e.vNode.label;const wNode=e.wNode.label;let p1;let p2;if(!edge.points){edge.points=[];p1=wNode;p2=vNode}else{p1=edge.points[0];p2=edge.points[edge.points.length-1]}edge.points.unshift(intersectRect(vNode,p1));edge.points.push(intersectRect(wNode,p2))}};time(" makeSpaceForEdgeLabels",()=>makeSpaceForEdgeLabels(g));time(" removeSelfEdges",()=>removeSelfEdges(g));time(" acyclic_run",()=>acyclic_run(g));time(" nestingGraph_run",()=>nestingGraph_run(g));time(" rank",()=>rank(asNonCompoundGraph(g)));time(" injectEdgeLabelProxies",()=>injectEdgeLabelProxies(g));time(" removeEmptyRanks",()=>removeEmptyRanks(g));time(" nestingGraph_cleanup",()=>nestingGraph_cleanup(g));time(" assignRankMinMax",()=>assignRankMinMax(g));time(" removeEdgeLabelProxies",()=>removeEdgeLabelProxies(g));time(" normalize",()=>normalize(g));time(" parentDummyChains",()=>parentDummyChains(g));time(" addBorderSegments",()=>addBorderSegments(g));time(" order",()=>order(g));time(" insertSelfEdges",()=>insertSelfEdges(g));time(" coordinateSystem_adjust",()=>coordinateSystem_adjust(g));time(" position",()=>position(g));time(" positionSelfEdges",()=>positionSelfEdges(g));time(" removeBorderNodes",()=>removeBorderNodes(g));time(" denormalize",()=>denormalize(g));time(" fixupEdgeLabelCoords",()=>fixupEdgeLabelCoords(g));time(" coordinateSystem_undo",()=>coordinateSystem_undo(g));time(" translateGraph",()=>translateGraph(g));time(" assignNodeIntersects",()=>assignNodeIntersects(g));time(" acyclic_undo",()=>acyclic_undo(g))};const updateSourceGraph=(graph,g)=>{for(const node of graph.nodes.values()){const label=node.label;if(label){const v=node.v;const layoutLabel=g.node(v).label;label.x=layoutLabel.x;label.y=layoutLabel.y;if(g.children(v).length){label.width=layoutLabel.width;label.height=layoutLabel.height}}}for(const e of graph.edges.values()){const label=g.edge(e.v,e.w).label;e.label.points=label.points;if("x"in label){e.label.x=label.x;e.label.y=label.y}}graph.state=graph.state||{};graph.state.width=g.state.width;graph.state.height=g.state.height};time("layout",()=>{const layoutGraph=time(" buildLayoutGraph",()=>buildLayoutGraph(graph));time(" runLayout",()=>runLayout(layoutGraph,time));time(" updateSourceGraph",()=>updateSourceGraph(graph,layoutGraph))})};dagre.Graph=class{constructor(layout){layout=layout||{};this._directed="directed"in layout?layout.directed:true;this._compound="compound"in layout?layout.compound:false;this.state={};this.layout={};this._defaultNodeLabelFn=()=>{return undefined};this.nodes=new Map;this.edges=new Map;if(this._compound){this._parent={};this._children={};this._children["\0"]={}}}isDirected(){return this._directed}isCompound(){return this._compound}setDefaultNodeLabel(newDefault){this._defaultNodeLabelFn=newDefault}setNode(v,label){const node=this.nodes.get(v);if(node){if(label){node.label=label}}else{const node={label:label?label:this._defaultNodeLabelFn(v),in:[],out:[],predecessors:{},successors:{},v:v};this.nodes.set(v,node);if(this._compound){this._parent[v]="\0";this._children[v]={};this._children["\0"][v]=true}}}node(v){return this.nodes.get(v)}hasNode(v){return this.nodes.has(v)}removeNode(v){const node=this.nodes.get(v);if(node){if(this._compound){delete this._children[this._parent[v]][v];delete this._parent[v];for(const child of this.children(v)){this.setParent(child)}delete this._children[v]}for(const edge of node.in){this.removeEdge(edge)}for(const edge of node.out){this.removeEdge(edge)}this.nodes.delete(v)}}setParent(v,parent){if(!this._compound){throw new Error("Cannot set parent in a non-compound graph")}if(parent){for(let ancestor=parent;ancestor!==undefined;ancestor=this.parent(ancestor)){if(ancestor===v){throw new Error("Setting "+parent+" as parent of "+v+" would create a cycle.")}}this.setNode(parent)}else{parent="\0"}delete this._children[this._parent[v]][v];this._parent[v]=parent;this._children[parent][v]=true}parent(v){if(this._compound){const parent=this._parent[v];if(parent!=="\0"){return parent}}return null}children(v){if(this._compound){return Object.keys(this._children[v===undefined?"\0":v])}else if(v===undefined){return this.nodes.keys()}else if(this.hasNode(v)){return[]}return null}predecessors(v){return Object.keys(this.nodes.get(v).predecessors)}successors(v){return Object.keys(this.nodes.get(v).successors)}neighbors(v){return Array.from(new Set(this.predecessors(v).concat(this.successors(v))))}edge(v,w){return this.edges.get(this._edgeKey(this._directed,v,w))}setEdge(v,w,label,name){const key=this._edgeKey(this._directed,v,w,name);const edge=this.edges.get(key);if(edge){edge.label=label}else{if(!this._directed&&v>w){const tmp=v;v=w;w=tmp}const edge={label:label,v:v,w:w,name:name,key:key,vNode:null,wNode:null};this.edges.set(key,edge);this.setNode(v);this.setNode(w);const wNode=this.nodes.get(w);const vNode=this.nodes.get(v);edge.wNode=wNode;edge.vNode=vNode;const incrementOrInitEntry=(map,k)=>{if(map[k]){map[k]++}else{map[k]=1}};incrementOrInitEntry(wNode.predecessors,v);incrementOrInitEntry(vNode.successors,w);wNode.in.push(edge);vNode.out.push(edge)}}removeEdge(edge){const key=edge.key;const v=edge.v;const w=edge.w;const decrementOrRemoveEntry=(map,k)=>{if(!--map[k]){delete map[k]}};const wNode=edge.wNode;const vNode=edge.vNode;decrementOrRemoveEntry(wNode.predecessors,v);decrementOrRemoveEntry(vNode.successors,w);wNode.in=wNode.in.filter(edge=>edge.key!==key);vNode.out=vNode.out.filter(edge=>edge.key!==key);this.edges.delete(key)}_edgeKey(isDirected,v,w,name){if(!isDirected&&v>w){return name?w+":"+v+":"+name:w+":"+v+":"}return name?v+":"+w+":"+name:v+":"+w+":"}toString(){return["[nodes]",Array.from(this.nodes.values()).map(n=>JSON.stringify(n.label)).join("\n"),"[edges]",Array.from(this.edges.values()).map(e=>JSON.stringify(e.label)).join("\n"),"[parents]",JSON.stringify(this._parent,null,2),"[children]",JSON.stringify(this._children,null,2)].join("\n")}};if(typeof window!=="undefined"&&typeof window==="object"){window.dagre=dagre}if(typeof module!=="undefined"&&typeof module.exports==="object"){module.exports=dagre} |