var grapher=grapher||{};var dagre=window.dagre;grapher.Graph=class{constructor(compound,layout){this._layout=layout;this._isCompound=compound;this._nodes=new Map;this._edges=new Map;this._children={};this._children["\0"]={};this._parent={}}setNode(node){const key=node.name;const value=this._nodes.get(key);if(value){value.label=node}else{this._nodes.set(key,{v:key,label:node});if(this._isCompound){this._parent[key]="\0";this._children[key]={};this._children["\0"][key]=true}}}setEdge(edge){if(!this._nodes.has(edge.v)){throw new grapher.Error("Invalid edge '"+JSON.stringify(edge.v)+"'.")}if(!this._nodes.has(edge.w)){throw new grapher.Error("Invalid edge '"+JSON.stringify(edge.w)+"'.")}const key=edge.v+":"+edge.w;if(!this._edges.has(key)){this._edges.set(key,{v:edge.v,w:edge.w,label:edge})}}setParent(node,parent){if(!this._isCompound){throw new Error("Cannot set parent in a non-compound graph")}parent+="";for(let ancestor=parent;ancestor;ancestor=this.parent(ancestor)){if(ancestor===node){throw new Error("Setting "+parent+" as parent of "+node+" would create a cycle")}}delete this._children[this._parent[node]][node];this._parent[node]=parent;this._children[parent][node]=true;return this}get nodes(){return this._nodes}hasNode(key){return this._nodes.has(key)}node(key){return this._nodes.get(key)}get edges(){return this._edges}parent(key){if(this._isCompound){const parent=this._parent[key];if(parent!=="\0"){return parent}}return null}children(key){key=key===undefined?"\0":key;if(this._isCompound){const children=this._children[key];if(children){return Object.keys(children)}}else if(key==="\0"){return this.nodes.keys()}else if(this.hasNode(key)){return[]}return null}build(document,origin){const createGroup=name=>{const element=document.createElementNS("http://www.w3.org/2000/svg","g");element.setAttribute("id",name);element.setAttribute("class",name);origin.appendChild(element);return element};const clusterGroup=createGroup("clusters");const edgePathGroup=createGroup("edge-paths");const edgeLabelGroup=createGroup("edge-labels");const nodeGroup=createGroup("nodes");const edgePathGroupDefs=document.createElementNS("http://www.w3.org/2000/svg","defs");edgePathGroup.appendChild(edgePathGroupDefs);const marker=id=>{const element=document.createElementNS("http://www.w3.org/2000/svg","marker");element.setAttribute("id",id);element.setAttribute("viewBox","0 0 10 10");element.setAttribute("refX",9);element.setAttribute("refY",5);element.setAttribute("markerUnits","strokeWidth");element.setAttribute("markerWidth",8);element.setAttribute("markerHeight",6);element.setAttribute("orient","auto");const markerPath=document.createElementNS("http://www.w3.org/2000/svg","path");markerPath.setAttribute("d","M 0 0 L 10 5 L 0 10 L 4 5 z");markerPath.style.setProperty("stroke-width",1);element.appendChild(markerPath);return element};edgePathGroupDefs.appendChild(marker("arrowhead"));edgePathGroupDefs.appendChild(marker("arrowhead-select"));edgePathGroupDefs.appendChild(marker("arrowhead-hover"));for(const nodeId of this.nodes.keys()){const entry=this.node(nodeId);const node=entry.label;if(this.children(nodeId).length==0){node.build(document,nodeGroup)}else{node.rectangle=document.createElementNS("http://www.w3.org/2000/svg","rect");if(node.rx){node.rectangle.setAttribute("rx",entry.rx)}if(node.ry){node.rectangle.setAttribute("ry",entry.ry)}node.element=document.createElementNS("http://www.w3.org/2000/svg","g");node.element.setAttribute("class","cluster");node.element.appendChild(node.rectangle);clusterGroup.appendChild(node.element)}}for(const edge of this.edges.values()){edge.label.build(document,edgePathGroup,edgeLabelGroup)}}measure(){for(const key of this.nodes.keys()){const entry=this.node(key);if(this.children(key).length==0){const node=entry.label;node.measure()}}}layout(){dagre.layout(this,this._layout);for(const key of this.nodes.keys()){const entry=this.node(key);if(this.children(key).length==0){const node=entry.label;node.layout()}}}update(){for(const nodeId of this.nodes.keys()){if(this.children(nodeId).length==0){const entry=this.node(nodeId);const node=entry.label;node.update()}else{const entry=this.node(nodeId);const node=entry.label;node.element.setAttribute("transform","translate("+node.x+","+node.y+")");node.rectangle.setAttribute("x",-node.width/2);node.rectangle.setAttribute("y",-node.height/2);node.rectangle.setAttribute("width",node.width);node.rectangle.setAttribute("height",node.height)}}for(const edge of this.edges.values()){edge.label.update()}}};grapher.Node=class{constructor(){this._blocks=[]}header(){const block=new grapher.Node.Header;this._blocks.push(block);return block}list(){const block=new grapher.Node.List;this._blocks.push(block);return block}canvas(){const block=new grapher.Node.Canvas;this._blocks.push(block);return block}build(document,parent){this.element=document.createElementNS("http://www.w3.org/2000/svg","g");if(this.id){this.element.setAttribute("id",this.id)}this.element.setAttribute("class",this.class?"node "+this.class:"node");this.element.style.opacity=0;parent.appendChild(this.element);this.border=document.createElementNS("http://www.w3.org/2000/svg","path");this.border.setAttribute("class","node node-border");for(let i=0;iblock.width));for(const block of this._blocks){block.width=this.width}}layout(){let y=0;for(const block of this._blocks){block.x=0;block.y=y;block.width=this.width;block.layout();y+=block.height}}update(){for(const block of this._blocks){block.update()}this.border.setAttribute("d",grapher.Node.roundedRect(0,0,this.width,this.height,true,true,true,true));this.element.setAttribute("transform","translate("+(this.x-this.width/2)+","+(this.y-this.height/2)+")");this.element.style.removeProperty("opacity")}select(){if(this.element){this.element.classList.add("select");return[this.element]}return[]}deselect(){if(this.element){this.element.classList.remove("select")}}static roundedRect(x,y,width,height,r1,r2,r3,r4){const radius=5;r1=r1?radius:0;r2=r2?radius:0;r3=r3?radius:0;r4=r4?radius:0;return"M"+(x+r1)+","+y+"h"+(width-r1-r2)+"a"+r2+","+r2+" 0 0 1 "+r2+","+r2+"v"+(height-r2-r3)+"a"+r3+","+r3+" 0 0 1 "+-r3+","+r3+"h"+(r3+r4-width)+"a"+r4+","+r4+" 0 0 1 "+-r4+","+-r4+"v"+(-height+r4+r1)+"a"+r1+","+r1+" 0 0 1 "+r1+","+-r1+"z"}};grapher.Node.Header=class{constructor(){this._entries=[]}add(id,classList,content,tooltip,handler){const entry=new grapher.Node.Header.Entry(id,classList,content,tooltip,handler);this._entries.push(entry);return entry}build(document,parent){this._document=document;for(const entry of this._entries){entry.build(document,parent)}if(!this.first){this.line=document.createElementNS("http://www.w3.org/2000/svg","line");parent.appendChild(this.line)}for(let i=0;i=0;i--){const entry=this._entries[i];if(i>0){x-=entry.width;entry.x=x}else{entry.x=0;entry.width=x}}}update(){for(let i=0;i{e.stopPropagation();this.emit("click")})}if(this.tooltip){const title=document.createElementNS("http://www.w3.org/2000/svg","title");title.textContent=this.tooltip;this.element.appendChild(title)}this.text.textContent=this.content||" "}measure(){const yPadding=4;const xPadding=7;const boundingBox=this.text.getBBox();this.width=boundingBox.width+xPadding+xPadding;this.height=boundingBox.height+yPadding+yPadding;this.tx=xPadding;this.ty=yPadding-boundingBox.y}layout(){}};grapher.Node.List=class{constructor(){this._items=[];this._events={}}add(name,value,tooltip,separator){const item=new grapher.Node.List.Item(name,value,tooltip,separator);this._items.push(item);return item}on(event,callback){this._events[event]=this._events[event]||[];this._events[event].push(callback)}emit(event,data){if(this._events&&this._events[event]){for(const callback of this._events[event]){callback(this,data)}}}build(document,parent){this._document=document;this.element=document.createElementNS("http://www.w3.org/2000/svg","g");this.element.setAttribute("class","node-attribute-list");if(this._events.click){this.element.addEventListener("click",e=>{e.stopPropagation();this.emit("click")})}this.background=document.createElementNS("http://www.w3.org/2000/svg","path");this.element.appendChild(this.background);parent.appendChild(this.element);for(const item of this._items){const group=document.createElementNS("http://www.w3.org/2000/svg","g");group.setAttribute("class","node-attribute");const text=document.createElementNS("http://www.w3.org/2000/svg","text");text.setAttribute("xml:space","preserve");if(item.tooltip){const title=document.createElementNS("http://www.w3.org/2000/svg","title");title.textContent=item.tooltip;text.appendChild(title)}const colon=item.type==="node"||item.type==="node[]";const name=document.createElementNS("http://www.w3.org/2000/svg","tspan");name.textContent=colon?item.name+":":item.name;if(item.separator.trim()!=="="&&!colon){name.style.fontWeight="bold"}text.appendChild(name);group.appendChild(text);this.element.appendChild(group);item.group=group;item.text=text;if(item.type==="node"){const node=item.value;node.build(document,item.group)}else if(item.type==="node[]"){for(const node of item.value){node.build(document,item.group)}}else{const tspan=document.createElementNS("http://www.w3.org/2000/svg","tspan");tspan.textContent=item.separator+item.value;item.text.appendChild(tspan)}}if(!this.first){this.line=document.createElementNS("http://www.w3.org/2000/svg","line");this.line.setAttribute("class","node");this.element.appendChild(this.line)}}measure(){this.width=75;this.height=3;const yPadding=1;const xPadding=6;for(let i=0;ivalue instanceof grapher.Node)){this.type="node[]"}}};grapher.Node.Canvas=class{constructor(){this.width=0;this.height=80}build(){}update(){}};grapher.Edge=class{constructor(from,to){this.from=from;this.to=to}build(document,edgePathGroupElement,edgeLabelGroupElement){const createElement=name=>{return document.createElementNS("http://www.w3.org/2000/svg",name)};this.element=createElement("path");if(this.id){this.element.setAttribute("id",this.id)}this.element.setAttribute("class",this.class?"edge-path "+this.class:"edge-path");edgePathGroupElement.appendChild(this.element);this.hitTest=createElement("path");this.hitTest.setAttribute("class","edge-path-hit-test");this.hitTest.addEventListener("pointerover",()=>this.emit("pointerover"));this.hitTest.addEventListener("pointerleave",()=>this.emit("pointerleave"));this.hitTest.addEventListener("click",()=>this.emit("click"));edgePathGroupElement.appendChild(this.hitTest);if(this.label){const tspan=createElement("tspan");tspan.setAttribute("xml:space","preserve");tspan.setAttribute("dy","1em");tspan.setAttribute("x","1");tspan.appendChild(document.createTextNode(this.label));this.labelElement=createElement("text");this.labelElement.appendChild(tspan);this.labelElement.style.opacity=0;this.labelElement.setAttribute("class","edge-label");if(this.id){this.labelElement.setAttribute("id","edge-label-"+this.id)}edgeLabelGroupElement.appendChild(this.labelElement);const edgeBox=this.labelElement.getBBox();this.width=edgeBox.width;this.height=edgeBox.height}}update(){const intersectRect=(node,point)=>{const x=node.x;const y=node.y;const dx=point.x-x;const dy=point.y-y;let h=node.height/2;let w=node.width/2;if(Math.abs(dy)*w>Math.abs(dx)*h){if(dy<0){h=-h}return{x:x+(dy===0?0:h*dx/dy),y:y+h}}if(dx<0){w=-w}return{x:x+w,y:y+(dx===0?0:w*dy/dx)}};const curvePath=(edge,tail,head)=>{const points=edge.points.slice(1,edge.points.length-1);points.unshift(intersectRect(tail,points[0]));points.push(intersectRect(head,points[points.length-1]));return new grapher.Edge.Curve(points).path.data};const edgePath=curvePath(this,this.from,this.to);this.element.setAttribute("d",edgePath);this.hitTest.setAttribute("d",edgePath);if(this.labelElement){this.labelElement.setAttribute("transform","translate("+(this.x-this.width/2)+","+(this.y-this.height/2)+")");this.labelElement.style.opacity=1}}select(){if(this.element){if(!this.element.classList.contains("select")){const path=this.element;path.classList.add("select");this.element=path.cloneNode(true);path.parentNode.replaceChild(this.element,path)}return[this.element]}return[]}deselect(){if(this.element&&this.element.classList.contains("select")){const path=this.element;path.classList.remove("select");this.element=path.cloneNode(true);path.parentNode.replaceChild(this.element,path)}}};grapher.Edge.Curve=class{constructor(points){this._path=new grapher.Edge.Path;this._x0=NaN;this._x1=NaN;this._y0=NaN;this._y1=NaN;this._state=0;for(let i=0;i