AIManage/public/onnx/onnx_view/grapher.js

1 line
18 KiB
JavaScript
Raw Normal View History

2024-06-06 22:17:58 +08:00
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(no