UNPKG

canvas-select-vite

Version:

一个用于图片标注的 javascript 库,基于 canvas,简单轻量,支持矩形、多边形、点、折线、圆形标注、网格标注。

2 lines (1 loc) 29.9 kB
(function(H,M){typeof exports=="object"&&typeof module<"u"?module.exports=M():typeof define=="function"&&define.amd?define(M):(H=typeof globalThis<"u"?globalThis:H||self,H.CanvasSelectVite=M())})(this,function(){"use strict";var F=Object.defineProperty;var j=(H,M,G)=>M in H?F(H,M,{enumerable:!0,configurable:!0,writable:!0,value:G}):H[M]=G;var h=(H,M,G)=>j(H,typeof M!="symbol"?M+"":M,G);function H(){const y=[],p="0123456789abcdef";for(let e=0;e<36;e++){const i=Math.floor(Math.random()*16);y[e]=p.slice(i,i+1)}y[14]="4";const t=y[19]&3|8;return y[19]=p.slice(t,t+1),y[8]=y[13]=y[18]=y[23]="-",y.join("")}function M(y,p){if(y.type===1&&p.type===1){const[[t,e],[i,s]]=y.coor,[[a,o],[c,r]]=p.coor;return t<=a&&e<=o&&i>=c&&s>=r}else if(y.type===1&&p.type===2){const[[t,e],[i,s]]=y.coor,a=p.coor;for(let o=0;o<a.length;o++){const[c,r]=a[o];if(c<t||c>i||r<e||r>s)return!1}return!0}else if(y.type===2&&p.type===1){const t=p.coor;for(let e=0;e<t.length;e++){const[i,s]=t[e];if(!G(i,s,y.coor))return!1}return!0}else if(y.type===2&&p.type===2){const t=y.coor,e=p.coor;for(let i=0;i<e.length;i++){const[s,a]=e[i];if(!G(s,a,t))return!1}return!0}return!1}function G(y,p,t){let e=!1;const i=t.length;for(let s=0,a=i-1;s<i;a=s++){const o=t[s][0],c=t[s][1],r=t[a][0],l=t[a][1];c>p!=l>p&&y<(r-o)*(p-c)/(l-c)+o&&(e=!e)}return e}class w{constructor(p,t){h(this,"label","");h(this,"hideLabel");h(this,"coor",[]);h(this,"strokeStyle");h(this,"fillStyle");h(this,"lineWidth");h(this,"labelFillStyle");h(this,"textFillStyle");h(this,"labelFont");h(this,"type");h(this,"active",!1);h(this,"creating",!1);h(this,"dragging",!1);h(this,"index");h(this,"uuid",H());h(this,"labelUp");h(this,"hide");this.index=t,Object.assign(this,p)}}class C extends w{constructor(t,e){super(t,e);h(this,"type",1)}get ctrlsData(){const[[t,e],[i,s]]=this.coor;return[[t,e],[t+(i-t)/2,e],[i,e],[i,e+(s-e)/2],[i,s],[t+(i-t)/2,s],[t,s],[t,e+(s-e)/2]]}}class D extends w{constructor(t,e){super(t,e);h(this,"type",2)}get ctrlsData(){return this.coor.length>2?this.coor:[]}}class k extends w{constructor(t,e){super(t,e);h(this,"type",3)}}class L{constructor(){h(this,"_eventTree",{})}on(p,t){const e=this._eventTree[p];Array.isArray(e)?e.push(t):this._eventTree[p]=[t]}emit(p,...t){const e=this._eventTree[p];Array.isArray(e)&&e.forEach(i=>i(...t))}off(p,t){const e=this._eventTree[p],i=e.find(s=>s===t);Array.isArray(e)&&i&&e.splice(i,1)}}class _ extends w{constructor(t,e){super(t,e);h(this,"type",4)}get ctrlsData(){return this.coor.length>1?this.coor:[]}}class W extends w{constructor(t,e){super(t,e);h(this,"type",5);h(this,"radius",0);this.radius=t.radius||this.radius}get ctrlsData(){const[t,e]=this.coor;return[[t,e-this.radius],[t+this.radius,e],[t,e+this.radius],[t-this.radius,e]]}}class A extends w{constructor(t,e){super(t,e);h(this,"type",6);h(this,"row",1);h(this,"col",1);h(this,"selected",[]);h(this,"selectedFillStyle");this.row=t.row>0?t.row:this.row,this.col=t.col>0?t.col:this.col,this.selected=Array.isArray(t.selected)?t.selected:[]}get ctrlsData(){const[[t,e],[i,s]]=this.coor;return[[t,e],[t+(i-t)/2,e],[i,e],[i,e+(s-e)/2],[i,s],[t+(i-t)/2,s],[t,s],[t,e+(s-e)/2]]}get gridRects(){const[[t,e],[i,s]]=this.coor,{row:a,col:o,strokeStyle:c,fillStyle:r,active:l,creating:g,lineWidth:I}=this,n=(i-t)/this.col,d=(s-e)/this.row,u=[];for(let f=0;f<a;f++)for(let v=0;v<o;v++){const S=[t+v*n,e+f*d],x=f*o+v,m=new C({coor:[S,[S[0]+n,S[1]+d]],strokeStyle:c,fillStyle:r,active:l,creating:g,lineWidth:I},x);u.push(m)}return u}}const P={name:"canvas-select-vite",version:"0.0.1",type:"module",files:["dist"],main:"./dist/canvas-select-vite.umd.js",module:"./dist/canvas-select-vite.es.js",types:"./dist/src/index.d.ts",exports:{types:"./dist/src/index.d.ts",import:"./dist/canvas-select-vite.es.js",require:"./dist/canvas-select-vite.umd.js"},scripts:{dev:"vite",build:"tsc && vite build"},devDependencies:{typescript:"~5.7.2",vite:"^6.0.1"},dependencies:{"vite-plugin-dts":"^4.3.0"},keywords:["canvas","marker","annotation","rect","polygon","dot","line","circle","grid","标注","矩形","多边形","点","折线","圆","网格"],author:"heylight",license:"MIT",homepage:"https://github.com/heylight/canvas-select",repository:{type:"git",url:"git+https://github.com/heylight/canvas-select.git"}};class N extends L{constructor(t,e){super();h(this,"version",P.version);h(this,"lock",!1);h(this,"readonly",!1);h(this,"MIN_WIDTH",10);h(this,"MIN_HEIGHT",10);h(this,"MIN_RADIUS",5);h(this,"strokeStyle","#0f0");h(this,"fillStyle","rgba(0, 0, 255, 0.1)");h(this,"lineWidth",1);h(this,"activeStrokeStyle","#f00");h(this,"activeFillStyle","rgba(255, 0, 0, 0.1)");h(this,"ctrlStrokeStyle","#000");h(this,"ctrlFillStyle","#fff");h(this,"ctrlRadius",3);h(this,"hideLabel",!1);h(this,"labelFillStyle","#fff");h(this,"labelFont","10px sans-serif");h(this,"textFillStyle","#000");h(this,"labelMaxLen",10);h(this,"WIDTH",0);h(this,"HEIGHT",0);h(this,"canvas");h(this,"ctx");h(this,"dataset",[]);h(this,"offScreen");h(this,"offScreenCtx");h(this,"magnifierCanvas");h(this,"magnifierCtx");h(this,"isMagnifierVisible",!0);h(this,"magnifierPosition","auto");h(this,"remmber");h(this,"mouse");h(this,"remmberOrigin",[0,0]);h(this,"createType",0);h(this,"ctrlIndex",-1);h(this,"image",new Image);h(this,"IMAGE_ORIGIN_WIDTH");h(this,"IMAGE_WIDTH",0);h(this,"IMAGE_ORIGIN_HEIGHT",0);h(this,"IMAGE_HEIGHT",0);h(this,"originX",0);h(this,"originY",0);h(this,"scaleStep",0);h(this,"scrollZoom",!0);h(this,"timer");h(this,"dblTouch",300);h(this,"dblTouchStore",0);h(this,"alpha",!0);h(this,"focusMode",!1);h(this,"evt");h(this,"scaleTouchStore",0);h(this,"isTouch2",!1);h(this,"isMobile",navigator.userAgent.includes("Mobile"));h(this,"labelUp",!1);h(this,"isCtrlKey",!1);h(this,"ctrlCode","ControlLeft");h(this,"gridMenuEnable",!0);h(this,"gridSelectedFillStyle","rgba(255, 255, 0, 0.6)");this.handleLoad=this.handleLoad.bind(this),this.handleContextmenu=this.handleContextmenu.bind(this),this.handleMousewheel=this.handleMousewheel.bind(this),this.handleMouseDown=this.handleMouseDown.bind(this),this.handleMouseMove=this.handleMouseMove.bind(this),this.handleMouseUp=this.handleMouseUp.bind(this),this.handleDblclick=this.handleDblclick.bind(this),this.handleKeyup=this.handleKeyup.bind(this),this.handleKeydown=this.handleKeydown.bind(this);const i=typeof t=="string"?document.querySelector(t):t;i instanceof HTMLCanvasElement?(this.canvas=i,this.offScreen=document.createElement("canvas"),this.initSetting(),this.initEvents(),e&&this.setImage(e)):console.warn("HTMLCanvasElement is required!")}get activeShape(){return this.dataset.find(t=>t.active)||{}}get scale(){return this.IMAGE_ORIGIN_WIDTH&&this.IMAGE_WIDTH?this.IMAGE_WIDTH/this.IMAGE_ORIGIN_WIDTH:1}get imageMin(){return Math.min(this.IMAGE_WIDTH,this.IMAGE_HEIGHT)}get imageOriginMax(){return Math.max(this.IMAGE_ORIGIN_WIDTH,this.IMAGE_ORIGIN_HEIGHT)}createMagnifierCanvas(){this.isMagnifierVisible&&(this.magnifierCanvas=this.magnifierCanvas||document.createElement("canvas"),this.magnifierCtx=this.magnifierCanvas&&this.magnifierCanvas.getContext("2d",{willReadFrequently:!0}),this.magnifierCanvas.style.position="fixed",this.magnifierCanvas.style.pointerEvents="none",this.magnifierCanvas.style.zIndex="1000",this.magnifierCanvas.style.border="1px solid black",this.magnifierCanvas.style.borderRadius="50%",this.magnifierCanvas.style.width="100px",this.magnifierCanvas.style.height="100px",document.body.appendChild(this.magnifierCanvas))}createMagnifier(t,e){this.magnifierCanvas?this.updateMagnifier(t,e):this.createMagnifierCanvas()}updateMagnifier(t,e){if(this.magnifierCanvas&&this.magnifierCtx){const s=window.devicePixelRatio||1;if(this.magnifierCanvas.width=100,this.magnifierCanvas.height=100,this.magnifierCtx.clearRect(0,0,100,100),this.magnifierPosition&&this.magnifierPosition.length===2){const[r,l]=this.magnifierPosition;this.magnifierCanvas.style.left=`${r}px`,this.magnifierCanvas.style.top=`${l}px`}else this.magnifierCanvas.style.left=`${t+10}px`,this.magnifierCanvas.style.top=`${e+10}px`;const a=this.getImageDataFromCanvas(this.canvas,[t*s-100/2,e*s-100/2,100,100]),o=this.magnifierCanvas.getContext("2d",{willReadFrequently:!0}).createImageData(this.magnifierCanvas.width,this.magnifierCanvas.height);let c=0;for(let r=0;r<100;r+=1)for(let l=0;l<100;l+=1){for(let g=r;g<r+1;g++)for(let I=l;I<l+1;I++){const n=(g*100+I)*4;o.data[n]=a.data[c],o.data[n+1]=a.data[c+1],o.data[n+2]=a.data[c+2],o.data[n+3]=a.data[c+3]}c+=4}this.magnifierCanvas.getContext("2d",{willReadFrequently:!0}).putImageData(o,0,0),this.magnifierCtx.strokeStyle="rgba(0, 0, 0, 0.5)",this.magnifierCtx.lineWidth=2,this.magnifierCtx.strokeRect(0,0,100,100)}}destroyMagnifier(){this.magnifierCanvas&&(this.magnifierCanvas.remove(),this.magnifierCanvas=null,this.magnifierCtx=null)}getImageDataFromCanvas(t,[e,i,s,a]){return t.getContext("2d",{willReadFrequently:!0}).getImageData(e,i,s,a)}mergeEvent(t){var o,c;let e=0,i=0,s=0,a=0;if(this.isMobile&&t.touches){const{clientX:r,clientY:l}=t.touches[0],g=t.target,{left:I,top:n}=g.getBoundingClientRect();if(e=Math.round(r-I),i=Math.round(l-n),((o=t.touches)==null?void 0:o.length)===2){const{clientX:d=0,clientY:u=0}=t.touches[1]||{};s=Math.round(Math.abs((d-r)/2+r)-I),a=Math.round(Math.abs((u-l)/2+l)-n)}else((c=t.touches)==null?void 0:c.length)===1&&(s=Math.round(r-I),a=Math.round(l-n))}else e=t.offsetX,i=t.offsetY;return{...t,mouseX:e,mouseY:i,mouseCX:s,mouseCY:a}}handleLoad(){this.emit("load",this.image.src),this.IMAGE_ORIGIN_WIDTH=this.IMAGE_WIDTH=this.image.width,this.IMAGE_ORIGIN_HEIGHT=this.IMAGE_HEIGHT=this.image.height,this.fitZoom()}handleContextmenu(t){t.preventDefault(),this.evt=t,this.lock}handleMousewheel(t){if(t.stopPropagation(),this.evt=t,this.lock||!this.scrollZoom)return;const{mouseX:e,mouseY:i}=this.mergeEvent(t);this.mouse=[e,i],this.setScale(t.deltaY<0,!0)}handleMouseDown(t){var r,l,g;if(t.stopPropagation(),this.evt=t,this.lock)return;const{mouseX:e,mouseY:i,mouseCX:s,mouseCY:a}=this.mergeEvent(t),o=Math.round(e/this.scale),c=Math.round(i/this.scale);if(this.mouse=this.isMobile&&((r=t.touches)==null?void 0:r.length)===2?[s,a]:[e,i],this.remmberOrigin=[e-this.originX,i-this.originY],!this.isMobile&&t.buttons===1||this.isMobile&&((l=t.touches)==null?void 0:l.length)===1){const I=this.activeShape.ctrlsData||[];if(this.ctrlIndex=I.findIndex(n=>this.isPointInCircle(this.mouse,n,this.ctrlRadius)),this.ctrlIndex>-1&&!this.readonly){const[n,d]=I[this.ctrlIndex];this.activeShape.type===2&&this.activeShape.coor.length>2&&this.ctrlIndex===0&&this.handleDblclick(t),this.remmber=[[o-n,c-d]]}else if(this.isInBackground(t)){if(this.activeShape.creating&&!this.readonly){if([2,4].includes(this.activeShape.type)){const[n,d]=this.activeShape.coor[this.activeShape.coor.length-1];if(n!==o&&d!==c){const u=Math.round(o-this.originX/this.scale),f=Math.round(c-this.originY/this.scale);this.activeShape.coor.push([u,f])}}}else if(this.createType!==0&&!this.readonly&&!this.isCtrlKey){let n;const d=Math.round(o-this.originX/this.scale),u=Math.round(c-this.originY/this.scale),f=[d,u];switch(this.createType){case 1:n=new C({coor:[f,f]},this.dataset.length),n.creating=!0;break;case 2:n=new D({coor:[f]},this.dataset.length),n.creating=!0;break;case 3:n=new k({coor:f},this.dataset.length),this.emit("add",n);break;case 4:n=new _({coor:[f]},this.dataset.length),n.creating=!0;break;case 5:n=new W({coor:f},this.dataset.length),n.creating=!0;break;case 6:n=new A({coor:[f,f]},this.dataset.length),n.creating=!0;break}this.dataset.forEach(v=>{v.active=!1}),n.active=!0,this.dataset.push(n)}else{const[n,d]=this.hitOnShape(this.mouse);if(n>-1){if(d.dragging=!0,this.dataset.forEach((u,f)=>u.active=f===n),this.dataset.splice(n,1),this.dataset.push(d),!this.readonly)if(this.remmber=[],[3,5].includes(d.type)){const[u,f]=d.coor;this.remmber=[[o-u,c-f]]}else d.coor.forEach(u=>{this.remmber.push([o-u[0],c-u[1]])});this.emit("select",d)}else this.activeShape.active=!1,this.dataset.sort((u,f)=>u.index-f.index),this.emit("select",null)}this.update()}}else if(!this.isMobile&&t.buttons===2||this.isMobile&&((g=t.touches)==null?void 0:g.length)===3&&!this.readonly){if([6].includes(this.activeShape.type)&&this.gridMenuEnable){const I=prompt("x 行 y 列 x,y",[this.activeShape.row,this.activeShape.col].join(","));if(typeof I=="string"){const[n,d]=I.split(",");/^[1-9]\d*$/.test(n)&&/^[1-9]\d*$/.test(d)&&(this.activeShape.row=Number(n),this.activeShape.col=Number(d),this.update())}}this.emit("contextmenu",t)}}handleMouseMove(t){var r,l,g,I;if(t.stopPropagation(),this.evt=t,this.lock)return;const{mouseX:e,mouseY:i,mouseCX:s,mouseCY:a}=this.mergeEvent(t),o=Math.round(e/this.scale),c=Math.round(i/this.scale);if(this.mouse=this.isMobile&&((r=t.touches)==null?void 0:r.length)===2?[s,a]:[e,i],(!this.isMobile&&t.buttons===1||this.isMobile&&((l=t.touches)==null?void 0:l.length)===1)&&this.activeShape.type){if(this.ctrlIndex>-1&&this.remmber.length&&(this.isInBackground(t)||this.activeShape.type===5)){const[[n,d]]=this.remmber;if([1,6].includes(this.activeShape.type)){const[[u,f],[v,S]]=this.activeShape.coor;let x=[];switch(this.ctrlIndex){case 0:x=[[o-n,c-d],[v,S]];break;case 1:x=[[u,c-d],[v,S]];break;case 2:x=[[u,c-d],[o-n,S]];break;case 3:x=[[u,f],[o-n,S]];break;case 4:x=[[u,f],[o-n,c-d]];break;case 5:x=[[u,f],[v,c-d]];break;case 6:x=[[o-n,f],[v,c-d]];break;case 7:x=[[o-n,f],[v,S]];break}let[[m,T],[b,E]]=x;(m<0||b<0||T<0||E<0||b>this.IMAGE_ORIGIN_WIDTH||E>this.IMAGE_ORIGIN_HEIGHT)&&(m<0&&(m=0),b<0&&(b=0),T<0&&(T=0),E<0&&(E=0),b>this.IMAGE_ORIGIN_WIDTH&&(b=this.IMAGE_ORIGIN_WIDTH),E>this.IMAGE_ORIGIN_HEIGHT&&(E=this.IMAGE_ORIGIN_HEIGHT)),b-m>=this.MIN_WIDTH&&E-T>=this.MIN_HEIGHT?this.activeShape.coor=[[m,T],[b,E]]:this.emit("warn",`Width cannot be less than ${this.MIN_WIDTH},Height cannot be less than${this.MIN_HEIGHT}。`)}else if([2,4].includes(this.activeShape.type)){const u=Math.round(o-this.originX/this.scale),f=Math.round(c-this.originY/this.scale),v=[u,f];this.activeShape.coor.splice(this.ctrlIndex,1,v)}else if(this.activeShape.type===5){const f=Math.round(o-this.originX/this.scale)-this.activeShape.coor[0];f>=this.MIN_RADIUS&&(this.activeShape.radius=f)}if(this.isMagnifierVisible){const[u,f]=this.isMobile?[s,a]:[e,i];this.createMagnifier(u,f)}}else if(this.activeShape.dragging&&!this.readonly){if(this.isMagnifierVisible&&this.activeShape.type===3){const[v,S]=this.isMobile?[s,a]:[e,i];this.createMagnifier(v,S)}let n=[],d=!0;const u=this.IMAGE_ORIGIN_WIDTH||this.WIDTH,f=this.IMAGE_ORIGIN_HEIGHT||this.HEIGHT;if([3,5].includes(this.activeShape.type)){const[v,S]=this.remmber[0],x=o-v,m=c-S;(x<0||x>u||m<0||m>f)&&(d=!1),n=[x,m]}else for(let v=0;v<this.activeShape.coor.length;v++){const S=this.remmber[v],x=o-S[0],m=c-S[1];(x<0||x>u||m<0||m>f)&&(d=!1),n.push([x,m])}d&&(this.activeShape.coor=n)}else if(this.activeShape.creating&&this.isInBackground(t)){const n=Math.round(o-this.originX/this.scale),d=Math.round(c-this.originY/this.scale);if([1,6].includes(this.activeShape.type))this.activeShape.coor.splice(1,1,[n,d]);else if(this.activeShape.type===5){const[u,f]=this.activeShape.coor,v=Math.sqrt((u-n)**2+(f-d)**2);this.activeShape.radius=v}}this.update()}else if([2,4].includes(this.activeShape.type)&&this.activeShape.creating)this.update();else if(!this.isMobile&&t.buttons===2&&t.which===3||this.isMobile&&((g=t.touches)==null?void 0:g.length)===1&&!this.isTouch2)this.originX=Math.round(e-this.remmberOrigin[0]),this.originY=Math.round(i-this.remmberOrigin[1]),this.update();else if(this.isMobile&&((I=t.touches)==null?void 0:I.length)===2){this.isTouch2=!0;const n=t.touches[0],d=t.touches[1],u=this.scaleTouchStore;this.scaleTouchStore=Math.abs((d.clientX-n.clientX)*(d.clientY-n.clientY)),this.setScale(this.scaleTouchStore>u,!0)}}handleMouseUp(t){var e;if(t.stopPropagation(),this.evt=t,!this.lock){if(this.destroyMagnifier(),this.isMobile){if(((e=t.touches)==null?void 0:e.length)===0&&(this.isTouch2=!1),Date.now()-this.dblTouchStore<this.dblTouch){this.handleDblclick(t);return}this.dblTouchStore=Date.now()}if(this.remmber=[],this.activeShape.type!==0&&!this.isCtrlKey&&(this.activeShape.dragging=!1,this.activeShape.creating)){if([1,6].includes(this.activeShape.type)){const[[i,s],[a,o]]=this.activeShape.coor;Math.abs(i-a)<this.MIN_WIDTH||Math.abs(s-o)<this.MIN_HEIGHT?(this.dataset.pop(),this.emit("warn",`Width cannot be less than ${this.MIN_WIDTH},Height cannot be less than ${this.MIN_HEIGHT}`)):(this.activeShape.coor=[[Math.min(i,a),Math.min(s,o)],[Math.max(i,a),Math.max(s,o)]],this.activeShape.creating=!1,this.emit("add",this.activeShape))}else this.activeShape.type===5&&(this.activeShape.radius<this.MIN_RADIUS?(this.dataset.pop(),this.emit("warn",`Radius cannot be less than ${this.MIN_WIDTH}`)):(this.activeShape.creating=!1,this.emit("add",this.activeShape)));this.update()}}}handleDblclick(t){if(t.stopPropagation(),this.evt=t,!this.lock)if([2,4].includes(this.activeShape.type)){const e=this.activeShape.type===2&&this.activeShape.coor.length>2,i=this.activeShape.type===4&&this.activeShape.coor.length>1;(e||i)&&(this.emit("add",this.activeShape),this.activeShape.creating=!1,this.update())}else[6].includes(this.activeShape.type)&&this.activeShape.active&&(this.activeShape.gridRects.forEach(e=>{if(this.isPointInRect(this.mouse,e.coor)){const i=this.activeShape.selected.findIndex(s=>e.index===s);i>-1?this.activeShape.selected.splice(i,1):this.activeShape.selected.push(e.index)}}),this.update())}handleKeydown(t){t.code===this.ctrlCode&&(this.isCtrlKey=!0)}handleKeyup(t){t.code===this.ctrlCode&&(this.isCtrlKey=!1),this.evt=t,!(this.lock||document.activeElement!==document.body||this.readonly)&&this.activeShape.type&&([2,4].includes(this.activeShape.type)&&t.key==="Escape"?(this.activeShape.coor.length>1&&this.activeShape.creating?this.activeShape.coor.pop():this.deleteByIndex(this.activeShape.index),this.update()):t.key==="Backspace"&&this.deleteByIndex(this.activeShape.index))}initSetting(){const t=window.devicePixelRatio||1;this.image.crossOrigin="anonymous",this.canvas.style.userSelect="none",this.ctx=this.ctx||this.canvas.getContext("2d",{alpha:this.alpha}),this.WIDTH=Math.round(this.canvas.clientWidth),this.HEIGHT=Math.round(this.canvas.clientHeight),this.canvas.width=this.WIDTH*t,this.canvas.height=this.HEIGHT*t,this.canvas.style.width=this.WIDTH+"px",this.canvas.style.height=this.HEIGHT+"px",this.offScreen.width=this.WIDTH,this.offScreen.height=this.HEIGHT,this.offScreenCtx=this.offScreenCtx||this.offScreen.getContext("2d",{willReadFrequently:!0}),this.ctx.scale(t,t)}initEvents(){this.image.addEventListener("load",this.handleLoad),this.canvas.addEventListener("touchstart",this.handleMouseDown),this.canvas.addEventListener("touchmove",this.handleMouseMove),this.canvas.addEventListener("touchend",this.handleMouseUp),this.canvas.addEventListener("contextmenu",this.handleContextmenu),this.canvas.addEventListener("mousewheel",this.handleMousewheel),this.canvas.addEventListener("wheel",this.handleMousewheel),this.canvas.addEventListener("mousedown",this.handleMouseDown),this.canvas.addEventListener("mousemove",this.handleMouseMove),this.canvas.addEventListener("mouseup",this.handleMouseUp),this.canvas.addEventListener("dblclick",this.handleDblclick),document.body.addEventListener("keydown",this.handleKeydown,!0),document.body.addEventListener("keyup",this.handleKeyup,!0)}setImage(t){this.image.src=t}setData(t){setTimeout(()=>{const e=[];t.forEach((i,s)=>{if(Object.prototype.toString.call(i).includes("Object")){let a;switch(i.type){case 1:a=new C(i,s);break;case 2:a=new D(i,s);break;case 3:a=new k(i,s);break;case 4:a=new _(i,s);break;case 5:a=new W(i,s);break;case 6:a=new A(i,s);break;default:console.warn("Invalid shape",i);break}[1,2,3,4,5,6].includes(i.type)&&e.push(a)}else console.warn("Shape must be an enumerable Object.",i)}),this.dataset=e,this.update()})}hitOnShape(t){let e=-1,i;for(let s=this.dataset.length-1;s>-1;s--){const a=this.dataset[s];if(!a.hide&&(a.type===3&&this.isPointInCircle(t,a.coor,this.ctrlRadius)||a.type===5&&this.isPointInCircle(t,a.coor,a.radius*this.scale)||a.type===1&&this.isPointInRect(t,a.coor)||a.type===2&&this.isPointInPolygon(t,a.coor)||a.type===4&&this.isPointInLine(t,a.coor)||a.type===6&&this.isPointInRect(t,a.coor))){if(this.focusMode&&!a.active)continue;e=s,i=a;break}}return[e,i]}isInBackground(t){const{mouseX:e,mouseY:i}=this.mergeEvent(t);return e>=this.originX&&i>=this.originY&&e<=this.originX+this.IMAGE_ORIGIN_WIDTH*this.scale&&i<=this.originY+this.IMAGE_ORIGIN_HEIGHT*this.scale}isPointInRect(t,e){const[i,s]=t,[[a,o],[c,r]]=e.map(l=>l.map(g=>g*this.scale));return a+this.originX<=i&&i<=c+this.originX&&o+this.originY<=s&&s<=r+this.originY}isPointInPolygon(t,e){this.offScreenCtx.save(),this.offScreenCtx.clearRect(0,0,this.WIDTH,this.HEIGHT),this.offScreenCtx.translate(this.originX,this.originY),this.offScreenCtx.beginPath(),e.forEach((a,o)=>{const[c,r]=a.map(l=>Math.round(l*this.scale));o===0?this.offScreenCtx.moveTo(c,r):this.offScreenCtx.lineTo(c,r)}),this.offScreenCtx.closePath(),this.offScreenCtx.fill();const i=this.offScreenCtx.getImageData(0,0,this.WIDTH,this.HEIGHT),s=(t[1]-1)*this.WIDTH*4+t[0]*4;return this.offScreenCtx.restore(),i.data[s+3]!==0}isPointInCircle(t,e,i){const[s,a]=t,[o,c]=e.map(l=>l*this.scale);return Math.sqrt((o+this.originX-s)**2+(c+this.originY-a)**2)<=i}isPointInLine(t,e){this.offScreenCtx.save(),this.offScreenCtx.clearRect(0,0,this.WIDTH,this.HEIGHT),this.offScreenCtx.translate(this.originX,this.originY),this.offScreenCtx.lineWidth=this.lineWidth>5?this.lineWidth:5,this.offScreenCtx.beginPath(),e.forEach((a,o)=>{const[c,r]=a.map(l=>Math.round(l*this.scale));o===0?this.offScreenCtx.moveTo(c,r):this.offScreenCtx.lineTo(c,r)}),this.offScreenCtx.stroke();const i=this.offScreenCtx.getImageData(0,0,this.WIDTH,this.HEIGHT),s=(t[1]-1)*this.WIDTH*4+t[0]*4;return this.offScreenCtx.restore(),i.data[s+3]!==0}isNested(t,e){return M(t,e)}drawRect(t,e){if(t.coor.length!==2)return;const{strokeStyle:i,fillStyle:s,active:a,creating:o,coor:c,lineWidth:r}=t,[[l,g],[I,n]]=c.map(f=>f.map(v=>Math.round(v*this.scale)));this.ctx.save(),this.ctx.lineWidth=r||this.lineWidth,this.ctx.fillStyle=e!=null&&e.isSelected?e==null?void 0:e.selectedFillStyle:s||this.fillStyle,this.ctx.strokeStyle=a||o?this.activeStrokeStyle:i||this.strokeStyle;const d=I-l,u=n-g;o||this.ctx.fillRect(l,g,d,u),this.ctx.strokeRect(l,g,d,u),this.ctx.restore(),this.drawLabel(c[0],t)}drawPolygon(t){const{strokeStyle:e,fillStyle:i,active:s,creating:a,coor:o,lineWidth:c}=t;if(this.ctx.save(),this.ctx.lineJoin="round",this.ctx.lineWidth=c||this.lineWidth,this.ctx.fillStyle=i||this.fillStyle,this.ctx.strokeStyle=s||a?this.activeStrokeStyle:e||this.strokeStyle,this.ctx.beginPath(),o.forEach((r,l)=>{const[g,I]=r.map(n=>Math.round(n*this.scale));l===0?this.ctx.moveTo(g,I):this.ctx.lineTo(g,I)}),a){const[r,l]=this.mouse||[];this.ctx.lineTo(r-this.originX,l-this.originY)}else o.length>2&&this.ctx.closePath();this.ctx.fill(),this.ctx.stroke(),this.ctx.restore(),this.drawLabel(o[0],t)}drawDot(t){const{strokeStyle:e,fillStyle:i,active:s,coor:a,lineWidth:o}=t,[c,r]=a.map(l=>l*this.scale);this.ctx.save(),this.ctx.lineWidth=o||this.lineWidth,this.ctx.fillStyle=i||this.ctrlFillStyle,this.ctx.strokeStyle=s?this.activeStrokeStyle:e||this.strokeStyle,this.ctx.beginPath(),this.ctx.arc(c,r,this.ctrlRadius,0,2*Math.PI,!0),this.ctx.fill(),this.ctx.arc(c,r,this.ctrlRadius,0,2*Math.PI,!0),this.ctx.stroke(),this.ctx.restore(),this.drawLabel(a,t)}drawCirle(t){const{strokeStyle:e,fillStyle:i,active:s,coor:a,label:o,creating:c,radius:r,ctrlsData:l,lineWidth:g}=t,[I,n]=a.map(d=>d*this.scale);this.ctx.save(),this.ctx.lineWidth=g||this.lineWidth,this.ctx.fillStyle=i||this.fillStyle,this.ctx.strokeStyle=s||c?this.activeStrokeStyle:e||this.strokeStyle,this.ctx.beginPath(),this.ctx.arc(I,n,r*this.scale,0,2*Math.PI,!0),this.ctx.fill(),this.ctx.arc(I,n,r*this.scale,0,2*Math.PI,!0),this.ctx.stroke(),this.ctx.restore(),this.drawLabel(l[0],t)}drawLine(t){const{strokeStyle:e,active:i,creating:s,coor:a,lineWidth:o}=t;if(this.ctx.save(),this.ctx.lineJoin="round",this.ctx.lineWidth=o||this.lineWidth,this.ctx.strokeStyle=i||s?this.activeStrokeStyle:e||this.strokeStyle,this.ctx.beginPath(),a.forEach((c,r)=>{const[l,g]=c.map(I=>Math.round(I*this.scale));r===0?this.ctx.moveTo(l,g):this.ctx.lineTo(l,g)}),s){const[c,r]=this.mouse||[];this.ctx.lineTo(c-this.originX,r-this.originY)}this.ctx.stroke(),this.ctx.restore(),this.drawLabel(a[0],t)}drawGrid(t){if(t.coor.length!==2)return;const{strokeStyle:e,fillStyle:i,active:s,creating:a,coor:o,lineWidth:c}=t,[[r,l],[g,I]]=o.map(u=>u.map(f=>Math.round(f*this.scale)));this.ctx.save(),this.ctx.lineWidth=c||this.lineWidth,this.ctx.fillStyle=i||this.fillStyle,this.ctx.strokeStyle=s||a?this.activeStrokeStyle:e||this.strokeStyle,t.gridRects.forEach((u,f)=>{var v;this.drawRect(u,{selectedFillStyle:t.selectedFillStyle||this.gridSelectedFillStyle,isSelected:(v=t.selected)==null?void 0:v.includes(f)})});const n=g-r,d=I-l;a||this.ctx.fillRect(r,l,n,d),this.ctx.strokeRect(r,l,n,d),this.ctx.restore(),this.drawLabel(o[0],t)}drawCtrl(t){const[e,i]=t.map(s=>s*this.scale);this.ctx.save(),this.ctx.beginPath(),this.ctx.fillStyle=this.ctrlFillStyle,this.ctx.strokeStyle=this.ctrlStrokeStyle,this.ctx.arc(e,i,this.ctrlRadius,0,2*Math.PI,!0),this.ctx.fill(),this.ctx.arc(e,i,this.ctrlRadius,0,2*Math.PI,!0),this.ctx.stroke(),this.ctx.restore()}drawCtrlList(t){t.ctrlsData.forEach((e,i)=>{t.type===5?i===1&&this.drawCtrl(e):this.drawCtrl(e)})}drawLabel(t,e){const{label:i="",labelFillStyle:s="",labelFont:a="",textFillStyle:o="",hideLabel:c,labelUp:r,lineWidth:l}=e,g=typeof c=="boolean"?c:this.hideLabel,I=typeof r=="boolean"?r:this.labelUp,n=l||this.lineWidth;if(i.length&&!g){this.ctx.font=a||this.labelFont;const d=4,u=4,f=i.length<this.labelMaxLen+1?i:`${i.slice(0,this.labelMaxLen)}...`,v=this.ctx.measureText(f),S=parseInt(this.ctx.font)-4,x=v.width+d*2,m=S+u*2,[T,b]=t.map(Y=>Y*this.scale),E=this.IMAGE_ORIGIN_WIDTH-t[0]<x/this.scale,O=this.IMAGE_ORIGIN_HEIGHT-t[1]<m/this.scale,X=t[1]>m/this.scale,R=I?X:O;this.ctx.save(),this.ctx.fillStyle=s||this.labelFillStyle,this.ctx.fillRect(E?T-v.width-d-n/2:T+n/2,R?b-m-n/2:b+n/2,x,m),this.ctx.fillStyle=o||this.textFillStyle,this.ctx.fillText(f,E?T-v.width:T+d+n/2,R?b-m+S+u:b+S+u+n/2,180),this.ctx.restore()}}update(){window.cancelAnimationFrame(this.timer),this.timer=window.requestAnimationFrame(()=>{this.ctx.save(),this.ctx.clearRect(0,0,this.WIDTH,this.HEIGHT),this.ctx.translate(this.originX,this.originY),this.IMAGE_WIDTH&&this.IMAGE_HEIGHT&&this.ctx.drawImage(this.image,0,0,this.IMAGE_WIDTH,this.IMAGE_HEIGHT);const t=this.focusMode?this.activeShape.type?[this.activeShape]:[]:this.dataset;for(let e=0;e<t.length;e++){const i=t[e];if(!i.hide)switch(i.type){case 1:this.drawRect(i);break;case 2:this.drawPolygon(i);break;case 3:this.drawDot(i);break;case 4:this.drawLine(i);break;case 5:this.drawCirle(i);break;case 6:this.drawGrid(i);break}}[1,2,4,5,6].includes(this.activeShape.type)&&!this.activeShape.hide&&this.drawCtrlList(this.activeShape),this.ctx.restore(),this.emit("updated",this.dataset)})}deleteByIndex(t){const e=this.dataset.findIndex(i=>i.index===t);e>-1&&(this.emit("delete",this.dataset[e]),this.dataset.splice(e,1),this.dataset.forEach((i,s)=>{i.index=s}),this.update())}calcStep(t=""){this.IMAGE_WIDTH<this.WIDTH&&this.IMAGE_HEIGHT<this.HEIGHT&&(t===""||t==="b")&&(this.setScale(!0,!1,!0),this.calcStep("b")),(this.IMAGE_WIDTH>this.WIDTH||this.IMAGE_HEIGHT>this.HEIGHT)&&(t===""||t==="s")&&(this.setScale(!1,!1,!0),this.calcStep("s"))}setScale(t,e=!1,i=!1){if(this.lock||!t&&this.imageMin<20||t&&this.IMAGE_WIDTH>this.imageOriginMax*100)return;t?this.scaleStep++:this.scaleStep--;let s=0,a=0;const[o,c]=this.mouse||[];e&&(s=(o-this.originX)/this.scale,a=(c-this.originY)/this.scale);const r=Math.abs(this.scaleStep),l=this.IMAGE_WIDTH;if(this.IMAGE_WIDTH=Math.round(this.IMAGE_ORIGIN_WIDTH*(this.scaleStep>=0?1.05:.95)**r),this.IMAGE_HEIGHT=Math.round(this.IMAGE_ORIGIN_HEIGHT*(this.scaleStep>=0?1.05:.95)**r),e)this.originX=o-s*this.scale,this.originY=c-a*this.scale;else{const g=this.IMAGE_WIDTH/l;this.originX=this.WIDTH/2-(this.WIDTH/2-this.originX)*g,this.originY=this.HEIGHT/2-(this.HEIGHT/2-this.originY)*g}i||this.update()}fitZoom(){this.calcStep(),this.IMAGE_HEIGHT/this.IMAGE_WIDTH>=this.HEIGHT/this.WIDTH?(this.IMAGE_WIDTH=this.IMAGE_ORIGIN_WIDTH/(this.IMAGE_ORIGIN_HEIGHT/this.HEIGHT),this.IMAGE_HEIGHT=this.HEIGHT):(this.IMAGE_WIDTH=this.WIDTH,this.IMAGE_HEIGHT=this.IMAGE_ORIGIN_HEIGHT/(this.IMAGE_ORIGIN_WIDTH/this.WIDTH)),this.originX=(this.WIDTH-this.IMAGE_WIDTH)/2,this.originY=(this.HEIGHT-this.IMAGE_HEIGHT)/2,this.update()}setFocusMode(t){this.focusMode=t,this.update()}destroy(){this.image.removeEventListener("load",this.handleLoad),this.canvas.removeEventListener("contextmenu",this.handleContextmenu),this.canvas.removeEventListener("mousewheel",this.handleMousewheel),this.canvas.removeEventListener("wheel",this.handleMousewheel),this.canvas.removeEventListener("mousedown",this.handleMouseDown),this.canvas.removeEventListener("touchend",this.handleMouseDown),this.canvas.removeEventListener("mousemove",this.handleMouseMove),this.canvas.removeEventListener("touchmove",this.handleMouseMove),this.canvas.removeEventListener("mouseup",this.handleMouseUp),this.canvas.removeEventListener("touchend",this.handleMouseUp),this.canvas.removeEventListener("dblclick",this.handleDblclick),document.body.removeEventListener("keydown",this.handleKeydown,!0),document.body.removeEventListener("keyup",this.handleKeyup,!0),this.canvas.width=this.WIDTH,this.canvas.height=this.HEIGHT,this.canvas.style.width=null,this.canvas.style.height=null,this.canvas.style.userSelect=null}resize(){this.canvas.width=null,this.canvas.height=null,this.canvas.style.width=null,this.canvas.style.height=null,this.initSetting(),this.update()}}return N});