dytools-canvas-engine 1.2.3 → 1.3.2

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/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
- "use strict";var N=Object.defineProperty;var ee=Object.getOwnPropertyDescriptor;var te=Object.getOwnPropertyNames;var ne=Object.prototype.hasOwnProperty;var ie=(m,e)=>{for(var t in e)N(m,t,{get:e[t],enumerable:!0})},se=(m,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of te(e))!ne.call(m,i)&&i!==t&&N(m,i,{get:()=>e[i],enumerable:!(s=ee(e,i))||s.enumerable});return m};var oe=m=>se(N({},"__esModule",{value:!0}),m);var ae={};ie(ae,{ApiTool:()=>H,CanvasEngine:()=>U,CircleObject:()=>q,ClickGestureRecognizer:()=>V,DomEventSource:()=>R,DragGestureRecognizer:()=>F,DrawingTool:()=>A,EngineEventType:()=>b,HoverTool:()=>B,LassoTool:()=>L,MoveTool:()=>S,PolygonObject:()=>K,ResizeTool:()=>D,SelectTool:()=>M,ToolLockManager:()=>k,Zone:()=>$});module.exports=oe(ae);var l=require("dytools-geometry"),W=class W{constructor(e,t,s,i,n,r,o,a,c,d){this._name=null;this._showName=!1;this._nameAnchor="TopLeft";this._visible=!0;if(this._id=e,t instanceof l.Rectangle){let h=t,g=s??"#000000",v=i??!1,E=n??!1,z=r??!1,T=o??0;this._rect=h,this._color=g,this._selectable=v,this._movable=E,this._resizable=z,this._zIndex=T}else{let h=t,g=s,v=i,E=n,z=r??"#000000",T=o??!1,I=a??!1,x=c??!1,C=d??0;this._rect=new l.Rectangle(new l.Point(h,g),new l.Size(v,E)),this._color=z,this._selectable=T,this._movable=I,this._resizable=x,this._zIndex=C}}get id(){return this._id}set id(e){this._id=e}get rect(){return this._rect.normalized()}get name(){return this._name}set name(e){this._name=e}get showName(){return this._showName}set showName(e){this._showName=e}get nameAnchor(){return this._nameAnchor}set nameAnchor(e){this._nameAnchor=e}get zIndex(){return this._zIndex}set zIndex(e){this._zIndex=e}get visible(){return this._visible??!1}set visible(e){this._visible=e}get color(){return this._color}set color(e){this._color=e}get selectable(){return this._selectable}set selectable(e){this._selectable=e}get movable(){return this._movable}set movable(e){this._movable=e}get resizable(){return this._resizable}set resizable(e){this._resizable=e}getBounds(){return this._rect}getOuterBounds(){let e=this._rect,t=this.getResizeHandles();return t.length===0||t.forEach(s=>{e=e.expand(s.rect)}),e}getEventInteractions(e){let t=[];if(this._resizable&&this.getResizeHandles().forEach(i=>{(e===null||i.rect.contains(e))&&t.push({eventTypePrefix:"resize",handleIndex:i.handleIndex})}),this._movable){let s=this.getBounds();(e===null||s.contains(e))&&t.push({eventTypePrefix:"move"})}if(this._selectable){let s=this.getBounds();(e===null||s.contains(e))&&t.push({eventTypePrefix:"select"})}return t}getResizeHandles(){let e=this._rect.origin.x,t=this._rect.origin.y,s=this._rect.size.width,i=this._rect.size.height,n=W.HANDLE_SIZE,r=n*10,o=n*6,a=1;s>=r&&i>=r?a=-1:s>=o&&i>=o&&(a=0);let c=s<o,d=i<o;return[{rect:new l.Rectangle(new l.Point(e-a*n-n,t-a*n-n),new l.Size(n*2,n*2)),handleIndex:0},c?null:{rect:new l.Rectangle(new l.Point(e+s/2-n,t-a*n-n),new l.Size(n*2,n*2)),handleIndex:1},{rect:new l.Rectangle(new l.Point(e+s+a*n-n,t-a*n-n),new l.Size(n*2,n*2)),handleIndex:2},d?null:{rect:new l.Rectangle(new l.Point(e+s+a*n-n,t+i/2-n),new l.Size(n*2,n*2)),handleIndex:3},{rect:new l.Rectangle(new l.Point(e+s+a*n-n,t+i+a*n-n),new l.Size(n*2,n*2)),handleIndex:4},c?null:{rect:new l.Rectangle(new l.Point(e+s/2-n,t+i+a*n-n),new l.Size(n*2,n*2)),handleIndex:5},{rect:new l.Rectangle(new l.Point(e-a*n-n,t+i+a*n-n),new l.Size(n*2,n*2)),handleIndex:6},d?null:{rect:new l.Rectangle(new l.Point(e-a*n-n,t+i/2-n),new l.Size(n*2,n*2)),handleIndex:7}].filter(g=>g!==null)}handleEvent(e,t){let s=e.data||{};if(e.type==="setcolor"&&this._color!==s.color){let n=this._color;this._color=s.color,t(b.ObjectColorChanged,{object:this,oldColor:n,newColor:this._color});return}if(e.type==="setzindex"&&this._zIndex!==s.zIndex){let n=this._zIndex;this._zIndex=s.zIndex,t(b.ObjectZIndexChanged,{object:this,oldZIndex:n,newZIndex:this._zIndex});return}if(e.type==="setselectable"&&this._selectable!==s.isSelectable){let n=this._selectable;this._selectable=s.isSelectable,t(b.ObjectSelectableChanged,{object:this,oldSelectable:n,newSelectable:this._selectable});return}if(e.type==="setmovable"&&this._movable!==s.isMovable){let n=this._movable;this._movable=s.isMovable,t(b.ObjectMovableChanged,{object:this,oldMovable:n,newMovable:this._movable});return}if(e.type==="setresizable"&&this._resizable!==s.isResizable){let n=this._resizable;this._resizable=s.isResizable,t(b.ObjectResizableChanged,{object:this,oldResizable:n,newResizable:this._resizable});return}if(e.type==="setvisible"&&this._visible!==s.isVisible){let n=this._visible??!0;this._visible=s.isVisible,t(b.ObjectVisibleChanged,{object:this,oldVisible:n,newVisible:this._visible??!0});return}let i=s.delta;if(e.type==="resize"){let n=this._rect.clone(),r=s.handleIndex;if(i==null||r==null){console.warn("Resize event missing required data:",e);return}let o=-1/0,a=i.x,c=i.y;if(a===0&&c===0)return;switch(r){case 0:a=Math.min(a,this._rect.size.width-o),c=Math.min(c,this._rect.size.height-o),this._rect.origin.x+=a,this._rect.origin.y+=c,this._rect.size.width-=a,this._rect.size.height-=c;break;case 1:c=Math.min(c,this._rect.size.height-o),this._rect.origin.y+=c,this._rect.size.height-=c;break;case 2:a=Math.max(a,o-this._rect.size.width),c=Math.min(c,this._rect.size.height-o),this._rect.origin.y+=c,this._rect.size.width+=a,this._rect.size.height-=c;break;case 3:a=Math.max(a,o-this._rect.size.width),this._rect.size.width+=a;break;case 4:a=Math.max(a,o-this._rect.size.width),c=Math.max(c,o-this._rect.size.height),this._rect.size.width+=a,this._rect.size.height+=c;break;case 5:c=Math.max(c,o-this._rect.size.height),this._rect.size.height+=c;break;case 6:a=Math.min(a,this._rect.size.width-o),c=Math.max(c,o-this._rect.size.height),this._rect.origin.x+=a,this._rect.size.width-=a,this._rect.size.height+=c;break;case 7:a=Math.min(a,this._rect.size.width-o),this._rect.origin.x+=a,this._rect.size.width-=a;break}t(b.ObjectResized,{object:this,oldSize:n.size,newSize:this._rect.clone().size}),t(b.ObjectPositionChanged,{object:this,oldPosition:n,newPosition:this._rect.clone()})}else e.type==="resizeend"&&this._rect.normalize();if(e.type.startsWith("move")){if(i==null){console.warn("Move event missing required data:",e);return}if(i.x===0&&i.y===0)return;let n=this._rect.clone();this._rect=this._rect.move(i),t(b.ObjectMoved,{object:this,oldPoint:n.origin,newPoint:this._rect.clone().origin}),t(b.ObjectPositionChanged,{object:this,oldPosition:n,newPosition:this._rect})}}render(e,t){let s=t.has("selected"),i=t.has("hovered"),n=t.has("hoversibling"),o=e.getTransform().a,a=u=>u/o,c=a(4),d=a(2),h=a(3),g=a(4),v=this._rect,E=v.origin.x,z=v.origin.y,T=v.size.width,I=v.size.height,x=(u,p,y,f,w)=>{let j=Math.max(0,Math.min(w,Math.min(y,f)/2)),P=new Path2D;return P.moveTo(u+j,p),P.lineTo(u+y-j,p),P.arcTo(u+y,p,u+y,p+j,j),P.lineTo(u+y,p+f-j),P.arcTo(u+y,p+f,u+y-j,p+f,j),P.lineTo(u+j,p+f),P.arcTo(u,p+f,u,p+f-j,j),P.lineTo(u,p+j),P.arcTo(u,p,u+j,p,j),P.closePath(),P},C=x(E,z,T,I,c);e.save(),e.strokeStyle=this._color;let _=e.strokeStyle;if(e.fillStyle=this.withAlpha(_,.06),e.fill(C),e.lineWidth=d,e.stroke(C),e.restore(),s){let u=E-g,p=z-g,y=T+g*2,f=I+g*2,w=x(u,p,y,f,c+g);e.save(),e.setLineDash([a(8),a(6)]),e.lineDashOffset=0,e.strokeStyle="rgba(0,0,0,0.4)",e.lineWidth=h,e.stroke(w),e.restore()}if(this._showName&&this._name){e.save(),e.font="12px sans-serif",e.fillStyle=this._color,e.textBaseline="top";let u=2,{x:p,y}=this._rect.origin,{width:f,height:w}=this._rect.size,j=p+u,P=y+u;switch(this._nameAnchor){case"TopLeft":j=p+u,P=y+u;break;case"TopRight":j=p+f-e.measureText(this._name).width-u,P=y+u;break;case"BottomLeft":j=p+u,P=y+w-14-u;break;case"BottomRight":j=p+f-e.measureText(this._name).width-u,P=y+w-14-u;break;case"Center":j=p+(f-e.measureText(this._name).width)/2,P=y+(w-12)/2;break}e.fillText(this._name,j,P),e.restore()}if(this._resizable&&i){e.save(),e.lineWidth=a(n?.5:1),e.strokeStyle=_,e.fillStyle=n?"transparent":"white",e.globalAlpha=n?.75:1;for(let u of this.getResizeHandles()||[]){if(!u)continue;let{x:p,y}=u.rect.origin,{width:f,height:w}=u.rect.size,j=a(4),P=x(p,y,f,w,j);e.fill(P),e.stroke(P)}e.restore()}}withAlpha(e,t){let s=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\s*\)/i);if(s){let i=parseInt(s[1]??"0",10),n=parseInt(s[2]??"0",10),r=parseInt(s[3]??"0",10);return`rgba(${i},${n},${r},${t})`}if(e.startsWith("#")){let i=e.slice(1);if(i.length===3&&(i=i.split("").map(n=>n+n).join("")),i.length===6||i.length===8){let n=parseInt(i.slice(0,2),16),r=parseInt(i.slice(2,4),16),o=parseInt(i.slice(4,6),16);return`rgba(${n},${r},${o},${t})`}}return e}};W.HANDLE_SIZE=6;var $=W,Z=class Z{constructor(e,t,s,i,n,r,o,a,c){this._name=null;this._showName=!1;this._visible=!0;if(this._id=e,t instanceof l.Point){let d=t,h=s,g=i??"#000000",v=n??!1,E=r??!1,z=o??!1,T=a??0;this._center=d,this._radius=h,this._color=g,this._selectable=v,this._movable=E,this._resizable=z,this._zIndex=T}else{let d=t,h=s,g=i,v=n??"#000000",E=r??!1,z=o??!1,T=a??!1,I=c??0;this._center=new l.Point(d,h),this._radius=g,this._color=v,this._selectable=E,this._movable=z,this._resizable=T,this._zIndex=I}}get id(){return this._id}set id(e){this._id=e}get center(){return this._center}get name(){return this._name}set name(e){this._name=e}get showName(){return this._showName}set showName(e){this._showName=e}get zIndex(){return this._zIndex}set zIndex(e){this._zIndex=e}get visible(){return this._visible??!1}set visible(e){this._visible=e}get color(){return this._color}set color(e){this._color=e}get selectable(){return this._selectable}set selectable(e){this._selectable=e}get movable(){return this._movable}set movable(e){this._movable=e}get resizable(){return this._resizable}set resizable(e){this._resizable=e}getBounds(){return new l.Rectangle(this.center.x-this._radius,this.center.y-this._radius,2*this._radius,2*this._radius)}getOuterBounds(){let e=this.getBounds(),t=this.getResizeHandles();return t.length===0||t.forEach(s=>{e=e.expand(s.rect)}),e}getEventInteractions(e){let t=[];if(this._resizable&&this.getResizeHandles().forEach(i=>{(e===null||i.rect.contains(e))&&t.push({eventTypePrefix:"resize",handleIndex:i.handleIndex})}),this._movable){let s=this.getBounds();(e===null||s.contains(e))&&t.push({eventTypePrefix:"move"})}if(this._selectable){let s=this.getBounds();(e===null||s.contains(e))&&t.push({eventTypePrefix:"select"})}return t}getResizeHandles(){let e=this.getBounds().origin.x,t=this.getBounds().origin.y,s=this.getBounds().size.width,i=this.getBounds().size.height,n=Z.HANDLE_SIZE,r=n*10,o=n*6,a=1;s>=r&&i>=r?a=-1:s>=o&&i>=o&&(a=0);let c=s<o,d=i<o;return[{rect:new l.Rectangle(new l.Point(e-a*n-n,t-a*n-n),new l.Size(n*2,n*2)),handleIndex:0},c?null:{rect:new l.Rectangle(new l.Point(e+s/2-n,t-a*n-n),new l.Size(n*2,n*2)),handleIndex:1},{rect:new l.Rectangle(new l.Point(e+s+a*n-n,t-a*n-n),new l.Size(n*2,n*2)),handleIndex:2},d?null:{rect:new l.Rectangle(new l.Point(e+s+a*n-n,t+i/2-n),new l.Size(n*2,n*2)),handleIndex:3},{rect:new l.Rectangle(new l.Point(e+s+a*n-n,t+i+a*n-n),new l.Size(n*2,n*2)),handleIndex:4},c?null:{rect:new l.Rectangle(new l.Point(e+s/2-n,t+i+a*n-n),new l.Size(n*2,n*2)),handleIndex:5},{rect:new l.Rectangle(new l.Point(e-a*n-n,t+i+a*n-n),new l.Size(n*2,n*2)),handleIndex:6},d?null:{rect:new l.Rectangle(new l.Point(e-a*n-n,t+i/2-n),new l.Size(n*2,n*2)),handleIndex:7}].filter(g=>g!==null)}handleEvent(e,t){let s=e.data||{};if(e.type==="setcolor"){let i=this._color;this._color=s.color,t(b.ObjectColorChanged,{object:this,oldColor:i,newColor:this._color});return}if(e.type==="setzindex"){let i=this._zIndex;this._zIndex=s.zIndex,t(b.ObjectZIndexChanged,{object:this,oldZIndex:i,newZIndex:this._zIndex});return}if(e.type==="setselectable"){let i=this._selectable;this._selectable=s.isSelectable,t(b.ObjectSelectableChanged,{object:this,oldSelectable:i,newSelectable:this._selectable});return}if(e.type==="setmovable"){let i=this._movable;this._movable=s.isMovable,t(b.ObjectMovableChanged,{object:this,oldMovable:i,newMovable:this._movable});return}if(e.type==="setresizable"){let i=this._resizable;this._resizable=s.isResizable,t(b.ObjectResizableChanged,{object:this,oldResizable:i,newResizable:this._resizable});return}if(e.type==="setvisible"){let i=this._visible??!0;this._visible=s.isVisible,t(b.ObjectVisibleChanged,{object:this,oldVisible:i,newVisible:this._visible??!0});return}}render(e,t){let s=t.has("selected"),i=t.has("hovered"),n=t.has("hoversibling"),o=e.getTransform().a,a=x=>x/o,c=this._center.x,d=this._center.y,h=this._radius,g=a(4),v=a(2),E=a(3),z=a(4),T=this.color,I=this.withAlpha(T,.06);if(e.save(),e.beginPath(),e.arc(c,d,h,0,Math.PI*2),e.fillStyle=I,e.strokeStyle=T,e.lineWidth=v,e.fill(),e.stroke(),e.restore(),s&&(e.save(),e.beginPath(),e.arc(c,d,h+z,0,Math.PI*2),e.setLineDash([a(8),a(6)]),e.strokeStyle="rgba(0,0,0,0.4)",e.lineWidth=E,e.stroke(),e.restore()),this._resizable&&i){let x=this.getResizeHandles?.()??[];e.save(),e.lineWidth=a(n?.5:1),e.strokeStyle=T,e.fillStyle=n?"transparent":"white",e.globalAlpha=n?.75:1;for(let C of x){let _=C.rect.origin.x,u=C.rect.origin.y,p=C.rect.size.width,y=C.rect.size.height,f=a(4),w=new Path2D;w.moveTo(_+f,u),w.lineTo(_+p-f,u),w.arcTo(_+p,u,_+p,u+f,f),w.lineTo(_+p,u+y-f),w.arcTo(_+p,u+y,_+p-f,u+y,f),w.lineTo(_+f,u+y),w.arcTo(_,u+y,_,u+y-f,f),w.lineTo(_,u+f),w.arcTo(_,u,_+f,u,f),w.closePath(),e.fill(w),e.stroke(w)}e.restore()}}withAlpha(e,t){let s=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\s*\)/i);if(s){let i=parseInt(s[1]??"0",10),n=parseInt(s[2]??"0",10),r=parseInt(s[3]??"0",10);return`rgba(${i},${n},${r},${t})`}if(e.startsWith("#")){let i=e.slice(1);if(i.length===3&&(i=i.split("").map(n=>n+n).join("")),i.length===6||i.length===8){let n=parseInt(i.slice(0,2),16),r=parseInt(i.slice(2,4),16),o=parseInt(i.slice(4,6),16);return`rgba(${n},${r},${o},${t})`}}return e}};Z.HANDLE_SIZE=6;var q=Z,K=class{constructor(e,t,s,i,n,r){this.visible=!0;this.id=e,this._points=t?t.slice():[],this.color=s??"#000000",this.selectable=i??!1,this.movable=n??!1,this.zIndex=r??0}get points(){return this._points}getBounds(){if(!this._points||this._points.length===0)return new l.Rectangle(new l.Point(0,0),new l.Size(0,0));let e=this._points[0].x,t=this._points[0].x,s=this._points[0].y,i=this._points[0].y;for(let n of this._points)n.x<e&&(e=n.x),n.x>t&&(t=n.x),n.y<s&&(s=n.y),n.y>i&&(i=n.y);return new l.Rectangle(new l.Point(e,s),new l.Size(t-e,i-s))}getOuterBounds(){return this.getBounds()}getEventInteractions(e){let t=[],s=this.getBounds();return this.movable&&(e===null||s.contains(e))&&t.push({eventTypePrefix:"move"}),this.selectable&&(e===null||s.contains(e))&&t.push({eventTypePrefix:"select"}),t}handleEvent(e,t){let s=e.data||{};if(e.type==="setcolor"){let i=this.color;this.color=s.color,t(b.ObjectColorChanged,{object:this,oldColor:i,newColor:this.color});return}if(e.type==="setzindex"){let i=this.zIndex;this.zIndex=s.zIndex,t(b.ObjectZIndexChanged,{object:this,oldZIndex:i,newZIndex:this.zIndex});return}if(e.type==="setselectable"){let i=this.selectable;this.selectable=s.isSelectable,t(b.ObjectSelectableChanged,{object:this,oldSelectable:i,newSelectable:this.selectable});return}if(e.type==="setmovable"){let i=this.movable;this.movable=s.isMovable,t(b.ObjectMovableChanged,{object:this,oldMovable:i,newMovable:this.movable});return}if(e.type==="setvisible"){let i=this.visible;this.visible=s.isVisible,t(b.ObjectVisibleChanged,{object:this,oldVisible:i,newVisible:this.visible});return}if(e.type.startsWith("move")){let i=s.delta;if(i==null){console.warn("Move event missing required data:",e);return}let n=this.getBounds();for(let o of this._points)o.x+=i.x,o.y+=i.y;let r=this.getBounds();t(b.ObjectMoved,{object:this,oldPoint:n.origin,newPoint:r.origin}),t(b.ObjectPositionChanged,{object:this,oldPosition:n,newPosition:r});return}}render(e,t){let s=t.has("selected"),i=t.has("hovered"),r=e.getTransform().a,o=g=>g/r,c=(()=>{if(!this._points||this._points.length===0)return null;let g=new Path2D;g.moveTo(this._points[0].x,this._points[0].y);for(let v=1;v<this._points.length;++v)g.lineTo(this._points[v].x,this._points[v].y);return g.closePath(),g})();if(!c)return;let d=this.getBounds();e.save(),e.strokeStyle=this.color;let h=e.strokeStyle;if(e.fillStyle=this.withAlpha(h,.06),e.lineWidth=o(2),e.fill(c),e.stroke(c),e.restore(),s){let g=o(3),v=o(4),E=d.origin.x-v,z=d.origin.y-v,T=d.size.width+v*2,I=d.size.height+v*2;e.save(),e.setLineDash([o(8),o(6)]),e.lineDashOffset=0,e.strokeStyle="rgba(0,0,0,0.4)",e.lineWidth=g,e.strokeRect(E,z,T,I),e.restore()}}withAlpha(e,t){let s=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\s*\)/i);if(s){let i=parseInt(s[1]??"0",10),n=parseInt(s[2]??"0",10),r=parseInt(s[3]??"0",10);return`rgba(${i},${n},${r},${t})`}if(e.startsWith("#")){let i=e.slice(1);if(i.length===3&&(i=i.split("").map(n=>n+n).join("")),i.length===6||i.length===8){let n=parseInt(i.slice(0,2),16),r=parseInt(i.slice(2,4),16),o=parseInt(i.slice(4,6),16);return`rgba(${n},${r},${o},${t})`}}return e}},Q=class{constructor(e=1e3){this.intervalId=null;this.interval=e,this.intervalId=null}attach(e,t){this.start(e)}detach(){this.stop()}start(e){this.intervalId=window.setInterval(()=>{e({type:"tick",data:{}})},this.interval)}stop(){this.intervalId!==null&&(clearInterval(this.intervalId),this.intervalId=null)}},R=class{constructor(e){this.listeners=[];this.canvas=e}attach(e,t){let s=(i,n,r)=>{typeof n=="string"&&(n=[n]);for(let o of n)i.addEventListener(o,r),this.listeners.push({target:i,type:o,handler:r})};s(this.canvas,"pointerdown",i=>{let n=i,r=new l.Point(n.offsetX,n.offsetY),o=t.screenToWorld(r),a=!!n.shiftKey,c=!!n.metaKey,d=!!n.ctrlKey,h=!!n.altKey;e({type:"pointerdown",data:{point:o,identifier:n.pointerId,pointerType:n.pointerType,originalEvent:n,button:n.button,shiftHeld:a,metaHeld:c,ctrlHeld:d,altHeld:h}})}),s(this.canvas,"pointermove",i=>{let n=i;n.preventDefault();let r=new l.Point(n.offsetX,n.offsetY),o=t.screenToWorld(r),a=!!n.shiftKey,c=!!n.metaKey,d=!!n.ctrlKey,h=!!n.altKey;e({type:"pointermove",data:{point:o,identifier:n.pointerId,pointerType:n.pointerType,originalEvent:n,button:n.button,shiftHeld:a,metaHeld:c,ctrlHeld:d,altHeld:h}})}),s(this.canvas,"pointerup",i=>{let n=i;n.preventDefault();let r=new l.Point(n.offsetX,n.offsetY),o=t.screenToWorld(r),a=!!n.shiftKey,c=!!n.metaKey,d=!!n.ctrlKey,h=!!n.altKey;e({type:"pointerup",data:{point:o,identifier:n.pointerId,pointerType:n.pointerType,originalEvent:n,button:n.button,shiftHeld:a,metaHeld:c,ctrlHeld:d,altHeld:h}})}),s(this.canvas,"pointercancel",i=>{let n=i;if(n.pointerType==="touch")return;n.preventDefault();let r=new l.Point(n.offsetX,n.offsetY),o=t.screenToWorld(r),a=!!n.shiftKey,c=!!n.metaKey,d=!!n.ctrlKey,h=!!n.altKey;e({type:"pointercancel",data:{point:o,identifier:n.pointerId,pointerType:n.pointerType,originalEvent:n,button:n.button,shiftHeld:a,metaHeld:c,ctrlHeld:d,altHeld:h}})}),s(this.canvas,["touchstart","touchmove","touchend","touchcancel"],i=>{let n=i;n.preventDefault();let r=o=>Array.from(o).map(a=>{let c=this.canvas.getBoundingClientRect();(c.top!=0||c.left!=0)&&console.warn("Canvas rect is not at 0,0, this may cause issues with touch coordinates.");let d=new l.Point(a.clientX,a.clientY),h=t.screenToWorld(d);return{identifier:a.identifier,point:h,originalTouch:a}});e({type:i.type,data:{touches:r(n.touches),targetTouches:r(n.targetTouches),changedTouches:r(n.changedTouches),originalEvent:n}})}),s(this.canvas,"wheel",i=>{i.preventDefault();let n=i,r=new l.Point(n.offsetX,n.offsetY),o=t.screenToWorld(r),a=new l.Vector(n.deltaX,n.deltaY);e({type:"wheel",data:{delta:a,point:o,originalEvent:n}})}),s(window,"resize",()=>{let i=new l.Size(window.innerWidth,window.innerHeight);e({type:"windowresize",data:{size:i}})})}detach(){this.listeners.forEach(({target:e,type:t,handler:s})=>{e.removeEventListener(t,s)}),this.listeners=[]}},O=class{constructor(e){this.id=crypto.randomUUID();this.visible=!0;this.zIndex=-1/0;this.selectable=!1;this.img=e}get width(){return this.img.naturalWidth}get height(){return this.img.naturalHeight}getEventInteractions(e){return[{eventTypePrefix:"drag"}]}getBounds(){return new l.Rectangle(new l.Point(0,0),new l.Size(this.img.width,this.img.height))}getOuterBounds(){return this.getBounds()}render(e,t){e.drawImage(this.img,0,0)}},X=class{constructor(){this.listeners=new Map}on(e,t,s){this.listeners.has(e)||this.listeners.set(e,new Set);let i=s?.once?(n=>{this.off(e,i),t(n)}):t;this.listeners.get(e).add(i)}off(e,t){this.listeners.get(e)?.delete(t)}emit(e,t){this.listeners.get(e)?.forEach(s=>s(t))}},b={ObjectPositionChanged:"object:positionchanged",ObjectResized:"object:resized",ObjectMoved:"object:moved",ObjectColorChanged:"object:colorchanged",ObjectZIndexChanged:"object:zindexchanged",ObjectSelectableChanged:"object:selectablechanged",ObjectMovableChanged:"object:movablechanged",ObjectResizableChanged:"object:resizablechanged",ObjectVisibleChanged:"object:visiblechanged",ObjectChanged:"object:changed",ObjectSelected:"object:selected",ObjectDeselected:"object:deselected",ObjectFlagsAdded:"object:flagsadded",ObjectFlagsRemoved:"object:flagsremoved",ObjectAdded:"object:added",ObjectRemoved:"object:removed",ViewportChanged:"viewport:changed",DrawingCompleted:"drawing:completed",EngineStarted:"engine:started",EngineError:"engine:error",EngineBackgroundChanged:"engine:backgroundchanged",EngineRenderStarted:"engine:renderstarted",EngineRenderCompleted:"engine:rendercompleted",EngineModeChanged:"engine:modechanged"},Y=class{constructor(e,t){this.engine=t,this.config=e}processToolEvent(e,t){this.config?.handleEvent&&this.config.handleEvent(e,this.engine)}},U=class{constructor(e,t={}){this.defaultBackgroundImage=`<svg xmlns="http://www.w3.org/2000/svg" width="816" height="1056">
1
+ "use strict";var $=Object.defineProperty;var te=Object.getOwnPropertyDescriptor;var ne=Object.getOwnPropertyNames;var ie=Object.prototype.hasOwnProperty;var se=(y,e)=>{for(var t in e)$(y,t,{get:e[t],enumerable:!0})},oe=(y,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ne(e))!ie.call(y,i)&&i!==t&&$(y,i,{get:()=>e[i],enumerable:!(s=te(e,i))||s.enumerable});return y};var ae=y=>oe($({},"__esModule",{value:!0}),y);var re={};se(re,{ApiTool:()=>F,CanvasEngine:()=>G,CircleObject:()=>K,ClickGestureRecognizer:()=>V,DomEventSource:()=>S,DragGestureRecognizer:()=>Z,DrawingTool:()=>L,EngineEventType:()=>b,HoverTool:()=>D,LassoTool:()=>H,MoveTool:()=>M,PolygonObject:()=>Q,ResizeTool:()=>A,SelectTool:()=>B,ToolLockManager:()=>k,Zone:()=>q});module.exports=ae(re);var c=require("dytools-geometry"),W=class W{constructor(e,t,s,i,n,o,a,r,l,d){this._name=null;this._showName=!1;this._nameAnchor="TopLeft";this._visible=!0;if(this._id=e,t instanceof c.Rectangle){let h=t,p=s??"#000000",u=i??!1,E=n??!1,P=o??!1,z=a??0;this._rect=h,this._color=p,this._selectable=u,this._movable=E,this._resizable=P,this._zIndex=z}else{let h=t,p=s,u=i,E=n,P=o??"#000000",z=a??!1,_=r??!1,O=l??!1,x=d??0;this._rect=new c.Rectangle(new c.Point(h,p),new c.Size(u,E)),this._color=P,this._selectable=z,this._movable=_,this._resizable=O,this._zIndex=x}}get id(){return this._id}set id(e){this._id=e}get rect(){return this._rect.normalized()}get name(){return this._name}set name(e){this._name=e}get showName(){return this._showName}set showName(e){this._showName=e}get nameAnchor(){return this._nameAnchor}set nameAnchor(e){this._nameAnchor=e}get zIndex(){return this._zIndex}set zIndex(e){this._zIndex=e}get visible(){return this._visible??!1}set visible(e){this._visible=e}get color(){return this._color}set color(e){this._color=e}get selectable(){return this._selectable}set selectable(e){this._selectable=e}get movable(){return this._movable}set movable(e){this._movable=e}get resizable(){return this._resizable}set resizable(e){this._resizable=e}getBounds(e){return this._rect}getOuterBounds(e){let t=this._rect,s=this.getResizeHandles(e);return s.length===0||s.forEach(i=>{t=t.expand(i.rect)}),t}getEventInteractions(e,t){let s=[];if(this._resizable&&this.getResizeHandles(t).forEach(n=>{(e===null||n.rect.contains(e))&&s.push({eventTypePrefix:"resize",handleIndex:n.handleIndex})}),this._movable){let i=this.getBounds(t);(e===null||i.contains(e))&&s.push({eventTypePrefix:"move"})}if(this._selectable){let i=this.getBounds(t);(e===null||i.contains(e))&&s.push({eventTypePrefix:"select"})}return s}getResizeHandles(e){let t=this._rect.origin.x,s=this._rect.origin.y,i=this._rect.size.width,n=this._rect.size.height,o=W.HANDLE_SIZE*e.currentScaleMultiplier,a=o*10,r=o*6,l=1;i>=a&&n>=a?l=-1:i>=r&&n>=r&&(l=0);let d=i<r,h=n<r;return[{rect:new c.Rectangle(new c.Point(t-l*o-o,s-l*o-o),new c.Size(o*2,o*2)),handleIndex:0},d?null:{rect:new c.Rectangle(new c.Point(t+i/2-o,s-l*o-o),new c.Size(o*2,o*2)),handleIndex:1},{rect:new c.Rectangle(new c.Point(t+i+l*o-o,s-l*o-o),new c.Size(o*2,o*2)),handleIndex:2},h?null:{rect:new c.Rectangle(new c.Point(t+i+l*o-o,s+n/2-o),new c.Size(o*2,o*2)),handleIndex:3},{rect:new c.Rectangle(new c.Point(t+i+l*o-o,s+n+l*o-o),new c.Size(o*2,o*2)),handleIndex:4},d?null:{rect:new c.Rectangle(new c.Point(t+i/2-o,s+n+l*o-o),new c.Size(o*2,o*2)),handleIndex:5},{rect:new c.Rectangle(new c.Point(t-l*o-o,s+n+l*o-o),new c.Size(o*2,o*2)),handleIndex:6},h?null:{rect:new c.Rectangle(new c.Point(t-l*o-o,s+n/2-o),new c.Size(o*2,o*2)),handleIndex:7}].filter(u=>u!==null)}handleEvent(e,t){let s=e.data||{};if(e.type==="setcolor"&&this._color!==s.color){let n=this._color;this._color=s.color,t(b.ObjectColorChanged,{object:this,oldColor:n,newColor:this._color});return}if(e.type==="setzindex"&&this._zIndex!==s.zIndex){let n=this._zIndex;this._zIndex=s.zIndex,t(b.ObjectZIndexChanged,{object:this,oldZIndex:n,newZIndex:this._zIndex});return}if(e.type==="setselectable"&&this._selectable!==s.isSelectable){let n=this._selectable;this._selectable=s.isSelectable,t(b.ObjectSelectableChanged,{object:this,oldSelectable:n,newSelectable:this._selectable});return}if(e.type==="setmovable"&&this._movable!==s.isMovable){let n=this._movable;this._movable=s.isMovable,t(b.ObjectMovableChanged,{object:this,oldMovable:n,newMovable:this._movable});return}if(e.type==="setresizable"&&this._resizable!==s.isResizable){let n=this._resizable;this._resizable=s.isResizable,t(b.ObjectResizableChanged,{object:this,oldResizable:n,newResizable:this._resizable});return}if(e.type==="setvisible"&&this._visible!==s.isVisible){let n=this._visible??!0;this._visible=s.isVisible,t(b.ObjectVisibleChanged,{object:this,oldVisible:n,newVisible:this._visible??!0});return}let i=s.delta;if(e.type==="resize"){let n=this._rect.clone(),o=s.handleIndex;if(i==null||o==null){console.warn("Resize event missing required data:",e);return}let a=-1/0,r=i.x,l=i.y;if(r===0&&l===0)return;switch(o){case 0:r=Math.min(r,this._rect.size.width-a),l=Math.min(l,this._rect.size.height-a),this._rect.origin.x+=r,this._rect.origin.y+=l,this._rect.size.width-=r,this._rect.size.height-=l;break;case 1:l=Math.min(l,this._rect.size.height-a),this._rect.origin.y+=l,this._rect.size.height-=l;break;case 2:r=Math.max(r,a-this._rect.size.width),l=Math.min(l,this._rect.size.height-a),this._rect.origin.y+=l,this._rect.size.width+=r,this._rect.size.height-=l;break;case 3:r=Math.max(r,a-this._rect.size.width),this._rect.size.width+=r;break;case 4:r=Math.max(r,a-this._rect.size.width),l=Math.max(l,a-this._rect.size.height),this._rect.size.width+=r,this._rect.size.height+=l;break;case 5:l=Math.max(l,a-this._rect.size.height),this._rect.size.height+=l;break;case 6:r=Math.min(r,this._rect.size.width-a),l=Math.max(l,a-this._rect.size.height),this._rect.origin.x+=r,this._rect.size.width-=r,this._rect.size.height+=l;break;case 7:r=Math.min(r,this._rect.size.width-a),this._rect.origin.x+=r,this._rect.size.width-=r;break}t(b.ObjectResized,{object:this,oldSize:n.size,newSize:this._rect.clone().size}),t(b.ObjectPositionChanged,{object:this,oldPosition:n,newPosition:this._rect.clone()})}else e.type==="resizeend"&&this._rect.normalize();if(e.type.startsWith("move")){if(i==null){console.warn("Move event missing required data:",e);return}if(i.x===0&&i.y===0)return;let n=this._rect.clone();this._rect=this._rect.move(i),t(b.ObjectMoved,{object:this,oldPoint:n.origin,newPoint:this._rect.clone().origin}),t(b.ObjectPositionChanged,{object:this,oldPosition:n,newPosition:this._rect})}}render(e,t,s){let i=t.has("selected"),n=t.has("hovered"),o=t.has("hoversibling"),r=e.getTransform().a,l=g=>g/r,d=l(4),h=l(2),p=l(3),u=l(4),E=this._rect,P=E.origin.x,z=E.origin.y,_=E.size.width,O=E.size.height,x=(g,f,v,m,C)=>{let w=Math.max(0,Math.min(C,Math.min(v,m)/2)),j=new Path2D;return j.moveTo(g+w,f),j.lineTo(g+v-w,f),j.arcTo(g+v,f,g+v,f+w,w),j.lineTo(g+v,f+m-w),j.arcTo(g+v,f+m,g+v-w,f+m,w),j.lineTo(g+w,f+m),j.arcTo(g,f+m,g,f+m-w,w),j.lineTo(g,f+w),j.arcTo(g,f,g+w,f,w),j.closePath(),j},T=x(P,z,_,O,d);e.save(),e.strokeStyle=this._color;let I=e.strokeStyle;if(e.fillStyle=this.withAlpha(I,.06),e.fill(T),e.lineWidth=h,e.stroke(T),e.restore(),i){let g=P-u,f=z-u,v=_+u*2,m=O+u*2,C=x(g,f,v,m,d+u);e.save(),e.setLineDash([l(8),l(6)]),e.lineDashOffset=0,e.strokeStyle="rgba(0,0,0,0.4)",e.lineWidth=p,e.stroke(C),e.restore()}if(this._showName&&this._name){e.save(),e.font="12px sans-serif",e.fillStyle=this._color,e.textBaseline="top";let g=2,{x:f,y:v}=this._rect.origin,{width:m,height:C}=this._rect.size,w=f+g,j=v+g;switch(this._nameAnchor){case"TopLeft":w=f+g,j=v+g;break;case"TopRight":w=f+m-e.measureText(this._name).width-g,j=v+g;break;case"BottomLeft":w=f+g,j=v+C-14-g;break;case"BottomRight":w=f+m-e.measureText(this._name).width-g,j=v+C-14-g;break;case"Center":w=f+(m-e.measureText(this._name).width)/2,j=v+(C-12)/2;break}e.fillText(this._name,w,j),e.restore()}if(this._resizable&&n){e.save(),e.lineWidth=l(o?.5:1),e.strokeStyle=I,e.fillStyle=o?"transparent":"white",e.globalAlpha=o?.75:1;for(let g of this.getResizeHandles(s)||[]){if(!g)continue;let{x:f,y:v}=g.rect.origin,{width:m,height:C}=g.rect.size,w=l(4),j=x(f,v,m,C,w);e.fill(j),e.stroke(j)}e.restore()}}withAlpha(e,t){let s=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\s*\)/i);if(s){let i=parseInt(s[1]??"0",10),n=parseInt(s[2]??"0",10),o=parseInt(s[3]??"0",10);return`rgba(${i},${n},${o},${t})`}if(e.startsWith("#")){let i=e.slice(1);if(i.length===3&&(i=i.split("").map(n=>n+n).join("")),i.length===6||i.length===8){let n=parseInt(i.slice(0,2),16),o=parseInt(i.slice(2,4),16),a=parseInt(i.slice(4,6),16);return`rgba(${n},${o},${a},${t})`}}return e}};W.HANDLE_SIZE=6;var q=W,N=class N{constructor(e,t,s,i,n,o,a,r,l){this._name=null;this._showName=!1;this._visible=!0;if(this._id=e,t instanceof c.Point){let d=t,h=s,p=i??"#000000",u=n??!1,E=o??!1,P=a??!1,z=r??0;this._center=d,this._radius=h,this._color=p,this._selectable=u,this._movable=E,this._resizable=P,this._zIndex=z}else{let d=t,h=s,p=i,u=n??"#000000",E=o??!1,P=a??!1,z=r??!1,_=l??0;this._center=new c.Point(d,h),this._radius=p,this._color=u,this._selectable=E,this._movable=P,this._resizable=z,this._zIndex=_}}get id(){return this._id}set id(e){this._id=e}get center(){return this._center}get name(){return this._name}set name(e){this._name=e}get showName(){return this._showName}set showName(e){this._showName=e}get zIndex(){return this._zIndex}set zIndex(e){this._zIndex=e}get visible(){return this._visible??!1}set visible(e){this._visible=e}get color(){return this._color}set color(e){this._color=e}get selectable(){return this._selectable}set selectable(e){this._selectable=e}get movable(){return this._movable}set movable(e){this._movable=e}get resizable(){return this._resizable}set resizable(e){this._resizable=e}getBounds(){return new c.Rectangle(this.center.x-this._radius,this.center.y-this._radius,2*this._radius,2*this._radius)}getOuterBounds(){let e=this.getBounds(),t=this.getResizeHandles();return t.length===0||t.forEach(s=>{e=e.expand(s.rect)}),e}getEventInteractions(e){let t=[];if(this._resizable&&this.getResizeHandles().forEach(i=>{(e===null||i.rect.contains(e))&&t.push({eventTypePrefix:"resize",handleIndex:i.handleIndex})}),this._movable){let s=this.getBounds();(e===null||s.contains(e))&&t.push({eventTypePrefix:"move"})}if(this._selectable){let s=this.getBounds();(e===null||s.contains(e))&&t.push({eventTypePrefix:"select"})}return t}getResizeHandles(){let e=this.getBounds().origin.x,t=this.getBounds().origin.y,s=this.getBounds().size.width,i=this.getBounds().size.height,n=N.HANDLE_SIZE,o=n*10,a=n*6,r=1;s>=o&&i>=o?r=-1:s>=a&&i>=a&&(r=0);let l=s<a,d=i<a;return[{rect:new c.Rectangle(new c.Point(e-r*n-n,t-r*n-n),new c.Size(n*2,n*2)),handleIndex:0},l?null:{rect:new c.Rectangle(new c.Point(e+s/2-n,t-r*n-n),new c.Size(n*2,n*2)),handleIndex:1},{rect:new c.Rectangle(new c.Point(e+s+r*n-n,t-r*n-n),new c.Size(n*2,n*2)),handleIndex:2},d?null:{rect:new c.Rectangle(new c.Point(e+s+r*n-n,t+i/2-n),new c.Size(n*2,n*2)),handleIndex:3},{rect:new c.Rectangle(new c.Point(e+s+r*n-n,t+i+r*n-n),new c.Size(n*2,n*2)),handleIndex:4},l?null:{rect:new c.Rectangle(new c.Point(e+s/2-n,t+i+r*n-n),new c.Size(n*2,n*2)),handleIndex:5},{rect:new c.Rectangle(new c.Point(e-r*n-n,t+i+r*n-n),new c.Size(n*2,n*2)),handleIndex:6},d?null:{rect:new c.Rectangle(new c.Point(e-r*n-n,t+i/2-n),new c.Size(n*2,n*2)),handleIndex:7}].filter(p=>p!==null)}handleEvent(e,t){let s=e.data||{};if(e.type==="setcolor"){let i=this._color;this._color=s.color,t(b.ObjectColorChanged,{object:this,oldColor:i,newColor:this._color});return}if(e.type==="setzindex"){let i=this._zIndex;this._zIndex=s.zIndex,t(b.ObjectZIndexChanged,{object:this,oldZIndex:i,newZIndex:this._zIndex});return}if(e.type==="setselectable"){let i=this._selectable;this._selectable=s.isSelectable,t(b.ObjectSelectableChanged,{object:this,oldSelectable:i,newSelectable:this._selectable});return}if(e.type==="setmovable"){let i=this._movable;this._movable=s.isMovable,t(b.ObjectMovableChanged,{object:this,oldMovable:i,newMovable:this._movable});return}if(e.type==="setresizable"){let i=this._resizable;this._resizable=s.isResizable,t(b.ObjectResizableChanged,{object:this,oldResizable:i,newResizable:this._resizable});return}if(e.type==="setvisible"){let i=this._visible??!0;this._visible=s.isVisible,t(b.ObjectVisibleChanged,{object:this,oldVisible:i,newVisible:this._visible??!0});return}}render(e,t){let s=t.has("selected"),i=t.has("hovered"),n=t.has("hoversibling"),a=e.getTransform().a,r=O=>O/a,l=this._center.x,d=this._center.y,h=this._radius,p=r(4),u=r(2),E=r(3),P=r(4),z=this.color,_=this.withAlpha(z,.06);if(e.save(),e.beginPath(),e.arc(l,d,h,0,Math.PI*2),e.fillStyle=_,e.strokeStyle=z,e.lineWidth=u,e.fill(),e.stroke(),e.restore(),s&&(e.save(),e.beginPath(),e.arc(l,d,h+P,0,Math.PI*2),e.setLineDash([r(8),r(6)]),e.strokeStyle="rgba(0,0,0,0.4)",e.lineWidth=E,e.stroke(),e.restore()),this._resizable&&i){let O=this.getResizeHandles?.()??[];e.save(),e.lineWidth=r(n?.5:1),e.strokeStyle=z,e.fillStyle=n?"transparent":"white",e.globalAlpha=n?.75:1;for(let x of O){let T=x.rect.origin.x,I=x.rect.origin.y,g=x.rect.size.width,f=x.rect.size.height,v=r(4),m=new Path2D;m.moveTo(T+v,I),m.lineTo(T+g-v,I),m.arcTo(T+g,I,T+g,I+v,v),m.lineTo(T+g,I+f-v),m.arcTo(T+g,I+f,T+g-v,I+f,v),m.lineTo(T+v,I+f),m.arcTo(T,I+f,T,I+f-v,v),m.lineTo(T,I+v),m.arcTo(T,I,T+v,I,v),m.closePath(),e.fill(m),e.stroke(m)}e.restore()}}withAlpha(e,t){let s=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\s*\)/i);if(s){let i=parseInt(s[1]??"0",10),n=parseInt(s[2]??"0",10),o=parseInt(s[3]??"0",10);return`rgba(${i},${n},${o},${t})`}if(e.startsWith("#")){let i=e.slice(1);if(i.length===3&&(i=i.split("").map(n=>n+n).join("")),i.length===6||i.length===8){let n=parseInt(i.slice(0,2),16),o=parseInt(i.slice(2,4),16),a=parseInt(i.slice(4,6),16);return`rgba(${n},${o},${a},${t})`}}return e}};N.HANDLE_SIZE=6;var K=N,Q=class{constructor(e,t,s,i,n,o){this.visible=!0;this.id=e,this._points=t?t.slice():[],this.color=s??"#000000",this.selectable=i??!1,this.movable=n??!1,this.zIndex=o??0}get points(){return this._points}getBounds(){if(!this._points||this._points.length===0)return new c.Rectangle(new c.Point(0,0),new c.Size(0,0));let e=this._points[0].x,t=this._points[0].x,s=this._points[0].y,i=this._points[0].y;for(let n of this._points)n.x<e&&(e=n.x),n.x>t&&(t=n.x),n.y<s&&(s=n.y),n.y>i&&(i=n.y);return new c.Rectangle(new c.Point(e,s),new c.Size(t-e,i-s))}getOuterBounds(){return this.getBounds()}getEventInteractions(e){let t=[],s=this.getBounds();return this.movable&&(e===null||s.contains(e))&&t.push({eventTypePrefix:"move"}),this.selectable&&(e===null||s.contains(e))&&t.push({eventTypePrefix:"select"}),t}handleEvent(e,t){let s=e.data||{};if(e.type==="setcolor"){let i=this.color;this.color=s.color,t(b.ObjectColorChanged,{object:this,oldColor:i,newColor:this.color});return}if(e.type==="setzindex"){let i=this.zIndex;this.zIndex=s.zIndex,t(b.ObjectZIndexChanged,{object:this,oldZIndex:i,newZIndex:this.zIndex});return}if(e.type==="setselectable"){let i=this.selectable;this.selectable=s.isSelectable,t(b.ObjectSelectableChanged,{object:this,oldSelectable:i,newSelectable:this.selectable});return}if(e.type==="setmovable"){let i=this.movable;this.movable=s.isMovable,t(b.ObjectMovableChanged,{object:this,oldMovable:i,newMovable:this.movable});return}if(e.type==="setvisible"){let i=this.visible;this.visible=s.isVisible,t(b.ObjectVisibleChanged,{object:this,oldVisible:i,newVisible:this.visible});return}if(e.type.startsWith("move")){let i=s.delta;if(i==null){console.warn("Move event missing required data:",e);return}let n=this.getBounds();for(let a of this._points)a.x+=i.x,a.y+=i.y;let o=this.getBounds();t(b.ObjectMoved,{object:this,oldPoint:n.origin,newPoint:o.origin}),t(b.ObjectPositionChanged,{object:this,oldPosition:n,newPosition:o});return}}render(e,t){let s=t.has("selected"),i=t.has("hovered"),o=e.getTransform().a,a=p=>p/o,l=(()=>{if(!this._points||this._points.length===0)return null;let p=new Path2D;p.moveTo(this._points[0].x,this._points[0].y);for(let u=1;u<this._points.length;++u)p.lineTo(this._points[u].x,this._points[u].y);return p.closePath(),p})();if(!l)return;let d=this.getBounds();e.save(),e.strokeStyle=this.color;let h=e.strokeStyle;if(e.fillStyle=this.withAlpha(h,.06),e.lineWidth=a(2),e.fill(l),e.stroke(l),e.restore(),s){let p=a(3),u=a(4),E=d.origin.x-u,P=d.origin.y-u,z=d.size.width+u*2,_=d.size.height+u*2;e.save(),e.setLineDash([a(8),a(6)]),e.lineDashOffset=0,e.strokeStyle="rgba(0,0,0,0.4)",e.lineWidth=p,e.strokeRect(E,P,z,_),e.restore()}}withAlpha(e,t){let s=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\s*\)/i);if(s){let i=parseInt(s[1]??"0",10),n=parseInt(s[2]??"0",10),o=parseInt(s[3]??"0",10);return`rgba(${i},${n},${o},${t})`}if(e.startsWith("#")){let i=e.slice(1);if(i.length===3&&(i=i.split("").map(n=>n+n).join("")),i.length===6||i.length===8){let n=parseInt(i.slice(0,2),16),o=parseInt(i.slice(2,4),16),a=parseInt(i.slice(4,6),16);return`rgba(${n},${o},${a},${t})`}}return e}},X=class{constructor(e=1e3){this.intervalId=null;this.interval=e,this.intervalId=null}attach(e,t){this.start(e)}detach(){this.stop()}start(e){this.intervalId=window.setInterval(()=>{e({type:"tick",data:{}})},this.interval)}stop(){this.intervalId!==null&&(clearInterval(this.intervalId),this.intervalId=null)}},S=class{constructor(e){this.listeners=[];this.canvas=e}attach(e,t){let s=(i,n,o)=>{typeof n=="string"&&(n=[n]);for(let a of n)i.addEventListener(a,o),this.listeners.push({target:i,type:a,handler:o})};s(this.canvas,"pointerdown",i=>{let n=i,o=new c.Point(n.offsetX,n.offsetY),a=t.screenToWorld(o),r=!!n.shiftKey,l=!!n.metaKey,d=!!n.ctrlKey,h=!!n.altKey;e({type:"pointerdown",data:{point:a,identifier:n.pointerId,pointerType:n.pointerType,originalEvent:n,button:n.button,shiftHeld:r,metaHeld:l,ctrlHeld:d,altHeld:h}})}),s(this.canvas,"pointermove",i=>{let n=i;n.preventDefault();let o=new c.Point(n.offsetX,n.offsetY),a=t.screenToWorld(o),r=!!n.shiftKey,l=!!n.metaKey,d=!!n.ctrlKey,h=!!n.altKey;e({type:"pointermove",data:{point:a,identifier:n.pointerId,pointerType:n.pointerType,originalEvent:n,button:n.button,shiftHeld:r,metaHeld:l,ctrlHeld:d,altHeld:h}})}),s(this.canvas,"pointerup",i=>{let n=i;n.preventDefault();let o=new c.Point(n.offsetX,n.offsetY),a=t.screenToWorld(o),r=!!n.shiftKey,l=!!n.metaKey,d=!!n.ctrlKey,h=!!n.altKey;e({type:"pointerup",data:{point:a,identifier:n.pointerId,pointerType:n.pointerType,originalEvent:n,button:n.button,shiftHeld:r,metaHeld:l,ctrlHeld:d,altHeld:h}})}),s(this.canvas,"pointercancel",i=>{let n=i;if(n.pointerType==="touch")return;n.preventDefault();let o=new c.Point(n.offsetX,n.offsetY),a=t.screenToWorld(o),r=!!n.shiftKey,l=!!n.metaKey,d=!!n.ctrlKey,h=!!n.altKey;e({type:"pointercancel",data:{point:a,identifier:n.pointerId,pointerType:n.pointerType,originalEvent:n,button:n.button,shiftHeld:r,metaHeld:l,ctrlHeld:d,altHeld:h}})}),s(this.canvas,["touchstart","touchmove","touchend","touchcancel"],i=>{let n=i;n.preventDefault();let o=a=>Array.from(a).map(r=>{let l=this.canvas.getBoundingClientRect();(l.top!=0||l.left!=0)&&console.warn("Canvas rect is not at 0,0, this may cause issues with touch coordinates.");let d=new c.Point(r.clientX,r.clientY),h=t.screenToWorld(d);return{identifier:r.identifier,point:h,originalTouch:r}});e({type:i.type,data:{touches:o(n.touches),targetTouches:o(n.targetTouches),changedTouches:o(n.changedTouches),originalEvent:n}})}),s(this.canvas,"wheel",i=>{i.preventDefault();let n=i,o=new c.Point(n.offsetX,n.offsetY),a=t.screenToWorld(o),r=new c.Vector(n.deltaX,n.deltaY);e({type:"wheel",data:{delta:r,point:a,originalEvent:n}})}),s(window,"resize",()=>{let i=new c.Size(window.innerWidth,window.innerHeight);e({type:"windowresize",data:{size:i}})})}detach(){this.listeners.forEach(({target:e,type:t,handler:s})=>{e.removeEventListener(t,s)}),this.listeners=[]}},R=class{constructor(e){this.id=crypto.randomUUID();this.visible=!0;this.zIndex=-1/0;this.selectable=!1;this.img=e}get width(){return this.img.naturalWidth}get height(){return this.img.naturalHeight}getEventInteractions(e){return[{eventTypePrefix:"drag"}]}getBounds(){return new c.Rectangle(new c.Point(0,0),new c.Size(this.img.width,this.img.height))}getOuterBounds(){return this.getBounds()}render(e,t){e.drawImage(this.img,0,0)}},Y=class{constructor(){this.listeners=new Map}on(e,t,s){this.listeners.has(e)||this.listeners.set(e,new Set);let i=s?.once?(n=>{this.off(e,i),t(n)}):t;this.listeners.get(e).add(i)}off(e,t){this.listeners.get(e)?.delete(t)}emit(e,t){this.listeners.get(e)?.forEach(s=>s(t))}},b={ObjectPositionChanged:"object:positionchanged",ObjectResized:"object:resized",ObjectMoved:"object:moved",ObjectColorChanged:"object:colorchanged",ObjectZIndexChanged:"object:zindexchanged",ObjectSelectableChanged:"object:selectablechanged",ObjectMovableChanged:"object:movablechanged",ObjectResizableChanged:"object:resizablechanged",ObjectVisibleChanged:"object:visiblechanged",ObjectChanged:"object:changed",ObjectSelected:"object:selected",ObjectDeselected:"object:deselected",ObjectFlagsAdded:"object:flagsadded",ObjectFlagsRemoved:"object:flagsremoved",ObjectAdded:"object:added",ObjectRemoved:"object:removed",ViewportChanged:"viewport:changed",DrawingCompleted:"drawing:completed",EngineStarted:"engine:started",EngineError:"engine:error",EngineBackgroundChanged:"engine:backgroundchanged",EngineRenderStarted:"engine:renderstarted",EngineRenderCompleted:"engine:rendercompleted",EngineModeChanged:"engine:modechanged"},U=class{constructor(e,t){this.engine=t,this.config=e}processToolEvent(e,t){this.config?.handleEvent&&this.config.handleEvent(e,this.engine)}},G=class{constructor(e,t={}){this.defaultBackgroundImage=`<svg xmlns="http://www.w3.org/2000/svg" width="816" height="1056">
2
2
  <rect width="100%" height="100%" fill="#FFF"/>
3
3
  <text x="50%" y="50%" text-anchor="middle" fill="#888"
4
4
  font-family="monospace" font-size="24">
5
5
  Sample Page
6
6
  </text>
7
- </svg>`;this.document=new Blob([this.defaultBackgroundImage],{type:"image/svg+xml;charset=utf-8"});this.emitter=new X;this.toolLockManager=new k;this.eventSources=[];this.recognizers=[];this.tools=[];this.manualRenderers=[];this.modeRenderers=[];this.eventQueue=[];this.processingQueue=!1;this.renderScheduled=!1;this.flags=new Map;this.objects=[];this.needsRender=!1;this.toolRegistry=new Map;this.modes={};this.currentMode="";this.defaultOptions={initialZoom:1,initialPan:{x:10,y:10},defaultMode:"default",addTimerEventSource:!1,proxyObjectsForEvents:!0};this._pan=new l.Vector(0,0);this._zoom=1;this.on=this.emitter.on.bind(this.emitter);this.off=this.emitter.off.bind(this.emitter);this.emitExternal=this.emitter.emit.bind(this.emitter);this.options=this.createOptions(t);let s=document.querySelector(e);if(!s)throw new Error(`Container ${e} not found`);this.container=s,this.canvas=document.createElement("canvas"),this.canvas.width=this.container.clientWidth*10,this.canvas.height=this.container.clientHeight*10,this.container.appendChild(this.canvas),this.ctx=this.canvas.getContext("2d"),this.setupDefaultEventSources(),this.setupDefaultTools(),this.setupDefaultRecognizers(),this.setupDefaultModes(),this.setupRenderNodes(),this._zoom=this.options.initialZoom,this._pan=new l.Vector(this.options.initialPan.x,this.options.initialPan.y),this.switchMode(this.options.defaultMode),this.emitExternal(b.EngineStarted,{}),this.emitExternal(b.ViewportChanged,{oldPan:new l.Vector(0,0),newPan:this.pan,oldZoom:1,newZoom:this.zoom}),this.setBackgroundImage(this.document).then()}get pan(){return this._pan.clone()}get zoom(){return this._zoom}screenToWorld(e){return new l.Point((e.x-this.pan.x)/this.zoom,(e.y-this.pan.y)/this.zoom)}worldToScreen(e){return new l.Point(e.x*this.zoom+this.pan.x,e.y*this.zoom+this.pan.y)}processToolEvent(e,t,s,i,n){e.type.startsWith("windowresize")||(this.canvas.width=this.container.clientWidth,this.canvas.height=this.container.clientHeight)}createOptions(e){return{...this.defaultOptions,...e}}setupDefaultEventSources(){this.options.addTimerEventSource&&this.register(new Q),this.register(new R(this.canvas))}setupDefaultRecognizers(){this.register(new F),this.register(new V)}setupDefaultTools(){this.registerTool("hover",()=>new B,!0),this.registerTool("select",()=>new M,!0),this.registerTool("drawing",()=>new A,!0),this.registerTool("move",()=>new S,!0),this.registerTool("resize",()=>new D,!0),this.registerTool("lasso",()=>new L,!0),this.registerTool("pan",()=>new J,!0),this.registerTool("zoom",()=>new G,!0),this.registerTool("api",()=>new H,!0)}setupDefaultModes(){this.defineMode("default",{tools:["hover","select","resize","move","pan","zoom","api"]}),this.defineMode("move",{tools:["hover","select","resize","move","pan","zoom","api"]}),this.defineMode("create",{tools:["drawing","zoom","api"],handleEvent(e,t){e.type===b.DrawingCompleted&&t.switchMode("default")}}),this.defineMode("lasso",{tools:["hover","select","lasso","zoom","api"],handleEvent(e,t){e.type==="lassoselected"&&t.switchMode("default")}})}setupRenderNodes(){}wrapInteractiveObject(e){let t=this;return new Proxy(e,{set(s,i,n){let r=s[i],o=Reflect.set(s,i,n);return typeof i=="string"&&i.startsWith("_")||r!==n&&t.emitExternal(b.ObjectChanged,{object:s,property:i.toString(),oldValue:r,newValue:n}),o}})}registerTool(e,t,s=!0){if(this.toolRegistry.has(e))throw new Error(`Tool '${e}' already registered.`);this.toolRegistry.set(e,{factory:t,singleton:s})}resolveTool(e){let t=this.toolRegistry.get(e);if(!t)throw new Error(`Unknown tool '${e}'`);return t.singleton?("instance"in t||(t.instance=t.factory()),t.instance):t.factory()}defineMode(e,t){if(this.modes[e])throw new Error(`Mode '${e}' already defined.`);this.modes[e]=t}get mode(){return this.currentMode}switchMode(e){if(!this.modes[e])throw new Error(`Unknown mode '${e}'`);if(this.toolLockManager.isLocked){console.warn("Cannot switch modes while tools are locked. Please release all locks first.");return}if(this.currentMode===e){console.warn(`Already in mode '${e}', no switch needed.`);return}let t=this.currentMode;this.currentMode=e;let s=this.modes[e];if(s.tools==null||s.tools.length==0)return;let i=s.tools;this.tools=[...new Set(i.map(n=>this.resolveTool(n)))],this.modeRenderers=s.renderers||[],s.handleEvent&&this.tools.push(new Y(s,this)),this.emitExternal(b.EngineModeChanged,{newMode:this.currentMode,oldMode:t})}get renderers(){let e=this.tools.filter(t=>typeof t=="object"&&t!==null&&("renderBeforeAll"in t||"renderBeforeObject"in t||"renderAfterObject"in t||"renderAfterAll"in t)&&(typeof t.renderBeforeAll=="function"||typeof t.renderBeforeObject=="function"||typeof t.renderAfterObject=="function"||typeof t.renderAfterAll=="function")).map(t=>t);return[...new Set([...this.manualRenderers,...this.modeRenderers,...e])]}get viewableWidth(){return this.canvas.width}get viewableHeight(){return this.canvas.height}get width(){let e=this.getObjectsWithFlag("canvas-background").filter(s=>typeof s=="object"&&s instanceof O),t;return e.length==0?this.canvas.width:(e.length>=1&&(t=e[0]),t.width)}get height(){let e=this.getObjectsWithFlag("canvas-background").filter(s=>typeof s=="object"&&s instanceof O),t;return e.length==0?this.canvas.height:(e.length>=1&&(t=e[0]),t.height)}get documentBlob(){return this.document}async setBackgroundImage(e){let t=this.width,s=this.height,i;e instanceof File||e instanceof Blob?i=e:i=await this.loadImageFromUrl(e),this.document=i;let n=URL.createObjectURL(i),r=await this.loadImage(n),o=this.getObjectsWithFlag("canvas-background");if(o.length>0){let a=o.find(c=>c instanceof O);a&&(a.img=r)}else{let a=new O(r);this.objects.push(a),this.setFlag(a.id,"canvas-background")}this.emitExternal(b.EngineBackgroundChanged,{newImage:r,newWidth:r.width,newHeight:r.height,oldWidth:t,oldHeight:s}),this.requestRender()}async loadImageFromUrl(e){let t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch image: ${t.status} ${t.statusText}`);return await t.blob()}loadImage(e){return new Promise((t,s)=>{if(e instanceof HTMLImageElement){e.complete&&e.naturalWidth!==0?t(e):(e.onload=()=>t(e),e.onerror=s);return}let i=new Image;i.onload=()=>t(i),i.onerror=s,i.src=e})}getObject(e){return this.objects.find(s=>s.id===e)}addObject(e){if(this.objects.find(s=>s.id===e.id))throw new Error(`Object with id '${e.id}' already exists.`);this.objects.push(e),this.enqueue({type:"redraw",data:{}},!0),this.emitExternal(b.ObjectAdded,{object:this.options.proxyObjectsForEvents?this.wrapInteractiveObject(e):e})}removeObject(e){let t=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!t)throw new Error(`Object not found: ${e}`);let s=this.objects.indexOf(t);if(s!==-1){this.objects.splice(s,1);let i=typeof e=="string"?e:e.id;this.flags.delete(i),this.emitExternal(b.ObjectRemoved,{object:t})}else console.warn("Attempted to remove an object that does not exist in the engine:",t);this.redraw()}moveObjectToPoint(e,t,s){let i=typeof e=="string"?this.objects.find(o=>o.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let n=typeof t=="number"?t:t.x,r=typeof t=="number"?s??0:t.y;this.enqueue({type:"api:moveto",data:{x:n,y:r},targets:[i]})}moveObjectByVector(e,t,s){let i=typeof e=="string"?this.objects.find(o=>o.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let n=typeof t=="number"?t:t.x,r=typeof t=="number"?s??0:t.y;this.enqueue({type:"api:moveby",data:{dx:n,dy:r},targets:[i]})}resizeObjectToSize(e,t,s){let i=typeof e=="string"?this.objects.find(o=>o.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let n=typeof t=="number"?t:t.width,r=typeof t=="number"?s??0:t.height;this.enqueue({type:"api:resizeto",data:{width:n,height:r},targets:[i]})}resizeObjectByVector(e,t,s){let i=typeof e=="string"?this.objects.find(o=>o.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let n=typeof t=="number"?t:t.x,r=typeof t=="number"?s??0:t.y;this.enqueue({type:"api:resizeby",data:{dw:n,dh:r},targets:[i]})}setObjectColor(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setcolor",data:{color:t},targets:[s]})}setObjectZIndex(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setzindex",data:{zIndex:t},targets:[s]})}updateObjectSelectability(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setselectable",data:{isSelectable:t},targets:[s]})}updateObjectMovability(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setmovable",data:{isMovable:t},targets:[s]})}updateObjectResizeability(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setresizable",data:{isResizable:t},targets:[s]})}updateObjectVisibility(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);s.visible!==t&&this.enqueue({type:"api:setvisible",data:{visible:t},targets:[s]})}setFlag(e,t){let s=typeof e=="string"?this.objects.find(r=>r.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);let i=typeof e=="string"?e:e.id;if(this.flags.has(i)||this.flags.set(i,new Set),t=="selected"&&!s.selectable)return console.warn(`Cannot set flag '${t}' on non-selectable object`,s);let n=this.flags.get(i);n.has(t)||(n.add(t),this.emitExternal(b.ObjectFlagsAdded,{object:s,addedFlags:[t],currentFlags:[...this.flags.get(i)]}),t==="selected"&&this.emitExternal(b.ObjectSelected,{object:s}),this.ensureEventLoop())}clearFlag(e,t){let s=typeof e=="string"?this.objects.find(n=>n.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);let i=typeof e=="string"?e:e.id;this.flags.get(i)?.delete(t),this.emitExternal(b.ObjectFlagsRemoved,{object:s,removedFlags:[t],currentFlags:[...this.flags.get(i)||[]]}),t==="selected"&&this.emitExternal(b.ObjectDeselected,{object:s}),this.ensureEventLoop()}hasFlag(e,t){let s=typeof e=="string"?e:e.id;return this.flags.get(s)?.has(t)??!1}clearAllFlags(e){for(let[t,s]of this.flags.entries()){let i=this.objects.find(n=>n.id===t)??null;if(!i)throw new Error(`Object not found: ${t}`);s.delete(e),this.emitExternal(b.ObjectFlagsRemoved,{object:i,removedFlags:[e],currentFlags:[...this.flags.get(t)||[]]}),e==="selected"&&this.emitExternal(b.ObjectDeselected,{object:i})}this.ensureEventLoop()}getObjectsWithFlag(e){return[...this.flags.entries()].filter(([t,s])=>s.has(e)).filter(([t,s])=>{let i=this.objects.find(n=>n.id===t)??null;if(!i)throw new Error(`Object not found: ${t}`);return e==="selected"?i.selectable:!0}).map(([t])=>this.objects.find(s=>s.id===t))}setZoom(e,t){if(e<=0){console.warn("Zoom must be greater than 0, ignoring.");return}let s=this.zoom,i=new l.Vector(this.pan.x,this.pan.y);if(this._zoom=e,t){let n=t.x-(t.x-this.pan.x)*(e/s),r=t.y-(t.y-this.pan.y)*(e/s);this._pan=new l.Vector(n,r)}this.emitExternal(b.ViewportChanged,{oldPan:i,newPan:this.pan,oldZoom:s,newZoom:this.zoom}),this.ensureEventLoop()}setPan(e,t){let s=this.pan.clone();typeof e=="number"?this._pan=new l.Vector(e,t??0):this._pan=e.clone(),this.emitExternal(b.ViewportChanged,{oldPan:s,newPan:this.pan,oldZoom:this.zoom,newZoom:this.zoom}),this.ensureEventLoop()}setSelectedObjects(e){let t=e.map(r=>typeof r=="string"?this.objects.find(o=>o.id===r):r),s=this.getSelectedObjects(),i=s.filter(r=>!t.includes(r)),n=t.filter(r=>!s.includes(r));i.forEach(r=>this.clearFlag(r,"selected")),n.forEach(r=>this.setFlag(r,"selected")),this.ensureEventLoop()}getSelectedObjects(){return this.getObjectsWithFlag("selected").filter(e=>e.selectable)}getAllObjects(){let e=this.getObjectsWithFlag("canvas-background").filter(t=>typeof t=="object"&&t instanceof O);return[...this.objects].filter(t=>e.includes(t)==!1)}getTopMostInteractionPerEventType(e){let t=new Map,s=[...this.objects].sort((i,n)=>(i.zIndex??0)-(n.zIndex??0));for(let i=s.length-1;i>=0;i--){let n=s[i];if(!n||!n.visible)continue;n.getEventInteractions(e).forEach(o=>{let a=o.eventTypePrefix;if(!t.has(a)){let c={object:n,interaction:o};t.set(a,c)}})}return t}enqueue(e,t=!1){if(t&&this.eventQueue.find(i=>i.type===e.type)){this.ensureEventLoop();return}this.eventQueue.push(e),this.ensureEventLoop()}ensureEventLoop(){this.processingQueue||(this.processingQueue=!0,setTimeout(()=>this.processQueue(),0))}processQueue(){for(;this.eventQueue.length;){let e=this.eventQueue.shift();if(!e.stopPropagation&&(this.recognizers.forEach(t=>{e.stopPropagation||t.process(e,s=>this.eventQueue.push(s))}),!e.stopPropagation&&(this.tools.forEach(t=>{e.stopPropagation||t.processToolEvent(e,s=>this.eventQueue.push(s),this.emitExternal,this,this.toolLockManager.getToolLock(t))}),!e.stopPropagation&&(this.processToolEvent(e,t=>this.eventQueue.push(t),this.emitExternal,this,this.toolLockManager.getToolLock(this)),e.type.startsWith("pointer")==!1,e.targets&&e.targets.length>0)))){let t=e.targets;for(let s of t)s.handleEvent&&s.handleEvent(e,this.emitExternal)}}this.processingQueue=!1,this.requestRender()}addEventSource(e){this.eventSources.push(e),e.attach(t=>this.enqueue(t),this)}removeEventSource(e){this.eventSources=this.eventSources.filter(t=>t!==e),e.detach?.()}addRecognizer(e){this.recognizers.push(e)}addRenderNode(e){this.renderers.push(e)}register(e){typeof e=="object"&&e!==null&&"attach"in e&&typeof e.attach=="function"&&this.addEventSource(e),typeof e=="object"&&e!==null&&"process"in e&&typeof e.process=="function"&&this.addRecognizer(e),typeof e=="object"&&e!==null&&("renderBeforeAll"in e||"renderBeforeObject"in e||"renderAfterObject"in e||"renderAfterAll"in e)&&(typeof e.renderBeforeAll=="function"||typeof e.renderBeforeObject=="function"||typeof e.renderAfterObject=="function"||typeof e.renderAfterAll=="function")&&this.addRenderNode(e)}redraw(){this.requestRender()}requestRender(){this.needsRender=!0,this.renderScheduled||(this.renderScheduled=!0,requestAnimationFrame(()=>{this.needsRender&&(this.doRender(this.ctx),this.needsRender=!1),this.renderScheduled=!1}))}doRender(e){e.save(),e.setTransform(this.zoom,0,0,this.zoom,this.pan.x,this.pan.y),e.clearRect(-this.pan.x/this.zoom,-this.pan.y/this.zoom,this.canvas.width/this.zoom,this.canvas.height/this.zoom),this.emitExternal(b.EngineRenderStarted,{}),this.renderers.forEach(t=>t.renderBeforeAll?.(e,this));for(let t of this.objects.filter(s=>s.visible).sort((s,i)=>s.zIndex-i.zIndex))this.renderers.forEach(s=>s.renderBeforeObject?.(e,this,t)),t.render(e,this.flags.get(t.id)??new Set),this.renderers.forEach(s=>s.renderAfterObject?.(e,this,t));this.renderers.forEach(t=>t.renderAfterAll?.(e,this)),this.emitExternal(b.EngineRenderCompleted,{}),e.restore()}dispose(){this.eventSources.forEach(e=>e.detach?.())}},k=class{constructor(){this.currentTool=null}get isLocked(){return this.currentTool!==null}getToolLock(e){return{hasLock:()=>this.currentTool===e,acquire:()=>this.currentTool===null||this.currentTool===e?(this.currentTool=e,!0):!1,release:()=>this.currentTool===null||this.currentTool===e?(this.currentTool=null,!0):(console.warn("Tool lock released by a tool that does not own it:",e),!1)}}},G=class{constructor(){this.passive=!1;this.wheelZoomFactor=.25;this.pinchZoomFactor=.25;this.minZoom=.01;this.maxZoom=10}processToolEvent(e,t,s,i,n){switch(e.type){case"wheel":this.handleWheelZoom(e,i,n);break;case"gesture":this.handlePinchZoom(e,i,n);break;case"keyZoomIn":break;case"keyZoomOut":break}}handleWheelZoom(e,t,s){let i=e.data||{},n=i.delta||new l.Vector(0,0),r=i.point||new l.Point(0,0),o=t.viewableWidth/t.width,a=t.viewableHeight/t.height,d=Math.min(o,a)*.1,h=(n.y<0?d:-1*d)*this.wheelZoomFactor+1;this.applyZoom(t,h,r.x*t.zoom+t.pan.x,r.y*t.zoom+t.pan.y,s)}handlePinchZoom(e,t,s){let i=e.data||{},n=i.scaleDelta,r=i.clientX,o=i.clientY,a=1+n*this.pinchZoomFactor;this.applyZoom(t,a,r,o,s)}applyZoom(e,t,s,i,n){let r=e.zoom,o=Math.min(Math.max(r*t,this.minZoom),this.maxZoom);o!==r&&n.acquire()&&(e.pan.x=s-(s-e.pan.x)*(o/r),e.pan.y=i-(i-e.pan.y)*(o/r),e.setZoom(o,new l.Point(s,i)),n.release())}},J=class{constructor(){this.priority=-1/0;this.active=!1;this.startClient=new l.Point(0,0);this.origPan=new l.Vector(0,0)}processToolEvent(e,t,s,i,n){if(!e.type.startsWith("drag"))return!1;let o=(e.data||{}).point,a=i.worldToScreen(o);if(o!==null){var c=i.getTopMostInteractionPerEventType(o);if(c&&c.has("drag")){var d=c.get("drag");if(d&&i.hasFlag(d.object,"canvas-background")){if(e.type==="dragstart"){if(!n.acquire())return;this.startClient=a,this.origPan=i.pan.clone(),this.active=!0}if(e.type==="dragend"||e.type==="dragcancel"){this.active=!1,this.startClient=new l.Point(0,0),this.origPan=new l.Vector(0,0),n.release();return}if(this.active==!1)return;n.hasLock()&&i.setPan(this.origPan.add(a.getDeltaFromPoint(this.startClient)))}}}}},S=class{constructor(){this.objectsBeingMoved=[];this.lastDelta=null}processToolEvent(e,t,s,i,n){let r=e.data||{},o=r.point,a=r.delta,c=this.lastDelta==null?a:this.lastDelta,d=this.lastDelta==null?a:a?.subtract(c);switch(e.type){case"dragstart":if(!o)return;let g=i.getTopMostInteractionPerEventType(o).get("move");if(g){if(!n.acquire())return;let v=i.getSelectedObjects();v.length===0||v.some(E=>E===g.object)===!1?this.objectsBeingMoved=[g.object]:this.objectsBeingMoved=v}break;case"drag":if(!a||this.objectsBeingMoved==null||this.objectsBeingMoved.length===0)return;this.lastDelta=a,t({type:"move",data:{delta:d,point:o},targets:this.objectsBeingMoved});break;case"dragend":if(!a||this.objectsBeingMoved==null||this.objectsBeingMoved.length===0){this.lastDelta=null,this.objectsBeingMoved=[];return}t({type:"move",data:{origin,delta:d,point:o},targets:this.objectsBeingMoved}),this.lastDelta=null,this.objectsBeingMoved=[],n.release();break;case"dragcancel":(!a||this.objectsBeingMoved==null||this.objectsBeingMoved.length===0)&&(this.lastDelta=null,this.objectsBeingMoved=[]),t({type:"move",data:{origin,delta:c?.subtract(a)||new l.Vector(0,0),point:origin},targets:this.objectsBeingMoved}),this.lastDelta=null,this.objectsBeingMoved=[],n.release();break}}},M=class{constructor(){this.priority=100}processToolEvent(e,t,s,i,n){if(e.type!=="click")return;let r=e.data||{},o=r.point;if(!o)return;let c=i.getTopMostInteractionPerEventType(o).get("select"),d=i.getSelectedObjects(),h=r.metaHeld||r.ctrlHeld||r.shiftHeld;if(c){let g=d.some(E=>E===c.object);if(!(d.length===1&&g)){if(!n.acquire())return;h?i.setSelectedObjects([...d,c.object]):i.setSelectedObjects([c.object]),n.release()}}else i.setSelectedObjects([])}},B=class{constructor(){this.priority=-100}processToolEvent(e,t,s,i,n){if(e.type!=="pointermove")return;let o=(e.data||{}).point;if(!o)return;for(let c of i.getObjectsWithFlag("hoversibling"))i.clearFlag(c,"hoversibling"),i.setFlag(c,"hovered");for(let c of i.getObjectsWithFlag("hovered"))c.getOuterBounds().contains(o)||i.clearFlag(c,"hovered");for(let c of i.getAllObjects())c.getBounds().contains(o)&&i.setFlag(c,"hovered");let a=!1;for(let c of i.getSelectedObjects())i.hasFlag(c,"hovered")&&(a=!0);if(a)for(let c of i.getSelectedObjects())i.hasFlag(c,"hovered")||(i.setFlag(c,"hovered"),i.setFlag(c,"hoversibling"))}},D=class{constructor(){this.activeHandleIndex=null;this.objectsBeingResized=[];this.lastDelta=null}processToolEvent(e,t,s,i,n){let r=e.data||{},o=r.point,a=r.delta,c=r.origin,d=this.lastDelta==null?a:this.lastDelta,h=this.lastDelta==null?a:a?.subtract(d);switch(e.type){case"dragstart":if(!o)return;let v=i.getTopMostInteractionPerEventType(o).get("resize");if(v&&v.interaction.handleIndex!=null){if(!n.acquire())return;let E=i.getSelectedObjects();E.length===0||E.some(z=>z===v.object)===!1?this.objectsBeingResized=[v.object]:this.objectsBeingResized=E,this.activeHandleIndex=v.interaction.handleIndex,t({type:"resizestart",data:{handleIndex:this.activeHandleIndex,point:o},targets:this.objectsBeingResized})}break;case"drag":if(this.activeHandleIndex==null||!a||this.objectsBeingResized==null||this.objectsBeingResized.length===0)return;this.lastDelta=a,t({type:"resize",data:{handleIndex:this.activeHandleIndex,delta:h,point:o},targets:this.objectsBeingResized});break;case"dragend":if(this.activeHandleIndex==null||!a||this.objectsBeingResized==null||this.objectsBeingResized.length===0){this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[];return}t({type:"resize",data:{handleIndex:this.activeHandleIndex,origin:c,delta:h,point:o},targets:this.objectsBeingResized}),t({type:"resizeend",data:{handleIndex:this.activeHandleIndex,delta:h,point:o},targets:this.objectsBeingResized}),this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[],n.release();break;case"dragcancel":(this.activeHandleIndex==null||!a||this.objectsBeingResized==null||this.objectsBeingResized.length===0)&&(this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[]),t({type:"resize",data:{handleIndex:this.activeHandleIndex,origin:c,delta:d?.subtract(a)||new l.Vector(0,0),point:c},targets:this.objectsBeingResized}),this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[],n.release();break}}},A=class{constructor(e="black"){this.drawing=!1;this.startPt=null;this.currentPt=null;this.defaultColor="black";this.defaultColor=e}processToolEvent(e,t,s,i,n){let o=(e.data||{}).point;switch(e.type){case"dragstart":if(!o||!n.acquire())return;this.drawing=!0,this.startPt=o,this.currentPt=o;break;case"drag":if(!this.drawing||!n.hasLock()||!o)return;this.currentPt=o;break;case"dragend":if(this.drawing&&n.hasLock()&&this.startPt&&o){this.currentPt=o;let a=Math.min(this.startPt.x,this.currentPt.x),c=Math.min(this.startPt.y,this.currentPt.y),d=Math.abs(this.currentPt.x-this.startPt.x),h=Math.abs(this.currentPt.y-this.startPt.y),g=new l.Rectangle(a,c,d,h),v=i.getAllObjects().reduce((E,z)=>Math.max(E,z.zIndex),0);this.drawing=!1,n.release(),s(b.DrawingCompleted,{rect:g,maxZ:v})}case"dragcancel":this.drawing&&n.hasLock()&&(this.drawing=!1,this.startPt=null,this.currentPt=null,n.release());break}}renderAfterAll(e,t){if(!this.drawing||!this.startPt||!this.currentPt)return;let s=Math.min(this.startPt.x,this.currentPt.x),i=Math.min(this.startPt.y,this.currentPt.y),n=Math.abs(this.currentPt.x-this.startPt.x),r=Math.abs(this.currentPt.y-this.startPt.y);e.save(),e.strokeStyle=this.defaultColor,e.lineWidth=2/e.getTransform().a,e.setLineDash([4/e.getTransform().a,2/e.getTransform().a]),e.strokeRect(s,i,n,r),e.setLineDash([]),e.restore()}},L=class{constructor(){this.lassoing=!1;this.points=[]}processToolEvent(e,t,s,i,n){let o=(e.data||{}).point;switch(e.type){case"dragstart":if(!o||!n.acquire())return;this.lassoing=!0,this.points=[o];break;case"drag":if(!this.lassoing||!n.hasLock()||!o)return;this.points.push(o);break;case"dragend":if(this.lassoing&&n.hasLock()&&o){this.points.push(o);let a=new l.Polygon(this.points),c=[];for(let d of i.getAllObjects()){let h=d.getBounds();if(a.containsRect(h)){c.push(d);continue}}i.setSelectedObjects(c),t({type:"lassoselected",data:{polygon:a,selectedObjects:c}})}case"dragcancel":this.lassoing&&n.hasLock()&&(this.lassoing=!1,this.points=[],n.release());break}}renderAfterAll(e,t){if(!(!this.lassoing||this.points.length===0)){e.save(),e.strokeStyle="black",e.lineWidth=1/e.getTransform().a,e.setLineDash([4/e.getTransform().a,2/e.getTransform().a]),e.beginPath(),e.moveTo(this.points[0].x,this.points[0].y);for(let s=1;s<this.points.length;s++)e.lineTo(this.points[s].x,this.points[s].y);e.stroke(),e.restore()}}},H=class{processToolEvent(e,t,s,i,n){if(!e.type.startsWith("api:"))return;e.stopPropagation=!0;let r=e.targets;if(!r||r.length===0)return;let o=r[0];if(!o){console.warn("API event has no target object:",e);return}if(!i.getAllObjects().includes(o)){console.warn("API event targets an object not in the engine:",o);return}switch(e.type){case"api:moveto":{if(!n.acquire())return;let{x:a,y:c}=e.data,h=o.getBounds().origin,g=new l.Vector(a-h.x,c-h.y);t({type:"move",data:{delta:g,origin:h,point:h},targets:[o]}),n.release();break}case"api:moveby":{if(!n.acquire())return;let{dx:a,dy:c}=e.data;t({type:"move",data:{delta:new l.Vector(a,c)},targets:[o]}),n.release();break}case"api:resizeto":{if(!n.acquire())return;let{width:a,height:c}=e.data,d=o.getBounds(),h=d.origin,g=a-d.size.width,v=c-d.size.height;t({type:"resizestart",data:{handleIndex:4,origin:h,point:h},targets:[o]}),t({type:"resize",data:{handleIndex:4,delta:new l.Vector(g,v),point:h},targets:[o]}),t({type:"resizeend",data:{handleIndex:4,delta:new l.Vector(g,v),point:h},targets:[o]}),n.release();break}case"api:resizeby":{if(!n.acquire())return;let{dW:a,dH:c}=e.data,h=o.getBounds().origin;t({type:"resizestart",data:{handleIndex:4,origin:h,point:h},targets:[o]}),t({type:"resize",data:{handleIndex:4,delta:new l.Vector(a,c),point:h},targets:[o]}),t({type:"resizeend",data:{handleIndex:4,delta:new l.Vector(a,c),point:h},targets:[o]}),n.release();break}case"api:setcolor":{let{color:a}=e.data;t({type:"setcolor",data:{color:a},targets:[o]});break}case"api:setzindex":{let{zIndex:a}=e.data;t({type:"setzindex",data:{zIndex:a},targets:[o]});break}case"api:setselectable":{let{isSelectable:a}=e.data;t({type:"setselectable",data:{isSelectable:a},targets:[o]});break}case"api:setmovable":{if(!n.acquire())return;let{isMovable:a}=e.data;t({type:"setmovable",data:{isMovable:a},targets:[o]}),n.release();break}case"api:setresizable":{if(!n.acquire())return;let{isResizable:a}=e.data;t({type:"setresizable",data:{isResizable:a},targets:[o]}),n.release();break}case"api:setvisible":{let{visible:a}=e.data;t({type:"setvisible",data:{isVisible:a},targets:[o]});break}}}},F=class{constructor(e=5){this.activePointerIds=new Set;this.isDragging=!1;this.buttonStart=null;this.origin=new l.Point(0,0);this.moveThreshold=e}process(e,t){let{type:s,data:i={}}=e;switch(s){case"pointerdown":if(i.pointerType!=="touch"){let n=i.point,r=e.data?.identifier,o=i.button;this.handleStart(r,i.pointerType,n,o,t)}break;case"touchstart":{let n=this.getTouches(e);if(n.length===1){let r=n[0],o=r.point,a=r.identifier;this.handleStart(a,"touch",o,null,t)}break}case"pointermove":if(i.pointerType!=="touch"){let n=i.point,r=e.data?.identifier,o=n?.getDeltaFromPoint(this.origin)||new l.Vector(0,0),a=i.button;this.handleMove(r,i.pointerType,n,o,a,t)}break;case"touchmove":{let n=this.findActiveTouch(e);if(n){let r=n.point,o=n.identifier,a=r?.getDeltaFromPoint(this.origin)||new l.Vector(0,0);this.handleMove(o,"touch",r,a,null,t)}break}case"pointerup":case"pointercancel":if(i.pointerType!=="touch"){let n=i.point,r=e.data?.identifier,o=n?.getDeltaFromPoint(this.origin)||new l.Vector(0,0),a=i.button;this.handleEnd(r,i.pointerType,n,o,a,t)}break;case"touchend":case"touchcancel":{let n=this.findActiveTouch(e);if(n){let r=n.point,o=n.identifier,a=r?.getDeltaFromPoint(this.origin)||new l.Vector(0,0);this.handleEnd(o,"touch",r,a,null,t)}break}}}handleStart(e,t,s,i,n){this.isDragging||e==null||s==null||s.x==null||s.y==null||n==null||(this.activePointerIds.add(e),this.origin=s,this.buttonStart=i??null,n({type:"dragpotential",data:{identifier:e,pointerType:t,point:origin}}))}handleMove(e,t,s,i,n,r){if(!(e==null||s==null||i==null||!this.activePointerIds.has(e)||r==null)){var o=s.subtract(i);!this.isDragging&&(this.buttonStart==null||this.buttonStart==0)&&(i.length()>=this.moveThreshold?(this.activePointerIds.clear(),this.activePointerIds.add(e),this.isDragging=!0,r({type:"dragstart",data:{identifier:e,pointerType:t,point:o}})):r({type:"dragpotentialmove",data:{identifier:e,pointerType:t,origin:o,delta:i,point:s}})),this.isDragging&&r({type:"drag",data:{identifier:e,pointerType:t,origin:o,delta:i,point:s}})}}handleEnd(e,t,s,i,n,r){if(!this.isDragging||e==null||s==null||i==null||!this.activePointerIds.has(e)||r==null){this.activePointerIds.clear();return}var o=s.add(i);r({type:"dragend",data:{identifier:e,pointerType:t,origin:o,point:s,delta:i}}),this.activePointerIds.clear(),this.isDragging=!1,this.buttonStart=null}getTouches(e){return e.data?.changedTouches??[]}findActiveTouch(e){return this.getTouches(e).find(t=>this.activePointerIds.has(t.identifier))}},V=class{constructor(e=5){this.activePointerIds=new Set;this.origin=new l.Point(0,0);this.moveThreshold=e}process(e,t){let{type:s,data:i={}}=e;switch(s){case"pointerdown":if(i.pointerType!=="touch"){let n=i.point,r=e.data?.identifier;this.handleStart(r,n)}break;case"touchstart":{let n=this.getTouches(e);if(n.length===1){let r=n[0],o=r.point,a=r.identifier;this.handleStart(a,o)}break}case"pointermove":if(i.pointerType!=="touch"){let n=i.point,r=e.data?.identifier,o=n?.getDeltaFromPoint(this.origin)||new l.Vector(0,0);this.handleMove(r,n,o)}break;case"touchmove":{let n=this.findActiveTouch(e);if(n){let r=n.point,o=n.identifier,a=r?.getDeltaFromPoint(this.origin)||new l.Vector(0,0);this.handleMove(o,r,a)}break}case"pointerup":case"pointercancel":if(i.pointerType!=="touch"){let n=i.point,r=e.data?.identifier,o=n?.getDeltaFromPoint(this.origin)||new l.Vector(0,0),a=e.data?.shiftHeld??!1,c=e.data?.metaHeld??!1,d=e.data?.ctrlHeld??!1,h=e.data?.altHeld??!1;this.handleEnd(r,i.pointerType,n,o,{shiftHeld:a,metaHeld:c,ctrlHeld:d,altHeld:h},t)}break;case"touchend":case"touchcancel":{let n=this.findActiveTouch(e);if(n){let r=n.point,o=n.identifier,a=r?.getDeltaFromPoint(this.origin)||new l.Vector(0,0);this.handleEnd(o,"touch",r,a,t)}break}}}handleStart(e,t){e==null||t==null||t.x==null||t.y==null||(this.activePointerIds.add(e),this.origin=t)}handleMove(e,t,s){e==null||t==null||s==null||!this.activePointerIds.has(e)||s.length()>=this.moveThreshold&&this.activePointerIds.clear()}handleEnd(e,t,s,i,n,r){if(!(e==null||s==null||i==null||!this.activePointerIds.has(e)||r==null)){if(i.length()>=this.moveThreshold){this.activePointerIds.clear();return}var o={identifier:e,pointerType:t,point:s};n&&(o={...o,...n}),r({type:"click",data:o}),this.activePointerIds.clear()}}getTouches(e){return e.data?.changedTouches??[]}findActiveTouch(e){return this.getTouches(e).find(t=>this.activePointerIds.has(t.identifier))}};0&&(module.exports={ApiTool,CanvasEngine,CircleObject,ClickGestureRecognizer,DomEventSource,DragGestureRecognizer,DrawingTool,EngineEventType,HoverTool,LassoTool,MoveTool,PolygonObject,ResizeTool,SelectTool,ToolLockManager,Zone});
7
+ </svg>`;this.document=new Blob([this.defaultBackgroundImage],{type:"image/svg+xml;charset=utf-8"});this.emitter=new Y;this.toolLockManager=new k;this.eventSources=[];this.recognizers=[];this.tools=[];this.manualRenderers=[];this.modeRenderers=[];this.eventQueue=[];this.processingQueue=!1;this.renderScheduled=!1;this.flags=new Map;this.objects=[];this.needsRender=!1;this.toolRegistry=new Map;this.modes={};this.currentMode="";this.defaultOptions={initialZoom:1,initialPan:{x:10,y:10},defaultMode:"default",addTimerEventSource:!1,proxyObjectsForEvents:!0};this._pan=new c.Vector(0,0);this._zoom=1;this.on=this.emitter.on.bind(this.emitter);this.off=this.emitter.off.bind(this.emitter);this.emitExternal=this.emitter.emit.bind(this.emitter);this.options=this.createOptions(t);let s=document.querySelector(e);if(!s)throw new Error(`Container ${e} not found`);this.container=s,this.canvas=document.createElement("canvas"),this.canvas.width=this.container.clientWidth*10,this.canvas.height=this.container.clientHeight*10,this.container.appendChild(this.canvas),this.ctx=this.canvas.getContext("2d"),this.setupDefaultEventSources(),this.setupDefaultTools(),this.setupDefaultRecognizers(),this.setupDefaultModes(),this.setupRenderNodes(),this._zoom=this.options.initialZoom,this._pan=new c.Vector(this.options.initialPan.x,this.options.initialPan.y),this.switchMode(this.options.defaultMode),this.emitExternal(b.EngineStarted,{}),this.emitExternal(b.ViewportChanged,{oldPan:new c.Vector(0,0),newPan:this.pan,oldZoom:1,newZoom:this.zoom}),this.setBackgroundImage(this.document).then()}get pan(){return this._pan.clone()}get zoom(){return this._zoom}screenToWorld(e){return new c.Point((e.x-this.pan.x)/this.zoom,(e.y-this.pan.y)/this.zoom)}worldToScreen(e){return new c.Point(e.x*this.zoom+this.pan.x,e.y*this.zoom+this.pan.y)}processToolEvent(e,t,s,i,n){e.type.startsWith("windowresize")||(this.canvas.width=this.container.clientWidth,this.canvas.height=this.container.clientHeight)}createOptions(e){return{...this.defaultOptions,...e}}setupDefaultEventSources(){this.options.addTimerEventSource&&this.register(new X),this.register(new S(this.canvas))}setupDefaultRecognizers(){this.register(new Z),this.register(new V)}setupDefaultTools(){this.registerTool("hover",()=>new D,!0),this.registerTool("select",()=>new B,!0),this.registerTool("drawing",()=>new L,!0),this.registerTool("move",()=>new M,!0),this.registerTool("resize",()=>new A,!0),this.registerTool("lasso",()=>new H,!0),this.registerTool("pan",()=>new ee,!0),this.registerTool("zoom",()=>new J(this.options.zoomOptions),!0),this.registerTool("api",()=>new F,!0)}setupDefaultModes(){this.defineMode("default",{tools:["hover","select","resize","move","pan","zoom","api"]}),this.defineMode("move",{tools:["hover","select","resize","move","pan","zoom","api"]}),this.defineMode("create",{tools:["drawing","zoom","api"],handleEvent(e,t){e.type===b.DrawingCompleted&&t.switchMode("default")}}),this.defineMode("lasso",{tools:["hover","select","lasso","zoom","api"],handleEvent(e,t){e.type==="lassoselected"&&t.switchMode("default")}})}setupRenderNodes(){}wrapInteractiveObject(e){let t=this;return new Proxy(e,{set(s,i,n){let o=s[i],a=Reflect.set(s,i,n);return typeof i=="string"&&i.startsWith("_")||o!==n&&t.emitExternal(b.ObjectChanged,{object:s,property:i.toString(),oldValue:o,newValue:n}),a}})}registerTool(e,t,s=!0){if(this.toolRegistry.has(e))throw new Error(`Tool '${e}' already registered.`);this.toolRegistry.set(e,{factory:t,singleton:s})}resolveTool(e){let t=this.toolRegistry.get(e);if(!t)throw new Error(`Unknown tool '${e}'`);return t.singleton?("instance"in t||(t.instance=t.factory()),t.instance):t.factory()}defineMode(e,t){if(this.modes[e])throw new Error(`Mode '${e}' already defined.`);this.modes[e]=t}get mode(){return this.currentMode}switchMode(e){if(!this.modes[e])throw new Error(`Unknown mode '${e}'`);if(this.toolLockManager.isLocked){console.warn("Cannot switch modes while tools are locked. Please release all locks first.");return}if(this.currentMode===e){console.warn(`Already in mode '${e}', no switch needed.`);return}let t=this.currentMode;this.currentMode=e;let s=this.modes[e];if(s.tools==null||s.tools.length==0)return;let i=s.tools;this.tools=[...new Set(i.map(n=>this.resolveTool(n)))],this.modeRenderers=s.renderers||[],s.handleEvent&&this.tools.push(new U(s,this)),this.emitExternal(b.EngineModeChanged,{newMode:this.currentMode,oldMode:t})}get renderers(){let e=this.tools.filter(t=>typeof t=="object"&&t!==null&&("renderBeforeAll"in t||"renderBeforeObject"in t||"renderAfterObject"in t||"renderAfterAll"in t)&&(typeof t.renderBeforeAll=="function"||typeof t.renderBeforeObject=="function"||typeof t.renderAfterObject=="function"||typeof t.renderAfterAll=="function")).map(t=>t);return[...new Set([...this.manualRenderers,...this.modeRenderers,...e])]}get viewableWidth(){return this.canvas.width}get viewableHeight(){return this.canvas.height}get width(){let e=this.getObjectsWithFlag("canvas-background").filter(s=>typeof s=="object"&&s instanceof R),t;return e.length==0?this.canvas.width:(e.length>=1&&(t=e[0]),t.width)}get height(){let e=this.getObjectsWithFlag("canvas-background").filter(s=>typeof s=="object"&&s instanceof R),t;return e.length==0?this.canvas.height:(e.length>=1&&(t=e[0]),t.height)}get documentBlob(){return this.document}async setBackgroundImage(e){let t=this.width,s=this.height,i;e instanceof File||e instanceof Blob?i=e:i=await this.loadImageFromUrl(e),this.document=i;let n=URL.createObjectURL(i),o=await this.loadImage(n),a=this.getObjectsWithFlag("canvas-background");if(a.length>0){let r=a.find(l=>l instanceof R);r&&(r.img=o)}else{let r=new R(o);this.objects.push(r),this.setFlag(r.id,"canvas-background")}this.emitExternal(b.EngineBackgroundChanged,{newImage:o,newWidth:o.width,newHeight:o.height,oldWidth:t,oldHeight:s}),this.requestRender()}async loadImageFromUrl(e){let t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch image: ${t.status} ${t.statusText}`);return await t.blob()}loadImage(e){return new Promise((t,s)=>{if(e instanceof HTMLImageElement){e.complete&&e.naturalWidth!==0?t(e):(e.onload=()=>t(e),e.onerror=s);return}let i=new Image;i.onload=()=>t(i),i.onerror=s,i.src=e})}getObject(e){return this.objects.find(s=>s.id===e)}addObject(e){if(this.objects.find(s=>s.id===e.id))throw new Error(`Object with id '${e.id}' already exists.`);this.objects.push(e),this.enqueue({type:"redraw",data:{}},!0),this.emitExternal(b.ObjectAdded,{object:this.options.proxyObjectsForEvents?this.wrapInteractiveObject(e):e})}removeObject(e){let t=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!t)throw new Error(`Object not found: ${e}`);let s=this.objects.indexOf(t);if(s!==-1){this.objects.splice(s,1);let i=typeof e=="string"?e:e.id;this.flags.delete(i),this.emitExternal(b.ObjectRemoved,{object:t})}else console.warn("Attempted to remove an object that does not exist in the engine:",t);this.redraw()}moveObjectToPoint(e,t,s){let i=typeof e=="string"?this.objects.find(a=>a.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let n=typeof t=="number"?t:t.x,o=typeof t=="number"?s??0:t.y;this.enqueue({type:"api:moveto",data:{x:n,y:o},targets:[i]})}moveObjectByVector(e,t,s){let i=typeof e=="string"?this.objects.find(a=>a.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let n=typeof t=="number"?t:t.x,o=typeof t=="number"?s??0:t.y;this.enqueue({type:"api:moveby",data:{dx:n,dy:o},targets:[i]})}resizeObjectToSize(e,t,s){let i=typeof e=="string"?this.objects.find(a=>a.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let n=typeof t=="number"?t:t.width,o=typeof t=="number"?s??0:t.height;this.enqueue({type:"api:resizeto",data:{width:n,height:o},targets:[i]})}resizeObjectByVector(e,t,s){let i=typeof e=="string"?this.objects.find(a=>a.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let n=typeof t=="number"?t:t.x,o=typeof t=="number"?s??0:t.y;this.enqueue({type:"api:resizeby",data:{dw:n,dh:o},targets:[i]})}setObjectColor(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setcolor",data:{color:t},targets:[s]})}setObjectZIndex(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setzindex",data:{zIndex:t},targets:[s]})}updateObjectSelectability(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setselectable",data:{isSelectable:t},targets:[s]})}updateObjectMovability(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setmovable",data:{isMovable:t},targets:[s]})}updateObjectResizeability(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setresizable",data:{isResizable:t},targets:[s]})}updateObjectVisibility(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);s.visible!==t&&this.enqueue({type:"api:setvisible",data:{visible:t},targets:[s]})}setFlag(e,t){let s=typeof e=="string"?this.objects.find(o=>o.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);let i=typeof e=="string"?e:e.id;if(this.flags.has(i)||this.flags.set(i,new Set),t=="selected"&&!s.selectable)return console.warn(`Cannot set flag '${t}' on non-selectable object`,s);let n=this.flags.get(i);n.has(t)||(n.add(t),this.emitExternal(b.ObjectFlagsAdded,{object:s,addedFlags:[t],currentFlags:[...this.flags.get(i)]}),t==="selected"&&this.emitExternal(b.ObjectSelected,{object:s}),this.ensureEventLoop())}clearFlag(e,t){let s=typeof e=="string"?this.objects.find(n=>n.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);let i=typeof e=="string"?e:e.id;this.flags.get(i)?.delete(t),this.emitExternal(b.ObjectFlagsRemoved,{object:s,removedFlags:[t],currentFlags:[...this.flags.get(i)||[]]}),t==="selected"&&this.emitExternal(b.ObjectDeselected,{object:s}),this.ensureEventLoop()}hasFlag(e,t){let s=typeof e=="string"?e:e.id;return this.flags.get(s)?.has(t)??!1}clearAllFlags(e){for(let[t,s]of this.flags.entries()){let i=this.objects.find(n=>n.id===t)??null;if(!i)throw new Error(`Object not found: ${t}`);s.delete(e),this.emitExternal(b.ObjectFlagsRemoved,{object:i,removedFlags:[e],currentFlags:[...this.flags.get(t)||[]]}),e==="selected"&&this.emitExternal(b.ObjectDeselected,{object:i})}this.ensureEventLoop()}getObjectsWithFlag(e){return[...this.flags.entries()].filter(([t,s])=>s.has(e)).filter(([t,s])=>{let i=this.objects.find(n=>n.id===t)??null;if(!i)throw new Error(`Object not found: ${t}`);return e==="selected"?i.selectable:!0}).map(([t])=>this.objects.find(s=>s.id===t))}setZoom(e,t){if(e<=0){console.warn("Zoom must be greater than 0, ignoring.");return}let s=this.zoom,i=new c.Vector(this.pan.x,this.pan.y);if(this._zoom=e,t){let n=t.x-(t.x-this.pan.x)*(e/s),o=t.y-(t.y-this.pan.y)*(e/s);this._pan=new c.Vector(n,o)}this.emitExternal(b.ViewportChanged,{oldPan:i,newPan:this.pan,oldZoom:s,newZoom:this.zoom}),this.ensureEventLoop()}setPan(e,t){let s=this.pan.clone();typeof e=="number"?this._pan=new c.Vector(e,t??0):this._pan=e.clone(),this.emitExternal(b.ViewportChanged,{oldPan:s,newPan:this.pan,oldZoom:this.zoom,newZoom:this.zoom}),this.ensureEventLoop()}setSelectedObjects(e){let t=e.map(o=>typeof o=="string"?this.objects.find(a=>a.id===o):o),s=this.getSelectedObjects(),i=s.filter(o=>!t.includes(o)),n=t.filter(o=>!s.includes(o));i.forEach(o=>this.clearFlag(o,"selected")),n.forEach(o=>this.setFlag(o,"selected")),this.ensureEventLoop()}getSelectedObjects(){return this.getObjectsWithFlag("selected").filter(e=>e.selectable)}getAllObjects(){let e=this.getObjectsWithFlag("canvas-background").filter(t=>typeof t=="object"&&t instanceof R);return[...this.objects].filter(t=>e.includes(t)==!1)}getTopMostInteractionPerEventType(e,t){let s=new Map,i=[...this.objects].sort((n,o)=>(n.zIndex??0)-(o.zIndex??0));for(let n=i.length-1;n>=0;n--){let o=i[n];if(!o||!o.visible)continue;o.getEventInteractions(e,t).forEach(r=>{let l=r.eventTypePrefix;if(!s.has(l)){let d={object:o,interaction:r};s.set(l,d)}})}return s}enqueue(e,t=!1){if(t&&this.eventQueue.find(i=>i.type===e.type)){this.ensureEventLoop();return}this.eventQueue.push(e),this.ensureEventLoop()}ensureEventLoop(){this.processingQueue||(this.processingQueue=!0,setTimeout(()=>this.processQueue(),0))}processQueue(){for(;this.eventQueue.length;){let e=this.eventQueue.shift();if(!e.stopPropagation&&(this.recognizers.forEach(t=>{e.stopPropagation||t.process(e,s=>this.eventQueue.push(s))}),!e.stopPropagation&&(this.tools.forEach(t=>{e.stopPropagation||t.processToolEvent(e,s=>this.eventQueue.push(s),this.emitExternal,this,this.toolLockManager.getToolLock(t))}),!e.stopPropagation&&(this.processToolEvent(e,t=>this.eventQueue.push(t),this.emitExternal,this,this.toolLockManager.getToolLock(this)),e.type.startsWith("pointer")==!1,e.targets&&e.targets.length>0)))){let t=e.targets;for(let s of t)s.handleEvent&&s.handleEvent(e,this.emitExternal)}}this.processingQueue=!1,this.requestRender()}addEventSource(e){this.eventSources.push(e),e.attach(t=>this.enqueue(t),this)}removeEventSource(e){this.eventSources=this.eventSources.filter(t=>t!==e),e.detach?.()}addRecognizer(e){this.recognizers.push(e)}addRenderNode(e){this.renderers.push(e)}register(e){typeof e=="object"&&e!==null&&"attach"in e&&typeof e.attach=="function"&&this.addEventSource(e),typeof e=="object"&&e!==null&&"process"in e&&typeof e.process=="function"&&this.addRecognizer(e),typeof e=="object"&&e!==null&&("renderBeforeAll"in e||"renderBeforeObject"in e||"renderAfterObject"in e||"renderAfterAll"in e)&&(typeof e.renderBeforeAll=="function"||typeof e.renderBeforeObject=="function"||typeof e.renderAfterObject=="function"||typeof e.renderAfterAll=="function")&&this.addRenderNode(e)}redraw(){this.requestRender()}requestRender(){this.needsRender=!0,this.renderScheduled||(this.renderScheduled=!0,requestAnimationFrame(()=>{this.needsRender&&(this.doRender(this.ctx),this.needsRender=!1),this.renderScheduled=!1}))}get renderingContext(){return{currentZoom:this.zoom,currentScaleMultiplier:1/(this.viewableWidth/this.width)}}doRender(e){e.save(),e.setTransform(this.zoom,0,0,this.zoom,this.pan.x,this.pan.y),e.clearRect(-this.pan.x/this.zoom,-this.pan.y/this.zoom,this.canvas.width/this.zoom,this.canvas.height/this.zoom),this.emitExternal(b.EngineRenderStarted,{});let t=this.renderingContext;this.renderers.forEach(s=>s.renderBeforeAll?.(e,this));for(let s of this.objects.filter(i=>i.visible).sort((i,n)=>i.zIndex-n.zIndex))this.renderers.forEach(i=>i.renderBeforeObject?.(e,this,s)),s.render(e,this.flags.get(s.id)??new Set,t),this.renderers.forEach(i=>i.renderAfterObject?.(e,this,s));this.renderers.forEach(s=>s.renderAfterAll?.(e,this)),this.emitExternal(b.EngineRenderCompleted,{}),e.restore()}dispose(){this.eventSources.forEach(e=>e.detach?.())}},k=class{constructor(){this.currentTool=null}get isLocked(){return this.currentTool!==null}getToolLock(e){return{hasLock:()=>this.currentTool===e,acquire:()=>this.currentTool===null||this.currentTool===e?(this.currentTool=e,!0):!1,release:()=>this.currentTool===null||this.currentTool===e?(this.currentTool=null,!0):(console.warn("Tool lock released by a tool that does not own it:",e),!1)}}},J=class{get defaultOptions(){return{wheelZoomFactor:.25,pinchZoomFactor:.25,minZoom:.01,maxZoom:10}}constructor(e={}){this.options=this.createOptions(e)}createOptions(e){return{...this.defaultOptions,...e}}processToolEvent(e,t,s,i,n){switch(e.type){case"wheel":this.handleWheelZoom(e,i,n);break;case"gesture":this.handlePinchZoom(e,i,n);break;case"keyZoomIn":break;case"keyZoomOut":break}}handleWheelZoom(e,t,s){let i=e.data||{},n=i.delta||new c.Vector(0,0),o=i.point||new c.Point(0,0),a=t.viewableWidth/t.width,r=t.viewableHeight/t.height,d=Math.min(a,r)*.1,h=(n.y<0?d:-1*d)*(this.options.wheelZoomFactor??1)+1;this.applyZoom(t,h,o.x*t.zoom+t.pan.x,o.y*t.zoom+t.pan.y,s)}handlePinchZoom(e,t,s){let i=e.data||{},n=i.scaleDelta,o=i.clientX,a=i.clientY,r=1+n*(this.options.pinchZoomFactor??1);this.applyZoom(t,r,o,a,s)}applyZoom(e,t,s,i,n){let o=e.zoom,a=Math.min(Math.max(o*t,this.options.minZoom??.01),this.options.maxZoom??10);a!==o&&n.acquire()&&(e.pan.x=s-(s-e.pan.x)*(a/o),e.pan.y=i-(i-e.pan.y)*(a/o),e.setZoom(a,new c.Point(s,i)),n.release())}},ee=class{constructor(){this.priority=-1/0;this.active=!1;this.startClient=new c.Point(0,0);this.origPan=new c.Vector(0,0)}processToolEvent(e,t,s,i,n){if(!e.type.startsWith("drag"))return!1;let a=(e.data||{}).point,r=i.worldToScreen(a);if(a!==null){var l=i.getTopMostInteractionPerEventType(a,i.renderingContext);if(l&&l.has("drag")){var d=l.get("drag");if(d&&i.hasFlag(d.object,"canvas-background")){if(e.type==="dragstart"){if(!n.acquire())return;this.startClient=r,this.origPan=i.pan.clone(),this.active=!0}if(e.type==="dragend"||e.type==="dragcancel"){this.active=!1,this.startClient=new c.Point(0,0),this.origPan=new c.Vector(0,0),n.release();return}if(this.active==!1)return;n.hasLock()&&i.setPan(this.origPan.add(r.getDeltaFromPoint(this.startClient)))}}}}},M=class{constructor(){this.objectsBeingMoved=[];this.lastDelta=null}processToolEvent(e,t,s,i,n){let o=e.data||{},a=o.point,r=o.delta,l=this.lastDelta==null?r:this.lastDelta,d=this.lastDelta==null?r:r?.subtract(l);switch(e.type){case"dragstart":if(!a)return;let p=i.getTopMostInteractionPerEventType(a,i.renderingContext).get("move");if(p){if(!n.acquire())return;let u=i.getSelectedObjects();u.length===0||u.some(E=>E===p.object)===!1?this.objectsBeingMoved=[p.object]:this.objectsBeingMoved=u}break;case"drag":if(!r||this.objectsBeingMoved==null||this.objectsBeingMoved.length===0)return;this.lastDelta=r,t({type:"move",data:{delta:d,point:a},targets:this.objectsBeingMoved});break;case"dragend":if(!r||this.objectsBeingMoved==null||this.objectsBeingMoved.length===0){this.lastDelta=null,this.objectsBeingMoved=[];return}t({type:"move",data:{origin,delta:d,point:a},targets:this.objectsBeingMoved}),this.lastDelta=null,this.objectsBeingMoved=[],n.release();break;case"dragcancel":(!r||this.objectsBeingMoved==null||this.objectsBeingMoved.length===0)&&(this.lastDelta=null,this.objectsBeingMoved=[]),t({type:"move",data:{origin,delta:l?.subtract(r)||new c.Vector(0,0),point:origin},targets:this.objectsBeingMoved}),this.lastDelta=null,this.objectsBeingMoved=[],n.release();break}}},B=class{constructor(){this.priority=100}processToolEvent(e,t,s,i,n){if(e.type!=="click")return;let o=e.data||{},a=o.point;if(!a)return;let l=i.getTopMostInteractionPerEventType(a,i.renderingContext).get("select"),d=i.getSelectedObjects(),h=o.metaHeld||o.ctrlHeld||o.shiftHeld;if(l){let p=d.some(E=>E===l.object);if(!(d.length===1&&p)){if(!n.acquire())return;h?i.setSelectedObjects([...d,l.object]):i.setSelectedObjects([l.object]),n.release()}}else i.setSelectedObjects([])}},D=class{constructor(){this.priority=-100}processToolEvent(e,t,s,i,n){if(e.type!=="pointermove")return;let a=(e.data||{}).point;if(!a)return;for(let l of i.getObjectsWithFlag("hoversibling"))i.clearFlag(l,"hoversibling"),i.setFlag(l,"hovered");for(let l of i.getObjectsWithFlag("hovered"))l.getOuterBounds(i.renderingContext).contains(a)||i.clearFlag(l,"hovered");for(let l of i.getAllObjects())l.getBounds(i.renderingContext).contains(a)&&i.setFlag(l,"hovered");let r=!1;for(let l of i.getSelectedObjects())i.hasFlag(l,"hovered")&&(r=!0);if(r)for(let l of i.getSelectedObjects())i.hasFlag(l,"hovered")||(i.setFlag(l,"hovered"),i.setFlag(l,"hoversibling"))}},A=class{constructor(){this.activeHandleIndex=null;this.objectsBeingResized=[];this.lastDelta=null}processToolEvent(e,t,s,i,n){let o=e.data||{},a=o.point,r=o.delta,l=o.origin,d=this.lastDelta==null?r:this.lastDelta,h=this.lastDelta==null?r:r?.subtract(d);switch(e.type){case"dragstart":if(!a)return;let u=i.getTopMostInteractionPerEventType(a,i.renderingContext).get("resize");if(u&&u.interaction.handleIndex!=null){if(!n.acquire())return;let E=i.getSelectedObjects();E.length===0||E.some(P=>P===u.object)===!1?this.objectsBeingResized=[u.object]:this.objectsBeingResized=E,this.activeHandleIndex=u.interaction.handleIndex,t({type:"resizestart",data:{handleIndex:this.activeHandleIndex,point:a},targets:this.objectsBeingResized})}break;case"drag":if(this.activeHandleIndex==null||!r||this.objectsBeingResized==null||this.objectsBeingResized.length===0)return;this.lastDelta=r,t({type:"resize",data:{handleIndex:this.activeHandleIndex,delta:h,point:a},targets:this.objectsBeingResized});break;case"dragend":if(this.activeHandleIndex==null||!r||this.objectsBeingResized==null||this.objectsBeingResized.length===0){this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[];return}t({type:"resize",data:{handleIndex:this.activeHandleIndex,origin:l,delta:h,point:a},targets:this.objectsBeingResized}),t({type:"resizeend",data:{handleIndex:this.activeHandleIndex,delta:h,point:a},targets:this.objectsBeingResized}),this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[],n.release();break;case"dragcancel":(this.activeHandleIndex==null||!r||this.objectsBeingResized==null||this.objectsBeingResized.length===0)&&(this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[]),t({type:"resize",data:{handleIndex:this.activeHandleIndex,origin:l,delta:d?.subtract(r)||new c.Vector(0,0),point:l},targets:this.objectsBeingResized}),this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[],n.release();break}}},L=class{constructor(e="black"){this.drawing=!1;this.startPt=null;this.currentPt=null;this.defaultColor="black";this.defaultColor=e}processToolEvent(e,t,s,i,n){let a=(e.data||{}).point;switch(e.type){case"dragstart":if(!a||!n.acquire())return;this.drawing=!0,this.startPt=a,this.currentPt=a;break;case"drag":if(!this.drawing||!n.hasLock()||!a)return;this.currentPt=a;break;case"dragend":if(this.drawing&&n.hasLock()&&this.startPt&&a){this.currentPt=a;let r=Math.min(this.startPt.x,this.currentPt.x),l=Math.min(this.startPt.y,this.currentPt.y),d=Math.abs(this.currentPt.x-this.startPt.x),h=Math.abs(this.currentPt.y-this.startPt.y),p=new c.Rectangle(r,l,d,h),u=i.getAllObjects().reduce((E,P)=>Math.max(E,P.zIndex),0);this.drawing=!1,n.release(),s(b.DrawingCompleted,{rect:p,maxZ:u})}case"dragcancel":this.drawing&&n.hasLock()&&(this.drawing=!1,this.startPt=null,this.currentPt=null,n.release());break}}renderAfterAll(e,t){if(!this.drawing||!this.startPt||!this.currentPt)return;let s=Math.min(this.startPt.x,this.currentPt.x),i=Math.min(this.startPt.y,this.currentPt.y),n=Math.abs(this.currentPt.x-this.startPt.x),o=Math.abs(this.currentPt.y-this.startPt.y);e.save(),e.strokeStyle=this.defaultColor,e.lineWidth=2/e.getTransform().a,e.setLineDash([4/e.getTransform().a,2/e.getTransform().a]),e.strokeRect(s,i,n,o),e.setLineDash([]),e.restore()}},H=class{constructor(){this.lassoing=!1;this.points=[]}processToolEvent(e,t,s,i,n){let a=(e.data||{}).point;switch(e.type){case"dragstart":if(!a||!n.acquire())return;this.lassoing=!0,this.points=[a];break;case"drag":if(!this.lassoing||!n.hasLock()||!a)return;this.points.push(a);break;case"dragend":if(this.lassoing&&n.hasLock()&&a){this.points.push(a);let r=new c.Polygon(this.points),l=[];for(let d of i.getAllObjects()){let h=d.getBounds();if(r.containsRect(h)){l.push(d);continue}}i.setSelectedObjects(l),t({type:"lassoselected",data:{polygon:r,selectedObjects:l}})}case"dragcancel":this.lassoing&&n.hasLock()&&(this.lassoing=!1,this.points=[],n.release());break}}renderAfterAll(e,t){if(!(!this.lassoing||this.points.length===0)){e.save(),e.strokeStyle="black",e.lineWidth=1/e.getTransform().a,e.setLineDash([4/e.getTransform().a,2/e.getTransform().a]),e.beginPath(),e.moveTo(this.points[0].x,this.points[0].y);for(let s=1;s<this.points.length;s++)e.lineTo(this.points[s].x,this.points[s].y);e.stroke(),e.restore()}}},F=class{processToolEvent(e,t,s,i,n){if(!e.type.startsWith("api:"))return;e.stopPropagation=!0;let o=e.targets;if(!o||o.length===0)return;let a=o[0];if(!a){console.warn("API event has no target object:",e);return}if(!i.getAllObjects().includes(a)){console.warn("API event targets an object not in the engine:",a);return}switch(e.type){case"api:moveto":{if(!n.acquire())return;let{x:r,y:l}=e.data,h=a.getBounds(i.renderingContext).origin,p=new c.Vector(r-h.x,l-h.y);t({type:"move",data:{delta:p,origin:h,point:h},targets:[a]}),n.release();break}case"api:moveby":{if(!n.acquire())return;let{dx:r,dy:l}=e.data;t({type:"move",data:{delta:new c.Vector(r,l)},targets:[a]}),n.release();break}case"api:resizeto":{if(!n.acquire())return;let{width:r,height:l}=e.data,d=a.getBounds(i.renderingContext),h=d.origin,p=r-d.size.width,u=l-d.size.height;t({type:"resizestart",data:{handleIndex:4,origin:h,point:h},targets:[a]}),t({type:"resize",data:{handleIndex:4,delta:new c.Vector(p,u),point:h},targets:[a]}),t({type:"resizeend",data:{handleIndex:4,delta:new c.Vector(p,u),point:h},targets:[a]}),n.release();break}case"api:resizeby":{if(!n.acquire())return;let{dW:r,dH:l}=e.data,h=a.getBounds(i.renderingContext).origin;t({type:"resizestart",data:{handleIndex:4,origin:h,point:h},targets:[a]}),t({type:"resize",data:{handleIndex:4,delta:new c.Vector(r,l),point:h},targets:[a]}),t({type:"resizeend",data:{handleIndex:4,delta:new c.Vector(r,l),point:h},targets:[a]}),n.release();break}case"api:setcolor":{let{color:r}=e.data;t({type:"setcolor",data:{color:r},targets:[a]});break}case"api:setzindex":{let{zIndex:r}=e.data;t({type:"setzindex",data:{zIndex:r},targets:[a]});break}case"api:setselectable":{let{isSelectable:r}=e.data;t({type:"setselectable",data:{isSelectable:r},targets:[a]});break}case"api:setmovable":{if(!n.acquire())return;let{isMovable:r}=e.data;t({type:"setmovable",data:{isMovable:r},targets:[a]}),n.release();break}case"api:setresizable":{if(!n.acquire())return;let{isResizable:r}=e.data;t({type:"setresizable",data:{isResizable:r},targets:[a]}),n.release();break}case"api:setvisible":{let{visible:r}=e.data;t({type:"setvisible",data:{isVisible:r},targets:[a]});break}}}},Z=class{constructor(e=5){this.activePointerIds=new Set;this.isDragging=!1;this.buttonStart=null;this.origin=new c.Point(0,0);this.moveThreshold=e}process(e,t){let{type:s,data:i={}}=e;switch(s){case"pointerdown":if(i.pointerType!=="touch"){let n=i.point,o=e.data?.identifier,a=i.button;this.handleStart(o,i.pointerType,n,a,t)}break;case"touchstart":{let n=this.getTouches(e);if(n.length===1){let o=n[0],a=o.point,r=o.identifier;this.handleStart(r,"touch",a,null,t)}break}case"pointermove":if(i.pointerType!=="touch"){let n=i.point,o=e.data?.identifier,a=n?.getDeltaFromPoint(this.origin)||new c.Vector(0,0),r=i.button;this.handleMove(o,i.pointerType,n,a,r,t)}break;case"touchmove":{let n=this.findActiveTouch(e);if(n){let o=n.point,a=n.identifier,r=o?.getDeltaFromPoint(this.origin)||new c.Vector(0,0);this.handleMove(a,"touch",o,r,null,t)}break}case"pointerup":case"pointercancel":if(i.pointerType!=="touch"){let n=i.point,o=e.data?.identifier,a=n?.getDeltaFromPoint(this.origin)||new c.Vector(0,0),r=i.button;this.handleEnd(o,i.pointerType,n,a,r,t)}break;case"touchend":case"touchcancel":{let n=this.findActiveTouch(e);if(n){let o=n.point,a=n.identifier,r=o?.getDeltaFromPoint(this.origin)||new c.Vector(0,0);this.handleEnd(a,"touch",o,r,null,t)}break}}}handleStart(e,t,s,i,n){this.isDragging||e==null||s==null||s.x==null||s.y==null||n==null||(this.activePointerIds.add(e),this.origin=s,this.buttonStart=i??null,n({type:"dragpotential",data:{identifier:e,pointerType:t,point:origin}}))}handleMove(e,t,s,i,n,o){if(!(e==null||s==null||i==null||!this.activePointerIds.has(e)||o==null)){var a=s.subtract(i);!this.isDragging&&(this.buttonStart==null||this.buttonStart==0)&&(i.length()>=this.moveThreshold?(this.activePointerIds.clear(),this.activePointerIds.add(e),this.isDragging=!0,o({type:"dragstart",data:{identifier:e,pointerType:t,point:a}})):o({type:"dragpotentialmove",data:{identifier:e,pointerType:t,origin:a,delta:i,point:s}})),this.isDragging&&o({type:"drag",data:{identifier:e,pointerType:t,origin:a,delta:i,point:s}})}}handleEnd(e,t,s,i,n,o){if(!this.isDragging||e==null||s==null||i==null||!this.activePointerIds.has(e)||o==null){this.activePointerIds.clear();return}var a=s.add(i);o({type:"dragend",data:{identifier:e,pointerType:t,origin:a,point:s,delta:i}}),this.activePointerIds.clear(),this.isDragging=!1,this.buttonStart=null}getTouches(e){return e.data?.changedTouches??[]}findActiveTouch(e){return this.getTouches(e).find(t=>this.activePointerIds.has(t.identifier))}},V=class{constructor(e=5){this.activePointerIds=new Set;this.origin=new c.Point(0,0);this.moveThreshold=e}process(e,t){let{type:s,data:i={}}=e;switch(s){case"pointerdown":if(i.pointerType!=="touch"){let n=i.point,o=e.data?.identifier;this.handleStart(o,n)}break;case"touchstart":{let n=this.getTouches(e);if(n.length===1){let o=n[0],a=o.point,r=o.identifier;this.handleStart(r,a)}break}case"pointermove":if(i.pointerType!=="touch"){let n=i.point,o=e.data?.identifier,a=n?.getDeltaFromPoint(this.origin)||new c.Vector(0,0);this.handleMove(o,n,a)}break;case"touchmove":{let n=this.findActiveTouch(e);if(n){let o=n.point,a=n.identifier,r=o?.getDeltaFromPoint(this.origin)||new c.Vector(0,0);this.handleMove(a,o,r)}break}case"pointerup":case"pointercancel":if(i.pointerType!=="touch"){let n=i.point,o=e.data?.identifier,a=n?.getDeltaFromPoint(this.origin)||new c.Vector(0,0),r=e.data?.shiftHeld??!1,l=e.data?.metaHeld??!1,d=e.data?.ctrlHeld??!1,h=e.data?.altHeld??!1;this.handleEnd(o,i.pointerType,n,a,{shiftHeld:r,metaHeld:l,ctrlHeld:d,altHeld:h},t)}break;case"touchend":case"touchcancel":{let n=this.findActiveTouch(e);if(n){let o=n.point,a=n.identifier,r=o?.getDeltaFromPoint(this.origin)||new c.Vector(0,0);this.handleEnd(a,"touch",o,r,t)}break}}}handleStart(e,t){e==null||t==null||t.x==null||t.y==null||(this.activePointerIds.add(e),this.origin=t)}handleMove(e,t,s){e==null||t==null||s==null||!this.activePointerIds.has(e)||s.length()>=this.moveThreshold&&this.activePointerIds.clear()}handleEnd(e,t,s,i,n,o){if(!(e==null||s==null||i==null||!this.activePointerIds.has(e)||o==null)){if(i.length()>=this.moveThreshold){this.activePointerIds.clear();return}var a={identifier:e,pointerType:t,point:s};n&&(a={...a,...n}),o({type:"click",data:a}),this.activePointerIds.clear()}}getTouches(e){return e.data?.changedTouches??[]}findActiveTouch(e){return this.getTouches(e).find(t=>this.activePointerIds.has(t.identifier))}};0&&(module.exports={ApiTool,CanvasEngine,CircleObject,ClickGestureRecognizer,DomEventSource,DragGestureRecognizer,DrawingTool,EngineEventType,HoverTool,LassoTool,MoveTool,PolygonObject,ResizeTool,SelectTool,ToolLockManager,Zone});
package/dist/index.d.cts CHANGED
@@ -10,6 +10,12 @@ interface CanvasEvent {
10
10
  stopPropagation?: boolean;
11
11
  tool?: ToolPipelineNode;
12
12
  }
13
+ interface ZoomToolOptions {
14
+ wheelZoomFactor?: number;
15
+ pinchZoomFactor?: number;
16
+ minZoom?: number;
17
+ maxZoom?: number;
18
+ }
13
19
  /**
14
20
  * Rectangular interactive zone with resize handles and move region.
15
21
  */
@@ -50,26 +56,26 @@ declare class Zone implements InteractiveObject {
50
56
  constructor(id: string, x: number, y: number, width: number, height: number, color?: string, isSelectable?: boolean, isMovable?: boolean, isResizable?: boolean, zIndex?: number);
51
57
  constructor(id: string, rect: Rectangle, color?: string, isSelectable?: boolean, isMovable?: boolean, isResizable?: boolean, zIndex?: number);
52
58
  /** Tight bounds of the zone body */
53
- getBounds(): Rectangle;
59
+ getBounds(context: InteractiveObjectContext): Rectangle;
54
60
  /** Bounds including resize handles */
55
- getOuterBounds(): Rectangle;
61
+ getOuterBounds(context: InteractiveObjectContext): Rectangle;
56
62
  /**
57
63
  * Reports which interactions this zone supports at the given point.
58
64
  * If atPoint is null, returns all possible interactions.
59
65
  */
60
- getEventInteractions(atPoint: Point | null): EventInteraction[];
66
+ getEventInteractions(atPoint: Point | null, context: InteractiveObjectContext): EventInteraction[];
61
67
  /**
62
68
  * Returns eight candidate handle positions for resizing, adjusting
63
69
  * their offset (inside, middle, or outside) based on object dimensions.
64
70
  */
65
- getResizeHandles(): Array<{
71
+ getResizeHandles(context: InteractiveObjectContext): Array<{
66
72
  rect: Rectangle;
67
73
  handleIndex: number;
68
74
  }>;
69
75
  /** No custom event handling; defaults to flags and tool logic */
70
76
  handleEvent?(evt: CanvasEvent, emitExternal: (type: keyof EngineEventPayloads, payload: EngineEventPayloads[keyof EngineEventPayloads]) => void): void;
71
77
  /** Render the zone with optional handles and selection styling */
72
- render(ctx: CanvasRenderingContext2D, flags: Set<string>): void;
78
+ render(ctx: CanvasRenderingContext2D, flags: Set<string>, context: InteractiveObjectContext): void;
73
79
  /**
74
80
  * Return a rgba() string for any valid CSS color with a custom alpha.
75
81
  * Uses the canvas context to normalize named colors, hex, hsl(), etc.
@@ -207,21 +213,25 @@ interface EventInteraction {
207
213
  /**
208
214
  * Basic interactive object contract
209
215
  */
216
+ interface InteractiveObjectContext {
217
+ currentZoom: number;
218
+ currentScaleMultiplier: number;
219
+ }
210
220
  interface InteractiveObject {
211
221
  id: string;
212
222
  zIndex: number;
213
223
  visible?: boolean;
214
224
  selectable?: boolean;
215
225
  /** The tight bounds of the object’s geometry (for hit-tests, layout) */
216
- getBounds(): Rectangle;
226
+ getBounds(context: InteractiveObjectContext): Rectangle;
217
227
  /** The full interaction bounds (handles, halos, shadows, etc.) */
218
- getOuterBounds(): Rectangle;
228
+ getOuterBounds(context: InteractiveObjectContext): Rectangle;
219
229
  /** Optional hit-test for pointer events */
220
- getEventInteractions(atPoint: Point | null): EventInteraction[];
230
+ getEventInteractions(atPoint: Point | null, context: InteractiveObjectContext): EventInteraction[];
221
231
  /** Optional event handler for custom events */
222
232
  handleEvent?(evt: CanvasEvent, emitExternal: (type: keyof EngineEventPayloads, payload: EngineEventPayloads[keyof EngineEventPayloads]) => void): void;
223
233
  /** Render the object, given selection/hover flags */
224
- render(ctx: CanvasRenderingContext2D, flags: Set<string>): void;
234
+ render(ctx: CanvasRenderingContext2D, flags: Set<string>, context: InteractiveObjectContext): void;
225
235
  }
226
236
  /**
227
237
  * Converts raw inputs into semantic pipeline events
@@ -395,6 +405,7 @@ interface CanvasEngineOptions {
395
405
  defaultMode?: string;
396
406
  addTimerEventSource?: boolean;
397
407
  proxyObjectsForEvents?: boolean;
408
+ zoomOptions?: ZoomToolOptions;
398
409
  }
399
410
  interface ModeConfig {
400
411
  tools: string[];
@@ -556,7 +567,7 @@ declare class CanvasEngine {
556
567
  /**
557
568
  * Returns a map from event-prefix → topmost object that supports it at (x,y).
558
569
  */
559
- getTopMostInteractionPerEventType(point: Point): Map<string, InteractionEntry>;
570
+ getTopMostInteractionPerEventType(point: Point, context: InteractiveObjectContext): Map<string, InteractionEntry>;
560
571
  /** QUEUE HELPERS **/
561
572
  /** Called by any EventSource to enqueue a raw event */
562
573
  private enqueue;
@@ -576,6 +587,7 @@ declare class CanvasEngine {
576
587
  /** RENDERING **/
577
588
  redraw(): void;
578
589
  private requestRender;
590
+ get renderingContext(): InteractiveObjectContext;
579
591
  private doRender;
580
592
  dispose(): void;
581
593
  }
@@ -678,4 +690,4 @@ declare class ClickGestureRecognizer implements GestureRecognizer {
678
690
  private findActiveTouch;
679
691
  }
680
692
 
681
- export { ApiTool, CanvasEngine, type CanvasEvent, CircleObject, ClickGestureRecognizer, DomEventSource, DragGestureRecognizer, DrawingTool, type EngineEventPayloads, EngineEventType, type EventSource, type GestureRecognizer, HoverTool, type InteractiveObject, LassoTool, MoveTool, PolygonObject, type RenderPipelineNode, ResizeTool, SelectTool, ToolLockManager, type ToolPipelineNode, Zone };
693
+ export { ApiTool, CanvasEngine, type CanvasEvent, CircleObject, ClickGestureRecognizer, DomEventSource, DragGestureRecognizer, DrawingTool, type EngineEventPayloads, EngineEventType, type EventSource, type GestureRecognizer, HoverTool, type InteractiveObject, type InteractiveObjectContext, LassoTool, MoveTool, PolygonObject, type RenderPipelineNode, ResizeTool, SelectTool, ToolLockManager, type ToolPipelineNode, Zone, type ZoomToolOptions };
package/dist/index.d.ts CHANGED
@@ -10,6 +10,12 @@ interface CanvasEvent {
10
10
  stopPropagation?: boolean;
11
11
  tool?: ToolPipelineNode;
12
12
  }
13
+ interface ZoomToolOptions {
14
+ wheelZoomFactor?: number;
15
+ pinchZoomFactor?: number;
16
+ minZoom?: number;
17
+ maxZoom?: number;
18
+ }
13
19
  /**
14
20
  * Rectangular interactive zone with resize handles and move region.
15
21
  */
@@ -50,26 +56,26 @@ declare class Zone implements InteractiveObject {
50
56
  constructor(id: string, x: number, y: number, width: number, height: number, color?: string, isSelectable?: boolean, isMovable?: boolean, isResizable?: boolean, zIndex?: number);
51
57
  constructor(id: string, rect: Rectangle, color?: string, isSelectable?: boolean, isMovable?: boolean, isResizable?: boolean, zIndex?: number);
52
58
  /** Tight bounds of the zone body */
53
- getBounds(): Rectangle;
59
+ getBounds(context: InteractiveObjectContext): Rectangle;
54
60
  /** Bounds including resize handles */
55
- getOuterBounds(): Rectangle;
61
+ getOuterBounds(context: InteractiveObjectContext): Rectangle;
56
62
  /**
57
63
  * Reports which interactions this zone supports at the given point.
58
64
  * If atPoint is null, returns all possible interactions.
59
65
  */
60
- getEventInteractions(atPoint: Point | null): EventInteraction[];
66
+ getEventInteractions(atPoint: Point | null, context: InteractiveObjectContext): EventInteraction[];
61
67
  /**
62
68
  * Returns eight candidate handle positions for resizing, adjusting
63
69
  * their offset (inside, middle, or outside) based on object dimensions.
64
70
  */
65
- getResizeHandles(): Array<{
71
+ getResizeHandles(context: InteractiveObjectContext): Array<{
66
72
  rect: Rectangle;
67
73
  handleIndex: number;
68
74
  }>;
69
75
  /** No custom event handling; defaults to flags and tool logic */
70
76
  handleEvent?(evt: CanvasEvent, emitExternal: (type: keyof EngineEventPayloads, payload: EngineEventPayloads[keyof EngineEventPayloads]) => void): void;
71
77
  /** Render the zone with optional handles and selection styling */
72
- render(ctx: CanvasRenderingContext2D, flags: Set<string>): void;
78
+ render(ctx: CanvasRenderingContext2D, flags: Set<string>, context: InteractiveObjectContext): void;
73
79
  /**
74
80
  * Return a rgba() string for any valid CSS color with a custom alpha.
75
81
  * Uses the canvas context to normalize named colors, hex, hsl(), etc.
@@ -207,21 +213,25 @@ interface EventInteraction {
207
213
  /**
208
214
  * Basic interactive object contract
209
215
  */
216
+ interface InteractiveObjectContext {
217
+ currentZoom: number;
218
+ currentScaleMultiplier: number;
219
+ }
210
220
  interface InteractiveObject {
211
221
  id: string;
212
222
  zIndex: number;
213
223
  visible?: boolean;
214
224
  selectable?: boolean;
215
225
  /** The tight bounds of the object’s geometry (for hit-tests, layout) */
216
- getBounds(): Rectangle;
226
+ getBounds(context: InteractiveObjectContext): Rectangle;
217
227
  /** The full interaction bounds (handles, halos, shadows, etc.) */
218
- getOuterBounds(): Rectangle;
228
+ getOuterBounds(context: InteractiveObjectContext): Rectangle;
219
229
  /** Optional hit-test for pointer events */
220
- getEventInteractions(atPoint: Point | null): EventInteraction[];
230
+ getEventInteractions(atPoint: Point | null, context: InteractiveObjectContext): EventInteraction[];
221
231
  /** Optional event handler for custom events */
222
232
  handleEvent?(evt: CanvasEvent, emitExternal: (type: keyof EngineEventPayloads, payload: EngineEventPayloads[keyof EngineEventPayloads]) => void): void;
223
233
  /** Render the object, given selection/hover flags */
224
- render(ctx: CanvasRenderingContext2D, flags: Set<string>): void;
234
+ render(ctx: CanvasRenderingContext2D, flags: Set<string>, context: InteractiveObjectContext): void;
225
235
  }
226
236
  /**
227
237
  * Converts raw inputs into semantic pipeline events
@@ -395,6 +405,7 @@ interface CanvasEngineOptions {
395
405
  defaultMode?: string;
396
406
  addTimerEventSource?: boolean;
397
407
  proxyObjectsForEvents?: boolean;
408
+ zoomOptions?: ZoomToolOptions;
398
409
  }
399
410
  interface ModeConfig {
400
411
  tools: string[];
@@ -556,7 +567,7 @@ declare class CanvasEngine {
556
567
  /**
557
568
  * Returns a map from event-prefix → topmost object that supports it at (x,y).
558
569
  */
559
- getTopMostInteractionPerEventType(point: Point): Map<string, InteractionEntry>;
570
+ getTopMostInteractionPerEventType(point: Point, context: InteractiveObjectContext): Map<string, InteractionEntry>;
560
571
  /** QUEUE HELPERS **/
561
572
  /** Called by any EventSource to enqueue a raw event */
562
573
  private enqueue;
@@ -576,6 +587,7 @@ declare class CanvasEngine {
576
587
  /** RENDERING **/
577
588
  redraw(): void;
578
589
  private requestRender;
590
+ get renderingContext(): InteractiveObjectContext;
579
591
  private doRender;
580
592
  dispose(): void;
581
593
  }
@@ -678,4 +690,4 @@ declare class ClickGestureRecognizer implements GestureRecognizer {
678
690
  private findActiveTouch;
679
691
  }
680
692
 
681
- export { ApiTool, CanvasEngine, type CanvasEvent, CircleObject, ClickGestureRecognizer, DomEventSource, DragGestureRecognizer, DrawingTool, type EngineEventPayloads, EngineEventType, type EventSource, type GestureRecognizer, HoverTool, type InteractiveObject, LassoTool, MoveTool, PolygonObject, type RenderPipelineNode, ResizeTool, SelectTool, ToolLockManager, type ToolPipelineNode, Zone };
693
+ export { ApiTool, CanvasEngine, type CanvasEvent, CircleObject, ClickGestureRecognizer, DomEventSource, DragGestureRecognizer, DrawingTool, type EngineEventPayloads, EngineEventType, type EventSource, type GestureRecognizer, HoverTool, type InteractiveObject, type InteractiveObjectContext, LassoTool, MoveTool, PolygonObject, type RenderPipelineNode, ResizeTool, SelectTool, ToolLockManager, type ToolPipelineNode, Zone, type ZoomToolOptions };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import{Rectangle as w,Size as T,Point as v,Vector as m,Polygon as ne}from"dytools-geometry";var M=class M{constructor(e,n,s,i,t,r,o,a,l,c){this._name=null;this._showName=!1;this._nameAnchor="TopLeft";this._visible=!0;if(this._id=e,n instanceof w){let d=n,b=s??"#000000",g=i??!1,E=t??!1,I=r??!1,x=o??0;this._rect=d,this._color=b,this._selectable=g,this._movable=E,this._resizable=I,this._zIndex=x}else{let d=n,b=s,g=i,E=t,I=r??"#000000",x=o??!1,O=a??!1,R=l??!1,k=c??0;this._rect=new w(new v(d,b),new T(g,E)),this._color=I,this._selectable=x,this._movable=O,this._resizable=R,this._zIndex=k}}get id(){return this._id}set id(e){this._id=e}get rect(){return this._rect.normalized()}get name(){return this._name}set name(e){this._name=e}get showName(){return this._showName}set showName(e){this._showName=e}get nameAnchor(){return this._nameAnchor}set nameAnchor(e){this._nameAnchor=e}get zIndex(){return this._zIndex}set zIndex(e){this._zIndex=e}get visible(){return this._visible??!1}set visible(e){this._visible=e}get color(){return this._color}set color(e){this._color=e}get selectable(){return this._selectable}set selectable(e){this._selectable=e}get movable(){return this._movable}set movable(e){this._movable=e}get resizable(){return this._resizable}set resizable(e){this._resizable=e}getBounds(){return this._rect}getOuterBounds(){let e=this._rect,n=this.getResizeHandles();return n.length===0||n.forEach(s=>{e=e.expand(s.rect)}),e}getEventInteractions(e){let n=[];if(this._resizable&&this.getResizeHandles().forEach(i=>{(e===null||i.rect.contains(e))&&n.push({eventTypePrefix:"resize",handleIndex:i.handleIndex})}),this._movable){let s=this.getBounds();(e===null||s.contains(e))&&n.push({eventTypePrefix:"move"})}if(this._selectable){let s=this.getBounds();(e===null||s.contains(e))&&n.push({eventTypePrefix:"select"})}return n}getResizeHandles(){let e=this._rect.origin.x,n=this._rect.origin.y,s=this._rect.size.width,i=this._rect.size.height,t=M.HANDLE_SIZE,r=t*10,o=t*6,a=1;s>=r&&i>=r?a=-1:s>=o&&i>=o&&(a=0);let l=s<o,c=i<o;return[{rect:new w(new v(e-a*t-t,n-a*t-t),new T(t*2,t*2)),handleIndex:0},l?null:{rect:new w(new v(e+s/2-t,n-a*t-t),new T(t*2,t*2)),handleIndex:1},{rect:new w(new v(e+s+a*t-t,n-a*t-t),new T(t*2,t*2)),handleIndex:2},c?null:{rect:new w(new v(e+s+a*t-t,n+i/2-t),new T(t*2,t*2)),handleIndex:3},{rect:new w(new v(e+s+a*t-t,n+i+a*t-t),new T(t*2,t*2)),handleIndex:4},l?null:{rect:new w(new v(e+s/2-t,n+i+a*t-t),new T(t*2,t*2)),handleIndex:5},{rect:new w(new v(e-a*t-t,n+i+a*t-t),new T(t*2,t*2)),handleIndex:6},c?null:{rect:new w(new v(e-a*t-t,n+i/2-t),new T(t*2,t*2)),handleIndex:7}].filter(b=>b!==null)}handleEvent(e,n){let s=e.data||{};if(e.type==="setcolor"&&this._color!==s.color){let t=this._color;this._color=s.color,n(u.ObjectColorChanged,{object:this,oldColor:t,newColor:this._color});return}if(e.type==="setzindex"&&this._zIndex!==s.zIndex){let t=this._zIndex;this._zIndex=s.zIndex,n(u.ObjectZIndexChanged,{object:this,oldZIndex:t,newZIndex:this._zIndex});return}if(e.type==="setselectable"&&this._selectable!==s.isSelectable){let t=this._selectable;this._selectable=s.isSelectable,n(u.ObjectSelectableChanged,{object:this,oldSelectable:t,newSelectable:this._selectable});return}if(e.type==="setmovable"&&this._movable!==s.isMovable){let t=this._movable;this._movable=s.isMovable,n(u.ObjectMovableChanged,{object:this,oldMovable:t,newMovable:this._movable});return}if(e.type==="setresizable"&&this._resizable!==s.isResizable){let t=this._resizable;this._resizable=s.isResizable,n(u.ObjectResizableChanged,{object:this,oldResizable:t,newResizable:this._resizable});return}if(e.type==="setvisible"&&this._visible!==s.isVisible){let t=this._visible??!0;this._visible=s.isVisible,n(u.ObjectVisibleChanged,{object:this,oldVisible:t,newVisible:this._visible??!0});return}let i=s.delta;if(e.type==="resize"){let t=this._rect.clone(),r=s.handleIndex;if(i==null||r==null){console.warn("Resize event missing required data:",e);return}let o=-1/0,a=i.x,l=i.y;if(a===0&&l===0)return;switch(r){case 0:a=Math.min(a,this._rect.size.width-o),l=Math.min(l,this._rect.size.height-o),this._rect.origin.x+=a,this._rect.origin.y+=l,this._rect.size.width-=a,this._rect.size.height-=l;break;case 1:l=Math.min(l,this._rect.size.height-o),this._rect.origin.y+=l,this._rect.size.height-=l;break;case 2:a=Math.max(a,o-this._rect.size.width),l=Math.min(l,this._rect.size.height-o),this._rect.origin.y+=l,this._rect.size.width+=a,this._rect.size.height-=l;break;case 3:a=Math.max(a,o-this._rect.size.width),this._rect.size.width+=a;break;case 4:a=Math.max(a,o-this._rect.size.width),l=Math.max(l,o-this._rect.size.height),this._rect.size.width+=a,this._rect.size.height+=l;break;case 5:l=Math.max(l,o-this._rect.size.height),this._rect.size.height+=l;break;case 6:a=Math.min(a,this._rect.size.width-o),l=Math.max(l,o-this._rect.size.height),this._rect.origin.x+=a,this._rect.size.width-=a,this._rect.size.height+=l;break;case 7:a=Math.min(a,this._rect.size.width-o),this._rect.origin.x+=a,this._rect.size.width-=a;break}n(u.ObjectResized,{object:this,oldSize:t.size,newSize:this._rect.clone().size}),n(u.ObjectPositionChanged,{object:this,oldPosition:t,newPosition:this._rect.clone()})}else e.type==="resizeend"&&this._rect.normalize();if(e.type.startsWith("move")){if(i==null){console.warn("Move event missing required data:",e);return}if(i.x===0&&i.y===0)return;let t=this._rect.clone();this._rect=this._rect.move(i),n(u.ObjectMoved,{object:this,oldPoint:t.origin,newPoint:this._rect.clone().origin}),n(u.ObjectPositionChanged,{object:this,oldPosition:t,newPosition:this._rect})}}render(e,n){let s=n.has("selected"),i=n.has("hovered"),t=n.has("hoversibling"),o=e.getTransform().a,a=h=>h/o,l=a(4),c=a(2),d=a(3),b=a(4),g=this._rect,E=g.origin.x,I=g.origin.y,x=g.size.width,O=g.size.height,R=(h,p,y,f,j)=>{let P=Math.max(0,Math.min(j,Math.min(y,f)/2)),z=new Path2D;return z.moveTo(h+P,p),z.lineTo(h+y-P,p),z.arcTo(h+y,p,h+y,p+P,P),z.lineTo(h+y,p+f-P),z.arcTo(h+y,p+f,h+y-P,p+f,P),z.lineTo(h+P,p+f),z.arcTo(h,p+f,h,p+f-P,P),z.lineTo(h,p+P),z.arcTo(h,p,h+P,p,P),z.closePath(),z},k=R(E,I,x,O,l);e.save(),e.strokeStyle=this._color;let C=e.strokeStyle;if(e.fillStyle=this.withAlpha(C,.06),e.fill(k),e.lineWidth=c,e.stroke(k),e.restore(),s){let h=E-b,p=I-b,y=x+b*2,f=O+b*2,j=R(h,p,y,f,l+b);e.save(),e.setLineDash([a(8),a(6)]),e.lineDashOffset=0,e.strokeStyle="rgba(0,0,0,0.4)",e.lineWidth=d,e.stroke(j),e.restore()}if(this._showName&&this._name){e.save(),e.font="12px sans-serif",e.fillStyle=this._color,e.textBaseline="top";let h=2,{x:p,y}=this._rect.origin,{width:f,height:j}=this._rect.size,P=p+h,z=y+h;switch(this._nameAnchor){case"TopLeft":P=p+h,z=y+h;break;case"TopRight":P=p+f-e.measureText(this._name).width-h,z=y+h;break;case"BottomLeft":P=p+h,z=y+j-14-h;break;case"BottomRight":P=p+f-e.measureText(this._name).width-h,z=y+j-14-h;break;case"Center":P=p+(f-e.measureText(this._name).width)/2,z=y+(j-12)/2;break}e.fillText(this._name,P,z),e.restore()}if(this._resizable&&i){e.save(),e.lineWidth=a(t?.5:1),e.strokeStyle=C,e.fillStyle=t?"transparent":"white",e.globalAlpha=t?.75:1;for(let h of this.getResizeHandles()||[]){if(!h)continue;let{x:p,y}=h.rect.origin,{width:f,height:j}=h.rect.size,P=a(4),z=R(p,y,f,j,P);e.fill(z),e.stroke(z)}e.restore()}}withAlpha(e,n){let s=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\s*\)/i);if(s){let i=parseInt(s[1]??"0",10),t=parseInt(s[2]??"0",10),r=parseInt(s[3]??"0",10);return`rgba(${i},${t},${r},${n})`}if(e.startsWith("#")){let i=e.slice(1);if(i.length===3&&(i=i.split("").map(t=>t+t).join("")),i.length===6||i.length===8){let t=parseInt(i.slice(0,2),16),r=parseInt(i.slice(2,4),16),o=parseInt(i.slice(4,6),16);return`rgba(${t},${r},${o},${n})`}}return e}};M.HANDLE_SIZE=6;var G=M,B=class B{constructor(e,n,s,i,t,r,o,a,l){this._name=null;this._showName=!1;this._visible=!0;if(this._id=e,n instanceof v){let c=n,d=s,b=i??"#000000",g=t??!1,E=r??!1,I=o??!1,x=a??0;this._center=c,this._radius=d,this._color=b,this._selectable=g,this._movable=E,this._resizable=I,this._zIndex=x}else{let c=n,d=s,b=i,g=t??"#000000",E=r??!1,I=o??!1,x=a??!1,O=l??0;this._center=new v(c,d),this._radius=b,this._color=g,this._selectable=E,this._movable=I,this._resizable=x,this._zIndex=O}}get id(){return this._id}set id(e){this._id=e}get center(){return this._center}get name(){return this._name}set name(e){this._name=e}get showName(){return this._showName}set showName(e){this._showName=e}get zIndex(){return this._zIndex}set zIndex(e){this._zIndex=e}get visible(){return this._visible??!1}set visible(e){this._visible=e}get color(){return this._color}set color(e){this._color=e}get selectable(){return this._selectable}set selectable(e){this._selectable=e}get movable(){return this._movable}set movable(e){this._movable=e}get resizable(){return this._resizable}set resizable(e){this._resizable=e}getBounds(){return new w(this.center.x-this._radius,this.center.y-this._radius,2*this._radius,2*this._radius)}getOuterBounds(){let e=this.getBounds(),n=this.getResizeHandles();return n.length===0||n.forEach(s=>{e=e.expand(s.rect)}),e}getEventInteractions(e){let n=[];if(this._resizable&&this.getResizeHandles().forEach(i=>{(e===null||i.rect.contains(e))&&n.push({eventTypePrefix:"resize",handleIndex:i.handleIndex})}),this._movable){let s=this.getBounds();(e===null||s.contains(e))&&n.push({eventTypePrefix:"move"})}if(this._selectable){let s=this.getBounds();(e===null||s.contains(e))&&n.push({eventTypePrefix:"select"})}return n}getResizeHandles(){let e=this.getBounds().origin.x,n=this.getBounds().origin.y,s=this.getBounds().size.width,i=this.getBounds().size.height,t=B.HANDLE_SIZE,r=t*10,o=t*6,a=1;s>=r&&i>=r?a=-1:s>=o&&i>=o&&(a=0);let l=s<o,c=i<o;return[{rect:new w(new v(e-a*t-t,n-a*t-t),new T(t*2,t*2)),handleIndex:0},l?null:{rect:new w(new v(e+s/2-t,n-a*t-t),new T(t*2,t*2)),handleIndex:1},{rect:new w(new v(e+s+a*t-t,n-a*t-t),new T(t*2,t*2)),handleIndex:2},c?null:{rect:new w(new v(e+s+a*t-t,n+i/2-t),new T(t*2,t*2)),handleIndex:3},{rect:new w(new v(e+s+a*t-t,n+i+a*t-t),new T(t*2,t*2)),handleIndex:4},l?null:{rect:new w(new v(e+s/2-t,n+i+a*t-t),new T(t*2,t*2)),handleIndex:5},{rect:new w(new v(e-a*t-t,n+i+a*t-t),new T(t*2,t*2)),handleIndex:6},c?null:{rect:new w(new v(e-a*t-t,n+i/2-t),new T(t*2,t*2)),handleIndex:7}].filter(b=>b!==null)}handleEvent(e,n){let s=e.data||{};if(e.type==="setcolor"){let i=this._color;this._color=s.color,n(u.ObjectColorChanged,{object:this,oldColor:i,newColor:this._color});return}if(e.type==="setzindex"){let i=this._zIndex;this._zIndex=s.zIndex,n(u.ObjectZIndexChanged,{object:this,oldZIndex:i,newZIndex:this._zIndex});return}if(e.type==="setselectable"){let i=this._selectable;this._selectable=s.isSelectable,n(u.ObjectSelectableChanged,{object:this,oldSelectable:i,newSelectable:this._selectable});return}if(e.type==="setmovable"){let i=this._movable;this._movable=s.isMovable,n(u.ObjectMovableChanged,{object:this,oldMovable:i,newMovable:this._movable});return}if(e.type==="setresizable"){let i=this._resizable;this._resizable=s.isResizable,n(u.ObjectResizableChanged,{object:this,oldResizable:i,newResizable:this._resizable});return}if(e.type==="setvisible"){let i=this._visible??!0;this._visible=s.isVisible,n(u.ObjectVisibleChanged,{object:this,oldVisible:i,newVisible:this._visible??!0});return}}render(e,n){let s=n.has("selected"),i=n.has("hovered"),t=n.has("hoversibling"),o=e.getTransform().a,a=R=>R/o,l=this._center.x,c=this._center.y,d=this._radius,b=a(4),g=a(2),E=a(3),I=a(4),x=this.color,O=this.withAlpha(x,.06);if(e.save(),e.beginPath(),e.arc(l,c,d,0,Math.PI*2),e.fillStyle=O,e.strokeStyle=x,e.lineWidth=g,e.fill(),e.stroke(),e.restore(),s&&(e.save(),e.beginPath(),e.arc(l,c,d+I,0,Math.PI*2),e.setLineDash([a(8),a(6)]),e.strokeStyle="rgba(0,0,0,0.4)",e.lineWidth=E,e.stroke(),e.restore()),this._resizable&&i){let R=this.getResizeHandles?.()??[];e.save(),e.lineWidth=a(t?.5:1),e.strokeStyle=x,e.fillStyle=t?"transparent":"white",e.globalAlpha=t?.75:1;for(let k of R){let C=k.rect.origin.x,h=k.rect.origin.y,p=k.rect.size.width,y=k.rect.size.height,f=a(4),j=new Path2D;j.moveTo(C+f,h),j.lineTo(C+p-f,h),j.arcTo(C+p,h,C+p,h+f,f),j.lineTo(C+p,h+y-f),j.arcTo(C+p,h+y,C+p-f,h+y,f),j.lineTo(C+f,h+y),j.arcTo(C,h+y,C,h+y-f,f),j.lineTo(C,h+f),j.arcTo(C,h,C+f,h,f),j.closePath(),e.fill(j),e.stroke(j)}e.restore()}}withAlpha(e,n){let s=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\s*\)/i);if(s){let i=parseInt(s[1]??"0",10),t=parseInt(s[2]??"0",10),r=parseInt(s[3]??"0",10);return`rgba(${i},${t},${r},${n})`}if(e.startsWith("#")){let i=e.slice(1);if(i.length===3&&(i=i.split("").map(t=>t+t).join("")),i.length===6||i.length===8){let t=parseInt(i.slice(0,2),16),r=parseInt(i.slice(2,4),16),o=parseInt(i.slice(4,6),16);return`rgba(${t},${r},${o},${n})`}}return e}};B.HANDLE_SIZE=6;var J=B,ee=class{constructor(e,n,s,i,t,r){this.visible=!0;this.id=e,this._points=n?n.slice():[],this.color=s??"#000000",this.selectable=i??!1,this.movable=t??!1,this.zIndex=r??0}get points(){return this._points}getBounds(){if(!this._points||this._points.length===0)return new w(new v(0,0),new T(0,0));let e=this._points[0].x,n=this._points[0].x,s=this._points[0].y,i=this._points[0].y;for(let t of this._points)t.x<e&&(e=t.x),t.x>n&&(n=t.x),t.y<s&&(s=t.y),t.y>i&&(i=t.y);return new w(new v(e,s),new T(n-e,i-s))}getOuterBounds(){return this.getBounds()}getEventInteractions(e){let n=[],s=this.getBounds();return this.movable&&(e===null||s.contains(e))&&n.push({eventTypePrefix:"move"}),this.selectable&&(e===null||s.contains(e))&&n.push({eventTypePrefix:"select"}),n}handleEvent(e,n){let s=e.data||{};if(e.type==="setcolor"){let i=this.color;this.color=s.color,n(u.ObjectColorChanged,{object:this,oldColor:i,newColor:this.color});return}if(e.type==="setzindex"){let i=this.zIndex;this.zIndex=s.zIndex,n(u.ObjectZIndexChanged,{object:this,oldZIndex:i,newZIndex:this.zIndex});return}if(e.type==="setselectable"){let i=this.selectable;this.selectable=s.isSelectable,n(u.ObjectSelectableChanged,{object:this,oldSelectable:i,newSelectable:this.selectable});return}if(e.type==="setmovable"){let i=this.movable;this.movable=s.isMovable,n(u.ObjectMovableChanged,{object:this,oldMovable:i,newMovable:this.movable});return}if(e.type==="setvisible"){let i=this.visible;this.visible=s.isVisible,n(u.ObjectVisibleChanged,{object:this,oldVisible:i,newVisible:this.visible});return}if(e.type.startsWith("move")){let i=s.delta;if(i==null){console.warn("Move event missing required data:",e);return}let t=this.getBounds();for(let o of this._points)o.x+=i.x,o.y+=i.y;let r=this.getBounds();n(u.ObjectMoved,{object:this,oldPoint:t.origin,newPoint:r.origin}),n(u.ObjectPositionChanged,{object:this,oldPosition:t,newPosition:r});return}}render(e,n){let s=n.has("selected"),i=n.has("hovered"),r=e.getTransform().a,o=b=>b/r,l=(()=>{if(!this._points||this._points.length===0)return null;let b=new Path2D;b.moveTo(this._points[0].x,this._points[0].y);for(let g=1;g<this._points.length;++g)b.lineTo(this._points[g].x,this._points[g].y);return b.closePath(),b})();if(!l)return;let c=this.getBounds();e.save(),e.strokeStyle=this.color;let d=e.strokeStyle;if(e.fillStyle=this.withAlpha(d,.06),e.lineWidth=o(2),e.fill(l),e.stroke(l),e.restore(),s){let b=o(3),g=o(4),E=c.origin.x-g,I=c.origin.y-g,x=c.size.width+g*2,O=c.size.height+g*2;e.save(),e.setLineDash([o(8),o(6)]),e.lineDashOffset=0,e.strokeStyle="rgba(0,0,0,0.4)",e.lineWidth=b,e.strokeRect(E,I,x,O),e.restore()}}withAlpha(e,n){let s=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\s*\)/i);if(s){let i=parseInt(s[1]??"0",10),t=parseInt(s[2]??"0",10),r=parseInt(s[3]??"0",10);return`rgba(${i},${t},${r},${n})`}if(e.startsWith("#")){let i=e.slice(1);if(i.length===3&&(i=i.split("").map(t=>t+t).join("")),i.length===6||i.length===8){let t=parseInt(i.slice(0,2),16),r=parseInt(i.slice(2,4),16),o=parseInt(i.slice(4,6),16);return`rgba(${t},${r},${o},${n})`}}return e}},D=class{constructor(e=1e3){this.intervalId=null;this.interval=e,this.intervalId=null}attach(e,n){this.start(e)}detach(){this.stop()}start(e){this.intervalId=window.setInterval(()=>{e({type:"tick",data:{}})},this.interval)}stop(){this.intervalId!==null&&(clearInterval(this.intervalId),this.intervalId=null)}},A=class{constructor(e){this.listeners=[];this.canvas=e}attach(e,n){let s=(i,t,r)=>{typeof t=="string"&&(t=[t]);for(let o of t)i.addEventListener(o,r),this.listeners.push({target:i,type:o,handler:r})};s(this.canvas,"pointerdown",i=>{let t=i,r=new v(t.offsetX,t.offsetY),o=n.screenToWorld(r),a=!!t.shiftKey,l=!!t.metaKey,c=!!t.ctrlKey,d=!!t.altKey;e({type:"pointerdown",data:{point:o,identifier:t.pointerId,pointerType:t.pointerType,originalEvent:t,button:t.button,shiftHeld:a,metaHeld:l,ctrlHeld:c,altHeld:d}})}),s(this.canvas,"pointermove",i=>{let t=i;t.preventDefault();let r=new v(t.offsetX,t.offsetY),o=n.screenToWorld(r),a=!!t.shiftKey,l=!!t.metaKey,c=!!t.ctrlKey,d=!!t.altKey;e({type:"pointermove",data:{point:o,identifier:t.pointerId,pointerType:t.pointerType,originalEvent:t,button:t.button,shiftHeld:a,metaHeld:l,ctrlHeld:c,altHeld:d}})}),s(this.canvas,"pointerup",i=>{let t=i;t.preventDefault();let r=new v(t.offsetX,t.offsetY),o=n.screenToWorld(r),a=!!t.shiftKey,l=!!t.metaKey,c=!!t.ctrlKey,d=!!t.altKey;e({type:"pointerup",data:{point:o,identifier:t.pointerId,pointerType:t.pointerType,originalEvent:t,button:t.button,shiftHeld:a,metaHeld:l,ctrlHeld:c,altHeld:d}})}),s(this.canvas,"pointercancel",i=>{let t=i;if(t.pointerType==="touch")return;t.preventDefault();let r=new v(t.offsetX,t.offsetY),o=n.screenToWorld(r),a=!!t.shiftKey,l=!!t.metaKey,c=!!t.ctrlKey,d=!!t.altKey;e({type:"pointercancel",data:{point:o,identifier:t.pointerId,pointerType:t.pointerType,originalEvent:t,button:t.button,shiftHeld:a,metaHeld:l,ctrlHeld:c,altHeld:d}})}),s(this.canvas,["touchstart","touchmove","touchend","touchcancel"],i=>{let t=i;t.preventDefault();let r=o=>Array.from(o).map(a=>{let l=this.canvas.getBoundingClientRect();(l.top!=0||l.left!=0)&&console.warn("Canvas rect is not at 0,0, this may cause issues with touch coordinates.");let c=new v(a.clientX,a.clientY),d=n.screenToWorld(c);return{identifier:a.identifier,point:d,originalTouch:a}});e({type:i.type,data:{touches:r(t.touches),targetTouches:r(t.targetTouches),changedTouches:r(t.changedTouches),originalEvent:t}})}),s(this.canvas,"wheel",i=>{i.preventDefault();let t=i,r=new v(t.offsetX,t.offsetY),o=n.screenToWorld(r),a=new m(t.deltaX,t.deltaY);e({type:"wheel",data:{delta:a,point:o,originalEvent:t}})}),s(window,"resize",()=>{let i=new T(window.innerWidth,window.innerHeight);e({type:"windowresize",data:{size:i}})})}detach(){this.listeners.forEach(({target:e,type:n,handler:s})=>{e.removeEventListener(n,s)}),this.listeners=[]}},S=class{constructor(e){this.id=crypto.randomUUID();this.visible=!0;this.zIndex=-1/0;this.selectable=!1;this.img=e}get width(){return this.img.naturalWidth}get height(){return this.img.naturalHeight}getEventInteractions(e){return[{eventTypePrefix:"drag"}]}getBounds(){return new w(new v(0,0),new T(this.img.width,this.img.height))}getOuterBounds(){return this.getBounds()}render(e,n){e.drawImage(this.img,0,0)}},L=class{constructor(){this.listeners=new Map}on(e,n,s){this.listeners.has(e)||this.listeners.set(e,new Set);let i=s?.once?(t=>{this.off(e,i),n(t)}):n;this.listeners.get(e).add(i)}off(e,n){this.listeners.get(e)?.delete(n)}emit(e,n){this.listeners.get(e)?.forEach(s=>s(n))}},u={ObjectPositionChanged:"object:positionchanged",ObjectResized:"object:resized",ObjectMoved:"object:moved",ObjectColorChanged:"object:colorchanged",ObjectZIndexChanged:"object:zindexchanged",ObjectSelectableChanged:"object:selectablechanged",ObjectMovableChanged:"object:movablechanged",ObjectResizableChanged:"object:resizablechanged",ObjectVisibleChanged:"object:visiblechanged",ObjectChanged:"object:changed",ObjectSelected:"object:selected",ObjectDeselected:"object:deselected",ObjectFlagsAdded:"object:flagsadded",ObjectFlagsRemoved:"object:flagsremoved",ObjectAdded:"object:added",ObjectRemoved:"object:removed",ViewportChanged:"viewport:changed",DrawingCompleted:"drawing:completed",EngineStarted:"engine:started",EngineError:"engine:error",EngineBackgroundChanged:"engine:backgroundchanged",EngineRenderStarted:"engine:renderstarted",EngineRenderCompleted:"engine:rendercompleted",EngineModeChanged:"engine:modechanged"},H=class{constructor(e,n){this.engine=n,this.config=e}processToolEvent(e,n){this.config?.handleEvent&&this.config.handleEvent(e,this.engine)}},te=class{constructor(e,n={}){this.defaultBackgroundImage=`<svg xmlns="http://www.w3.org/2000/svg" width="816" height="1056">
1
+ import{Rectangle as w,Size as z,Point as p,Vector as E,Polygon as ie}from"dytools-geometry";var B=class B{constructor(e,t,s,i,n,o,a,r,l,c){this._name=null;this._showName=!1;this._nameAnchor="TopLeft";this._visible=!0;if(this._id=e,t instanceof w){let d=t,g=s??"#000000",h=i??!1,y=n??!1,I=o??!1,_=a??0;this._rect=d,this._color=g,this._selectable=h,this._movable=y,this._resizable=I,this._zIndex=_}else{let d=t,g=s,h=i,y=n,I=o??"#000000",_=a??!1,O=r??!1,k=l??!1,R=c??0;this._rect=new w(new p(d,g),new z(h,y)),this._color=I,this._selectable=_,this._movable=O,this._resizable=k,this._zIndex=R}}get id(){return this._id}set id(e){this._id=e}get rect(){return this._rect.normalized()}get name(){return this._name}set name(e){this._name=e}get showName(){return this._showName}set showName(e){this._showName=e}get nameAnchor(){return this._nameAnchor}set nameAnchor(e){this._nameAnchor=e}get zIndex(){return this._zIndex}set zIndex(e){this._zIndex=e}get visible(){return this._visible??!1}set visible(e){this._visible=e}get color(){return this._color}set color(e){this._color=e}get selectable(){return this._selectable}set selectable(e){this._selectable=e}get movable(){return this._movable}set movable(e){this._movable=e}get resizable(){return this._resizable}set resizable(e){this._resizable=e}getBounds(e){return this._rect}getOuterBounds(e){let t=this._rect,s=this.getResizeHandles(e);return s.length===0||s.forEach(i=>{t=t.expand(i.rect)}),t}getEventInteractions(e,t){let s=[];if(this._resizable&&this.getResizeHandles(t).forEach(n=>{(e===null||n.rect.contains(e))&&s.push({eventTypePrefix:"resize",handleIndex:n.handleIndex})}),this._movable){let i=this.getBounds(t);(e===null||i.contains(e))&&s.push({eventTypePrefix:"move"})}if(this._selectable){let i=this.getBounds(t);(e===null||i.contains(e))&&s.push({eventTypePrefix:"select"})}return s}getResizeHandles(e){let t=this._rect.origin.x,s=this._rect.origin.y,i=this._rect.size.width,n=this._rect.size.height,o=B.HANDLE_SIZE*e.currentScaleMultiplier,a=o*10,r=o*6,l=1;i>=a&&n>=a?l=-1:i>=r&&n>=r&&(l=0);let c=i<r,d=n<r;return[{rect:new w(new p(t-l*o-o,s-l*o-o),new z(o*2,o*2)),handleIndex:0},c?null:{rect:new w(new p(t+i/2-o,s-l*o-o),new z(o*2,o*2)),handleIndex:1},{rect:new w(new p(t+i+l*o-o,s-l*o-o),new z(o*2,o*2)),handleIndex:2},d?null:{rect:new w(new p(t+i+l*o-o,s+n/2-o),new z(o*2,o*2)),handleIndex:3},{rect:new w(new p(t+i+l*o-o,s+n+l*o-o),new z(o*2,o*2)),handleIndex:4},c?null:{rect:new w(new p(t+i/2-o,s+n+l*o-o),new z(o*2,o*2)),handleIndex:5},{rect:new w(new p(t-l*o-o,s+n+l*o-o),new z(o*2,o*2)),handleIndex:6},d?null:{rect:new w(new p(t-l*o-o,s+n/2-o),new z(o*2,o*2)),handleIndex:7}].filter(h=>h!==null)}handleEvent(e,t){let s=e.data||{};if(e.type==="setcolor"&&this._color!==s.color){let n=this._color;this._color=s.color,t(u.ObjectColorChanged,{object:this,oldColor:n,newColor:this._color});return}if(e.type==="setzindex"&&this._zIndex!==s.zIndex){let n=this._zIndex;this._zIndex=s.zIndex,t(u.ObjectZIndexChanged,{object:this,oldZIndex:n,newZIndex:this._zIndex});return}if(e.type==="setselectable"&&this._selectable!==s.isSelectable){let n=this._selectable;this._selectable=s.isSelectable,t(u.ObjectSelectableChanged,{object:this,oldSelectable:n,newSelectable:this._selectable});return}if(e.type==="setmovable"&&this._movable!==s.isMovable){let n=this._movable;this._movable=s.isMovable,t(u.ObjectMovableChanged,{object:this,oldMovable:n,newMovable:this._movable});return}if(e.type==="setresizable"&&this._resizable!==s.isResizable){let n=this._resizable;this._resizable=s.isResizable,t(u.ObjectResizableChanged,{object:this,oldResizable:n,newResizable:this._resizable});return}if(e.type==="setvisible"&&this._visible!==s.isVisible){let n=this._visible??!0;this._visible=s.isVisible,t(u.ObjectVisibleChanged,{object:this,oldVisible:n,newVisible:this._visible??!0});return}let i=s.delta;if(e.type==="resize"){let n=this._rect.clone(),o=s.handleIndex;if(i==null||o==null){console.warn("Resize event missing required data:",e);return}let a=-1/0,r=i.x,l=i.y;if(r===0&&l===0)return;switch(o){case 0:r=Math.min(r,this._rect.size.width-a),l=Math.min(l,this._rect.size.height-a),this._rect.origin.x+=r,this._rect.origin.y+=l,this._rect.size.width-=r,this._rect.size.height-=l;break;case 1:l=Math.min(l,this._rect.size.height-a),this._rect.origin.y+=l,this._rect.size.height-=l;break;case 2:r=Math.max(r,a-this._rect.size.width),l=Math.min(l,this._rect.size.height-a),this._rect.origin.y+=l,this._rect.size.width+=r,this._rect.size.height-=l;break;case 3:r=Math.max(r,a-this._rect.size.width),this._rect.size.width+=r;break;case 4:r=Math.max(r,a-this._rect.size.width),l=Math.max(l,a-this._rect.size.height),this._rect.size.width+=r,this._rect.size.height+=l;break;case 5:l=Math.max(l,a-this._rect.size.height),this._rect.size.height+=l;break;case 6:r=Math.min(r,this._rect.size.width-a),l=Math.max(l,a-this._rect.size.height),this._rect.origin.x+=r,this._rect.size.width-=r,this._rect.size.height+=l;break;case 7:r=Math.min(r,this._rect.size.width-a),this._rect.origin.x+=r,this._rect.size.width-=r;break}t(u.ObjectResized,{object:this,oldSize:n.size,newSize:this._rect.clone().size}),t(u.ObjectPositionChanged,{object:this,oldPosition:n,newPosition:this._rect.clone()})}else e.type==="resizeend"&&this._rect.normalize();if(e.type.startsWith("move")){if(i==null){console.warn("Move event missing required data:",e);return}if(i.x===0&&i.y===0)return;let n=this._rect.clone();this._rect=this._rect.move(i),t(u.ObjectMoved,{object:this,oldPoint:n.origin,newPoint:this._rect.clone().origin}),t(u.ObjectPositionChanged,{object:this,oldPosition:n,newPosition:this._rect})}}render(e,t,s){let i=t.has("selected"),n=t.has("hovered"),o=t.has("hoversibling"),r=e.getTransform().a,l=b=>b/r,c=l(4),d=l(2),g=l(3),h=l(4),y=this._rect,I=y.origin.x,_=y.origin.y,O=y.size.width,k=y.size.height,R=(b,f,v,m,S)=>{let j=Math.max(0,Math.min(S,Math.min(v,m)/2)),P=new Path2D;return P.moveTo(b+j,f),P.lineTo(b+v-j,f),P.arcTo(b+v,f,b+v,f+j,j),P.lineTo(b+v,f+m-j),P.arcTo(b+v,f+m,b+v-j,f+m,j),P.lineTo(b+j,f+m),P.arcTo(b,f+m,b,f+m-j,j),P.lineTo(b,f+j),P.arcTo(b,f,b+j,f,j),P.closePath(),P},x=R(I,_,O,k,c);e.save(),e.strokeStyle=this._color;let C=e.strokeStyle;if(e.fillStyle=this.withAlpha(C,.06),e.fill(x),e.lineWidth=d,e.stroke(x),e.restore(),i){let b=I-h,f=_-h,v=O+h*2,m=k+h*2,S=R(b,f,v,m,c+h);e.save(),e.setLineDash([l(8),l(6)]),e.lineDashOffset=0,e.strokeStyle="rgba(0,0,0,0.4)",e.lineWidth=g,e.stroke(S),e.restore()}if(this._showName&&this._name){e.save(),e.font="12px sans-serif",e.fillStyle=this._color,e.textBaseline="top";let b=2,{x:f,y:v}=this._rect.origin,{width:m,height:S}=this._rect.size,j=f+b,P=v+b;switch(this._nameAnchor){case"TopLeft":j=f+b,P=v+b;break;case"TopRight":j=f+m-e.measureText(this._name).width-b,P=v+b;break;case"BottomLeft":j=f+b,P=v+S-14-b;break;case"BottomRight":j=f+m-e.measureText(this._name).width-b,P=v+S-14-b;break;case"Center":j=f+(m-e.measureText(this._name).width)/2,P=v+(S-12)/2;break}e.fillText(this._name,j,P),e.restore()}if(this._resizable&&n){e.save(),e.lineWidth=l(o?.5:1),e.strokeStyle=C,e.fillStyle=o?"transparent":"white",e.globalAlpha=o?.75:1;for(let b of this.getResizeHandles(s)||[]){if(!b)continue;let{x:f,y:v}=b.rect.origin,{width:m,height:S}=b.rect.size,j=l(4),P=R(f,v,m,S,j);e.fill(P),e.stroke(P)}e.restore()}}withAlpha(e,t){let s=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\s*\)/i);if(s){let i=parseInt(s[1]??"0",10),n=parseInt(s[2]??"0",10),o=parseInt(s[3]??"0",10);return`rgba(${i},${n},${o},${t})`}if(e.startsWith("#")){let i=e.slice(1);if(i.length===3&&(i=i.split("").map(n=>n+n).join("")),i.length===6||i.length===8){let n=parseInt(i.slice(0,2),16),o=parseInt(i.slice(2,4),16),a=parseInt(i.slice(4,6),16);return`rgba(${n},${o},${a},${t})`}}return e}};B.HANDLE_SIZE=6;var J=B,D=class D{constructor(e,t,s,i,n,o,a,r,l){this._name=null;this._showName=!1;this._visible=!0;if(this._id=e,t instanceof p){let c=t,d=s,g=i??"#000000",h=n??!1,y=o??!1,I=a??!1,_=r??0;this._center=c,this._radius=d,this._color=g,this._selectable=h,this._movable=y,this._resizable=I,this._zIndex=_}else{let c=t,d=s,g=i,h=n??"#000000",y=o??!1,I=a??!1,_=r??!1,O=l??0;this._center=new p(c,d),this._radius=g,this._color=h,this._selectable=y,this._movable=I,this._resizable=_,this._zIndex=O}}get id(){return this._id}set id(e){this._id=e}get center(){return this._center}get name(){return this._name}set name(e){this._name=e}get showName(){return this._showName}set showName(e){this._showName=e}get zIndex(){return this._zIndex}set zIndex(e){this._zIndex=e}get visible(){return this._visible??!1}set visible(e){this._visible=e}get color(){return this._color}set color(e){this._color=e}get selectable(){return this._selectable}set selectable(e){this._selectable=e}get movable(){return this._movable}set movable(e){this._movable=e}get resizable(){return this._resizable}set resizable(e){this._resizable=e}getBounds(){return new w(this.center.x-this._radius,this.center.y-this._radius,2*this._radius,2*this._radius)}getOuterBounds(){let e=this.getBounds(),t=this.getResizeHandles();return t.length===0||t.forEach(s=>{e=e.expand(s.rect)}),e}getEventInteractions(e){let t=[];if(this._resizable&&this.getResizeHandles().forEach(i=>{(e===null||i.rect.contains(e))&&t.push({eventTypePrefix:"resize",handleIndex:i.handleIndex})}),this._movable){let s=this.getBounds();(e===null||s.contains(e))&&t.push({eventTypePrefix:"move"})}if(this._selectable){let s=this.getBounds();(e===null||s.contains(e))&&t.push({eventTypePrefix:"select"})}return t}getResizeHandles(){let e=this.getBounds().origin.x,t=this.getBounds().origin.y,s=this.getBounds().size.width,i=this.getBounds().size.height,n=D.HANDLE_SIZE,o=n*10,a=n*6,r=1;s>=o&&i>=o?r=-1:s>=a&&i>=a&&(r=0);let l=s<a,c=i<a;return[{rect:new w(new p(e-r*n-n,t-r*n-n),new z(n*2,n*2)),handleIndex:0},l?null:{rect:new w(new p(e+s/2-n,t-r*n-n),new z(n*2,n*2)),handleIndex:1},{rect:new w(new p(e+s+r*n-n,t-r*n-n),new z(n*2,n*2)),handleIndex:2},c?null:{rect:new w(new p(e+s+r*n-n,t+i/2-n),new z(n*2,n*2)),handleIndex:3},{rect:new w(new p(e+s+r*n-n,t+i+r*n-n),new z(n*2,n*2)),handleIndex:4},l?null:{rect:new w(new p(e+s/2-n,t+i+r*n-n),new z(n*2,n*2)),handleIndex:5},{rect:new w(new p(e-r*n-n,t+i+r*n-n),new z(n*2,n*2)),handleIndex:6},c?null:{rect:new w(new p(e-r*n-n,t+i/2-n),new z(n*2,n*2)),handleIndex:7}].filter(g=>g!==null)}handleEvent(e,t){let s=e.data||{};if(e.type==="setcolor"){let i=this._color;this._color=s.color,t(u.ObjectColorChanged,{object:this,oldColor:i,newColor:this._color});return}if(e.type==="setzindex"){let i=this._zIndex;this._zIndex=s.zIndex,t(u.ObjectZIndexChanged,{object:this,oldZIndex:i,newZIndex:this._zIndex});return}if(e.type==="setselectable"){let i=this._selectable;this._selectable=s.isSelectable,t(u.ObjectSelectableChanged,{object:this,oldSelectable:i,newSelectable:this._selectable});return}if(e.type==="setmovable"){let i=this._movable;this._movable=s.isMovable,t(u.ObjectMovableChanged,{object:this,oldMovable:i,newMovable:this._movable});return}if(e.type==="setresizable"){let i=this._resizable;this._resizable=s.isResizable,t(u.ObjectResizableChanged,{object:this,oldResizable:i,newResizable:this._resizable});return}if(e.type==="setvisible"){let i=this._visible??!0;this._visible=s.isVisible,t(u.ObjectVisibleChanged,{object:this,oldVisible:i,newVisible:this._visible??!0});return}}render(e,t){let s=t.has("selected"),i=t.has("hovered"),n=t.has("hoversibling"),a=e.getTransform().a,r=k=>k/a,l=this._center.x,c=this._center.y,d=this._radius,g=r(4),h=r(2),y=r(3),I=r(4),_=this.color,O=this.withAlpha(_,.06);if(e.save(),e.beginPath(),e.arc(l,c,d,0,Math.PI*2),e.fillStyle=O,e.strokeStyle=_,e.lineWidth=h,e.fill(),e.stroke(),e.restore(),s&&(e.save(),e.beginPath(),e.arc(l,c,d+I,0,Math.PI*2),e.setLineDash([r(8),r(6)]),e.strokeStyle="rgba(0,0,0,0.4)",e.lineWidth=y,e.stroke(),e.restore()),this._resizable&&i){let k=this.getResizeHandles?.()??[];e.save(),e.lineWidth=r(n?.5:1),e.strokeStyle=_,e.fillStyle=n?"transparent":"white",e.globalAlpha=n?.75:1;for(let R of k){let x=R.rect.origin.x,C=R.rect.origin.y,b=R.rect.size.width,f=R.rect.size.height,v=r(4),m=new Path2D;m.moveTo(x+v,C),m.lineTo(x+b-v,C),m.arcTo(x+b,C,x+b,C+v,v),m.lineTo(x+b,C+f-v),m.arcTo(x+b,C+f,x+b-v,C+f,v),m.lineTo(x+v,C+f),m.arcTo(x,C+f,x,C+f-v,v),m.lineTo(x,C+v),m.arcTo(x,C,x+v,C,v),m.closePath(),e.fill(m),e.stroke(m)}e.restore()}}withAlpha(e,t){let s=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\s*\)/i);if(s){let i=parseInt(s[1]??"0",10),n=parseInt(s[2]??"0",10),o=parseInt(s[3]??"0",10);return`rgba(${i},${n},${o},${t})`}if(e.startsWith("#")){let i=e.slice(1);if(i.length===3&&(i=i.split("").map(n=>n+n).join("")),i.length===6||i.length===8){let n=parseInt(i.slice(0,2),16),o=parseInt(i.slice(2,4),16),a=parseInt(i.slice(4,6),16);return`rgba(${n},${o},${a},${t})`}}return e}};D.HANDLE_SIZE=6;var ee=D,te=class{constructor(e,t,s,i,n,o){this.visible=!0;this.id=e,this._points=t?t.slice():[],this.color=s??"#000000",this.selectable=i??!1,this.movable=n??!1,this.zIndex=o??0}get points(){return this._points}getBounds(){if(!this._points||this._points.length===0)return new w(new p(0,0),new z(0,0));let e=this._points[0].x,t=this._points[0].x,s=this._points[0].y,i=this._points[0].y;for(let n of this._points)n.x<e&&(e=n.x),n.x>t&&(t=n.x),n.y<s&&(s=n.y),n.y>i&&(i=n.y);return new w(new p(e,s),new z(t-e,i-s))}getOuterBounds(){return this.getBounds()}getEventInteractions(e){let t=[],s=this.getBounds();return this.movable&&(e===null||s.contains(e))&&t.push({eventTypePrefix:"move"}),this.selectable&&(e===null||s.contains(e))&&t.push({eventTypePrefix:"select"}),t}handleEvent(e,t){let s=e.data||{};if(e.type==="setcolor"){let i=this.color;this.color=s.color,t(u.ObjectColorChanged,{object:this,oldColor:i,newColor:this.color});return}if(e.type==="setzindex"){let i=this.zIndex;this.zIndex=s.zIndex,t(u.ObjectZIndexChanged,{object:this,oldZIndex:i,newZIndex:this.zIndex});return}if(e.type==="setselectable"){let i=this.selectable;this.selectable=s.isSelectable,t(u.ObjectSelectableChanged,{object:this,oldSelectable:i,newSelectable:this.selectable});return}if(e.type==="setmovable"){let i=this.movable;this.movable=s.isMovable,t(u.ObjectMovableChanged,{object:this,oldMovable:i,newMovable:this.movable});return}if(e.type==="setvisible"){let i=this.visible;this.visible=s.isVisible,t(u.ObjectVisibleChanged,{object:this,oldVisible:i,newVisible:this.visible});return}if(e.type.startsWith("move")){let i=s.delta;if(i==null){console.warn("Move event missing required data:",e);return}let n=this.getBounds();for(let a of this._points)a.x+=i.x,a.y+=i.y;let o=this.getBounds();t(u.ObjectMoved,{object:this,oldPoint:n.origin,newPoint:o.origin}),t(u.ObjectPositionChanged,{object:this,oldPosition:n,newPosition:o});return}}render(e,t){let s=t.has("selected"),i=t.has("hovered"),o=e.getTransform().a,a=g=>g/o,l=(()=>{if(!this._points||this._points.length===0)return null;let g=new Path2D;g.moveTo(this._points[0].x,this._points[0].y);for(let h=1;h<this._points.length;++h)g.lineTo(this._points[h].x,this._points[h].y);return g.closePath(),g})();if(!l)return;let c=this.getBounds();e.save(),e.strokeStyle=this.color;let d=e.strokeStyle;if(e.fillStyle=this.withAlpha(d,.06),e.lineWidth=a(2),e.fill(l),e.stroke(l),e.restore(),s){let g=a(3),h=a(4),y=c.origin.x-h,I=c.origin.y-h,_=c.size.width+h*2,O=c.size.height+h*2;e.save(),e.setLineDash([a(8),a(6)]),e.lineDashOffset=0,e.strokeStyle="rgba(0,0,0,0.4)",e.lineWidth=g,e.strokeRect(y,I,_,O),e.restore()}}withAlpha(e,t){let s=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\s*\)/i);if(s){let i=parseInt(s[1]??"0",10),n=parseInt(s[2]??"0",10),o=parseInt(s[3]??"0",10);return`rgba(${i},${n},${o},${t})`}if(e.startsWith("#")){let i=e.slice(1);if(i.length===3&&(i=i.split("").map(n=>n+n).join("")),i.length===6||i.length===8){let n=parseInt(i.slice(0,2),16),o=parseInt(i.slice(2,4),16),a=parseInt(i.slice(4,6),16);return`rgba(${n},${o},${a},${t})`}}return e}},A=class{constructor(e=1e3){this.intervalId=null;this.interval=e,this.intervalId=null}attach(e,t){this.start(e)}detach(){this.stop()}start(e){this.intervalId=window.setInterval(()=>{e({type:"tick",data:{}})},this.interval)}stop(){this.intervalId!==null&&(clearInterval(this.intervalId),this.intervalId=null)}},L=class{constructor(e){this.listeners=[];this.canvas=e}attach(e,t){let s=(i,n,o)=>{typeof n=="string"&&(n=[n]);for(let a of n)i.addEventListener(a,o),this.listeners.push({target:i,type:a,handler:o})};s(this.canvas,"pointerdown",i=>{let n=i,o=new p(n.offsetX,n.offsetY),a=t.screenToWorld(o),r=!!n.shiftKey,l=!!n.metaKey,c=!!n.ctrlKey,d=!!n.altKey;e({type:"pointerdown",data:{point:a,identifier:n.pointerId,pointerType:n.pointerType,originalEvent:n,button:n.button,shiftHeld:r,metaHeld:l,ctrlHeld:c,altHeld:d}})}),s(this.canvas,"pointermove",i=>{let n=i;n.preventDefault();let o=new p(n.offsetX,n.offsetY),a=t.screenToWorld(o),r=!!n.shiftKey,l=!!n.metaKey,c=!!n.ctrlKey,d=!!n.altKey;e({type:"pointermove",data:{point:a,identifier:n.pointerId,pointerType:n.pointerType,originalEvent:n,button:n.button,shiftHeld:r,metaHeld:l,ctrlHeld:c,altHeld:d}})}),s(this.canvas,"pointerup",i=>{let n=i;n.preventDefault();let o=new p(n.offsetX,n.offsetY),a=t.screenToWorld(o),r=!!n.shiftKey,l=!!n.metaKey,c=!!n.ctrlKey,d=!!n.altKey;e({type:"pointerup",data:{point:a,identifier:n.pointerId,pointerType:n.pointerType,originalEvent:n,button:n.button,shiftHeld:r,metaHeld:l,ctrlHeld:c,altHeld:d}})}),s(this.canvas,"pointercancel",i=>{let n=i;if(n.pointerType==="touch")return;n.preventDefault();let o=new p(n.offsetX,n.offsetY),a=t.screenToWorld(o),r=!!n.shiftKey,l=!!n.metaKey,c=!!n.ctrlKey,d=!!n.altKey;e({type:"pointercancel",data:{point:a,identifier:n.pointerId,pointerType:n.pointerType,originalEvent:n,button:n.button,shiftHeld:r,metaHeld:l,ctrlHeld:c,altHeld:d}})}),s(this.canvas,["touchstart","touchmove","touchend","touchcancel"],i=>{let n=i;n.preventDefault();let o=a=>Array.from(a).map(r=>{let l=this.canvas.getBoundingClientRect();(l.top!=0||l.left!=0)&&console.warn("Canvas rect is not at 0,0, this may cause issues with touch coordinates.");let c=new p(r.clientX,r.clientY),d=t.screenToWorld(c);return{identifier:r.identifier,point:d,originalTouch:r}});e({type:i.type,data:{touches:o(n.touches),targetTouches:o(n.targetTouches),changedTouches:o(n.changedTouches),originalEvent:n}})}),s(this.canvas,"wheel",i=>{i.preventDefault();let n=i,o=new p(n.offsetX,n.offsetY),a=t.screenToWorld(o),r=new E(n.deltaX,n.deltaY);e({type:"wheel",data:{delta:r,point:a,originalEvent:n}})}),s(window,"resize",()=>{let i=new z(window.innerWidth,window.innerHeight);e({type:"windowresize",data:{size:i}})})}detach(){this.listeners.forEach(({target:e,type:t,handler:s})=>{e.removeEventListener(t,s)}),this.listeners=[]}},M=class{constructor(e){this.id=crypto.randomUUID();this.visible=!0;this.zIndex=-1/0;this.selectable=!1;this.img=e}get width(){return this.img.naturalWidth}get height(){return this.img.naturalHeight}getEventInteractions(e){return[{eventTypePrefix:"drag"}]}getBounds(){return new w(new p(0,0),new z(this.img.width,this.img.height))}getOuterBounds(){return this.getBounds()}render(e,t){e.drawImage(this.img,0,0)}},H=class{constructor(){this.listeners=new Map}on(e,t,s){this.listeners.has(e)||this.listeners.set(e,new Set);let i=s?.once?(n=>{this.off(e,i),t(n)}):t;this.listeners.get(e).add(i)}off(e,t){this.listeners.get(e)?.delete(t)}emit(e,t){this.listeners.get(e)?.forEach(s=>s(t))}},u={ObjectPositionChanged:"object:positionchanged",ObjectResized:"object:resized",ObjectMoved:"object:moved",ObjectColorChanged:"object:colorchanged",ObjectZIndexChanged:"object:zindexchanged",ObjectSelectableChanged:"object:selectablechanged",ObjectMovableChanged:"object:movablechanged",ObjectResizableChanged:"object:resizablechanged",ObjectVisibleChanged:"object:visiblechanged",ObjectChanged:"object:changed",ObjectSelected:"object:selected",ObjectDeselected:"object:deselected",ObjectFlagsAdded:"object:flagsadded",ObjectFlagsRemoved:"object:flagsremoved",ObjectAdded:"object:added",ObjectRemoved:"object:removed",ViewportChanged:"viewport:changed",DrawingCompleted:"drawing:completed",EngineStarted:"engine:started",EngineError:"engine:error",EngineBackgroundChanged:"engine:backgroundchanged",EngineRenderStarted:"engine:renderstarted",EngineRenderCompleted:"engine:rendercompleted",EngineModeChanged:"engine:modechanged"},F=class{constructor(e,t){this.engine=t,this.config=e}processToolEvent(e,t){this.config?.handleEvent&&this.config.handleEvent(e,this.engine)}},ne=class{constructor(e,t={}){this.defaultBackgroundImage=`<svg xmlns="http://www.w3.org/2000/svg" width="816" height="1056">
2
2
  <rect width="100%" height="100%" fill="#FFF"/>
3
3
  <text x="50%" y="50%" text-anchor="middle" fill="#888"
4
4
  font-family="monospace" font-size="24">
5
5
  Sample Page
6
6
  </text>
7
- </svg>`;this.document=new Blob([this.defaultBackgroundImage],{type:"image/svg+xml;charset=utf-8"});this.emitter=new L;this.toolLockManager=new F;this.eventSources=[];this.recognizers=[];this.tools=[];this.manualRenderers=[];this.modeRenderers=[];this.eventQueue=[];this.processingQueue=!1;this.renderScheduled=!1;this.flags=new Map;this.objects=[];this.needsRender=!1;this.toolRegistry=new Map;this.modes={};this.currentMode="";this.defaultOptions={initialZoom:1,initialPan:{x:10,y:10},defaultMode:"default",addTimerEventSource:!1,proxyObjectsForEvents:!0};this._pan=new m(0,0);this._zoom=1;this.on=this.emitter.on.bind(this.emitter);this.off=this.emitter.off.bind(this.emitter);this.emitExternal=this.emitter.emit.bind(this.emitter);this.options=this.createOptions(n);let s=document.querySelector(e);if(!s)throw new Error(`Container ${e} not found`);this.container=s,this.canvas=document.createElement("canvas"),this.canvas.width=this.container.clientWidth*10,this.canvas.height=this.container.clientHeight*10,this.container.appendChild(this.canvas),this.ctx=this.canvas.getContext("2d"),this.setupDefaultEventSources(),this.setupDefaultTools(),this.setupDefaultRecognizers(),this.setupDefaultModes(),this.setupRenderNodes(),this._zoom=this.options.initialZoom,this._pan=new m(this.options.initialPan.x,this.options.initialPan.y),this.switchMode(this.options.defaultMode),this.emitExternal(u.EngineStarted,{}),this.emitExternal(u.ViewportChanged,{oldPan:new m(0,0),newPan:this.pan,oldZoom:1,newZoom:this.zoom}),this.setBackgroundImage(this.document).then()}get pan(){return this._pan.clone()}get zoom(){return this._zoom}screenToWorld(e){return new v((e.x-this.pan.x)/this.zoom,(e.y-this.pan.y)/this.zoom)}worldToScreen(e){return new v(e.x*this.zoom+this.pan.x,e.y*this.zoom+this.pan.y)}processToolEvent(e,n,s,i,t){e.type.startsWith("windowresize")||(this.canvas.width=this.container.clientWidth,this.canvas.height=this.container.clientHeight)}createOptions(e){return{...this.defaultOptions,...e}}setupDefaultEventSources(){this.options.addTimerEventSource&&this.register(new D),this.register(new A(this.canvas))}setupDefaultRecognizers(){this.register(new Y),this.register(new U)}setupDefaultTools(){this.registerTool("hover",()=>new $,!0),this.registerTool("select",()=>new N,!0),this.registerTool("drawing",()=>new K,!0),this.registerTool("move",()=>new Z,!0),this.registerTool("resize",()=>new q,!0),this.registerTool("lasso",()=>new Q,!0),this.registerTool("pan",()=>new W,!0),this.registerTool("zoom",()=>new V,!0),this.registerTool("api",()=>new X,!0)}setupDefaultModes(){this.defineMode("default",{tools:["hover","select","resize","move","pan","zoom","api"]}),this.defineMode("move",{tools:["hover","select","resize","move","pan","zoom","api"]}),this.defineMode("create",{tools:["drawing","zoom","api"],handleEvent(e,n){e.type===u.DrawingCompleted&&n.switchMode("default")}}),this.defineMode("lasso",{tools:["hover","select","lasso","zoom","api"],handleEvent(e,n){e.type==="lassoselected"&&n.switchMode("default")}})}setupRenderNodes(){}wrapInteractiveObject(e){let n=this;return new Proxy(e,{set(s,i,t){let r=s[i],o=Reflect.set(s,i,t);return typeof i=="string"&&i.startsWith("_")||r!==t&&n.emitExternal(u.ObjectChanged,{object:s,property:i.toString(),oldValue:r,newValue:t}),o}})}registerTool(e,n,s=!0){if(this.toolRegistry.has(e))throw new Error(`Tool '${e}' already registered.`);this.toolRegistry.set(e,{factory:n,singleton:s})}resolveTool(e){let n=this.toolRegistry.get(e);if(!n)throw new Error(`Unknown tool '${e}'`);return n.singleton?("instance"in n||(n.instance=n.factory()),n.instance):n.factory()}defineMode(e,n){if(this.modes[e])throw new Error(`Mode '${e}' already defined.`);this.modes[e]=n}get mode(){return this.currentMode}switchMode(e){if(!this.modes[e])throw new Error(`Unknown mode '${e}'`);if(this.toolLockManager.isLocked){console.warn("Cannot switch modes while tools are locked. Please release all locks first.");return}if(this.currentMode===e){console.warn(`Already in mode '${e}', no switch needed.`);return}let n=this.currentMode;this.currentMode=e;let s=this.modes[e];if(s.tools==null||s.tools.length==0)return;let i=s.tools;this.tools=[...new Set(i.map(t=>this.resolveTool(t)))],this.modeRenderers=s.renderers||[],s.handleEvent&&this.tools.push(new H(s,this)),this.emitExternal(u.EngineModeChanged,{newMode:this.currentMode,oldMode:n})}get renderers(){let e=this.tools.filter(n=>typeof n=="object"&&n!==null&&("renderBeforeAll"in n||"renderBeforeObject"in n||"renderAfterObject"in n||"renderAfterAll"in n)&&(typeof n.renderBeforeAll=="function"||typeof n.renderBeforeObject=="function"||typeof n.renderAfterObject=="function"||typeof n.renderAfterAll=="function")).map(n=>n);return[...new Set([...this.manualRenderers,...this.modeRenderers,...e])]}get viewableWidth(){return this.canvas.width}get viewableHeight(){return this.canvas.height}get width(){let e=this.getObjectsWithFlag("canvas-background").filter(s=>typeof s=="object"&&s instanceof S),n;return e.length==0?this.canvas.width:(e.length>=1&&(n=e[0]),n.width)}get height(){let e=this.getObjectsWithFlag("canvas-background").filter(s=>typeof s=="object"&&s instanceof S),n;return e.length==0?this.canvas.height:(e.length>=1&&(n=e[0]),n.height)}get documentBlob(){return this.document}async setBackgroundImage(e){let n=this.width,s=this.height,i;e instanceof File||e instanceof Blob?i=e:i=await this.loadImageFromUrl(e),this.document=i;let t=URL.createObjectURL(i),r=await this.loadImage(t),o=this.getObjectsWithFlag("canvas-background");if(o.length>0){let a=o.find(l=>l instanceof S);a&&(a.img=r)}else{let a=new S(r);this.objects.push(a),this.setFlag(a.id,"canvas-background")}this.emitExternal(u.EngineBackgroundChanged,{newImage:r,newWidth:r.width,newHeight:r.height,oldWidth:n,oldHeight:s}),this.requestRender()}async loadImageFromUrl(e){let n=await fetch(e);if(!n.ok)throw new Error(`Failed to fetch image: ${n.status} ${n.statusText}`);return await n.blob()}loadImage(e){return new Promise((n,s)=>{if(e instanceof HTMLImageElement){e.complete&&e.naturalWidth!==0?n(e):(e.onload=()=>n(e),e.onerror=s);return}let i=new Image;i.onload=()=>n(i),i.onerror=s,i.src=e})}getObject(e){return this.objects.find(s=>s.id===e)}addObject(e){if(this.objects.find(s=>s.id===e.id))throw new Error(`Object with id '${e.id}' already exists.`);this.objects.push(e),this.enqueue({type:"redraw",data:{}},!0),this.emitExternal(u.ObjectAdded,{object:this.options.proxyObjectsForEvents?this.wrapInteractiveObject(e):e})}removeObject(e){let n=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!n)throw new Error(`Object not found: ${e}`);let s=this.objects.indexOf(n);if(s!==-1){this.objects.splice(s,1);let i=typeof e=="string"?e:e.id;this.flags.delete(i),this.emitExternal(u.ObjectRemoved,{object:n})}else console.warn("Attempted to remove an object that does not exist in the engine:",n);this.redraw()}moveObjectToPoint(e,n,s){let i=typeof e=="string"?this.objects.find(o=>o.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let t=typeof n=="number"?n:n.x,r=typeof n=="number"?s??0:n.y;this.enqueue({type:"api:moveto",data:{x:t,y:r},targets:[i]})}moveObjectByVector(e,n,s){let i=typeof e=="string"?this.objects.find(o=>o.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let t=typeof n=="number"?n:n.x,r=typeof n=="number"?s??0:n.y;this.enqueue({type:"api:moveby",data:{dx:t,dy:r},targets:[i]})}resizeObjectToSize(e,n,s){let i=typeof e=="string"?this.objects.find(o=>o.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let t=typeof n=="number"?n:n.width,r=typeof n=="number"?s??0:n.height;this.enqueue({type:"api:resizeto",data:{width:t,height:r},targets:[i]})}resizeObjectByVector(e,n,s){let i=typeof e=="string"?this.objects.find(o=>o.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let t=typeof n=="number"?n:n.x,r=typeof n=="number"?s??0:n.y;this.enqueue({type:"api:resizeby",data:{dw:t,dh:r},targets:[i]})}setObjectColor(e,n){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setcolor",data:{color:n},targets:[s]})}setObjectZIndex(e,n){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setzindex",data:{zIndex:n},targets:[s]})}updateObjectSelectability(e,n){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setselectable",data:{isSelectable:n},targets:[s]})}updateObjectMovability(e,n){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setmovable",data:{isMovable:n},targets:[s]})}updateObjectResizeability(e,n){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setresizable",data:{isResizable:n},targets:[s]})}updateObjectVisibility(e,n){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);s.visible!==n&&this.enqueue({type:"api:setvisible",data:{visible:n},targets:[s]})}setFlag(e,n){let s=typeof e=="string"?this.objects.find(r=>r.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);let i=typeof e=="string"?e:e.id;if(this.flags.has(i)||this.flags.set(i,new Set),n=="selected"&&!s.selectable)return console.warn(`Cannot set flag '${n}' on non-selectable object`,s);let t=this.flags.get(i);t.has(n)||(t.add(n),this.emitExternal(u.ObjectFlagsAdded,{object:s,addedFlags:[n],currentFlags:[...this.flags.get(i)]}),n==="selected"&&this.emitExternal(u.ObjectSelected,{object:s}),this.ensureEventLoop())}clearFlag(e,n){let s=typeof e=="string"?this.objects.find(t=>t.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);let i=typeof e=="string"?e:e.id;this.flags.get(i)?.delete(n),this.emitExternal(u.ObjectFlagsRemoved,{object:s,removedFlags:[n],currentFlags:[...this.flags.get(i)||[]]}),n==="selected"&&this.emitExternal(u.ObjectDeselected,{object:s}),this.ensureEventLoop()}hasFlag(e,n){let s=typeof e=="string"?e:e.id;return this.flags.get(s)?.has(n)??!1}clearAllFlags(e){for(let[n,s]of this.flags.entries()){let i=this.objects.find(t=>t.id===n)??null;if(!i)throw new Error(`Object not found: ${n}`);s.delete(e),this.emitExternal(u.ObjectFlagsRemoved,{object:i,removedFlags:[e],currentFlags:[...this.flags.get(n)||[]]}),e==="selected"&&this.emitExternal(u.ObjectDeselected,{object:i})}this.ensureEventLoop()}getObjectsWithFlag(e){return[...this.flags.entries()].filter(([n,s])=>s.has(e)).filter(([n,s])=>{let i=this.objects.find(t=>t.id===n)??null;if(!i)throw new Error(`Object not found: ${n}`);return e==="selected"?i.selectable:!0}).map(([n])=>this.objects.find(s=>s.id===n))}setZoom(e,n){if(e<=0){console.warn("Zoom must be greater than 0, ignoring.");return}let s=this.zoom,i=new m(this.pan.x,this.pan.y);if(this._zoom=e,n){let t=n.x-(n.x-this.pan.x)*(e/s),r=n.y-(n.y-this.pan.y)*(e/s);this._pan=new m(t,r)}this.emitExternal(u.ViewportChanged,{oldPan:i,newPan:this.pan,oldZoom:s,newZoom:this.zoom}),this.ensureEventLoop()}setPan(e,n){let s=this.pan.clone();typeof e=="number"?this._pan=new m(e,n??0):this._pan=e.clone(),this.emitExternal(u.ViewportChanged,{oldPan:s,newPan:this.pan,oldZoom:this.zoom,newZoom:this.zoom}),this.ensureEventLoop()}setSelectedObjects(e){let n=e.map(r=>typeof r=="string"?this.objects.find(o=>o.id===r):r),s=this.getSelectedObjects(),i=s.filter(r=>!n.includes(r)),t=n.filter(r=>!s.includes(r));i.forEach(r=>this.clearFlag(r,"selected")),t.forEach(r=>this.setFlag(r,"selected")),this.ensureEventLoop()}getSelectedObjects(){return this.getObjectsWithFlag("selected").filter(e=>e.selectable)}getAllObjects(){let e=this.getObjectsWithFlag("canvas-background").filter(n=>typeof n=="object"&&n instanceof S);return[...this.objects].filter(n=>e.includes(n)==!1)}getTopMostInteractionPerEventType(e){let n=new Map,s=[...this.objects].sort((i,t)=>(i.zIndex??0)-(t.zIndex??0));for(let i=s.length-1;i>=0;i--){let t=s[i];if(!t||!t.visible)continue;t.getEventInteractions(e).forEach(o=>{let a=o.eventTypePrefix;if(!n.has(a)){let l={object:t,interaction:o};n.set(a,l)}})}return n}enqueue(e,n=!1){if(n&&this.eventQueue.find(i=>i.type===e.type)){this.ensureEventLoop();return}this.eventQueue.push(e),this.ensureEventLoop()}ensureEventLoop(){this.processingQueue||(this.processingQueue=!0,setTimeout(()=>this.processQueue(),0))}processQueue(){for(;this.eventQueue.length;){let e=this.eventQueue.shift();if(!e.stopPropagation&&(this.recognizers.forEach(n=>{e.stopPropagation||n.process(e,s=>this.eventQueue.push(s))}),!e.stopPropagation&&(this.tools.forEach(n=>{e.stopPropagation||n.processToolEvent(e,s=>this.eventQueue.push(s),this.emitExternal,this,this.toolLockManager.getToolLock(n))}),!e.stopPropagation&&(this.processToolEvent(e,n=>this.eventQueue.push(n),this.emitExternal,this,this.toolLockManager.getToolLock(this)),e.type.startsWith("pointer")==!1,e.targets&&e.targets.length>0)))){let n=e.targets;for(let s of n)s.handleEvent&&s.handleEvent(e,this.emitExternal)}}this.processingQueue=!1,this.requestRender()}addEventSource(e){this.eventSources.push(e),e.attach(n=>this.enqueue(n),this)}removeEventSource(e){this.eventSources=this.eventSources.filter(n=>n!==e),e.detach?.()}addRecognizer(e){this.recognizers.push(e)}addRenderNode(e){this.renderers.push(e)}register(e){typeof e=="object"&&e!==null&&"attach"in e&&typeof e.attach=="function"&&this.addEventSource(e),typeof e=="object"&&e!==null&&"process"in e&&typeof e.process=="function"&&this.addRecognizer(e),typeof e=="object"&&e!==null&&("renderBeforeAll"in e||"renderBeforeObject"in e||"renderAfterObject"in e||"renderAfterAll"in e)&&(typeof e.renderBeforeAll=="function"||typeof e.renderBeforeObject=="function"||typeof e.renderAfterObject=="function"||typeof e.renderAfterAll=="function")&&this.addRenderNode(e)}redraw(){this.requestRender()}requestRender(){this.needsRender=!0,this.renderScheduled||(this.renderScheduled=!0,requestAnimationFrame(()=>{this.needsRender&&(this.doRender(this.ctx),this.needsRender=!1),this.renderScheduled=!1}))}doRender(e){e.save(),e.setTransform(this.zoom,0,0,this.zoom,this.pan.x,this.pan.y),e.clearRect(-this.pan.x/this.zoom,-this.pan.y/this.zoom,this.canvas.width/this.zoom,this.canvas.height/this.zoom),this.emitExternal(u.EngineRenderStarted,{}),this.renderers.forEach(n=>n.renderBeforeAll?.(e,this));for(let n of this.objects.filter(s=>s.visible).sort((s,i)=>s.zIndex-i.zIndex))this.renderers.forEach(s=>s.renderBeforeObject?.(e,this,n)),n.render(e,this.flags.get(n.id)??new Set),this.renderers.forEach(s=>s.renderAfterObject?.(e,this,n));this.renderers.forEach(n=>n.renderAfterAll?.(e,this)),this.emitExternal(u.EngineRenderCompleted,{}),e.restore()}dispose(){this.eventSources.forEach(e=>e.detach?.())}},F=class{constructor(){this.currentTool=null}get isLocked(){return this.currentTool!==null}getToolLock(e){return{hasLock:()=>this.currentTool===e,acquire:()=>this.currentTool===null||this.currentTool===e?(this.currentTool=e,!0):!1,release:()=>this.currentTool===null||this.currentTool===e?(this.currentTool=null,!0):(console.warn("Tool lock released by a tool that does not own it:",e),!1)}}},V=class{constructor(){this.passive=!1;this.wheelZoomFactor=.25;this.pinchZoomFactor=.25;this.minZoom=.01;this.maxZoom=10}processToolEvent(e,n,s,i,t){switch(e.type){case"wheel":this.handleWheelZoom(e,i,t);break;case"gesture":this.handlePinchZoom(e,i,t);break;case"keyZoomIn":break;case"keyZoomOut":break}}handleWheelZoom(e,n,s){let i=e.data||{},t=i.delta||new m(0,0),r=i.point||new v(0,0),o=n.viewableWidth/n.width,a=n.viewableHeight/n.height,c=Math.min(o,a)*.1,d=(t.y<0?c:-1*c)*this.wheelZoomFactor+1;this.applyZoom(n,d,r.x*n.zoom+n.pan.x,r.y*n.zoom+n.pan.y,s)}handlePinchZoom(e,n,s){let i=e.data||{},t=i.scaleDelta,r=i.clientX,o=i.clientY,a=1+t*this.pinchZoomFactor;this.applyZoom(n,a,r,o,s)}applyZoom(e,n,s,i,t){let r=e.zoom,o=Math.min(Math.max(r*n,this.minZoom),this.maxZoom);o!==r&&t.acquire()&&(e.pan.x=s-(s-e.pan.x)*(o/r),e.pan.y=i-(i-e.pan.y)*(o/r),e.setZoom(o,new v(s,i)),t.release())}},W=class{constructor(){this.priority=-1/0;this.active=!1;this.startClient=new v(0,0);this.origPan=new m(0,0)}processToolEvent(e,n,s,i,t){if(!e.type.startsWith("drag"))return!1;let o=(e.data||{}).point,a=i.worldToScreen(o);if(o!==null){var l=i.getTopMostInteractionPerEventType(o);if(l&&l.has("drag")){var c=l.get("drag");if(c&&i.hasFlag(c.object,"canvas-background")){if(e.type==="dragstart"){if(!t.acquire())return;this.startClient=a,this.origPan=i.pan.clone(),this.active=!0}if(e.type==="dragend"||e.type==="dragcancel"){this.active=!1,this.startClient=new v(0,0),this.origPan=new m(0,0),t.release();return}if(this.active==!1)return;t.hasLock()&&i.setPan(this.origPan.add(a.getDeltaFromPoint(this.startClient)))}}}}},Z=class{constructor(){this.objectsBeingMoved=[];this.lastDelta=null}processToolEvent(e,n,s,i,t){let r=e.data||{},o=r.point,a=r.delta,l=this.lastDelta==null?a:this.lastDelta,c=this.lastDelta==null?a:a?.subtract(l);switch(e.type){case"dragstart":if(!o)return;let b=i.getTopMostInteractionPerEventType(o).get("move");if(b){if(!t.acquire())return;let g=i.getSelectedObjects();g.length===0||g.some(E=>E===b.object)===!1?this.objectsBeingMoved=[b.object]:this.objectsBeingMoved=g}break;case"drag":if(!a||this.objectsBeingMoved==null||this.objectsBeingMoved.length===0)return;this.lastDelta=a,n({type:"move",data:{delta:c,point:o},targets:this.objectsBeingMoved});break;case"dragend":if(!a||this.objectsBeingMoved==null||this.objectsBeingMoved.length===0){this.lastDelta=null,this.objectsBeingMoved=[];return}n({type:"move",data:{origin,delta:c,point:o},targets:this.objectsBeingMoved}),this.lastDelta=null,this.objectsBeingMoved=[],t.release();break;case"dragcancel":(!a||this.objectsBeingMoved==null||this.objectsBeingMoved.length===0)&&(this.lastDelta=null,this.objectsBeingMoved=[]),n({type:"move",data:{origin,delta:l?.subtract(a)||new m(0,0),point:origin},targets:this.objectsBeingMoved}),this.lastDelta=null,this.objectsBeingMoved=[],t.release();break}}},N=class{constructor(){this.priority=100}processToolEvent(e,n,s,i,t){if(e.type!=="click")return;let r=e.data||{},o=r.point;if(!o)return;let l=i.getTopMostInteractionPerEventType(o).get("select"),c=i.getSelectedObjects(),d=r.metaHeld||r.ctrlHeld||r.shiftHeld;if(l){let b=c.some(E=>E===l.object);if(!(c.length===1&&b)){if(!t.acquire())return;d?i.setSelectedObjects([...c,l.object]):i.setSelectedObjects([l.object]),t.release()}}else i.setSelectedObjects([])}},$=class{constructor(){this.priority=-100}processToolEvent(e,n,s,i,t){if(e.type!=="pointermove")return;let o=(e.data||{}).point;if(!o)return;for(let l of i.getObjectsWithFlag("hoversibling"))i.clearFlag(l,"hoversibling"),i.setFlag(l,"hovered");for(let l of i.getObjectsWithFlag("hovered"))l.getOuterBounds().contains(o)||i.clearFlag(l,"hovered");for(let l of i.getAllObjects())l.getBounds().contains(o)&&i.setFlag(l,"hovered");let a=!1;for(let l of i.getSelectedObjects())i.hasFlag(l,"hovered")&&(a=!0);if(a)for(let l of i.getSelectedObjects())i.hasFlag(l,"hovered")||(i.setFlag(l,"hovered"),i.setFlag(l,"hoversibling"))}},q=class{constructor(){this.activeHandleIndex=null;this.objectsBeingResized=[];this.lastDelta=null}processToolEvent(e,n,s,i,t){let r=e.data||{},o=r.point,a=r.delta,l=r.origin,c=this.lastDelta==null?a:this.lastDelta,d=this.lastDelta==null?a:a?.subtract(c);switch(e.type){case"dragstart":if(!o)return;let g=i.getTopMostInteractionPerEventType(o).get("resize");if(g&&g.interaction.handleIndex!=null){if(!t.acquire())return;let E=i.getSelectedObjects();E.length===0||E.some(I=>I===g.object)===!1?this.objectsBeingResized=[g.object]:this.objectsBeingResized=E,this.activeHandleIndex=g.interaction.handleIndex,n({type:"resizestart",data:{handleIndex:this.activeHandleIndex,point:o},targets:this.objectsBeingResized})}break;case"drag":if(this.activeHandleIndex==null||!a||this.objectsBeingResized==null||this.objectsBeingResized.length===0)return;this.lastDelta=a,n({type:"resize",data:{handleIndex:this.activeHandleIndex,delta:d,point:o},targets:this.objectsBeingResized});break;case"dragend":if(this.activeHandleIndex==null||!a||this.objectsBeingResized==null||this.objectsBeingResized.length===0){this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[];return}n({type:"resize",data:{handleIndex:this.activeHandleIndex,origin:l,delta:d,point:o},targets:this.objectsBeingResized}),n({type:"resizeend",data:{handleIndex:this.activeHandleIndex,delta:d,point:o},targets:this.objectsBeingResized}),this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[],t.release();break;case"dragcancel":(this.activeHandleIndex==null||!a||this.objectsBeingResized==null||this.objectsBeingResized.length===0)&&(this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[]),n({type:"resize",data:{handleIndex:this.activeHandleIndex,origin:l,delta:c?.subtract(a)||new m(0,0),point:l},targets:this.objectsBeingResized}),this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[],t.release();break}}},K=class{constructor(e="black"){this.drawing=!1;this.startPt=null;this.currentPt=null;this.defaultColor="black";this.defaultColor=e}processToolEvent(e,n,s,i,t){let o=(e.data||{}).point;switch(e.type){case"dragstart":if(!o||!t.acquire())return;this.drawing=!0,this.startPt=o,this.currentPt=o;break;case"drag":if(!this.drawing||!t.hasLock()||!o)return;this.currentPt=o;break;case"dragend":if(this.drawing&&t.hasLock()&&this.startPt&&o){this.currentPt=o;let a=Math.min(this.startPt.x,this.currentPt.x),l=Math.min(this.startPt.y,this.currentPt.y),c=Math.abs(this.currentPt.x-this.startPt.x),d=Math.abs(this.currentPt.y-this.startPt.y),b=new w(a,l,c,d),g=i.getAllObjects().reduce((E,I)=>Math.max(E,I.zIndex),0);this.drawing=!1,t.release(),s(u.DrawingCompleted,{rect:b,maxZ:g})}case"dragcancel":this.drawing&&t.hasLock()&&(this.drawing=!1,this.startPt=null,this.currentPt=null,t.release());break}}renderAfterAll(e,n){if(!this.drawing||!this.startPt||!this.currentPt)return;let s=Math.min(this.startPt.x,this.currentPt.x),i=Math.min(this.startPt.y,this.currentPt.y),t=Math.abs(this.currentPt.x-this.startPt.x),r=Math.abs(this.currentPt.y-this.startPt.y);e.save(),e.strokeStyle=this.defaultColor,e.lineWidth=2/e.getTransform().a,e.setLineDash([4/e.getTransform().a,2/e.getTransform().a]),e.strokeRect(s,i,t,r),e.setLineDash([]),e.restore()}},Q=class{constructor(){this.lassoing=!1;this.points=[]}processToolEvent(e,n,s,i,t){let o=(e.data||{}).point;switch(e.type){case"dragstart":if(!o||!t.acquire())return;this.lassoing=!0,this.points=[o];break;case"drag":if(!this.lassoing||!t.hasLock()||!o)return;this.points.push(o);break;case"dragend":if(this.lassoing&&t.hasLock()&&o){this.points.push(o);let a=new ne(this.points),l=[];for(let c of i.getAllObjects()){let d=c.getBounds();if(a.containsRect(d)){l.push(c);continue}}i.setSelectedObjects(l),n({type:"lassoselected",data:{polygon:a,selectedObjects:l}})}case"dragcancel":this.lassoing&&t.hasLock()&&(this.lassoing=!1,this.points=[],t.release());break}}renderAfterAll(e,n){if(!(!this.lassoing||this.points.length===0)){e.save(),e.strokeStyle="black",e.lineWidth=1/e.getTransform().a,e.setLineDash([4/e.getTransform().a,2/e.getTransform().a]),e.beginPath(),e.moveTo(this.points[0].x,this.points[0].y);for(let s=1;s<this.points.length;s++)e.lineTo(this.points[s].x,this.points[s].y);e.stroke(),e.restore()}}},X=class{processToolEvent(e,n,s,i,t){if(!e.type.startsWith("api:"))return;e.stopPropagation=!0;let r=e.targets;if(!r||r.length===0)return;let o=r[0];if(!o){console.warn("API event has no target object:",e);return}if(!i.getAllObjects().includes(o)){console.warn("API event targets an object not in the engine:",o);return}switch(e.type){case"api:moveto":{if(!t.acquire())return;let{x:a,y:l}=e.data,d=o.getBounds().origin,b=new m(a-d.x,l-d.y);n({type:"move",data:{delta:b,origin:d,point:d},targets:[o]}),t.release();break}case"api:moveby":{if(!t.acquire())return;let{dx:a,dy:l}=e.data;n({type:"move",data:{delta:new m(a,l)},targets:[o]}),t.release();break}case"api:resizeto":{if(!t.acquire())return;let{width:a,height:l}=e.data,c=o.getBounds(),d=c.origin,b=a-c.size.width,g=l-c.size.height;n({type:"resizestart",data:{handleIndex:4,origin:d,point:d},targets:[o]}),n({type:"resize",data:{handleIndex:4,delta:new m(b,g),point:d},targets:[o]}),n({type:"resizeend",data:{handleIndex:4,delta:new m(b,g),point:d},targets:[o]}),t.release();break}case"api:resizeby":{if(!t.acquire())return;let{dW:a,dH:l}=e.data,d=o.getBounds().origin;n({type:"resizestart",data:{handleIndex:4,origin:d,point:d},targets:[o]}),n({type:"resize",data:{handleIndex:4,delta:new m(a,l),point:d},targets:[o]}),n({type:"resizeend",data:{handleIndex:4,delta:new m(a,l),point:d},targets:[o]}),t.release();break}case"api:setcolor":{let{color:a}=e.data;n({type:"setcolor",data:{color:a},targets:[o]});break}case"api:setzindex":{let{zIndex:a}=e.data;n({type:"setzindex",data:{zIndex:a},targets:[o]});break}case"api:setselectable":{let{isSelectable:a}=e.data;n({type:"setselectable",data:{isSelectable:a},targets:[o]});break}case"api:setmovable":{if(!t.acquire())return;let{isMovable:a}=e.data;n({type:"setmovable",data:{isMovable:a},targets:[o]}),t.release();break}case"api:setresizable":{if(!t.acquire())return;let{isResizable:a}=e.data;n({type:"setresizable",data:{isResizable:a},targets:[o]}),t.release();break}case"api:setvisible":{let{visible:a}=e.data;n({type:"setvisible",data:{isVisible:a},targets:[o]});break}}}},Y=class{constructor(e=5){this.activePointerIds=new Set;this.isDragging=!1;this.buttonStart=null;this.origin=new v(0,0);this.moveThreshold=e}process(e,n){let{type:s,data:i={}}=e;switch(s){case"pointerdown":if(i.pointerType!=="touch"){let t=i.point,r=e.data?.identifier,o=i.button;this.handleStart(r,i.pointerType,t,o,n)}break;case"touchstart":{let t=this.getTouches(e);if(t.length===1){let r=t[0],o=r.point,a=r.identifier;this.handleStart(a,"touch",o,null,n)}break}case"pointermove":if(i.pointerType!=="touch"){let t=i.point,r=e.data?.identifier,o=t?.getDeltaFromPoint(this.origin)||new m(0,0),a=i.button;this.handleMove(r,i.pointerType,t,o,a,n)}break;case"touchmove":{let t=this.findActiveTouch(e);if(t){let r=t.point,o=t.identifier,a=r?.getDeltaFromPoint(this.origin)||new m(0,0);this.handleMove(o,"touch",r,a,null,n)}break}case"pointerup":case"pointercancel":if(i.pointerType!=="touch"){let t=i.point,r=e.data?.identifier,o=t?.getDeltaFromPoint(this.origin)||new m(0,0),a=i.button;this.handleEnd(r,i.pointerType,t,o,a,n)}break;case"touchend":case"touchcancel":{let t=this.findActiveTouch(e);if(t){let r=t.point,o=t.identifier,a=r?.getDeltaFromPoint(this.origin)||new m(0,0);this.handleEnd(o,"touch",r,a,null,n)}break}}}handleStart(e,n,s,i,t){this.isDragging||e==null||s==null||s.x==null||s.y==null||t==null||(this.activePointerIds.add(e),this.origin=s,this.buttonStart=i??null,t({type:"dragpotential",data:{identifier:e,pointerType:n,point:origin}}))}handleMove(e,n,s,i,t,r){if(!(e==null||s==null||i==null||!this.activePointerIds.has(e)||r==null)){var o=s.subtract(i);!this.isDragging&&(this.buttonStart==null||this.buttonStart==0)&&(i.length()>=this.moveThreshold?(this.activePointerIds.clear(),this.activePointerIds.add(e),this.isDragging=!0,r({type:"dragstart",data:{identifier:e,pointerType:n,point:o}})):r({type:"dragpotentialmove",data:{identifier:e,pointerType:n,origin:o,delta:i,point:s}})),this.isDragging&&r({type:"drag",data:{identifier:e,pointerType:n,origin:o,delta:i,point:s}})}}handleEnd(e,n,s,i,t,r){if(!this.isDragging||e==null||s==null||i==null||!this.activePointerIds.has(e)||r==null){this.activePointerIds.clear();return}var o=s.add(i);r({type:"dragend",data:{identifier:e,pointerType:n,origin:o,point:s,delta:i}}),this.activePointerIds.clear(),this.isDragging=!1,this.buttonStart=null}getTouches(e){return e.data?.changedTouches??[]}findActiveTouch(e){return this.getTouches(e).find(n=>this.activePointerIds.has(n.identifier))}},U=class{constructor(e=5){this.activePointerIds=new Set;this.origin=new v(0,0);this.moveThreshold=e}process(e,n){let{type:s,data:i={}}=e;switch(s){case"pointerdown":if(i.pointerType!=="touch"){let t=i.point,r=e.data?.identifier;this.handleStart(r,t)}break;case"touchstart":{let t=this.getTouches(e);if(t.length===1){let r=t[0],o=r.point,a=r.identifier;this.handleStart(a,o)}break}case"pointermove":if(i.pointerType!=="touch"){let t=i.point,r=e.data?.identifier,o=t?.getDeltaFromPoint(this.origin)||new m(0,0);this.handleMove(r,t,o)}break;case"touchmove":{let t=this.findActiveTouch(e);if(t){let r=t.point,o=t.identifier,a=r?.getDeltaFromPoint(this.origin)||new m(0,0);this.handleMove(o,r,a)}break}case"pointerup":case"pointercancel":if(i.pointerType!=="touch"){let t=i.point,r=e.data?.identifier,o=t?.getDeltaFromPoint(this.origin)||new m(0,0),a=e.data?.shiftHeld??!1,l=e.data?.metaHeld??!1,c=e.data?.ctrlHeld??!1,d=e.data?.altHeld??!1;this.handleEnd(r,i.pointerType,t,o,{shiftHeld:a,metaHeld:l,ctrlHeld:c,altHeld:d},n)}break;case"touchend":case"touchcancel":{let t=this.findActiveTouch(e);if(t){let r=t.point,o=t.identifier,a=r?.getDeltaFromPoint(this.origin)||new m(0,0);this.handleEnd(o,"touch",r,a,n)}break}}}handleStart(e,n){e==null||n==null||n.x==null||n.y==null||(this.activePointerIds.add(e),this.origin=n)}handleMove(e,n,s){e==null||n==null||s==null||!this.activePointerIds.has(e)||s.length()>=this.moveThreshold&&this.activePointerIds.clear()}handleEnd(e,n,s,i,t,r){if(!(e==null||s==null||i==null||!this.activePointerIds.has(e)||r==null)){if(i.length()>=this.moveThreshold){this.activePointerIds.clear();return}var o={identifier:e,pointerType:n,point:s};t&&(o={...o,...t}),r({type:"click",data:o}),this.activePointerIds.clear()}}getTouches(e){return e.data?.changedTouches??[]}findActiveTouch(e){return this.getTouches(e).find(n=>this.activePointerIds.has(n.identifier))}};export{X as ApiTool,te as CanvasEngine,J as CircleObject,U as ClickGestureRecognizer,A as DomEventSource,Y as DragGestureRecognizer,K as DrawingTool,u as EngineEventType,$ as HoverTool,Q as LassoTool,Z as MoveTool,ee as PolygonObject,q as ResizeTool,N as SelectTool,F as ToolLockManager,G as Zone};
7
+ </svg>`;this.document=new Blob([this.defaultBackgroundImage],{type:"image/svg+xml;charset=utf-8"});this.emitter=new H;this.toolLockManager=new Z;this.eventSources=[];this.recognizers=[];this.tools=[];this.manualRenderers=[];this.modeRenderers=[];this.eventQueue=[];this.processingQueue=!1;this.renderScheduled=!1;this.flags=new Map;this.objects=[];this.needsRender=!1;this.toolRegistry=new Map;this.modes={};this.currentMode="";this.defaultOptions={initialZoom:1,initialPan:{x:10,y:10},defaultMode:"default",addTimerEventSource:!1,proxyObjectsForEvents:!0};this._pan=new E(0,0);this._zoom=1;this.on=this.emitter.on.bind(this.emitter);this.off=this.emitter.off.bind(this.emitter);this.emitExternal=this.emitter.emit.bind(this.emitter);this.options=this.createOptions(t);let s=document.querySelector(e);if(!s)throw new Error(`Container ${e} not found`);this.container=s,this.canvas=document.createElement("canvas"),this.canvas.width=this.container.clientWidth*10,this.canvas.height=this.container.clientHeight*10,this.container.appendChild(this.canvas),this.ctx=this.canvas.getContext("2d"),this.setupDefaultEventSources(),this.setupDefaultTools(),this.setupDefaultRecognizers(),this.setupDefaultModes(),this.setupRenderNodes(),this._zoom=this.options.initialZoom,this._pan=new E(this.options.initialPan.x,this.options.initialPan.y),this.switchMode(this.options.defaultMode),this.emitExternal(u.EngineStarted,{}),this.emitExternal(u.ViewportChanged,{oldPan:new E(0,0),newPan:this.pan,oldZoom:1,newZoom:this.zoom}),this.setBackgroundImage(this.document).then()}get pan(){return this._pan.clone()}get zoom(){return this._zoom}screenToWorld(e){return new p((e.x-this.pan.x)/this.zoom,(e.y-this.pan.y)/this.zoom)}worldToScreen(e){return new p(e.x*this.zoom+this.pan.x,e.y*this.zoom+this.pan.y)}processToolEvent(e,t,s,i,n){e.type.startsWith("windowresize")||(this.canvas.width=this.container.clientWidth,this.canvas.height=this.container.clientHeight)}createOptions(e){return{...this.defaultOptions,...e}}setupDefaultEventSources(){this.options.addTimerEventSource&&this.register(new A),this.register(new L(this.canvas))}setupDefaultRecognizers(){this.register(new U),this.register(new G)}setupDefaultTools(){this.registerTool("hover",()=>new q,!0),this.registerTool("select",()=>new $,!0),this.registerTool("drawing",()=>new Q,!0),this.registerTool("move",()=>new N,!0),this.registerTool("resize",()=>new K,!0),this.registerTool("lasso",()=>new X,!0),this.registerTool("pan",()=>new W,!0),this.registerTool("zoom",()=>new V(this.options.zoomOptions),!0),this.registerTool("api",()=>new Y,!0)}setupDefaultModes(){this.defineMode("default",{tools:["hover","select","resize","move","pan","zoom","api"]}),this.defineMode("move",{tools:["hover","select","resize","move","pan","zoom","api"]}),this.defineMode("create",{tools:["drawing","zoom","api"],handleEvent(e,t){e.type===u.DrawingCompleted&&t.switchMode("default")}}),this.defineMode("lasso",{tools:["hover","select","lasso","zoom","api"],handleEvent(e,t){e.type==="lassoselected"&&t.switchMode("default")}})}setupRenderNodes(){}wrapInteractiveObject(e){let t=this;return new Proxy(e,{set(s,i,n){let o=s[i],a=Reflect.set(s,i,n);return typeof i=="string"&&i.startsWith("_")||o!==n&&t.emitExternal(u.ObjectChanged,{object:s,property:i.toString(),oldValue:o,newValue:n}),a}})}registerTool(e,t,s=!0){if(this.toolRegistry.has(e))throw new Error(`Tool '${e}' already registered.`);this.toolRegistry.set(e,{factory:t,singleton:s})}resolveTool(e){let t=this.toolRegistry.get(e);if(!t)throw new Error(`Unknown tool '${e}'`);return t.singleton?("instance"in t||(t.instance=t.factory()),t.instance):t.factory()}defineMode(e,t){if(this.modes[e])throw new Error(`Mode '${e}' already defined.`);this.modes[e]=t}get mode(){return this.currentMode}switchMode(e){if(!this.modes[e])throw new Error(`Unknown mode '${e}'`);if(this.toolLockManager.isLocked){console.warn("Cannot switch modes while tools are locked. Please release all locks first.");return}if(this.currentMode===e){console.warn(`Already in mode '${e}', no switch needed.`);return}let t=this.currentMode;this.currentMode=e;let s=this.modes[e];if(s.tools==null||s.tools.length==0)return;let i=s.tools;this.tools=[...new Set(i.map(n=>this.resolveTool(n)))],this.modeRenderers=s.renderers||[],s.handleEvent&&this.tools.push(new F(s,this)),this.emitExternal(u.EngineModeChanged,{newMode:this.currentMode,oldMode:t})}get renderers(){let e=this.tools.filter(t=>typeof t=="object"&&t!==null&&("renderBeforeAll"in t||"renderBeforeObject"in t||"renderAfterObject"in t||"renderAfterAll"in t)&&(typeof t.renderBeforeAll=="function"||typeof t.renderBeforeObject=="function"||typeof t.renderAfterObject=="function"||typeof t.renderAfterAll=="function")).map(t=>t);return[...new Set([...this.manualRenderers,...this.modeRenderers,...e])]}get viewableWidth(){return this.canvas.width}get viewableHeight(){return this.canvas.height}get width(){let e=this.getObjectsWithFlag("canvas-background").filter(s=>typeof s=="object"&&s instanceof M),t;return e.length==0?this.canvas.width:(e.length>=1&&(t=e[0]),t.width)}get height(){let e=this.getObjectsWithFlag("canvas-background").filter(s=>typeof s=="object"&&s instanceof M),t;return e.length==0?this.canvas.height:(e.length>=1&&(t=e[0]),t.height)}get documentBlob(){return this.document}async setBackgroundImage(e){let t=this.width,s=this.height,i;e instanceof File||e instanceof Blob?i=e:i=await this.loadImageFromUrl(e),this.document=i;let n=URL.createObjectURL(i),o=await this.loadImage(n),a=this.getObjectsWithFlag("canvas-background");if(a.length>0){let r=a.find(l=>l instanceof M);r&&(r.img=o)}else{let r=new M(o);this.objects.push(r),this.setFlag(r.id,"canvas-background")}this.emitExternal(u.EngineBackgroundChanged,{newImage:o,newWidth:o.width,newHeight:o.height,oldWidth:t,oldHeight:s}),this.requestRender()}async loadImageFromUrl(e){let t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch image: ${t.status} ${t.statusText}`);return await t.blob()}loadImage(e){return new Promise((t,s)=>{if(e instanceof HTMLImageElement){e.complete&&e.naturalWidth!==0?t(e):(e.onload=()=>t(e),e.onerror=s);return}let i=new Image;i.onload=()=>t(i),i.onerror=s,i.src=e})}getObject(e){return this.objects.find(s=>s.id===e)}addObject(e){if(this.objects.find(s=>s.id===e.id))throw new Error(`Object with id '${e.id}' already exists.`);this.objects.push(e),this.enqueue({type:"redraw",data:{}},!0),this.emitExternal(u.ObjectAdded,{object:this.options.proxyObjectsForEvents?this.wrapInteractiveObject(e):e})}removeObject(e){let t=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!t)throw new Error(`Object not found: ${e}`);let s=this.objects.indexOf(t);if(s!==-1){this.objects.splice(s,1);let i=typeof e=="string"?e:e.id;this.flags.delete(i),this.emitExternal(u.ObjectRemoved,{object:t})}else console.warn("Attempted to remove an object that does not exist in the engine:",t);this.redraw()}moveObjectToPoint(e,t,s){let i=typeof e=="string"?this.objects.find(a=>a.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let n=typeof t=="number"?t:t.x,o=typeof t=="number"?s??0:t.y;this.enqueue({type:"api:moveto",data:{x:n,y:o},targets:[i]})}moveObjectByVector(e,t,s){let i=typeof e=="string"?this.objects.find(a=>a.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let n=typeof t=="number"?t:t.x,o=typeof t=="number"?s??0:t.y;this.enqueue({type:"api:moveby",data:{dx:n,dy:o},targets:[i]})}resizeObjectToSize(e,t,s){let i=typeof e=="string"?this.objects.find(a=>a.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let n=typeof t=="number"?t:t.width,o=typeof t=="number"?s??0:t.height;this.enqueue({type:"api:resizeto",data:{width:n,height:o},targets:[i]})}resizeObjectByVector(e,t,s){let i=typeof e=="string"?this.objects.find(a=>a.id===e):e;if(!i)throw new Error(`Object not found: ${e}`);let n=typeof t=="number"?t:t.x,o=typeof t=="number"?s??0:t.y;this.enqueue({type:"api:resizeby",data:{dw:n,dh:o},targets:[i]})}setObjectColor(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setcolor",data:{color:t},targets:[s]})}setObjectZIndex(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setzindex",data:{zIndex:t},targets:[s]})}updateObjectSelectability(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setselectable",data:{isSelectable:t},targets:[s]})}updateObjectMovability(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setmovable",data:{isMovable:t},targets:[s]})}updateObjectResizeability(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);this.enqueue({type:"api:setresizable",data:{isResizable:t},targets:[s]})}updateObjectVisibility(e,t){let s=typeof e=="string"?this.objects.find(i=>i.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);s.visible!==t&&this.enqueue({type:"api:setvisible",data:{visible:t},targets:[s]})}setFlag(e,t){let s=typeof e=="string"?this.objects.find(o=>o.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);let i=typeof e=="string"?e:e.id;if(this.flags.has(i)||this.flags.set(i,new Set),t=="selected"&&!s.selectable)return console.warn(`Cannot set flag '${t}' on non-selectable object`,s);let n=this.flags.get(i);n.has(t)||(n.add(t),this.emitExternal(u.ObjectFlagsAdded,{object:s,addedFlags:[t],currentFlags:[...this.flags.get(i)]}),t==="selected"&&this.emitExternal(u.ObjectSelected,{object:s}),this.ensureEventLoop())}clearFlag(e,t){let s=typeof e=="string"?this.objects.find(n=>n.id===e):e;if(!s)throw new Error(`Object not found: ${e}`);let i=typeof e=="string"?e:e.id;this.flags.get(i)?.delete(t),this.emitExternal(u.ObjectFlagsRemoved,{object:s,removedFlags:[t],currentFlags:[...this.flags.get(i)||[]]}),t==="selected"&&this.emitExternal(u.ObjectDeselected,{object:s}),this.ensureEventLoop()}hasFlag(e,t){let s=typeof e=="string"?e:e.id;return this.flags.get(s)?.has(t)??!1}clearAllFlags(e){for(let[t,s]of this.flags.entries()){let i=this.objects.find(n=>n.id===t)??null;if(!i)throw new Error(`Object not found: ${t}`);s.delete(e),this.emitExternal(u.ObjectFlagsRemoved,{object:i,removedFlags:[e],currentFlags:[...this.flags.get(t)||[]]}),e==="selected"&&this.emitExternal(u.ObjectDeselected,{object:i})}this.ensureEventLoop()}getObjectsWithFlag(e){return[...this.flags.entries()].filter(([t,s])=>s.has(e)).filter(([t,s])=>{let i=this.objects.find(n=>n.id===t)??null;if(!i)throw new Error(`Object not found: ${t}`);return e==="selected"?i.selectable:!0}).map(([t])=>this.objects.find(s=>s.id===t))}setZoom(e,t){if(e<=0){console.warn("Zoom must be greater than 0, ignoring.");return}let s=this.zoom,i=new E(this.pan.x,this.pan.y);if(this._zoom=e,t){let n=t.x-(t.x-this.pan.x)*(e/s),o=t.y-(t.y-this.pan.y)*(e/s);this._pan=new E(n,o)}this.emitExternal(u.ViewportChanged,{oldPan:i,newPan:this.pan,oldZoom:s,newZoom:this.zoom}),this.ensureEventLoop()}setPan(e,t){let s=this.pan.clone();typeof e=="number"?this._pan=new E(e,t??0):this._pan=e.clone(),this.emitExternal(u.ViewportChanged,{oldPan:s,newPan:this.pan,oldZoom:this.zoom,newZoom:this.zoom}),this.ensureEventLoop()}setSelectedObjects(e){let t=e.map(o=>typeof o=="string"?this.objects.find(a=>a.id===o):o),s=this.getSelectedObjects(),i=s.filter(o=>!t.includes(o)),n=t.filter(o=>!s.includes(o));i.forEach(o=>this.clearFlag(o,"selected")),n.forEach(o=>this.setFlag(o,"selected")),this.ensureEventLoop()}getSelectedObjects(){return this.getObjectsWithFlag("selected").filter(e=>e.selectable)}getAllObjects(){let e=this.getObjectsWithFlag("canvas-background").filter(t=>typeof t=="object"&&t instanceof M);return[...this.objects].filter(t=>e.includes(t)==!1)}getTopMostInteractionPerEventType(e,t){let s=new Map,i=[...this.objects].sort((n,o)=>(n.zIndex??0)-(o.zIndex??0));for(let n=i.length-1;n>=0;n--){let o=i[n];if(!o||!o.visible)continue;o.getEventInteractions(e,t).forEach(r=>{let l=r.eventTypePrefix;if(!s.has(l)){let c={object:o,interaction:r};s.set(l,c)}})}return s}enqueue(e,t=!1){if(t&&this.eventQueue.find(i=>i.type===e.type)){this.ensureEventLoop();return}this.eventQueue.push(e),this.ensureEventLoop()}ensureEventLoop(){this.processingQueue||(this.processingQueue=!0,setTimeout(()=>this.processQueue(),0))}processQueue(){for(;this.eventQueue.length;){let e=this.eventQueue.shift();if(!e.stopPropagation&&(this.recognizers.forEach(t=>{e.stopPropagation||t.process(e,s=>this.eventQueue.push(s))}),!e.stopPropagation&&(this.tools.forEach(t=>{e.stopPropagation||t.processToolEvent(e,s=>this.eventQueue.push(s),this.emitExternal,this,this.toolLockManager.getToolLock(t))}),!e.stopPropagation&&(this.processToolEvent(e,t=>this.eventQueue.push(t),this.emitExternal,this,this.toolLockManager.getToolLock(this)),e.type.startsWith("pointer")==!1,e.targets&&e.targets.length>0)))){let t=e.targets;for(let s of t)s.handleEvent&&s.handleEvent(e,this.emitExternal)}}this.processingQueue=!1,this.requestRender()}addEventSource(e){this.eventSources.push(e),e.attach(t=>this.enqueue(t),this)}removeEventSource(e){this.eventSources=this.eventSources.filter(t=>t!==e),e.detach?.()}addRecognizer(e){this.recognizers.push(e)}addRenderNode(e){this.renderers.push(e)}register(e){typeof e=="object"&&e!==null&&"attach"in e&&typeof e.attach=="function"&&this.addEventSource(e),typeof e=="object"&&e!==null&&"process"in e&&typeof e.process=="function"&&this.addRecognizer(e),typeof e=="object"&&e!==null&&("renderBeforeAll"in e||"renderBeforeObject"in e||"renderAfterObject"in e||"renderAfterAll"in e)&&(typeof e.renderBeforeAll=="function"||typeof e.renderBeforeObject=="function"||typeof e.renderAfterObject=="function"||typeof e.renderAfterAll=="function")&&this.addRenderNode(e)}redraw(){this.requestRender()}requestRender(){this.needsRender=!0,this.renderScheduled||(this.renderScheduled=!0,requestAnimationFrame(()=>{this.needsRender&&(this.doRender(this.ctx),this.needsRender=!1),this.renderScheduled=!1}))}get renderingContext(){return{currentZoom:this.zoom,currentScaleMultiplier:1/(this.viewableWidth/this.width)}}doRender(e){e.save(),e.setTransform(this.zoom,0,0,this.zoom,this.pan.x,this.pan.y),e.clearRect(-this.pan.x/this.zoom,-this.pan.y/this.zoom,this.canvas.width/this.zoom,this.canvas.height/this.zoom),this.emitExternal(u.EngineRenderStarted,{});let t=this.renderingContext;this.renderers.forEach(s=>s.renderBeforeAll?.(e,this));for(let s of this.objects.filter(i=>i.visible).sort((i,n)=>i.zIndex-n.zIndex))this.renderers.forEach(i=>i.renderBeforeObject?.(e,this,s)),s.render(e,this.flags.get(s.id)??new Set,t),this.renderers.forEach(i=>i.renderAfterObject?.(e,this,s));this.renderers.forEach(s=>s.renderAfterAll?.(e,this)),this.emitExternal(u.EngineRenderCompleted,{}),e.restore()}dispose(){this.eventSources.forEach(e=>e.detach?.())}},Z=class{constructor(){this.currentTool=null}get isLocked(){return this.currentTool!==null}getToolLock(e){return{hasLock:()=>this.currentTool===e,acquire:()=>this.currentTool===null||this.currentTool===e?(this.currentTool=e,!0):!1,release:()=>this.currentTool===null||this.currentTool===e?(this.currentTool=null,!0):(console.warn("Tool lock released by a tool that does not own it:",e),!1)}}},V=class{get defaultOptions(){return{wheelZoomFactor:.25,pinchZoomFactor:.25,minZoom:.01,maxZoom:10}}constructor(e={}){this.options=this.createOptions(e)}createOptions(e){return{...this.defaultOptions,...e}}processToolEvent(e,t,s,i,n){switch(e.type){case"wheel":this.handleWheelZoom(e,i,n);break;case"gesture":this.handlePinchZoom(e,i,n);break;case"keyZoomIn":break;case"keyZoomOut":break}}handleWheelZoom(e,t,s){let i=e.data||{},n=i.delta||new E(0,0),o=i.point||new p(0,0),a=t.viewableWidth/t.width,r=t.viewableHeight/t.height,c=Math.min(a,r)*.1,d=(n.y<0?c:-1*c)*(this.options.wheelZoomFactor??1)+1;this.applyZoom(t,d,o.x*t.zoom+t.pan.x,o.y*t.zoom+t.pan.y,s)}handlePinchZoom(e,t,s){let i=e.data||{},n=i.scaleDelta,o=i.clientX,a=i.clientY,r=1+n*(this.options.pinchZoomFactor??1);this.applyZoom(t,r,o,a,s)}applyZoom(e,t,s,i,n){let o=e.zoom,a=Math.min(Math.max(o*t,this.options.minZoom??.01),this.options.maxZoom??10);a!==o&&n.acquire()&&(e.pan.x=s-(s-e.pan.x)*(a/o),e.pan.y=i-(i-e.pan.y)*(a/o),e.setZoom(a,new p(s,i)),n.release())}},W=class{constructor(){this.priority=-1/0;this.active=!1;this.startClient=new p(0,0);this.origPan=new E(0,0)}processToolEvent(e,t,s,i,n){if(!e.type.startsWith("drag"))return!1;let a=(e.data||{}).point,r=i.worldToScreen(a);if(a!==null){var l=i.getTopMostInteractionPerEventType(a,i.renderingContext);if(l&&l.has("drag")){var c=l.get("drag");if(c&&i.hasFlag(c.object,"canvas-background")){if(e.type==="dragstart"){if(!n.acquire())return;this.startClient=r,this.origPan=i.pan.clone(),this.active=!0}if(e.type==="dragend"||e.type==="dragcancel"){this.active=!1,this.startClient=new p(0,0),this.origPan=new E(0,0),n.release();return}if(this.active==!1)return;n.hasLock()&&i.setPan(this.origPan.add(r.getDeltaFromPoint(this.startClient)))}}}}},N=class{constructor(){this.objectsBeingMoved=[];this.lastDelta=null}processToolEvent(e,t,s,i,n){let o=e.data||{},a=o.point,r=o.delta,l=this.lastDelta==null?r:this.lastDelta,c=this.lastDelta==null?r:r?.subtract(l);switch(e.type){case"dragstart":if(!a)return;let g=i.getTopMostInteractionPerEventType(a,i.renderingContext).get("move");if(g){if(!n.acquire())return;let h=i.getSelectedObjects();h.length===0||h.some(y=>y===g.object)===!1?this.objectsBeingMoved=[g.object]:this.objectsBeingMoved=h}break;case"drag":if(!r||this.objectsBeingMoved==null||this.objectsBeingMoved.length===0)return;this.lastDelta=r,t({type:"move",data:{delta:c,point:a},targets:this.objectsBeingMoved});break;case"dragend":if(!r||this.objectsBeingMoved==null||this.objectsBeingMoved.length===0){this.lastDelta=null,this.objectsBeingMoved=[];return}t({type:"move",data:{origin,delta:c,point:a},targets:this.objectsBeingMoved}),this.lastDelta=null,this.objectsBeingMoved=[],n.release();break;case"dragcancel":(!r||this.objectsBeingMoved==null||this.objectsBeingMoved.length===0)&&(this.lastDelta=null,this.objectsBeingMoved=[]),t({type:"move",data:{origin,delta:l?.subtract(r)||new E(0,0),point:origin},targets:this.objectsBeingMoved}),this.lastDelta=null,this.objectsBeingMoved=[],n.release();break}}},$=class{constructor(){this.priority=100}processToolEvent(e,t,s,i,n){if(e.type!=="click")return;let o=e.data||{},a=o.point;if(!a)return;let l=i.getTopMostInteractionPerEventType(a,i.renderingContext).get("select"),c=i.getSelectedObjects(),d=o.metaHeld||o.ctrlHeld||o.shiftHeld;if(l){let g=c.some(y=>y===l.object);if(!(c.length===1&&g)){if(!n.acquire())return;d?i.setSelectedObjects([...c,l.object]):i.setSelectedObjects([l.object]),n.release()}}else i.setSelectedObjects([])}},q=class{constructor(){this.priority=-100}processToolEvent(e,t,s,i,n){if(e.type!=="pointermove")return;let a=(e.data||{}).point;if(!a)return;for(let l of i.getObjectsWithFlag("hoversibling"))i.clearFlag(l,"hoversibling"),i.setFlag(l,"hovered");for(let l of i.getObjectsWithFlag("hovered"))l.getOuterBounds(i.renderingContext).contains(a)||i.clearFlag(l,"hovered");for(let l of i.getAllObjects())l.getBounds(i.renderingContext).contains(a)&&i.setFlag(l,"hovered");let r=!1;for(let l of i.getSelectedObjects())i.hasFlag(l,"hovered")&&(r=!0);if(r)for(let l of i.getSelectedObjects())i.hasFlag(l,"hovered")||(i.setFlag(l,"hovered"),i.setFlag(l,"hoversibling"))}},K=class{constructor(){this.activeHandleIndex=null;this.objectsBeingResized=[];this.lastDelta=null}processToolEvent(e,t,s,i,n){let o=e.data||{},a=o.point,r=o.delta,l=o.origin,c=this.lastDelta==null?r:this.lastDelta,d=this.lastDelta==null?r:r?.subtract(c);switch(e.type){case"dragstart":if(!a)return;let h=i.getTopMostInteractionPerEventType(a,i.renderingContext).get("resize");if(h&&h.interaction.handleIndex!=null){if(!n.acquire())return;let y=i.getSelectedObjects();y.length===0||y.some(I=>I===h.object)===!1?this.objectsBeingResized=[h.object]:this.objectsBeingResized=y,this.activeHandleIndex=h.interaction.handleIndex,t({type:"resizestart",data:{handleIndex:this.activeHandleIndex,point:a},targets:this.objectsBeingResized})}break;case"drag":if(this.activeHandleIndex==null||!r||this.objectsBeingResized==null||this.objectsBeingResized.length===0)return;this.lastDelta=r,t({type:"resize",data:{handleIndex:this.activeHandleIndex,delta:d,point:a},targets:this.objectsBeingResized});break;case"dragend":if(this.activeHandleIndex==null||!r||this.objectsBeingResized==null||this.objectsBeingResized.length===0){this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[];return}t({type:"resize",data:{handleIndex:this.activeHandleIndex,origin:l,delta:d,point:a},targets:this.objectsBeingResized}),t({type:"resizeend",data:{handleIndex:this.activeHandleIndex,delta:d,point:a},targets:this.objectsBeingResized}),this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[],n.release();break;case"dragcancel":(this.activeHandleIndex==null||!r||this.objectsBeingResized==null||this.objectsBeingResized.length===0)&&(this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[]),t({type:"resize",data:{handleIndex:this.activeHandleIndex,origin:l,delta:c?.subtract(r)||new E(0,0),point:l},targets:this.objectsBeingResized}),this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[],n.release();break}}},Q=class{constructor(e="black"){this.drawing=!1;this.startPt=null;this.currentPt=null;this.defaultColor="black";this.defaultColor=e}processToolEvent(e,t,s,i,n){let a=(e.data||{}).point;switch(e.type){case"dragstart":if(!a||!n.acquire())return;this.drawing=!0,this.startPt=a,this.currentPt=a;break;case"drag":if(!this.drawing||!n.hasLock()||!a)return;this.currentPt=a;break;case"dragend":if(this.drawing&&n.hasLock()&&this.startPt&&a){this.currentPt=a;let r=Math.min(this.startPt.x,this.currentPt.x),l=Math.min(this.startPt.y,this.currentPt.y),c=Math.abs(this.currentPt.x-this.startPt.x),d=Math.abs(this.currentPt.y-this.startPt.y),g=new w(r,l,c,d),h=i.getAllObjects().reduce((y,I)=>Math.max(y,I.zIndex),0);this.drawing=!1,n.release(),s(u.DrawingCompleted,{rect:g,maxZ:h})}case"dragcancel":this.drawing&&n.hasLock()&&(this.drawing=!1,this.startPt=null,this.currentPt=null,n.release());break}}renderAfterAll(e,t){if(!this.drawing||!this.startPt||!this.currentPt)return;let s=Math.min(this.startPt.x,this.currentPt.x),i=Math.min(this.startPt.y,this.currentPt.y),n=Math.abs(this.currentPt.x-this.startPt.x),o=Math.abs(this.currentPt.y-this.startPt.y);e.save(),e.strokeStyle=this.defaultColor,e.lineWidth=2/e.getTransform().a,e.setLineDash([4/e.getTransform().a,2/e.getTransform().a]),e.strokeRect(s,i,n,o),e.setLineDash([]),e.restore()}},X=class{constructor(){this.lassoing=!1;this.points=[]}processToolEvent(e,t,s,i,n){let a=(e.data||{}).point;switch(e.type){case"dragstart":if(!a||!n.acquire())return;this.lassoing=!0,this.points=[a];break;case"drag":if(!this.lassoing||!n.hasLock()||!a)return;this.points.push(a);break;case"dragend":if(this.lassoing&&n.hasLock()&&a){this.points.push(a);let r=new ie(this.points),l=[];for(let c of i.getAllObjects()){let d=c.getBounds();if(r.containsRect(d)){l.push(c);continue}}i.setSelectedObjects(l),t({type:"lassoselected",data:{polygon:r,selectedObjects:l}})}case"dragcancel":this.lassoing&&n.hasLock()&&(this.lassoing=!1,this.points=[],n.release());break}}renderAfterAll(e,t){if(!(!this.lassoing||this.points.length===0)){e.save(),e.strokeStyle="black",e.lineWidth=1/e.getTransform().a,e.setLineDash([4/e.getTransform().a,2/e.getTransform().a]),e.beginPath(),e.moveTo(this.points[0].x,this.points[0].y);for(let s=1;s<this.points.length;s++)e.lineTo(this.points[s].x,this.points[s].y);e.stroke(),e.restore()}}},Y=class{processToolEvent(e,t,s,i,n){if(!e.type.startsWith("api:"))return;e.stopPropagation=!0;let o=e.targets;if(!o||o.length===0)return;let a=o[0];if(!a){console.warn("API event has no target object:",e);return}if(!i.getAllObjects().includes(a)){console.warn("API event targets an object not in the engine:",a);return}switch(e.type){case"api:moveto":{if(!n.acquire())return;let{x:r,y:l}=e.data,d=a.getBounds(i.renderingContext).origin,g=new E(r-d.x,l-d.y);t({type:"move",data:{delta:g,origin:d,point:d},targets:[a]}),n.release();break}case"api:moveby":{if(!n.acquire())return;let{dx:r,dy:l}=e.data;t({type:"move",data:{delta:new E(r,l)},targets:[a]}),n.release();break}case"api:resizeto":{if(!n.acquire())return;let{width:r,height:l}=e.data,c=a.getBounds(i.renderingContext),d=c.origin,g=r-c.size.width,h=l-c.size.height;t({type:"resizestart",data:{handleIndex:4,origin:d,point:d},targets:[a]}),t({type:"resize",data:{handleIndex:4,delta:new E(g,h),point:d},targets:[a]}),t({type:"resizeend",data:{handleIndex:4,delta:new E(g,h),point:d},targets:[a]}),n.release();break}case"api:resizeby":{if(!n.acquire())return;let{dW:r,dH:l}=e.data,d=a.getBounds(i.renderingContext).origin;t({type:"resizestart",data:{handleIndex:4,origin:d,point:d},targets:[a]}),t({type:"resize",data:{handleIndex:4,delta:new E(r,l),point:d},targets:[a]}),t({type:"resizeend",data:{handleIndex:4,delta:new E(r,l),point:d},targets:[a]}),n.release();break}case"api:setcolor":{let{color:r}=e.data;t({type:"setcolor",data:{color:r},targets:[a]});break}case"api:setzindex":{let{zIndex:r}=e.data;t({type:"setzindex",data:{zIndex:r},targets:[a]});break}case"api:setselectable":{let{isSelectable:r}=e.data;t({type:"setselectable",data:{isSelectable:r},targets:[a]});break}case"api:setmovable":{if(!n.acquire())return;let{isMovable:r}=e.data;t({type:"setmovable",data:{isMovable:r},targets:[a]}),n.release();break}case"api:setresizable":{if(!n.acquire())return;let{isResizable:r}=e.data;t({type:"setresizable",data:{isResizable:r},targets:[a]}),n.release();break}case"api:setvisible":{let{visible:r}=e.data;t({type:"setvisible",data:{isVisible:r},targets:[a]});break}}}},U=class{constructor(e=5){this.activePointerIds=new Set;this.isDragging=!1;this.buttonStart=null;this.origin=new p(0,0);this.moveThreshold=e}process(e,t){let{type:s,data:i={}}=e;switch(s){case"pointerdown":if(i.pointerType!=="touch"){let n=i.point,o=e.data?.identifier,a=i.button;this.handleStart(o,i.pointerType,n,a,t)}break;case"touchstart":{let n=this.getTouches(e);if(n.length===1){let o=n[0],a=o.point,r=o.identifier;this.handleStart(r,"touch",a,null,t)}break}case"pointermove":if(i.pointerType!=="touch"){let n=i.point,o=e.data?.identifier,a=n?.getDeltaFromPoint(this.origin)||new E(0,0),r=i.button;this.handleMove(o,i.pointerType,n,a,r,t)}break;case"touchmove":{let n=this.findActiveTouch(e);if(n){let o=n.point,a=n.identifier,r=o?.getDeltaFromPoint(this.origin)||new E(0,0);this.handleMove(a,"touch",o,r,null,t)}break}case"pointerup":case"pointercancel":if(i.pointerType!=="touch"){let n=i.point,o=e.data?.identifier,a=n?.getDeltaFromPoint(this.origin)||new E(0,0),r=i.button;this.handleEnd(o,i.pointerType,n,a,r,t)}break;case"touchend":case"touchcancel":{let n=this.findActiveTouch(e);if(n){let o=n.point,a=n.identifier,r=o?.getDeltaFromPoint(this.origin)||new E(0,0);this.handleEnd(a,"touch",o,r,null,t)}break}}}handleStart(e,t,s,i,n){this.isDragging||e==null||s==null||s.x==null||s.y==null||n==null||(this.activePointerIds.add(e),this.origin=s,this.buttonStart=i??null,n({type:"dragpotential",data:{identifier:e,pointerType:t,point:origin}}))}handleMove(e,t,s,i,n,o){if(!(e==null||s==null||i==null||!this.activePointerIds.has(e)||o==null)){var a=s.subtract(i);!this.isDragging&&(this.buttonStart==null||this.buttonStart==0)&&(i.length()>=this.moveThreshold?(this.activePointerIds.clear(),this.activePointerIds.add(e),this.isDragging=!0,o({type:"dragstart",data:{identifier:e,pointerType:t,point:a}})):o({type:"dragpotentialmove",data:{identifier:e,pointerType:t,origin:a,delta:i,point:s}})),this.isDragging&&o({type:"drag",data:{identifier:e,pointerType:t,origin:a,delta:i,point:s}})}}handleEnd(e,t,s,i,n,o){if(!this.isDragging||e==null||s==null||i==null||!this.activePointerIds.has(e)||o==null){this.activePointerIds.clear();return}var a=s.add(i);o({type:"dragend",data:{identifier:e,pointerType:t,origin:a,point:s,delta:i}}),this.activePointerIds.clear(),this.isDragging=!1,this.buttonStart=null}getTouches(e){return e.data?.changedTouches??[]}findActiveTouch(e){return this.getTouches(e).find(t=>this.activePointerIds.has(t.identifier))}},G=class{constructor(e=5){this.activePointerIds=new Set;this.origin=new p(0,0);this.moveThreshold=e}process(e,t){let{type:s,data:i={}}=e;switch(s){case"pointerdown":if(i.pointerType!=="touch"){let n=i.point,o=e.data?.identifier;this.handleStart(o,n)}break;case"touchstart":{let n=this.getTouches(e);if(n.length===1){let o=n[0],a=o.point,r=o.identifier;this.handleStart(r,a)}break}case"pointermove":if(i.pointerType!=="touch"){let n=i.point,o=e.data?.identifier,a=n?.getDeltaFromPoint(this.origin)||new E(0,0);this.handleMove(o,n,a)}break;case"touchmove":{let n=this.findActiveTouch(e);if(n){let o=n.point,a=n.identifier,r=o?.getDeltaFromPoint(this.origin)||new E(0,0);this.handleMove(a,o,r)}break}case"pointerup":case"pointercancel":if(i.pointerType!=="touch"){let n=i.point,o=e.data?.identifier,a=n?.getDeltaFromPoint(this.origin)||new E(0,0),r=e.data?.shiftHeld??!1,l=e.data?.metaHeld??!1,c=e.data?.ctrlHeld??!1,d=e.data?.altHeld??!1;this.handleEnd(o,i.pointerType,n,a,{shiftHeld:r,metaHeld:l,ctrlHeld:c,altHeld:d},t)}break;case"touchend":case"touchcancel":{let n=this.findActiveTouch(e);if(n){let o=n.point,a=n.identifier,r=o?.getDeltaFromPoint(this.origin)||new E(0,0);this.handleEnd(a,"touch",o,r,t)}break}}}handleStart(e,t){e==null||t==null||t.x==null||t.y==null||(this.activePointerIds.add(e),this.origin=t)}handleMove(e,t,s){e==null||t==null||s==null||!this.activePointerIds.has(e)||s.length()>=this.moveThreshold&&this.activePointerIds.clear()}handleEnd(e,t,s,i,n,o){if(!(e==null||s==null||i==null||!this.activePointerIds.has(e)||o==null)){if(i.length()>=this.moveThreshold){this.activePointerIds.clear();return}var a={identifier:e,pointerType:t,point:s};n&&(a={...a,...n}),o({type:"click",data:a}),this.activePointerIds.clear()}}getTouches(e){return e.data?.changedTouches??[]}findActiveTouch(e){return this.getTouches(e).find(t=>this.activePointerIds.has(t.identifier))}};export{Y as ApiTool,ne as CanvasEngine,ee as CircleObject,G as ClickGestureRecognizer,L as DomEventSource,U as DragGestureRecognizer,Q as DrawingTool,u as EngineEventType,q as HoverTool,X as LassoTool,N as MoveTool,te as PolygonObject,K as ResizeTool,$ as SelectTool,Z as ToolLockManager,J as Zone};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dytools-canvas-engine",
3
- "version": "1.2.3",
3
+ "version": "1.3.2",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",