dytools-canvas-engine 1.1.2 → 1.1.3
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 +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4,4 +4,4 @@
|
|
|
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(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 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,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 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,n){e.type===b.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(b.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 Y(s,this)),this.emitExternal(b.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 width(){let e=this.getObjectsWithFlag("canvas-background").filter(s=>typeof s=="object"&&s instanceof O),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 O),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(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: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:{}}),this.emitExternal(b.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(b.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}`);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(b.ObjectFlagsAdded,{object:s,addedFlags:[n],currentFlags:[...this.flags.get(i)]}),n==="selected"&&this.emitExternal(b.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(b.ObjectFlagsRemoved,{object:s,removedFlags:[n],currentFlags:[...this.flags.get(i)||[]]}),n==="selected"&&this.emitExternal(b.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(b.ObjectFlagsRemoved,{object:i,removedFlags:[e],currentFlags:[...this.flags.get(n)||[]]}),e==="selected"&&this.emitExternal(b.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 l.Vector(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 l.Vector(t,r)}this.emitExternal(b.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 l.Vector(e,n??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 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 O);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 c={object:t,interaction:o};n.set(a,c)}})}return n}enqueue(e){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(b.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(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.zoomFactor=1.1;this.pinchZoomFactor=.5;this.minZoom=.1;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 l.Vector(0,0),r=i.point||new l.Point(0,0),o=t.y<0?this.zoomFactor:1/this.zoomFactor;this.applyZoom(n,o,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 l.Point(s,i)),t.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,n,s,i,t){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(!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 l.Point(0,0),this.origPan=new l.Vector(0,0),t.release();return}if(this.active==!1)return;t.hasLock()&&i.setPan(this.origPan.add(a.getDeltaFromPoint(this.startClient)))}}}}},S=class{constructor(){this.objectsBeingMoved=[];this.lastDelta=null}processToolEvent(e,n,s,i,t){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(!t.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,n({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}n({type:"move",data:{origin,delta:d,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:c?.subtract(a)||new l.Vector(0,0),point:origin},targets:this.objectsBeingMoved}),this.lastDelta=null,this.objectsBeingMoved=[],t.release();break}}},M=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 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(!t.acquire())return;h?i.setSelectedObjects([...d,c.object]):i.setSelectedObjects([c.object]),t.release()}}else i.setSelectedObjects([])}},B=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 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,n,s,i,t){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(!t.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,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: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}n({type:"resize",data:{handleIndex:this.activeHandleIndex,origin:c,delta:h,point:o},targets:this.objectsBeingResized}),n({type:"resizeend",data:{handleIndex:this.activeHandleIndex,delta:h,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:c,delta:d?.subtract(a)||new l.Vector(0,0),point:c},targets:this.objectsBeingResized}),this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[],t.release();break}}},A=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),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,t.release(),s(b.DrawingCompleted,{rect:g,maxZ:v})}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()}},L=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 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),n({type:"lassoselected",data:{polygon:a,selectedObjects:c}})}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()}}},H=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:c}=e.data,h=o.getBounds().origin,g=new l.Vector(a-h.x,c-h.y);n({type:"move",data:{delta:g,origin:h,point:h},targets:[o]}),t.release();break}case"api:moveby":{if(!t.acquire())return;let{dx:a,dy:c}=e.data;n({type:"move",data:{delta:new l.Vector(a,c)},targets:[o]}),t.release();break}case"api:resizeto":{if(!t.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;n({type:"resizestart",data:{handleIndex:4,origin:h,point:h},targets:[o]}),n({type:"resize",data:{handleIndex:4,delta:new l.Vector(g,v),point:h},targets:[o]}),n({type:"resizeend",data:{handleIndex:4,delta:new l.Vector(g,v),point:h},targets:[o]}),t.release();break}case"api:resizeby":{if(!t.acquire())return;let{dW:a,dH:c}=e.data,h=o.getBounds().origin;n({type:"resizestart",data:{handleIndex:4,origin:h,point:h},targets:[o]}),n({type:"resize",data:{handleIndex:4,delta:new l.Vector(a,c),point:h},targets:[o]}),n({type:"resizeend",data:{handleIndex:4,delta:new l.Vector(a,c),point:h},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}}}},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,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 l.Vector(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 l.Vector(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 l.Vector(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 l.Vector(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))}},V=class{constructor(e=5){this.activePointerIds=new Set;this.origin=new l.Point(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 l.Vector(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 l.Vector(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 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,t,o,{shiftHeld:a,metaHeld:c,ctrlHeld:d,altHeld:h},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 l.Vector(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))}};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 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(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 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,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 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,n){e.type===b.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(b.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 Y(s,this)),this.emitExternal(b.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 width(){let e=this.getObjectsWithFlag("canvas-background").filter(s=>typeof s=="object"&&s instanceof O),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 O),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(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: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(b.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(b.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(b.ObjectFlagsAdded,{object:s,addedFlags:[n],currentFlags:[...this.flags.get(i)]}),n==="selected"&&this.emitExternal(b.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(b.ObjectFlagsRemoved,{object:s,removedFlags:[n],currentFlags:[...this.flags.get(i)||[]]}),n==="selected"&&this.emitExternal(b.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(b.ObjectFlagsRemoved,{object:i,removedFlags:[e],currentFlags:[...this.flags.get(n)||[]]}),e==="selected"&&this.emitExternal(b.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 l.Vector(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 l.Vector(t,r)}this.emitExternal(b.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 l.Vector(e,n??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 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 O);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 c={object:t,interaction:o};n.set(a,c)}})}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(b.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(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.zoomFactor=1.1;this.pinchZoomFactor=.5;this.minZoom=.1;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 l.Vector(0,0),r=i.point||new l.Point(0,0),o=t.y<0?this.zoomFactor:1/this.zoomFactor;this.applyZoom(n,o,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 l.Point(s,i)),t.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,n,s,i,t){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(!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 l.Point(0,0),this.origPan=new l.Vector(0,0),t.release();return}if(this.active==!1)return;t.hasLock()&&i.setPan(this.origPan.add(a.getDeltaFromPoint(this.startClient)))}}}}},S=class{constructor(){this.objectsBeingMoved=[];this.lastDelta=null}processToolEvent(e,n,s,i,t){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(!t.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,n({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}n({type:"move",data:{origin,delta:d,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:c?.subtract(a)||new l.Vector(0,0),point:origin},targets:this.objectsBeingMoved}),this.lastDelta=null,this.objectsBeingMoved=[],t.release();break}}},M=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 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(!t.acquire())return;h?i.setSelectedObjects([...d,c.object]):i.setSelectedObjects([c.object]),t.release()}}else i.setSelectedObjects([])}},B=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 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,n,s,i,t){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(!t.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,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: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}n({type:"resize",data:{handleIndex:this.activeHandleIndex,origin:c,delta:h,point:o},targets:this.objectsBeingResized}),n({type:"resizeend",data:{handleIndex:this.activeHandleIndex,delta:h,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:c,delta:d?.subtract(a)||new l.Vector(0,0),point:c},targets:this.objectsBeingResized}),this.activeHandleIndex=null,this.lastDelta=null,this.objectsBeingResized=[],t.release();break}}},A=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),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,t.release(),s(b.DrawingCompleted,{rect:g,maxZ:v})}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()}},L=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 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),n({type:"lassoselected",data:{polygon:a,selectedObjects:c}})}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()}}},H=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:c}=e.data,h=o.getBounds().origin,g=new l.Vector(a-h.x,c-h.y);n({type:"move",data:{delta:g,origin:h,point:h},targets:[o]}),t.release();break}case"api:moveby":{if(!t.acquire())return;let{dx:a,dy:c}=e.data;n({type:"move",data:{delta:new l.Vector(a,c)},targets:[o]}),t.release();break}case"api:resizeto":{if(!t.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;n({type:"resizestart",data:{handleIndex:4,origin:h,point:h},targets:[o]}),n({type:"resize",data:{handleIndex:4,delta:new l.Vector(g,v),point:h},targets:[o]}),n({type:"resizeend",data:{handleIndex:4,delta:new l.Vector(g,v),point:h},targets:[o]}),t.release();break}case"api:resizeby":{if(!t.acquire())return;let{dW:a,dH:c}=e.data,h=o.getBounds().origin;n({type:"resizestart",data:{handleIndex:4,origin:h,point:h},targets:[o]}),n({type:"resize",data:{handleIndex:4,delta:new l.Vector(a,c),point:h},targets:[o]}),n({type:"resizeend",data:{handleIndex:4,delta:new l.Vector(a,c),point:h},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}}}},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,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 l.Vector(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 l.Vector(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 l.Vector(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 l.Vector(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))}},V=class{constructor(e=5){this.activePointerIds=new Set;this.origin=new l.Point(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 l.Vector(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 l.Vector(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 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,t,o,{shiftHeld:a,metaHeld:c,ctrlHeld:d,altHeld:h},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 l.Vector(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))}};0&&(module.exports={ApiTool,CanvasEngine,CircleObject,ClickGestureRecognizer,DomEventSource,DragGestureRecognizer,DrawingTool,EngineEventType,HoverTool,LassoTool,MoveTool,PolygonObject,ResizeTool,SelectTool,ToolLockManager,Zone});
|
package/dist/index.js
CHANGED
|
@@ -4,4 +4,4 @@ import{Rectangle as w,Size as T,Point as v,Vector as m,Polygon as ne}from"dytool
|
|
|
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 Z,!0),this.registerTool("drawing",()=>new K,!0),this.registerTool("move",()=>new N,!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 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:{}}),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}`);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){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.zoomFactor=1.1;this.pinchZoomFactor=.5;this.minZoom=.1;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=t.y<0?this.zoomFactor:1/this.zoomFactor;this.applyZoom(n,o,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)))}}}}},N=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}}},Z=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,N as MoveTool,ee as PolygonObject,q as ResizeTool,Z 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 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 Z,!0),this.registerTool("drawing",()=>new K,!0),this.registerTool("move",()=>new N,!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 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.zoomFactor=1.1;this.pinchZoomFactor=.5;this.minZoom=.1;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=t.y<0?this.zoomFactor:1/this.zoomFactor;this.applyZoom(n,o,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)))}}}}},N=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}}},Z=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,N as MoveTool,ee as PolygonObject,q as ResizeTool,Z as SelectTool,F as ToolLockManager,G as Zone};
|