@html-graph/html-graph 0.0.48 → 0.0.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.umd.cjs CHANGED
@@ -1 +1 @@
1
- (function(v,w){typeof exports=="object"&&typeof module<"u"?w(exports):typeof define=="function"&&define.amd?define(["exports"],w):(v=typeof globalThis<"u"?globalThis:v||self,w(v.HTMLGraph={}))})(this,function(v){"use strict";var nt=Object.defineProperty;var st=(v,w,$)=>w in v?nt(v,w,{enumerable:!0,configurable:!0,writable:!0,value:$}):v[w]=$;var r=(v,w,$)=>st(v,typeof w!="symbol"?w+"":w,$);class w{constructor(t,e,o,n,i){r(this,"canvasWrapper",null);r(this,"host");r(this,"nodesContainer");r(this,"connectionsContainer");r(this,"canvas");r(this,"canvasCtx");r(this,"hostResizeObserver");r(this,"nodesResizeObserver");r(this,"nodeElementToIdMap",new Map);r(this,"nodeWrapperElementToIdMap",new Map);r(this,"nodeIdToWrapperElementMap",new Map);r(this,"connectionIdToElementMap",new Map);r(this,"currentZIndex",0);r(this,"layers",{"connections-on-top":{create:()=>{this.host.appendChild(this.nodesContainer),this.host.appendChild(this.connectionsContainer)},update:(t,e,o)=>{this.nodesContainer.style.transform=`matrix(${t}, 0, 0, ${t}, ${e}, ${o})`,this.connectionsContainer.style.transform=`matrix(${t}, 0, 0, ${t}, ${e}, ${o})`},moveOnTop:t=>{this.currentZIndex+=1;const e=this.nodeIdToWrapperElementMap.get(t);e.style.zIndex=`${this.currentZIndex}`}},"connections-follow-node":{create:()=>{this.host.appendChild(this.nodesContainer),this.connectionsContainer=this.nodesContainer},update:(t,e,o)=>{this.nodesContainer.style.transform=`matrix(${t}, 0, 0, ${t}, ${e}, ${o})`},moveOnTop:t=>{const e=this.nodeIdToWrapperElementMap.get(t);this.currentZIndex+=2,e.style.zIndex=`${this.currentZIndex}`,this.graphStore.getNodeAdjacentConnections(t).forEach(n=>{this.connectionIdToElementMap.get(n).style.zIndex=`${this.currentZIndex-1}`})}},"nodes-on-top":{create:()=>{this.host.appendChild(this.connectionsContainer),this.host.appendChild(this.nodesContainer)},update:(t,e,o)=>{this.nodesContainer.style.transform=`matrix(${t}, 0, 0, ${t}, ${e}, ${o})`,this.connectionsContainer.style.transform=`matrix(${t}, 0, 0, ${t}, ${e}, ${o})`},moveOnTop:t=>{this.currentZIndex+=1;const e=this.nodeIdToWrapperElementMap.get(t);e.style.zIndex=`${this.currentZIndex}`}}});this.graphStore=t,this.viewportTransformer=e,this.publicViewportTransformer=o,this.layersMode=n,this.backgroundDrawingFn=i,this.host=this.createHost(),this.canvas=this.createCanvas(),this.nodesContainer=this.createNodesContainer(),this.connectionsContainer=this.createConnectionsContainer();const h=this.canvas.getContext("2d");if(h===null)throw new Error("unable to get canvas context");this.canvasCtx=h,this.host.appendChild(this.canvas),this.layers[this.layersMode].create(),this.hostResizeObserver=this.createHostResizeObserver(),this.hostResizeObserver.observe(this.host),this.nodesResizeObserver=this.createNodesResizeObserver()}clear(){Array.from(this.connectionIdToElementMap.keys()).forEach(t=>{this.detachConnection(t)}),Array.from(this.nodeElementToIdMap.values()).forEach(t=>{this.detachNode(t)})}attach(t){this.canvasWrapper=t,this.canvasWrapper.appendChild(this.host)}detach(){this.canvasWrapper!==null&&(this.canvasWrapper.removeChild(this.host),this.canvasWrapper=null)}destroy(){this.hostResizeObserver.disconnect(),this.nodesResizeObserver.disconnect(),this.host.removeChild(this.canvas),this.host.removeChild(this.connectionsContainer),this.host.removeChild(this.nodesContainer),this.canvasWrapper!==null&&(this.canvasWrapper.removeChild(this.host),this.canvasWrapper=null)}applyTransform(){this.backgroundDrawingFn(this.canvasCtx,this.publicViewportTransformer);const[t,e]=this.viewportTransformer.getViewCoords(0,0),o=this.viewportTransformer.getViewScale();this.layers[this.layersMode].update(o,t,e)}attachNode(t){const e=this.graphStore.getNode(t),o=document.createElement("div");o.appendChild(e.element),o.style.position="absolute",o.style.top="0",o.style.left="0",o.style.zIndex=`${this.currentZIndex}`,this.currentZIndex+=1,o.style.visibility="hidden",this.nodesContainer.appendChild(o),this.nodeElementToIdMap.set(e.element,t),this.nodeWrapperElementToIdMap.set(o,t),this.nodeIdToWrapperElementMap.set(t,o),this.updateNodeCoords(t,e.x,e.y),this.nodesResizeObserver.observe(o),o.style.visibility="visible"}detachNode(t){const e=this.graphStore.getNode(t);this.nodesResizeObserver.unobserve(e.element),this.nodesContainer.removeChild(e.element);const o=this.nodeIdToWrapperElementMap.get(t);o.removeChild(e.element),this.nodeElementToIdMap.delete(e.element),this.nodeWrapperElementToIdMap.delete(o),this.nodeIdToWrapperElementMap.delete(t)}attachConnection(t){const o=this.graphStore.getConnection(t).controller.svg;o.style.transformOrigin="50% 50%",o.style.position="absolute",o.style.top="0",o.style.left="0",o.style.zIndex=`${this.currentZIndex}`,this.currentZIndex+=1,this.connectionIdToElementMap.set(t,o),this.updateConnectionCoords(t),this.connectionsContainer.appendChild(o)}detachConnection(t){const e=this.connectionIdToElementMap.get(t);this.connectionIdToElementMap.delete(t),this.connectionsContainer.removeChild(e)}moveNodeOnTop(t){this.layers[this.layersMode].moveOnTop(t)}updateNodeCoordinates(t){const e=this.graphStore.getNode(t),o=this.graphStore.getNodeAdjacentConnections(t);this.updateNodeCoords(t,e.x,e.y),o.forEach(n=>{this.updateConnectionCoords(n)})}updatePortConnections(t){this.graphStore.getPortAdjacentConnections(t).forEach(o=>{this.updateConnectionCoords(o)})}getViewportDimensions(){const t=this.host.getBoundingClientRect();return[t.width,t.height]}createHost(){const t=document.createElement("div");return t.style.width="100%",t.style.height="100%",t.style.position="relative",t.style.overflow="hidden",t}createCanvas(){const t=document.createElement("canvas");return t.style.position="absolute",t.style.inset="0",t}createNodesContainer(){const t=document.createElement("div");return t.style.position="absolute",t.style.top="0",t.style.left="0",t.style.width="0",t.style.height="0",t}createConnectionsContainer(){const t=document.createElement("div");return t.style.position="absolute",t.style.pointerEvents="none",t.style.top="0",t.style.left="0",t.style.width="0",t.style.height="0",t}createHostResizeObserver(){return new ResizeObserver(()=>{this.updateCanvasDimensions(),this.applyTransform()})}createNodesResizeObserver(){return new ResizeObserver(t=>{t.forEach(e=>{const o=e.target,n=this.nodeWrapperElementToIdMap.get(o),i=this.graphStore.getNode(n);this.updateNodeCoords(n,i.x,i.y),this.graphStore.getNodeAdjacentConnections(n).forEach(a=>{this.updateConnectionCoords(a)})})})}updateCanvasDimensions(){const{width:t,height:e}=this.host.getBoundingClientRect();this.canvas.width=t,this.canvas.height=e}updateNodeCoords(t,e,o){const n=this.nodeIdToWrapperElementMap.get(t),{width:i,height:h}=n.getBoundingClientRect(),a=this.viewportTransformer.getAbsScale(),c=this.graphStore.getNode(t),[l,g]=c.centerFn(i,h);n.style.transform=`matrix(1, 0, 0, 1, ${e-a*l}, ${o-a*g})`}updateConnectionCoords(t){const e=this.graphStore.getConnection(t),o=this.graphStore.getPort(e.from),n=this.graphStore.getPort(e.to),i=o.element.getBoundingClientRect(),h=n.element.getBoundingClientRect(),a=this.host.getBoundingClientRect(),[c,l]=this.viewportTransformer.getAbsCoords(i.left-a.left,i.top-a.top),[g,d]=this.viewportTransformer.getAbsCoords(h.left-a.left,h.top-a.top),m=this.viewportTransformer.getAbsScale(),[u,p]=o.centerFn(i.width*m,i.height*m),[f,y]=n.centerFn(h.width*m,h.height*m),S=u+c,N=p+l,E=f+g,b=y+d,T=Math.min(S,E),A=Math.min(N,b),P=Math.abs(E-S),I=Math.abs(b-N),tt=this.connectionIdToElementMap.get(t),et=S<=E,ot=N<=b;tt.style.transform=`matrix(${et?1:-1}, 0, 0, ${ot?1:-1}, ${T}, ${A})`,e.controller.update(T,A,P,I,o,n)}}class ${constructor(){r(this,"state",{scale:1,x:0,y:0})}getViewCoords(t,e){return[(t-this.state.x)/this.state.scale,(e-this.state.y)/this.state.scale]}getViewScale(){return 1/this.state.scale}getAbsCoords(t,e){return[t*this.state.scale+this.state.x,e*this.state.scale+this.state.y]}getAbsScale(){return this.state.scale}patchState(t,e,o){this.state={scale:t??this.state.scale,x:e??this.state.x,y:o??this.state.y}}}class z{constructor(t){this.transformer=t}getViewCoords(t,e){return this.transformer.getViewCoords(t,e)}getViewScale(){return this.transformer.getViewScale()}getAbsCoords(t,e){return this.transformer.getAbsCoords(t,e)}getAbsScale(){return this.transformer.getAbsScale()}}class B{constructor(){r(this,"nodes",Object.create(null));r(this,"ports",Object.create(null));r(this,"nodePorts",Object.create(null));r(this,"portNodeId",Object.create(null));r(this,"connections",Object.create(null));r(this,"incommingConnections",Object.create(null));r(this,"outcommingConnections",Object.create(null));r(this,"cycleConnections",Object.create(null))}getAllNodes(){return this.nodes}addNode(t,e,o,n,i){this.nodes[t]={element:e,x:o,y:n,centerFn:i},this.nodePorts[t]=Object.create(null)}hasNode(t){return this.nodes[t]!==void 0}getNode(t){return this.nodes[t]}updateNodeCoords(t,e,o){this.nodes[t].x=e,this.nodes[t].y=o}updateConnectionController(t,e){this.connections[t].controller=e}removeNode(t){this.getNodeAdjacentConnections(t).forEach(n=>{this.removeConnection(n)}),delete this.nodes[t];const o=this.nodePorts[t];Object.keys(o).forEach(n=>{delete this.portNodeId[n]}),delete this.nodePorts[t]}addPort(t,e,o,n,i){this.ports[t]={element:e,centerFn:n,direction:i},this.cycleConnections[t]={},this.incommingConnections[t]={},this.outcommingConnections[t]={},this.portNodeId[t]=o;const h=this.nodePorts[o];h!==void 0&&(h[t]=e)}getPort(t){return this.ports[t]}getPortNode(t){return this.portNodeId[t]}hasPort(t){return this.portNodeId[t]!==void 0}removePort(t){Object.keys(this.cycleConnections[t]).forEach(n=>{this.removeConnection(n)}),delete this.cycleConnections[t],Object.keys(this.incommingConnections[t]).forEach(n=>{this.removeConnection(n)}),delete this.incommingConnections[t],Object.keys(this.outcommingConnections[t]).forEach(n=>{this.removeConnection(n)}),delete this.outcommingConnections[t];const e=this.portNodeId[t];delete this.portNodeId[t];const o=this.nodePorts[e];delete o[t],delete this.ports[t]}addConnection(t,e,o,n){this.connections[t]={from:e,to:o,controller:n},e!==o?(this.outcommingConnections[e][t]=!0,this.incommingConnections[o][t]=!0):this.cycleConnections[e][t]=!0}getConnection(t){return this.connections[t]}hasConnection(t){return this.connections[t]!==void 0}removeConnection(t){const e=this.connections[t],o=e.from,n=e.to;delete this.cycleConnections[o][t],delete this.cycleConnections[n][t],delete this.incommingConnections[o][t],delete this.incommingConnections[n][t],delete this.outcommingConnections[o][t],delete this.outcommingConnections[n][t],delete this.connections[t]}getPortAdjacentConnections(t){return[...this.getPortIncomingConnections(t),...this.getPortOutcomingConnections(t),...this.getPortCycleConnections(t)]}getNodeAdjacentConnections(t){return[...this.getNodeIncomingConnections(t),...this.getNodeOutcomingConnections(t),...this.getNodeCycleConnections(t)]}clear(){this.nodes=Object.create(null),this.ports=Object.create(null),this.nodePorts=Object.create(null),this.portNodeId=Object.create(null),this.connections=Object.create(null),this.incommingConnections=Object.create(null),this.outcommingConnections=Object.create(null),this.cycleConnections=Object.create(null)}getPortIncomingConnections(t){return Object.keys(this.incommingConnections[t]??{})}getPortOutcomingConnections(t){return Object.keys(this.outcommingConnections[t]??{})}getPortCycleConnections(t){return Object.keys(this.cycleConnections[t]??{})}getNodeIncomingConnections(t){const e=Object.keys(this.nodePorts[t]);let o=[];return e.forEach(n=>{o=[...o,...this.getPortIncomingConnections(n)]}),o}getNodeOutcomingConnections(t){const e=Object.keys(this.nodePorts[t]);let o=[];return e.forEach(n=>{o=[...o,...this.getPortOutcomingConnections(n)]}),o}getNodeCycleConnections(t){const e=Object.keys(this.nodePorts[t]);let o=[];return e.forEach(n=>{o=[...o,...this.getPortCycleConnections(n)]}),o}}class G{constructor(t){this.graphStore=t}getNode(t){const e=this.graphStore.getNode(t);return e===void 0?null:{x:e.x,y:e.y,element:e.element}}getNodes(t){const e=Object.entries(this.graphStore.getAllNodes()).map(([o,n])=>({id:o,x:n.x,y:n.y,element:n.element}));if(t!==void 0){const o=new Set;return t.forEach(n=>{o.add(n)}),e.filter(n=>o.has(n.id))}return e}}class C{static getPortCenter(t){const{top:e,left:o,width:n,height:i}=t.element.getBoundingClientRect(),h=t.centerFn(n,i);return[o+h[0],e+h[1]]}static rotate(t,e,o){return[e[0]*t[0]-e[1]*t[1]+((1-e[0])*o[0]+e[1]*o[1]),e[1]*t[0]+e[0]*t[1]+((1-e[0])*o[1]-e[1]*o[0])]}static getDirectionVector(t,e,o){return[e*Math.cos(t??0),o*Math.sin(t??0)]}static getArrowPath(t,e,o,n,i){const a=[[0,0],[n,i],[n,-i]].map(d=>this.rotate(d,t,[0,0])).map(d=>[d[0]+e,d[1]+o]),c=`M ${a[0][0]} ${a[0][1]}`,l=`L ${a[1][0]} ${a[1][1]}`,g=`L ${a[2][0]} ${a[2][1]}`;return`${c} ${l} ${g}`}static getArrowOffsetPath(t,e,o,n,i){const a=[[n,0],[n+i,0]].map(c=>this.rotate(c,t,[0,0])).map(c=>[c[0]+e,c[1]+o]);return`M ${a[0][0]} ${a[0][1]} L ${a[1][0]} ${a[1][1]}`}}class x{constructor(t,e,o,n,i,h,a){r(this,"svg");r(this,"group");r(this,"line");r(this,"sourceArrow",null);r(this,"targetArrow",null);this.color=t,this.width=e,this.curvature=o,this.arrowLength=n,this.arrowWidth=i,this.hasSourceArrow=h,this.hasTargetArrow=a,this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.pointerEvents="none",this.group=document.createElementNS("http://www.w3.org/2000/svg","g"),this.svg.appendChild(this.group),this.line=document.createElementNS("http://www.w3.org/2000/svg","path"),this.line.setAttribute("stroke",this.color),this.line.setAttribute("stroke-width",`${this.width}`),this.line.setAttribute("fill","none"),this.group.appendChild(this.line),this.group.style.transformOrigin="50% 50%",this.hasSourceArrow&&(this.sourceArrow=document.createElementNS("http://www.w3.org/2000/svg","path"),this.sourceArrow.setAttribute("fill",this.color),this.group.appendChild(this.sourceArrow)),this.hasTargetArrow&&(this.targetArrow=document.createElementNS("http://www.w3.org/2000/svg","path"),this.targetArrow.setAttribute("fill",this.color),this.group.appendChild(this.targetArrow)),this.svg.style.overflow="visible"}update(t,e,o,n,i,h){this.svg.style.width=`${o}px`,this.svg.style.height=`${n}px`;const a=C.getPortCenter(i),c=C.getPortCenter(h),l=a[0]<=c[0]?1:-1,g=a[1]<=c[1]?1:-1;this.svg.style.transform=`translate(${t}px, ${e}px)`,this.group.style.transform=`scale(${l}, ${g})`;const d=C.getDirectionVector(i.direction,l,g),m=C.getDirectionVector(h.direction,l,g),u=C.rotate([this.arrowLength,0],d,[0,0]),p=C.rotate([o-this.arrowLength,n],m,[o,n]),f=[u[0]+d[0]*this.curvature,u[1]+d[1]*this.curvature],y=[p[0]-m[0]*this.curvature,p[1]-m[1]*this.curvature],S=`M ${u[0]} ${u[1]}`,N=`C ${f[0]} ${f[1]}, ${y[0]} ${y[1]}, ${p[0]} ${p[1]}`,E=`M 0 0 L ${u[0]} ${u[1]} `,b=` M ${p[0]} ${p[1]} L ${o} ${n}`,T=`${this.sourceArrow?"":E}${S} ${N}${this.targetArrow?"":b}`;if(this.line.setAttribute("d",T),this.sourceArrow){const A=C.getArrowPath(d,0,0,this.arrowLength,this.arrowWidth);this.sourceArrow.setAttribute("d",A)}if(this.targetArrow){const A=C.getArrowPath(m,o,n,-this.arrowLength,this.arrowWidth);this.targetArrow.setAttribute("d",A)}}}const L=s=>()=>new x(s.color??"#5c5c5c",s.width??1,s.curvature??90,s.arrowLength??15,s.arrowWidth??4,s.hasSourceArrow??!1,s.hasTargetArrow??!1);class V{constructor(t,e,o,n,i,h,a){r(this,"svg");r(this,"group");r(this,"line");r(this,"sourceArrow",null);r(this,"targetArrow",null);this.color=t,this.width=e,this.arrowLength=o,this.arrowWidth=n,this.minPortOffset=i,this.hasSourceArrow=h,this.hasTargetArrow=a,this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.pointerEvents="none",this.group=document.createElementNS("http://www.w3.org/2000/svg","g"),this.svg.appendChild(this.group),this.line=document.createElementNS("http://www.w3.org/2000/svg","path"),this.line.setAttribute("stroke",this.color),this.line.setAttribute("stroke-width",`${this.width}`),this.line.setAttribute("fill","none"),this.group.appendChild(this.line),this.group.style.transformOrigin="50% 50%",this.hasSourceArrow&&(this.sourceArrow=document.createElementNS("http://www.w3.org/2000/svg","path"),this.sourceArrow.setAttribute("fill",this.color),this.group.appendChild(this.sourceArrow)),this.hasTargetArrow&&(this.targetArrow=document.createElementNS("http://www.w3.org/2000/svg","path"),this.targetArrow.setAttribute("fill",this.color),this.group.appendChild(this.targetArrow)),this.svg.style.overflow="visible"}update(t,e,o,n,i,h){this.svg.style.width=`${o}px`,this.svg.style.height=`${n}px`;const a=C.getPortCenter(i),c=C.getPortCenter(h),l=a[0]<=c[0]?1:-1,g=a[1]<=c[1]?1:-1;this.svg.style.transform=`translate(${t}px, ${e}px)`,this.group.style.transform=`scale(${l}, ${g})`;const d=C.getDirectionVector(i.direction,l,g),m=C.getDirectionVector(h.direction,l,g),u=C.rotate([this.arrowLength+this.minPortOffset,0],d,[0,0]),p=C.rotate([o-this.arrowLength-this.minPortOffset,n],m,[o,n]),[f,y]=[o/2,n/2],S=l*(p[0]-u[0])>0?`M ${u[0]} ${u[1]} L ${f} ${u[1]} L ${f} ${p[1]} L ${p[0]} ${p[1]}`:`M ${u[0]} ${u[1]} L ${u[0]} ${y} L ${p[0]} ${y} L ${p[0]} ${p[1]}`,N=`M 0 0 L ${u[0]} ${u[1]} `,E=` M ${p[0]} ${p[1]} L ${o} ${n}`,b=C.getArrowOffsetPath(d,0,0,this.arrowLength,this.minPortOffset),T=C.getArrowOffsetPath(m,o,n,-this.arrowLength,-this.minPortOffset),A=`${this.sourceArrow?b:N}${S}${this.targetArrow?T:E}`;if(this.line.setAttribute("d",A),this.sourceArrow){const P=C.getArrowPath(d,0,0,this.arrowLength,this.arrowWidth);this.sourceArrow.setAttribute("d",P)}if(this.targetArrow){const P=C.getArrowPath(m,o,n,-this.arrowLength,this.arrowWidth);this.targetArrow.setAttribute("d",P)}}}const F=s=>()=>new V(s.color,s.width,s.arrowLength,s.arrowWidth,s.minPortOffset,s.hasSourceArrow,s.hasTargetArrow);var O=(s=>(s.Regular="regular",s.Cycle="cycle",s))(O||{});class M{constructor(){r(this,"counter",0)}next(){const t=`${this.counter}`;return this.counter++,t}reset(){this.counter=0}}class Y{constructor(t,e,o,n,i){r(this,"nodeIdGenerator",new M);r(this,"portIdGenerator",new M);r(this,"connectionIdGenerator",new M);this.graphStore=t,this.htmlController=e,this.viewportTransformer=o,this.nodesCenterFn=n,this.portsCenterFn=i}moveNodeOnTop(t){if(!this.graphStore.hasNode(t))throw new Error("failed to move on top nonexisting node");this.htmlController.moveNodeOnTop(t)}addNode(t,e,o,n,i,h){if(t===void 0)do t=this.nodeIdGenerator.next();while(this.graphStore.hasNode(t));if(this.graphStore.hasNode(t))throw new Error("failed to add node with existing id");this.graphStore.addNode(t,e,o,n,h??this.nodesCenterFn),this.htmlController.attachNode(t),i!==void 0&&Object.entries(i).forEach(([a,c])=>{c instanceof HTMLElement?this.markPort(a,c,t,this.portsCenterFn,null):this.markPort(a,c.element,t,c.centerFn??this.portsCenterFn,c.direction??null)})}markPort(t,e,o,n,i){if(t===void 0)do t=this.portIdGenerator.next();while(this.graphStore.hasPort(t));if(!this.graphStore.hasNode(o))throw new Error("failed to set port on nonexisting node");if(this.graphStore.hasPort(t))throw new Error("failed to add port with existing id");this.graphStore.addPort(t,e,o,n??this.portsCenterFn,i??null)}updatePortConnections(t){if(!this.graphStore.hasPort(t))throw new Error("failed to unset nonexisting port");this.htmlController.updatePortConnections(t)}unmarkPort(t){if(!this.graphStore.hasPort(t))throw new Error("failed to unset nonexisting port");this.graphStore.getPortAdjacentConnections(t).forEach(e=>{this.removeConnection(e)}),this.graphStore.removePort(t)}addConnection(t,e,o,n){if(t===void 0)do t=this.connectionIdGenerator.next();while(this.graphStore.hasConnection(t));if(!this.graphStore.hasPort(e))throw new Error("failed to add connection from nonexisting port");if(!this.graphStore.hasPort(o))throw new Error("failed to add connection to nonexisting port");this.graphStore.addConnection(t,e,o,n(O.Regular)),this.htmlController.attachConnection(t)}removeConnection(t){if(!this.graphStore.hasConnection(t))throw new Error("failed to remove nonexisting connection");this.htmlController.detachConnection(t),this.graphStore.removeConnection(t)}removeNode(t){if(!this.graphStore.hasNode(t))throw new Error("failed to remove nonexisting node");this.htmlController.detachNode(t),this.graphStore.removeNode(t)}patchViewportState(t,e,o){this.viewportTransformer.patchState(t,e,o),this.htmlController.applyTransform()}moveToNodes(t){if(t.length===0)return;const e=t.map(m=>this.graphStore.getNode(m)).filter(m=>m!==void 0);if(e.length<t.length)throw new Error("failed to move to nonexisting node");const[o,n]=e.reduce((m,u)=>[m[0]+u.x,m[1]+u.y],[0,0]),i=o/e.length,h=n/e.length,[a,c]=this.htmlController.getViewportDimensions(),l=this.viewportTransformer.getAbsScale(),g=i-l*a/2,d=h-l*c/2;this.patchViewportState(null,g,d)}updateNodeCoordinates(t,e,o){if(!this.graphStore.hasNode(t))throw new Error("failed to update coordinates of nonexisting node");this.graphStore.updateNodeCoords(t,e,o),this.htmlController.updateNodeCoordinates(t)}updateConnectionController(t,e){if(!this.graphStore.hasConnection(t))throw new Error("failed to update nonexisting connection");this.htmlController.detachConnection(t),this.graphStore.updateConnectionController(t,e),this.htmlController.attachConnection(t)}attach(t){this.htmlController.attach(t)}detach(){this.htmlController.detach()}clear(){this.htmlController.clear(),this.graphStore.clear(),this.nodeIdGenerator.reset(),this.portIdGenerator.reset(),this.connectionIdGenerator.reset()}destroy(){this.htmlController.destroy()}}class X{constructor(t,e,o,n){r(this,"publicViewportTransformer");r(this,"publicGraphStore");r(this,"canvasController");const i=new $,h=new B;this.publicViewportTransformer=new z(i),this.publicGraphStore=new G(h);const a=new w(h,i,this.publicViewportTransformer,t,e);this.canvasController=new Y(h,a,i,o,n)}}const k=(s,t)=>[s/2,t/2],Z=()=>()=>{},H=(s,t,e,o,n,i)=>{s.clearRect(0,0,s.canvas.width,s.canvas.height),s.fillStyle=i,s.fillRect(0,0,s.canvas.width,s.canvas.height);const h=t.getViewCoords(0,0),a=t.getViewScale(),c=o*a;let l=0,g=0,d=c/2;do d*=2,l=s.canvas.width/d,g=s.canvas.height/d;while(l*g>1e4);const m=h[0]-Math.floor(h[0]/d)*d,u=h[1]-Math.floor(h[1]/d)*d,p=n*a,f=2*Math.PI,y=m-d,S=u-d,N=s.canvas.width+m,E=s.canvas.height+u;s.fillStyle=e;for(let b=y;b<=N;b+=d)for(let T=S;T<=E;T+=d)s.beginPath(),s.arc(b,T,p,0,f),s.closePath(),s.fill()},U=(s,t,e,o)=>(n,i)=>{H(n,i,s,t,e,o)},J=(s,t)=>{s.fillStyle=t,s.fillRect(0,0,s.canvas.width,s.canvas.height)},K=s=>t=>{J(t,s)},Q=s=>{switch(s==null?void 0:s.type){case"custom":return s.drawingFn;case"dots":return U(s.dotColor??"#d8d8d8",s.dotGap??25,s.dotRadius??1.5,s.color??"#ffffff");case"color":return K(s.color??"#ffffff");default:return Z()}},j=s=>{switch(s==null?void 0:s.type){case"custom":return s.controllerFactory;case"straight":return F({color:s.color??"#5c5c5c",width:s.width??1,arrowLength:s.arrowLength??15,arrowWidth:s.arrowWidth??4,minPortOffset:s.minPortOffset??15,hasSourceArrow:s.hasSourceArrow??!1,hasTargetArrow:s.hasTargetArrow??!1});default:return L({color:s.color??"#5c5c5c",width:s.width??1,curvature:s.curvature??90,arrowLength:s.arrowLength??15,arrowWidth:s.arrowWidth??4,hasSourceArrow:s.hasSourceArrow??!1,hasTargetArrow:s.hasTargetArrow??!1})}},_=s=>{var t,e,o;return{background:{drawingFn:Q(s.background??{type:"none"})},nodes:{centerFn:((t=s.nodes)==null?void 0:t.centerFn)??k},ports:{centerFn:((e=s.ports)==null?void 0:e.centerFn)??k},connections:{controllerFactory:j(s.connections??{})},layers:{mode:((o=s.layers)==null?void 0:o.mode)??"connections-follow-node"}}};class D{constructor(t){r(this,"transformation");r(this,"model");r(this,"di");r(this,"connectionControllerFactory");this.apiOptions=t;const e=_(this.apiOptions??{});this.di=new X(e.layers.mode,e.background.drawingFn,e.nodes.centerFn,e.ports.centerFn),this.transformation=this.di.publicViewportTransformer,this.model=this.di.publicGraphStore,this.connectionControllerFactory=e.connections.controllerFactory}addNode(t){return this.di.canvasController.addNode(t.id,t.element,t.x,t.y,t.ports,t.centerFn),this}moveNodeOnTop(t){return this.di.canvasController.moveNodeOnTop(t),this}removeNode(t){return this.di.canvasController.removeNode(t),this}markPort(t){return this.di.canvasController.markPort(t.id,t.element,t.nodeId,t.centerFn,t.direction),this}updatePortConnections(t){return this.di.canvasController.updatePortConnections(t),this}unmarkPort(t){return this.di.canvasController.unmarkPort(t),this}addConnection(t){const e=t.options!==void 0?j(t.options):this.connectionControllerFactory;return this.di.canvasController.addConnection(t.id,t.from,t.to,e),this}removeConnection(t){return this.di.canvasController.removeConnection(t),this}patchViewportState(t){return this.di.canvasController.patchViewportState(t.scale??null,t.x??null,t.y??null),this}moveToNodes(t){return this.di.canvasController.moveToNodes(t),this}updateNodeCoordinates(t,e,o){return this.di.canvasController.updateNodeCoordinates(t,e,o),this}updateConnection(t,e){return e.controller!==void 0&&this.di.canvasController.updateConnectionController(t,e.controller),this}clear(){return this.di.canvasController.clear(),this}attach(t){return this.di.canvasController.attach(t),this}detach(){return this.di.canvasController.detach(),this}destroy(){this.di.canvasController.destroy()}}class W{constructor(t,e){r(this,"transformation");r(this,"model");r(this,"nodes",new Map);r(this,"grabbedNodeId",null);r(this,"onNodeDrag");r(this,"nodeIdGenerator",new M);r(this,"element",null);r(this,"onCanvasMouseUp",()=>{this.setCursor(null),this.grabbedNodeId=null});r(this,"onCanvasMouseMove",t=>{this.grabbedNodeId!==null&&(t.stopPropagation(),this.dragNode(this.grabbedNodeId,t.movementX,t.movementY))});r(this,"onCanvasTouchStart",t=>{this.previousTouchCoords=[t.touches[0].clientX,t.touches[0].clientY]});r(this,"onCanvasTouchMove",t=>{if(this.grabbedNodeId===null||t.touches.length!==1||this.previousTouchCoords===null)return;t.stopImmediatePropagation();const[e,o]=[t.touches[0].clientX-this.previousTouchCoords[0],t.touches[0].clientY-this.previousTouchCoords[1]];this.dragNode(this.grabbedNodeId,e,o),this.previousTouchCoords=[t.touches[0].clientX,t.touches[0].clientY]});r(this,"onCanvasTouchEnd",t=>{t.touches.length>0?this.previousTouchCoords=[t.touches[0].clientX,t.touches[0].clientY]:(this.previousTouchCoords=null,this.grabbedNodeId=null)});r(this,"previousTouchCoords",null);var o;this.canvas=t,this.transformation=this.canvas.transformation,this.model=this.canvas.model,this.onNodeDrag=((o=e==null?void 0:e.events)==null?void 0:o.onNodeDrag)??(()=>{})}addNode(t){let e=t.id;if(e===void 0)do e=this.nodeIdGenerator.next();while(this.nodes.has(e));this.canvas.addNode(t);const o=i=>{i.stopImmediatePropagation(),this.grabbedNodeId=e,this.setCursor("grab"),this.canvas.moveNodeOnTop(e)},n=i=>{i.touches.length===1&&(this.grabbedNodeId=e,this.canvas.moveNodeOnTop(e))};return this.nodes.set(e,{el:t.element,onMouseDown:o,onTouchStart:n}),t.element.addEventListener("mousedown",o),t.element.addEventListener("touchstart",n),this}removeNode(t){const e=this.nodes.get(t);return e!==void 0&&(e.el.removeEventListener("mousedown",e.onMouseDown),e.el.removeEventListener("touchstart",e.onTouchStart)),this.canvas.removeNode(t),this.nodes.delete(t),this}markPort(t){return this.canvas.markPort(t),this}updatePortConnections(t){return this.canvas.updatePortConnections(t),this}unmarkPort(t){return this.canvas.unmarkPort(t),this}addConnection(t){return this.canvas.addConnection(t),this}removeConnection(t){return this.canvas.removeConnection(t),this}patchViewportState(t){return this.canvas.patchViewportState(t),this}moveToNodes(t){return this.canvas.moveToNodes(t),this}updateNodeCoordinates(t,e,o){return this.canvas.updateNodeCoordinates(t,e,o),this}updateConnection(t,e){return this.canvas.updateConnection(t,e),this}moveNodeOnTop(t){return this.canvas.moveNodeOnTop(t),this}clear(){return this.canvas.clear(),this.nodes.forEach(t=>{t.el.removeEventListener("mousedown",t.onMouseDown),t.el.removeEventListener("touchstart",t.onTouchStart)}),this.nodes.clear(),this}attach(t){return this.canvas.attach(t),this.element=t,this.element.addEventListener("mouseup",this.onCanvasMouseUp),this.element.addEventListener("mousemove",this.onCanvasMouseMove),this.element.addEventListener("touchstart",this.onCanvasTouchStart),this.element.addEventListener("touchmove",this.onCanvasTouchMove),this.element.addEventListener("touchend",this.onCanvasTouchEnd),this.element.addEventListener("touchcancel",this.onCanvasTouchEnd),this}detach(){return this.canvas.detach(),this.element!==null&&(this.element.removeEventListener("mouseup",this.onCanvasMouseUp),this.element.removeEventListener("mousemove",this.onCanvasMouseMove),this.element.removeEventListener("touchstart",this.onCanvasTouchStart),this.element.removeEventListener("touchmove",this.onCanvasTouchMove),this.element.removeEventListener("touchend",this.onCanvasTouchEnd),this.element.removeEventListener("touchcancel",this.onCanvasTouchEnd),this.element=null),this}destroy(){this.detach(),this.nodes.forEach(t=>{t.el.removeEventListener("mousedown",t.onMouseDown),t.el.removeEventListener("touchstart",t.onTouchStart)}),this.nodes.clear(),this.canvas.destroy()}setCursor(t){this.element!==null&&(t!==null?this.element.style.cursor=t:this.element.style.removeProperty("cursor"))}dragNode(t,e,o){const n=this.model.getNode(t);if(n===null)throw new Error("failed to drag nonexisting node");const[i,h]=this.transformation.getViewCoords(n.x,n.y),a=i+e,c=h+o,[l,g]=this.transformation.getAbsCoords(a,c);this.canvas.updateNodeCoordinates(t,l,g),this.onNodeDrag(t)}}class R{constructor(t,e){r(this,"transformation");r(this,"model");r(this,"element",null);r(this,"isMoving",!1);r(this,"prevTouches",null);r(this,"onTransform");r(this,"isScalable");r(this,"isShiftable");r(this,"minViewScale");r(this,"maxViewScale");r(this,"wheelSensitivity");r(this,"onMouseDown",()=>{this.setCursor("grab"),this.isMoving=!0});r(this,"onMouseMove",t=>{if(!this.isMoving||!this.isShiftable)return;const e=-t.movementX,o=-t.movementY;this.moveViewport(e,o)});r(this,"onMouseUp",()=>{this.setCursor(null),this.isMoving=!1});r(this,"onWheelScroll",t=>{if(this.element===null||this.isScalable===!1)return;t.preventDefault();const{left:e,top:o}=this.element.getBoundingClientRect(),n=t.clientX-e,i=t.clientY-o,a=1/(t.deltaY<0?this.wheelSensitivity:1/this.wheelSensitivity);this.scaleViewport(a,n,i)});r(this,"onTouchStart",t=>{this.prevTouches=this.getAverageTouch(t)});r(this,"onTouchMove",t=>{if(this.prevTouches===null||this.element===null||!this.isShiftable)return;const e=this.getAverageTouch(t);if((e.touchesCnt===1||e.touchesCnt===2)&&this.moveViewport(-(e.x-this.prevTouches.x),-(e.y-this.prevTouches.y)),e.touchesCnt===2&&this.isScalable){const{left:o,top:n}=this.element.getBoundingClientRect(),i=this.prevTouches.x-o,h=this.prevTouches.y-n,c=1/(e.scale/this.prevTouches.scale);this.scaleViewport(c,i,h)}this.prevTouches=e,t.preventDefault()});r(this,"onTouchEnd",t=>{t.touches.length>0?this.prevTouches=this.getAverageTouch(t):this.prevTouches=null});var h,a,c,l,g,d,m,u,p,f,y;this.canvas=t,this.options=e,this.transformation=this.canvas.transformation,this.model=this.canvas.model;const o=((a=(h=this.options)==null?void 0:h.scale)==null?void 0:a.minContent)??null,n=((l=(c=this.options)==null?void 0:c.scale)==null?void 0:l.maxContent)??null;this.isScalable=((d=(g=this.options)==null?void 0:g.scale)==null?void 0:d.enabled)!==!1,this.minViewScale=n!==null?1/n:null,this.maxViewScale=o!==null?1/o:null,this.isShiftable=((u=(m=this.options)==null?void 0:m.shift)==null?void 0:u.enabled)!==!1;const i=(f=(p=this.options)==null?void 0:p.scale)==null?void 0:f.wheelSensitivity;this.wheelSensitivity=i!==void 0?i:1.2,this.onTransform=((y=e==null?void 0:e.events)==null?void 0:y.onTransform)??(()=>{})}addNode(t){return this.canvas.addNode(t),this}removeNode(t){return this.canvas.removeNode(t),this}markPort(t){return this.canvas.markPort(t),this}updatePortConnections(t){return this.canvas.updatePortConnections(t),this}unmarkPort(t){return this.canvas.unmarkPort(t),this}addConnection(t){return this.canvas.addConnection(t),this}removeConnection(t){return this.canvas.removeConnection(t),this}patchViewportState(t){return this.canvas.patchViewportState(t),this}moveToNodes(t){return this.canvas.moveToNodes(t),this}updateNodeCoordinates(t,e,o){return this.canvas.updateNodeCoordinates(t,e,o),this}updateConnection(t,e){return this.canvas.updateConnection(t,e),this}moveNodeOnTop(t){return this.canvas.moveNodeOnTop(t),this}clear(){return this.canvas.clear(),this}attach(t){return this.canvas.attach(t),this.element=t,this.element.addEventListener("mousedown",this.onMouseDown),this.element.addEventListener("mousemove",this.onMouseMove),this.element.addEventListener("mouseup",this.onMouseUp),this.element.addEventListener("wheel",this.onWheelScroll),this.element.addEventListener("touchstart",this.onTouchStart),this.element.addEventListener("touchmove",this.onTouchMove),this.element.addEventListener("touchend",this.onTouchEnd),this.element.addEventListener("touchcancel",this.onTouchEnd),this}detach(){return this.canvas.detach(),this.element!==null&&(this.element.removeEventListener("mousedown",this.onMouseDown),this.element.removeEventListener("mousemove",this.onMouseMove),this.element.removeEventListener("mouseup",this.onMouseUp),this.element.removeEventListener("wheel",this.onWheelScroll),this.element.removeEventListener("touchstart",this.onTouchStart),this.element.removeEventListener("touchmove",this.onTouchMove),this.element.removeEventListener("touchend",this.onTouchEnd),this.element.removeEventListener("touchcancel",this.onTouchEnd)),this.element=null,this}destroy(){this.detach(),this.canvas.destroy()}getAverageTouch(t){const e=[],o=t.touches.length;for(let c=0;c<o;c++)e.push([t.touches[c].clientX,t.touches[c].clientY]);const n=e.reduce((c,l)=>[c[0]+l[0],c[1]+l[1]],[0,0]),i=[n[0]/o,n[1]/o],a=e.map(c=>[c[0]-i[0],c[1]-i[1]]).reduce((c,l)=>c+Math.sqrt(l[0]*l[0]+l[1]*l[1]),0);return{x:i[0],y:i[1],scale:a/o,touchesCnt:o}}setCursor(t){this.element!==null&&(t!==null?this.element.style.cursor=t:this.element.style.removeProperty("cursor"))}moveViewport(t,e){const[o,n]=this.transformation.getAbsCoords(0,0),i=this.canvas.transformation.getAbsScale();this.canvas.patchViewportState({scale:i,x:o+i*t,y:n+i*e}),this.onTransform()}scaleViewport(t,e,o){const[n,i]=this.canvas.transformation.getAbsCoords(0,0),h=this.canvas.transformation.getAbsScale(),a=h*t,c=h*(1-t)*e+n,l=h*(1-t)*o+i;this.maxViewScale!==null&&a>this.maxViewScale&&a>h||this.minViewScale!==null&&a<this.minViewScale&&a<h||(this.canvas.patchViewportState({scale:a,x:c,y:l}),this.onTransform())}}class q{constructor(){r(this,"coreOptions");r(this,"dragOptions");r(this,"transformOptions");r(this,"isDraggable",!1);r(this,"isTransformable",!1)}setOptions(t){return this.coreOptions=t,this}setDraggableNodes(t){return this.isDraggable=!0,this.dragOptions=t,this}setTransformableCanvas(t){return this.isTransformable=!0,this.transformOptions=t,this}build(){let t=new D(this.coreOptions);return this.isDraggable&&(t=new W(t,this.dragOptions)),this.isTransformable&&(t=new R(t,this.transformOptions)),t}}v.BezierConnectionController=x,v.CanvasCore=D,v.ConnectionType=O,v.ConnectionUtils=C,v.DraggableNodesCanvas=W,v.HtmlGraphBuilder=q,v.StraightConnectionController=V,v.TransformableCanvas=R,v.createBezierConnectionControllerFactory=L,v.createStraightConnectionControllerFactory=F,Object.defineProperty(v,Symbol.toStringTag,{value:"Module"})});
1
+ (function(w,E){typeof exports=="object"&&typeof module<"u"?E(exports):typeof define=="function"&&define.amd?define(["exports"],E):(w=typeof globalThis<"u"?globalThis:w||self,E(w.HTMLGraph={}))})(this,function(w){"use strict";var rt=Object.defineProperty;var nt=(w,E,N)=>E in w?rt(w,E,{enumerable:!0,configurable:!0,writable:!0,value:N}):w[E]=N;var n=(w,E,N)=>nt(w,typeof E!="symbol"?E+"":E,N);class E{constructor(t,e,s,r,a){n(this,"canvasWrapper",null);n(this,"host");n(this,"nodesContainer");n(this,"connectionsContainer");n(this,"canvas");n(this,"canvasCtx");n(this,"hostResizeObserver");n(this,"nodesResizeObserver");n(this,"nodeElementToIdMap",new Map);n(this,"nodeWrapperElementToIdMap",new Map);n(this,"nodeIdToWrapperElementMap",new Map);n(this,"connectionIdToElementMap",new Map);n(this,"currentZIndex",0);n(this,"layers",{"edges-on-top":{create:()=>{this.host.appendChild(this.nodesContainer),this.host.appendChild(this.connectionsContainer)},update:(t,e,s)=>{this.nodesContainer.style.transform=`matrix(${t}, 0, 0, ${t}, ${e}, ${s})`,this.connectionsContainer.style.transform=`matrix(${t}, 0, 0, ${t}, ${e}, ${s})`},moveOnTop:t=>{this.currentZIndex+=1;const e=this.nodeIdToWrapperElementMap.get(t);e.style.zIndex=`${this.currentZIndex}`}},"edges-follow-node":{create:()=>{this.host.appendChild(this.nodesContainer),this.connectionsContainer=this.nodesContainer},update:(t,e,s)=>{this.nodesContainer.style.transform=`matrix(${t}, 0, 0, ${t}, ${e}, ${s})`},moveOnTop:t=>{const e=this.nodeIdToWrapperElementMap.get(t);this.currentZIndex+=2,e.style.zIndex=`${this.currentZIndex}`,this.graphStore.getNodeAdjacentConnections(t).forEach(r=>{this.connectionIdToElementMap.get(r).style.zIndex=`${this.currentZIndex-1}`})}},"nodes-on-top":{create:()=>{this.host.appendChild(this.connectionsContainer),this.host.appendChild(this.nodesContainer)},update:(t,e,s)=>{this.nodesContainer.style.transform=`matrix(${t}, 0, 0, ${t}, ${e}, ${s})`,this.connectionsContainer.style.transform=`matrix(${t}, 0, 0, ${t}, ${e}, ${s})`},moveOnTop:t=>{this.currentZIndex+=1;const e=this.nodeIdToWrapperElementMap.get(t);e.style.zIndex=`${this.currentZIndex}`}}});this.graphStore=t,this.viewportTransformer=e,this.publicViewportTransformer=s,this.layersMode=r,this.backgroundDrawingFn=a,this.host=this.createHost(),this.canvas=this.createCanvas(),this.nodesContainer=this.createNodesContainer(),this.connectionsContainer=this.createConnectionsContainer();const c=this.canvas.getContext("2d");if(c===null)throw new Error("unable to get canvas context");this.canvasCtx=c,this.host.appendChild(this.canvas),this.layers[this.layersMode].create(),this.hostResizeObserver=this.createHostResizeObserver(),this.hostResizeObserver.observe(this.host),this.nodesResizeObserver=this.createNodesResizeObserver()}clear(){Array.from(this.connectionIdToElementMap.keys()).forEach(t=>{this.detachConnection(t)}),Array.from(this.nodeElementToIdMap.values()).forEach(t=>{this.detachNode(t)})}attach(t){this.detach(),this.canvasWrapper=t,this.canvasWrapper.appendChild(this.host)}detach(){this.canvasWrapper!==null&&(this.canvasWrapper.removeChild(this.host),this.canvasWrapper=null)}destroy(){this.hostResizeObserver.disconnect(),this.nodesResizeObserver.disconnect(),this.host.removeChild(this.canvas),this.host.removeChild(this.connectionsContainer),this.host.removeChild(this.nodesContainer),this.canvasWrapper!==null&&(this.canvasWrapper.removeChild(this.host),this.canvasWrapper=null)}applyTransform(){this.backgroundDrawingFn(this.canvasCtx,this.publicViewportTransformer);const[t,e]=this.viewportTransformer.getViewCoords(0,0),s=this.viewportTransformer.getViewScale();this.layers[this.layersMode].update(s,t,e)}attachNode(t){const e=this.graphStore.getNode(t),s=document.createElement("div");s.appendChild(e.element),s.style.position="absolute",s.style.top="0",s.style.left="0",s.style.zIndex=`${this.currentZIndex}`,this.currentZIndex+=1,s.style.visibility="hidden",this.nodesContainer.appendChild(s),this.nodeElementToIdMap.set(e.element,t),this.nodeWrapperElementToIdMap.set(s,t),this.nodeIdToWrapperElementMap.set(t,s),this.updateNodeCoords(t,e.x,e.y),this.nodesResizeObserver.observe(s),s.style.visibility="visible"}detachNode(t){const e=this.graphStore.getNode(t);this.nodesResizeObserver.unobserve(e.element),this.nodesContainer.removeChild(e.element);const s=this.nodeIdToWrapperElementMap.get(t);s.removeChild(e.element),this.nodeElementToIdMap.delete(e.element),this.nodeWrapperElementToIdMap.delete(s),this.nodeIdToWrapperElementMap.delete(t)}attachConnection(t){const s=this.graphStore.getConnection(t).controller.svg;s.style.transformOrigin="50% 50%",s.style.position="absolute",s.style.top="0",s.style.left="0",s.style.zIndex=`${this.currentZIndex}`,this.currentZIndex+=1,this.connectionIdToElementMap.set(t,s),this.updateConnectionCoords(t),this.connectionsContainer.appendChild(s)}detachConnection(t){const e=this.connectionIdToElementMap.get(t);this.connectionIdToElementMap.delete(t),this.connectionsContainer.removeChild(e)}moveNodeOnTop(t){this.layers[this.layersMode].moveOnTop(t)}updateNodeCoordinates(t){const e=this.graphStore.getNode(t),s=this.graphStore.getNodeAdjacentConnections(t);this.updateNodeCoords(t,e.x,e.y),s.forEach(r=>{this.updateConnectionCoords(r)})}updatePortConnections(t){this.graphStore.getPortAdjacentConnections(t).forEach(s=>{this.updateConnectionCoords(s)})}getViewportDimensions(){const t=this.host.getBoundingClientRect();return[t.width,t.height]}createHost(){const t=document.createElement("div");return t.style.width="100%",t.style.height="100%",t.style.position="relative",t.style.overflow="hidden",t}createCanvas(){const t=document.createElement("canvas");return t.style.position="absolute",t.style.inset="0",t}createNodesContainer(){const t=document.createElement("div");return t.style.position="absolute",t.style.top="0",t.style.left="0",t.style.width="0",t.style.height="0",t}createConnectionsContainer(){const t=document.createElement("div");return t.style.position="absolute",t.style.pointerEvents="none",t.style.top="0",t.style.left="0",t.style.width="0",t.style.height="0",t}createHostResizeObserver(){return new ResizeObserver(()=>{this.updateCanvasDimensions(),this.applyTransform()})}createNodesResizeObserver(){return new ResizeObserver(t=>{t.forEach(e=>{const s=e.target,r=this.nodeWrapperElementToIdMap.get(s),a=this.graphStore.getNode(r);this.updateNodeCoords(r,a.x,a.y),this.graphStore.getNodeAdjacentConnections(r).forEach(h=>{this.updateConnectionCoords(h)})})})}updateCanvasDimensions(){const{width:t,height:e}=this.host.getBoundingClientRect();this.canvas.width=t,this.canvas.height=e}updateNodeCoords(t,e,s){const r=this.nodeIdToWrapperElementMap.get(t),{width:a,height:c}=r.getBoundingClientRect(),h=this.viewportTransformer.getAbsScale(),i=this.graphStore.getNode(t),[d,g]=i.centerFn(a,c);r.style.transform=`matrix(1, 0, 0, 1, ${e-h*d}, ${s-h*g})`}updateConnectionCoords(t){const e=this.graphStore.getConnection(t),s=this.graphStore.getPort(e.from),r=this.graphStore.getPort(e.to),a=s.element.getBoundingClientRect(),c=r.element.getBoundingClientRect(),h=this.host.getBoundingClientRect(),[i,d]=this.viewportTransformer.getAbsCoords(a.left-h.left,a.top-h.top),[g,l]=this.viewportTransformer.getAbsCoords(c.left-h.left,c.top-h.top),u=this.viewportTransformer.getAbsScale(),[C,m]=s.centerFn(a.width*u,a.height*u),[v,f]=r.centerFn(c.width*u,c.height*u),y=C+i,b=m+d,$=v+g,S=f+l,T=Math.min(y,$),x=Math.min(b,S),M=Math.abs($-y),O=Math.abs(S-b);e.controller.update(T,x,M,O,s,r)}}class N{constructor(){n(this,"state",{scale:1,x:0,y:0})}getViewCoords(t,e){return[(t-this.state.x)/this.state.scale,(e-this.state.y)/this.state.scale]}getViewScale(){return 1/this.state.scale}getAbsCoords(t,e){return[t*this.state.scale+this.state.x,e*this.state.scale+this.state.y]}getAbsScale(){return this.state.scale}patchState(t,e,s){this.state={scale:t??this.state.scale,x:e??this.state.x,y:s??this.state.y}}}class X{constructor(t){this.transformer=t}getViewCoords(t,e){return this.transformer.getViewCoords(t,e)}getViewScale(){return this.transformer.getViewScale()}getAbsCoords(t,e){return this.transformer.getAbsCoords(t,e)}getAbsScale(){return this.transformer.getAbsScale()}}class U{constructor(){n(this,"nodes",Object.create(null));n(this,"ports",Object.create(null));n(this,"nodePorts",Object.create(null));n(this,"portNodeId",Object.create(null));n(this,"connections",Object.create(null));n(this,"incommingConnections",Object.create(null));n(this,"outcommingConnections",Object.create(null));n(this,"cycleConnections",Object.create(null))}getAllNodes(){return this.nodes}addNode(t,e,s,r,a){this.nodes[t]={element:e,x:s,y:r,centerFn:a},this.nodePorts[t]=Object.create(null)}hasNode(t){return this.nodes[t]!==void 0}getNode(t){return this.nodes[t]}updateNodeCoords(t,e,s){this.nodes[t].x=e,this.nodes[t].y=s}updateConnectionController(t,e){this.connections[t].controller=e}removeNode(t){this.getNodeAdjacentConnections(t).forEach(r=>{this.removeConnection(r)}),delete this.nodes[t];const s=this.nodePorts[t];Object.keys(s).forEach(r=>{delete this.portNodeId[r]}),delete this.nodePorts[t]}addPort(t,e,s,r,a){this.ports[t]={element:e,centerFn:r,direction:a},this.cycleConnections[t]={},this.incommingConnections[t]={},this.outcommingConnections[t]={},this.portNodeId[t]=s;const c=this.nodePorts[s];c!==void 0&&(c[t]=e)}getPort(t){return this.ports[t]}getPortNode(t){return this.portNodeId[t]}hasPort(t){return this.portNodeId[t]!==void 0}removePort(t){Object.keys(this.cycleConnections[t]).forEach(r=>{this.removeConnection(r)}),delete this.cycleConnections[t],Object.keys(this.incommingConnections[t]).forEach(r=>{this.removeConnection(r)}),delete this.incommingConnections[t],Object.keys(this.outcommingConnections[t]).forEach(r=>{this.removeConnection(r)}),delete this.outcommingConnections[t];const e=this.portNodeId[t];delete this.portNodeId[t];const s=this.nodePorts[e];delete s[t],delete this.ports[t]}addConnection(t,e,s,r){this.connections[t]={from:e,to:s,controller:r},e!==s?(this.outcommingConnections[e][t]=!0,this.incommingConnections[s][t]=!0):this.cycleConnections[e][t]=!0}getConnection(t){return this.connections[t]}hasConnection(t){return this.connections[t]!==void 0}removeConnection(t){const e=this.connections[t],s=e.from,r=e.to;delete this.cycleConnections[s][t],delete this.cycleConnections[r][t],delete this.incommingConnections[s][t],delete this.incommingConnections[r][t],delete this.outcommingConnections[s][t],delete this.outcommingConnections[r][t],delete this.connections[t]}getPortAdjacentConnections(t){return[...this.getPortIncomingConnections(t),...this.getPortOutcomingConnections(t),...this.getPortCycleConnections(t)]}getNodeAdjacentConnections(t){return[...this.getNodeIncomingConnections(t),...this.getNodeOutcomingConnections(t),...this.getNodeCycleConnections(t)]}clear(){this.nodes=Object.create(null),this.ports=Object.create(null),this.nodePorts=Object.create(null),this.portNodeId=Object.create(null),this.connections=Object.create(null),this.incommingConnections=Object.create(null),this.outcommingConnections=Object.create(null),this.cycleConnections=Object.create(null)}getPortIncomingConnections(t){return Object.keys(this.incommingConnections[t]??{})}getPortOutcomingConnections(t){return Object.keys(this.outcommingConnections[t]??{})}getPortCycleConnections(t){return Object.keys(this.cycleConnections[t]??{})}getNodeIncomingConnections(t){const e=Object.keys(this.nodePorts[t]);let s=[];return e.forEach(r=>{s=[...s,...this.getPortIncomingConnections(r)]}),s}getNodeOutcomingConnections(t){const e=Object.keys(this.nodePorts[t]);let s=[];return e.forEach(r=>{s=[...s,...this.getPortOutcomingConnections(r)]}),s}getNodeCycleConnections(t){const e=Object.keys(this.nodePorts[t]);let s=[];return e.forEach(r=>{s=[...s,...this.getPortCycleConnections(r)]}),s}}class p{static getPortCenter(t){const{top:e,left:s,width:r,height:a}=t.element.getBoundingClientRect(),c=t.centerFn(r,a);return[s+c[0],e+c[1]]}static rotate(t,e,s){return[e[0]*t[0]-e[1]*t[1]+((1-e[0])*s[0]+e[1]*s[1]),e[1]*t[0]+e[0]*t[1]+((1-e[0])*s[1]-e[1]*s[0])]}static getDirectionVector(t,e,s){return[e*Math.cos(t??0),s*Math.sin(t??0)]}static getArrowPath(t,e,s,r,a){const h=[[0,0],[r,a],[r,-a]].map(l=>this.rotate(l,t,[0,0])).map(l=>[l[0]+e,l[1]+s]),i=`M ${h[0][0]} ${h[0][1]}`,d=`L ${h[1][0]} ${h[1][1]}`,g=`L ${h[2][0]} ${h[2][1]}`;return`${i} ${d} ${g}`}static getArrowOffsetPath(t,e,s,r,a){const h=[[r,0],[r+a,0]].map(i=>this.rotate(i,t,[0,0])).map(i=>[i[0]+e,i[1]+s]);return`M ${h[0][0]} ${h[0][1]} L ${h[1][0]} ${h[1][1]}`}static createStraightPath(t){return t.map((e,s)=>`${s===0?"M":"L"} ${e[0]} ${e[1]}`).join(" ")}}class V{constructor(t,e,s,r,a,c,h){n(this,"svg");n(this,"group");n(this,"line");n(this,"sourceArrow",null);n(this,"targetArrow",null);this.color=t,this.width=e,this.curvature=s,this.arrowLength=r,this.arrowWidth=a,this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.pointerEvents="none",this.group=document.createElementNS("http://www.w3.org/2000/svg","g"),this.svg.appendChild(this.group),this.line=document.createElementNS("http://www.w3.org/2000/svg","path"),this.line.setAttribute("stroke",this.color),this.line.setAttribute("stroke-width",`${this.width}`),this.line.setAttribute("fill","none"),this.group.appendChild(this.line),this.group.style.transformOrigin="50% 50%",c&&(this.sourceArrow=document.createElementNS("http://www.w3.org/2000/svg","path"),this.sourceArrow.setAttribute("fill",this.color),this.group.appendChild(this.sourceArrow)),h&&(this.targetArrow=document.createElementNS("http://www.w3.org/2000/svg","path"),this.targetArrow.setAttribute("fill",this.color),this.group.appendChild(this.targetArrow)),this.svg.style.overflow="visible"}update(t,e,s,r,a,c){this.svg.style.width=`${s}px`,this.svg.style.height=`${r}px`;const h=p.getPortCenter(a),i=p.getPortCenter(c),d=h[0]<=i[0]?1:-1,g=h[1]<=i[1]?1:-1;this.svg.style.transform=`translate(${t}px, ${e}px)`,this.group.style.transform=`scale(${d}, ${g})`;const l=p.getDirectionVector(a.direction,d,g),u=p.getDirectionVector(c.direction,d,g),C=p.rotate([this.arrowLength,0],l,[0,0]),m=p.rotate([s-this.arrowLength,r],u,[s,r]),v=[C[0]+l[0]*this.curvature,C[1]+l[1]*this.curvature],f=[m[0]-u[0]*this.curvature,m[1]-u[1]*this.curvature],y=`M ${C[0]} ${C[1]} C ${v[0]} ${v[1]}, ${f[0]} ${f[1]}, ${m[0]} ${m[1]}`,b=this.sourceArrow?"":`M 0 0 L ${C[0]} ${C[1]} `,$=this.targetArrow?"":` M ${m[0]} ${m[1]} L ${s} ${r}`,S=`${b}${y}${$}`;if(this.line.setAttribute("d",S),this.sourceArrow){const T=p.getArrowPath(l,0,0,this.arrowLength,this.arrowWidth);this.sourceArrow.setAttribute("d",T)}if(this.targetArrow){const T=p.getArrowPath(u,s,r,-this.arrowLength,this.arrowWidth);this.targetArrow.setAttribute("d",T)}}}class D{constructor(t,e,s,r,a,c,h,i){n(this,"svg");n(this,"group");n(this,"line");n(this,"sourceArrow",null);n(this,"targetArrow",null);n(this,"roundness");this.color=t,this.width=e,this.arrowLength=s,this.arrowWidth=r,this.minPortOffset=a,this.roundness=Math.min(this.minPortOffset,i),this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.pointerEvents="none",this.group=document.createElementNS("http://www.w3.org/2000/svg","g"),this.svg.appendChild(this.group),this.line=document.createElementNS("http://www.w3.org/2000/svg","path"),this.line.setAttribute("stroke",this.color),this.line.setAttribute("stroke-width",`${this.width}`),this.line.setAttribute("fill","none"),this.group.appendChild(this.line),this.group.style.transformOrigin="50% 50%",c&&(this.sourceArrow=document.createElementNS("http://www.w3.org/2000/svg","path"),this.sourceArrow.setAttribute("fill",this.color),this.group.appendChild(this.sourceArrow)),h&&(this.targetArrow=document.createElementNS("http://www.w3.org/2000/svg","path"),this.targetArrow.setAttribute("fill",this.color),this.group.appendChild(this.targetArrow)),this.svg.style.overflow="visible"}update(t,e,s,r,a,c){this.svg.style.width=`${s}px`,this.svg.style.height=`${r}px`;const h=p.getPortCenter(a),i=p.getPortCenter(c),d=h[0]<=i[0]?1:-1,g=h[1]<=i[1]?1:-1;this.svg.style.transform=`translate(${t}px, ${e}px)`,this.group.style.transform=`scale(${d}, ${g})`;const l=p.getDirectionVector(a.direction,d,g),u=p.getDirectionVector(c.direction,d,g);console.log(this.roundness);const C=this.arrowLength+this.minPortOffset,m=p.rotate([C,0],l,[0,0]),v=p.rotate([s-C,r],u,[s,r]),[f,y]=[s/2,r/2],$=d*(v[0]-m[0])>0?p.createStraightPath([[m[0],m[1]],[f,m[1]],[f,v[1]],[v[0],v[1]]]):p.createStraightPath([[m[0],m[1]],[m[0],y],[v[0],y],[v[0],v[1]]]),S=p.getArrowOffsetPath(l,0,0,this.arrowLength,this.minPortOffset),T=p.getArrowOffsetPath(u,s,r,-this.arrowLength,-this.minPortOffset),x=`M 0 0 L ${m[0]} ${m[1]} `,M=` M ${v[0]} ${v[1]} L ${s} ${r}`,O=this.sourceArrow?S:x,st=this.targetArrow?T:M,ot=`${O}${$}${st}`;if(this.line.setAttribute("d",ot),this.sourceArrow){const L=p.getArrowPath(l,0,0,this.arrowLength,this.arrowWidth);this.sourceArrow.setAttribute("d",L)}if(this.targetArrow){const L=p.getArrowPath(u,s,r,-this.arrowLength,this.arrowWidth);this.targetArrow.setAttribute("d",L)}}}class F{constructor(t,e,s,r,a,c,h){n(this,"svg");n(this,"group");n(this,"line");n(this,"arrow",null);this.color=t,this.width=e,this.arrowLength=s,this.arrowWidth=r,this.radius=c,this.smallRadius=h,this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.pointerEvents="none",this.group=document.createElementNS("http://www.w3.org/2000/svg","g"),this.svg.appendChild(this.group),this.line=document.createElementNS("http://www.w3.org/2000/svg","path"),this.line.setAttribute("stroke",this.color),this.line.setAttribute("stroke-width",`${this.width}`),this.line.setAttribute("fill","none"),this.group.appendChild(this.line),this.group.style.transformOrigin="50% 50%",a&&(this.arrow=document.createElementNS("http://www.w3.org/2000/svg","path"),this.arrow.setAttribute("fill",this.color),this.group.appendChild(this.arrow)),this.svg.style.overflow="visible",this.svg.style.width="0px",this.svg.style.height="0px"}update(t,e,s,r,a){this.svg.style.transform=`translate(${t}px, ${e}px)`;const c=p.getDirectionVector(a.direction,1,1),h=this.smallRadius,i=this.radius,d=Math.sqrt(h*h+i*i),g=h+i,l=this.arrowLength+d*(1-i/g),u=h*i/g,m=[[this.arrowLength,0],[l,u],[l,-u]].map(b=>p.rotate(b,c,[0,0])),v=[`M ${m[0][0]} ${m[0][1]}`,`A ${h} ${h} 0 0 1 ${m[1][0]} ${m[1][1]}`,`A ${i} ${i} 0 1 0 ${m[2][0]} ${m[2][1]}`,`A ${h} ${h} 0 0 1 ${m[0][0]} ${m[0][1]}`].join(" "),f=`M 0 0 L ${m[0][0]} ${m[0][1]} `,y=`${this.arrow!==null?"":f}${v}`;if(this.line.setAttribute("d",y),this.arrow){const b=p.getArrowPath(c,0,0,this.arrowLength,this.arrowWidth);this.arrow.setAttribute("d",b)}}}class k{constructor(t,e,s,r,a,c,h,i){n(this,"svg");n(this,"group");n(this,"line");n(this,"arrow",null);n(this,"roundness");n(this,"points");this.color=t,this.width=e,this.arrowLength=s,this.arrowWidth=r,this.side=c,this.minPortOffset=h,this.roundness=Math.min(i,this.minPortOffset,this.side/2),this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.pointerEvents="none",this.group=document.createElementNS("http://www.w3.org/2000/svg","g"),this.svg.appendChild(this.group),this.line=document.createElementNS("http://www.w3.org/2000/svg","path"),this.line.setAttribute("stroke",this.color),this.line.setAttribute("stroke-width",`${this.width}`),this.line.setAttribute("fill","none"),this.group.appendChild(this.line),this.group.style.transformOrigin="50% 50%",a&&(this.arrow=document.createElementNS("http://www.w3.org/2000/svg","path"),this.arrow.setAttribute("fill",this.color),this.group.appendChild(this.arrow)),this.svg.style.overflow="visible",this.svg.style.width="0px",this.svg.style.height="0px";const d=this.minPortOffset,g=this.side,l=this.arrowLength+d,u=this.roundness,C=l-u,m=l+u,v=g-u,f=l+2*g,y=f-u;console.log(u),this.points=[[this.arrowLength,0],[C,0],[l,u],[l,v],[m,g],[y,g],[f,v],[f,-v],[y,-g],[m,-g],[l,-v],[l,-u]]}update(t,e,s,r,a){this.svg.style.transform=`translate(${t}px, ${e}px)`;const c=p.getDirectionVector(a.direction,1,1),h=this.roundness,i=this.points.map(u=>p.rotate(u,c,[0,0])),d=[`M ${i[0][0]} ${i[0][1]}`,`L ${i[1][0]} ${i[1][1]}`,`A ${h} ${h} 0 0 1 ${i[2][0]} ${i[2][1]}`,`L ${i[3][0]} ${i[3][1]}`,`A ${h} ${h} 0 0 0 ${i[4][0]} ${i[4][1]}`,`L ${i[5][0]} ${i[5][1]}`,`A ${h} ${h} 0 0 0 ${i[6][0]} ${i[6][1]}`,`L ${i[7][0]} ${i[7][1]}`,`A ${h} ${h} 0 0 0 ${i[8][0]} ${i[8][1]}`,`L ${i[9][0]} ${i[9][1]}`,`A ${h} ${h} 0 0 0 ${i[10][0]} ${i[10][1]}`,`L ${i[11][0]} ${i[11][1]}`,`A ${h} ${h} 0 0 1 ${i[1][0]} ${i[1][1]}`].join(" "),g=`M 0 0 L ${i[0][0]} ${i[0][1]} `,l=`${this.arrow?"":g}${d}`;if(this.line.setAttribute("d",l),this.arrow){const u=p.getArrowPath(c,0,0,this.arrowLength,this.arrowWidth);this.arrow.setAttribute("d",u)}}}var A=(o=>(o.Regular="regular",o.Cycle="cycle",o))(A||{});const j=o=>t=>t==="cycle"?new F(o.color,o.width,o.arrowLength,o.arrowWidth,o.hasSourceArrow||o.hasTargetArrow,o.cycleRadius,o.smallCycleRadius):new V(o.color,o.width,o.curvature,o.arrowLength,o.arrowWidth,o.hasSourceArrow,o.hasTargetArrow),W=o=>t=>t===A.Cycle&&t==="cycle"?new k(o.color,o.width,o.arrowLength,o.arrowWidth,o.hasSourceArrow||o.hasTargetArrow,o.cycleSquareSide,o.minPortOffset,o.roundness):new D(o.color,o.width,o.arrowLength,o.arrowWidth,o.minPortOffset,o.hasSourceArrow,o.hasTargetArrow,o.roundness);class P{constructor(){n(this,"counter",0)}next(){const t=`${this.counter}`;return this.counter++,t}reset(){this.counter=0}}class Z{constructor(t,e,s,r,a){n(this,"nodeIdGenerator",new P);n(this,"portIdGenerator",new P);n(this,"connectionIdGenerator",new P);this.graphStore=t,this.htmlController=e,this.viewportTransformer=s,this.nodesCenterFn=r,this.portsCenterFn=a}moveNodeOnTop(t){if(!this.graphStore.hasNode(t))throw new Error("failed to move on top nonexisting node");this.htmlController.moveNodeOnTop(t)}addNode(t,e,s,r,a,c){if(t===void 0)do t=this.nodeIdGenerator.next();while(this.graphStore.hasNode(t));if(this.graphStore.hasNode(t))throw new Error("failed to add node with existing id");this.graphStore.addNode(t,e,s,r,c??this.nodesCenterFn),this.htmlController.attachNode(t),a!==void 0&&Object.entries(a).forEach(([h,i])=>{i instanceof HTMLElement?this.markPort(h,i,t,this.portsCenterFn,null):this.markPort(h,i.element,t,i.centerFn??this.portsCenterFn,i.direction??null)})}markPort(t,e,s,r,a){if(t===void 0)do t=this.portIdGenerator.next();while(this.graphStore.hasPort(t));if(!this.graphStore.hasNode(s))throw new Error("failed to set port on nonexisting node");if(this.graphStore.hasPort(t))throw new Error("failed to add port with existing id");this.graphStore.addPort(t,e,s,r??this.portsCenterFn,a??null)}updatePortConnections(t){if(!this.graphStore.hasPort(t))throw new Error("failed to unset nonexisting port");this.htmlController.updatePortConnections(t)}unmarkPort(t){if(!this.graphStore.hasPort(t))throw new Error("failed to unset nonexisting port");this.graphStore.getPortAdjacentConnections(t).forEach(e=>{this.removeConnection(e)}),this.graphStore.removePort(t)}addConnection(t,e,s,r){if(t===void 0)do t=this.connectionIdGenerator.next();while(this.graphStore.hasConnection(t));if(!this.graphStore.hasPort(e))throw new Error("failed to add connection from nonexisting port");if(!this.graphStore.hasPort(s))throw new Error("failed to add connection to nonexisting port");let a=A.Regular;e===s&&(a=A.Cycle),this.graphStore.addConnection(t,e,s,r(a)),this.htmlController.attachConnection(t)}removeConnection(t){if(!this.graphStore.hasConnection(t))throw new Error("failed to remove nonexisting connection");this.htmlController.detachConnection(t),this.graphStore.removeConnection(t)}removeNode(t){if(!this.graphStore.hasNode(t))throw new Error("failed to remove nonexisting node");this.htmlController.detachNode(t),this.graphStore.removeNode(t)}patchViewportState(t,e,s){this.viewportTransformer.patchState(t,e,s),this.htmlController.applyTransform()}moveToNodes(t){if(t.length===0)return;const e=t.map(u=>this.graphStore.getNode(u)).filter(u=>u!==void 0);if(e.length<t.length)throw new Error("failed to move to nonexisting node");const[s,r]=e.reduce((u,C)=>[u[0]+C.x,u[1]+C.y],[0,0]),a=s/e.length,c=r/e.length,[h,i]=this.htmlController.getViewportDimensions(),d=this.viewportTransformer.getAbsScale(),g=a-d*h/2,l=c-d*i/2;this.patchViewportState(null,g,l)}updateNodeCoordinates(t,e,s){if(!this.graphStore.hasNode(t))throw new Error("failed to update coordinates of nonexisting node");this.graphStore.updateNodeCoords(t,e,s),this.htmlController.updateNodeCoordinates(t)}updateConnectionController(t,e){if(!this.graphStore.hasConnection(t))throw new Error("failed to update nonexisting connection");this.htmlController.detachConnection(t),this.graphStore.updateConnectionController(t,e),this.htmlController.attachConnection(t)}attach(t){this.htmlController.attach(t)}detach(){this.htmlController.detach()}clear(){this.htmlController.clear(),this.graphStore.clear(),this.nodeIdGenerator.reset(),this.portIdGenerator.reset(),this.connectionIdGenerator.reset()}destroy(){this.htmlController.destroy()}}class H{constructor(t,e,s,r){n(this,"publicViewportTransformer");n(this,"canvasController");const a=new N,c=new U;this.publicViewportTransformer=new X(a);const h=new E(c,a,this.publicViewportTransformer,t,e);this.canvasController=new Z(c,h,a,s,r)}}const R=(o,t)=>[o/2,t/2],q=()=>()=>{},_=(o,t,e,s,r,a)=>{o.clearRect(0,0,o.canvas.width,o.canvas.height),o.fillStyle=a,o.fillRect(0,0,o.canvas.width,o.canvas.height);const c=t.getViewCoords(0,0),h=t.getViewScale(),i=s*h;let d=0,g=0,l=i/2;do l*=2,d=o.canvas.width/l,g=o.canvas.height/l;while(d*g>1e4);const u=c[0]-Math.floor(c[0]/l)*l,C=c[1]-Math.floor(c[1]/l)*l,m=r*h,v=2*Math.PI,f=u-l,y=C-l,b=o.canvas.width+u,$=o.canvas.height+C;o.fillStyle=e;for(let S=f;S<=b;S+=l)for(let T=y;T<=$;T+=l)o.beginPath(),o.arc(S,T,m,0,v),o.closePath(),o.fill()},J=(o,t,e,s)=>(r,a)=>{_(r,a,o,t,e,s)},K=(o,t)=>{o.fillStyle=t,o.fillRect(0,0,o.canvas.width,o.canvas.height)},Q=o=>t=>{K(t,o)},I=o=>{switch(o==null?void 0:o.type){case"custom":return o.drawingFn;case"dots":return J(o.dotColor??"#d8d8d8",o.dotGap??25,o.dotRadius??1.5,o.color??"#ffffff");case"color":return Q(o.color??"#ffffff");default:return q()}},B=o=>{switch(o==null?void 0:o.type){case"custom":return o.controllerFactory;case"straight":return W({color:o.color??"#5c5c5c",width:o.width??1,arrowLength:o.arrowLength??15,arrowWidth:o.arrowWidth??4,minPortOffset:o.minPortOffset??15,hasSourceArrow:o.hasSourceArrow??!1,hasTargetArrow:o.hasTargetArrow??!1,cycleSquareSide:o.cycleSquareSide??30,roundness:o.roundness??5});default:return j({color:o.color??"#5c5c5c",width:o.width??1,curvature:o.curvature??90,arrowLength:o.arrowLength??15,arrowWidth:o.arrowWidth??4,hasSourceArrow:o.hasSourceArrow??!1,hasTargetArrow:o.hasTargetArrow??!1,cycleRadius:o.cycleRadius??30,smallCycleRadius:o.smallCycleRadius??15})}},tt=o=>{var t,e,s;return{background:{drawingFn:I(o.background??{type:"none"})},nodes:{centerFn:((t=o.nodes)==null?void 0:t.centerFn)??R},ports:{centerFn:((e=o.ports)==null?void 0:e.centerFn)??R},edges:{controllerFactory:B(o.edges??{})},layers:{mode:((s=o.layers)==null?void 0:s.mode)??"edges-follow-node"}}};class z{constructor(t){n(this,"transformation");n(this,"di");n(this,"connectionControllerFactory");this.apiOptions=t;const e=tt(this.apiOptions??{});this.di=new H(e.layers.mode,e.background.drawingFn,e.nodes.centerFn,e.ports.centerFn),this.transformation=this.di.publicViewportTransformer,this.connectionControllerFactory=e.edges.controllerFactory}addNode(t){return this.di.canvasController.addNode(t.id,t.element,t.x,t.y,t.ports,t.centerFn),this}moveNodeOnTop(t){return this.di.canvasController.moveNodeOnTop(t),this}removeNode(t){return this.di.canvasController.removeNode(t),this}markPort(t){return this.di.canvasController.markPort(t.id,t.element,t.nodeId,t.centerFn,t.direction),this}updatePortEdges(t){return this.di.canvasController.updatePortConnections(t),this}unmarkPort(t){return this.di.canvasController.unmarkPort(t),this}addEdge(t){const e=t.options!==void 0?B(t.options):this.connectionControllerFactory;return this.di.canvasController.addConnection(t.id,t.from,t.to,e),this}removeEdge(t){return this.di.canvasController.removeConnection(t),this}patchViewportState(t){return this.di.canvasController.patchViewportState(t.scale??null,t.x??null,t.y??null),this}moveToNodes(t){return this.di.canvasController.moveToNodes(t),this}updateNodeCoordinates(t,e,s){return this.di.canvasController.updateNodeCoordinates(t,e,s),this}updateConnection(t,e){return e.controller!==void 0&&this.di.canvasController.updateConnectionController(t,e.controller),this}clear(){return this.di.canvasController.clear(),this}attach(t){return this.di.canvasController.attach(t),this}detach(){return this.di.canvasController.detach(),this}destroy(){this.di.canvasController.destroy()}}class G{constructor(t,e){n(this,"transformation");n(this,"nodes",new Map);n(this,"grabbedNodeId",null);n(this,"onNodeDrag");n(this,"onBeforeNodeDrag");n(this,"nodeIdGenerator",new P);n(this,"element",null);n(this,"onCanvasMouseUp",()=>{this.setCursor(null),this.grabbedNodeId=null});n(this,"onCanvasMouseMove",t=>{this.grabbedNodeId!==null&&(t.stopPropagation(),this.dragNode(this.grabbedNodeId,t.movementX,t.movementY))});n(this,"onCanvasTouchStart",t=>{this.previousTouchCoords=[t.touches[0].clientX,t.touches[0].clientY]});n(this,"onCanvasTouchMove",t=>{if(this.grabbedNodeId===null||t.touches.length!==1||this.previousTouchCoords===null)return;t.stopImmediatePropagation();const[e,s]=[t.touches[0].clientX-this.previousTouchCoords[0],t.touches[0].clientY-this.previousTouchCoords[1]];this.dragNode(this.grabbedNodeId,e,s),this.previousTouchCoords=[t.touches[0].clientX,t.touches[0].clientY]});n(this,"onCanvasTouchEnd",t=>{t.touches.length>0?this.previousTouchCoords=[t.touches[0].clientX,t.touches[0].clientY]:(this.previousTouchCoords=null,this.grabbedNodeId=null)});n(this,"previousTouchCoords",null);var a,c;this.canvas=t,this.transformation=this.canvas.transformation;const s=()=>{};this.onNodeDrag=((a=e==null?void 0:e.events)==null?void 0:a.onNodeDrag)??s;const r=()=>!0;this.onBeforeNodeDrag=((c=e==null?void 0:e.events)==null?void 0:c.onBeforeNodeDrag)??r}addNode(t){let e=t.id;if(e===void 0)do e=this.nodeIdGenerator.next();while(this.nodes.has(e));this.canvas.addNode(t);const s=a=>{this.onBeforeNodeDrag({nodeId:e,element:t.element,x:t.x,y:t.y})&&(a.stopImmediatePropagation(),this.grabbedNodeId=e,this.setCursor("grab"),this.canvas.moveNodeOnTop(e))},r=a=>{this.onBeforeNodeDrag({nodeId:e,element:t.element,x:t.x,y:t.y})&&a.touches.length===1&&(this.grabbedNodeId=e,this.canvas.moveNodeOnTop(e))};return this.nodes.set(e,{element:t.element,onMouseDown:s,onTouchStart:r,x:t.x,y:t.y}),t.element.addEventListener("mousedown",s),t.element.addEventListener("touchstart",r),this}removeNode(t){const e=this.nodes.get(t);return e!==void 0&&(e.element.removeEventListener("mousedown",e.onMouseDown),e.element.removeEventListener("touchstart",e.onTouchStart)),this.canvas.removeNode(t),this.nodes.delete(t),this}markPort(t){return this.canvas.markPort(t),this}updatePortEdges(t){return this.canvas.updatePortEdges(t),this}unmarkPort(t){return this.canvas.unmarkPort(t),this}addEdge(t){return this.canvas.addEdge(t),this}removeEdge(t){return this.canvas.removeEdge(t),this}patchViewportState(t){return this.canvas.patchViewportState(t),this}moveToNodes(t){return this.canvas.moveToNodes(t),this}updateNodeCoordinates(t,e,s){return this.canvas.updateNodeCoordinates(t,e,s),this}updateConnection(t,e){return this.canvas.updateConnection(t,e),this}moveNodeOnTop(t){return this.canvas.moveNodeOnTop(t),this}clear(){return this.canvas.clear(),this.nodes.forEach(t=>{t.element.removeEventListener("mousedown",t.onMouseDown),t.element.removeEventListener("touchstart",t.onTouchStart)}),this.nodes.clear(),this}attach(t){return this.detach(),this.element=t,this.canvas.attach(this.element),this.element.addEventListener("mouseup",this.onCanvasMouseUp),this.element.addEventListener("mousemove",this.onCanvasMouseMove),this.element.addEventListener("touchstart",this.onCanvasTouchStart),this.element.addEventListener("touchmove",this.onCanvasTouchMove),this.element.addEventListener("touchend",this.onCanvasTouchEnd),this.element.addEventListener("touchcancel",this.onCanvasTouchEnd),this}detach(){return this.canvas.detach(),this.element!==null&&(this.element.removeEventListener("mouseup",this.onCanvasMouseUp),this.element.removeEventListener("mousemove",this.onCanvasMouseMove),this.element.removeEventListener("touchstart",this.onCanvasTouchStart),this.element.removeEventListener("touchmove",this.onCanvasTouchMove),this.element.removeEventListener("touchend",this.onCanvasTouchEnd),this.element.removeEventListener("touchcancel",this.onCanvasTouchEnd),this.element=null),this}destroy(){this.detach(),this.nodes.forEach(t=>{t.element.removeEventListener("mousedown",t.onMouseDown),t.element.removeEventListener("touchstart",t.onTouchStart)}),this.nodes.clear(),this.canvas.destroy()}setCursor(t){this.element!==null&&(t!==null?this.element.style.cursor=t:this.element.style.removeProperty("cursor"))}dragNode(t,e,s){const r=this.nodes.get(t);if(r===void 0)throw new Error("failed to drag nonexisting node");const[a,c]=this.transformation.getViewCoords(r.x,r.y),h=a+e,i=c+s,[d,g]=this.transformation.getAbsCoords(h,i);r.x=d,r.y=g,this.canvas.updateNodeCoordinates(t,d,g),this.onNodeDrag({nodeId:t,element:r.element,x:r.x,y:r.y})}}class Y{constructor(t,e){n(this,"transformation");n(this,"element",null);n(this,"isMoving",!1);n(this,"prevTouches",null);n(this,"onTransform");n(this,"onBeforeTransform");n(this,"isScalable");n(this,"isShiftable");n(this,"minViewScale");n(this,"maxViewScale");n(this,"wheelSensitivity");n(this,"onMouseDown",()=>{this.setCursor("grab"),this.isMoving=!0});n(this,"onMouseMove",t=>{if(!this.isMoving||!this.isShiftable)return;const e=-t.movementX,s=-t.movementY;this.moveViewport(e,s)});n(this,"onMouseUp",()=>{this.setCursor(null),this.isMoving=!1});n(this,"onWheelScroll",t=>{if(this.element===null||this.isScalable===!1)return;t.preventDefault();const{left:e,top:s}=this.element.getBoundingClientRect(),r=t.clientX-e,a=t.clientY-s,h=1/(t.deltaY<0?this.wheelSensitivity:1/this.wheelSensitivity);this.scaleViewport(h,r,a)});n(this,"onTouchStart",t=>{this.prevTouches=this.getAverageTouch(t)});n(this,"onTouchMove",t=>{if(this.prevTouches===null||this.element===null||!this.isShiftable)return;const e=this.getAverageTouch(t);if((e.touchesCnt===1||e.touchesCnt===2)&&this.moveViewport(-(e.x-this.prevTouches.x),-(e.y-this.prevTouches.y)),e.touchesCnt===2&&this.isScalable){const{left:s,top:r}=this.element.getBoundingClientRect(),a=this.prevTouches.x-s,c=this.prevTouches.y-r,i=1/(e.scale/this.prevTouches.scale);this.scaleViewport(i,a,c)}this.prevTouches=e,t.preventDefault()});n(this,"onTouchEnd",t=>{t.touches.length>0?this.prevTouches=this.getAverageTouch(t):this.prevTouches=null});var i,d,g,l,u,C,m,v,f,y,b,$;this.canvas=t,this.options=e,this.transformation=this.canvas.transformation;const s=((d=(i=this.options)==null?void 0:i.scale)==null?void 0:d.min)??null,r=((l=(g=this.options)==null?void 0:g.scale)==null?void 0:l.max)??null;this.isScalable=((C=(u=this.options)==null?void 0:u.scale)==null?void 0:C.enabled)!==!1,this.minViewScale=r!==null?1/r:null,this.maxViewScale=s!==null?1/s:null,this.isShiftable=((v=(m=this.options)==null?void 0:m.shift)==null?void 0:v.enabled)!==!1;const a=(y=(f=this.options)==null?void 0:f.scale)==null?void 0:y.wheelSensitivity;this.wheelSensitivity=a!==void 0?a:1.2;const c=()=>{};this.onTransform=((b=e==null?void 0:e.events)==null?void 0:b.onTransform)??c;const h=()=>!0;this.onBeforeTransform=(($=e==null?void 0:e.events)==null?void 0:$.onBeforeTransform)??h}addNode(t){return this.canvas.addNode(t),this}removeNode(t){return this.canvas.removeNode(t),this}markPort(t){return this.canvas.markPort(t),this}updatePortEdges(t){return this.canvas.updatePortEdges(t),this}unmarkPort(t){return this.canvas.unmarkPort(t),this}addEdge(t){return this.canvas.addEdge(t),this}removeEdge(t){return this.canvas.removeEdge(t),this}patchViewportState(t){return this.canvas.patchViewportState(t),this}moveToNodes(t){return this.canvas.moveToNodes(t),this}updateNodeCoordinates(t,e,s){return this.canvas.updateNodeCoordinates(t,e,s),this}updateConnection(t,e){return this.canvas.updateConnection(t,e),this}moveNodeOnTop(t){return this.canvas.moveNodeOnTop(t),this}clear(){return this.canvas.clear(),this}attach(t){return this.detach(),this.element=t,this.canvas.attach(this.element),this.element.addEventListener("mousedown",this.onMouseDown),this.element.addEventListener("mousemove",this.onMouseMove),this.element.addEventListener("mouseup",this.onMouseUp),this.element.addEventListener("wheel",this.onWheelScroll),this.element.addEventListener("touchstart",this.onTouchStart),this.element.addEventListener("touchmove",this.onTouchMove),this.element.addEventListener("touchend",this.onTouchEnd),this.element.addEventListener("touchcancel",this.onTouchEnd),this}detach(){return this.canvas.detach(),this.element!==null&&(this.element.removeEventListener("mousedown",this.onMouseDown),this.element.removeEventListener("mousemove",this.onMouseMove),this.element.removeEventListener("mouseup",this.onMouseUp),this.element.removeEventListener("wheel",this.onWheelScroll),this.element.removeEventListener("touchstart",this.onTouchStart),this.element.removeEventListener("touchmove",this.onTouchMove),this.element.removeEventListener("touchend",this.onTouchEnd),this.element.removeEventListener("touchcancel",this.onTouchEnd),this.element=null),this}destroy(){this.detach(),this.canvas.destroy()}getAverageTouch(t){const e=[],s=t.touches.length;for(let i=0;i<s;i++)e.push([t.touches[i].clientX,t.touches[i].clientY]);const r=e.reduce((i,d)=>[i[0]+d[0],i[1]+d[1]],[0,0]),a=[r[0]/s,r[1]/s],h=e.map(i=>[i[0]-a[0],i[1]-a[1]]).reduce((i,d)=>i+Math.sqrt(d[0]*d[0]+d[1]*d[1]),0);return{x:a[0],y:a[1],scale:h/s,touchesCnt:s}}setCursor(t){this.element!==null&&(t!==null?this.element.style.cursor=t:this.element.style.removeProperty("cursor"))}moveViewport(t,e){const[s,r]=this.transformation.getAbsCoords(0,0),a=this.canvas.transformation.getAbsScale(),c={scale:a,x:s+a*t,y:r+a*e};this.onBeforeTransform({...c})&&(this.canvas.patchViewportState(c),this.onTransform(c))}scaleViewport(t,e,s){const[r,a]=this.canvas.transformation.getAbsCoords(0,0),c=this.canvas.transformation.getAbsScale(),h=c*t,i=c*(1-t)*e+r,d=c*(1-t)*s+a;if(this.maxViewScale!==null&&h>this.maxViewScale&&h>c||this.minViewScale!==null&&h<this.minViewScale&&h<c)return;const g={scale:h,x:i,y:d};this.onBeforeTransform({...g})&&(this.canvas.patchViewportState(g),this.onTransform(g))}}class et{constructor(){n(this,"coreOptions");n(this,"dragOptions");n(this,"transformOptions");n(this,"isDraggable",!1);n(this,"isTransformable",!1)}setOptions(t){return this.coreOptions=t,this}setUserDraggableNodes(t){return this.isDraggable=!0,this.dragOptions=t,this}setUserTransformableCanvas(t){return this.isTransformable=!0,this.transformOptions=t,this}build(){let t=new z(this.coreOptions);return this.isDraggable&&(t=new G(t,this.dragOptions)),this.isTransformable&&(t=new Y(t,this.transformOptions)),t}}w.BezierEdgeController=V,w.CanvasCore=z,w.CycleCircleEdgeController=F,w.CycleSquareEdgeController=k,w.EdgeType=A,w.EdgeUtils=p,w.HtmlGraphBuilder=et,w.StraightEdgeController=D,w.UserDraggableNodesCanvas=G,w.UserTransformableCanvas=Y,w.createBezierEdgeControllerFactory=j,w.createStraightEdgeControllerFactory=W,Object.defineProperty(w,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@html-graph/html-graph",
3
3
  "author": "Dmitry Marov",
4
4
  "private": false,
5
- "version": "0.0.48",
5
+ "version": "0.0.49",
6
6
  "type": "module",
7
7
  "main": "dist/main.js",
8
8
  "types": "dist/main.d.ts",
@@ -35,7 +35,7 @@
35
35
  "fix-lint": "eslint . --fix",
36
36
  "build": "tsc --p ./tsconfig-build-library.json && vite build",
37
37
  "preview": "vite preview",
38
- "beforebuild": "npm run lint && npm run check-formatting",
38
+ "before-build": "npm run lint && npm run check-formatting",
39
39
  "release-next-version": "tsx ./scripts/release-next-version.ts",
40
40
  "make-deps-graph": "npx depcruise lib --include-only \"^lib\" --output-type dot > ./deps-graph/deps-graph.dot"
41
41
  },