image-annotation-drawer 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -68,6 +68,10 @@ export declare class Drawer {
68
68
  * 撤销上一步操作
69
69
  */
70
70
  withdraw(): void;
71
+ /**
72
+ * 调整 canvas 尺寸以适配容器大小变化
73
+ */
74
+ resize(): void;
71
75
  /**
72
76
  * 绑定事件监听器
73
77
  */
package/dist/index.esm.js CHANGED
@@ -1 +1 @@
1
- function t(t,e){const n=e.width>=0?e.start.x:e.start.x+e.width,i=e.height>=0?e.start.y:e.start.y+e.height,s=Math.abs(e.width),a=Math.abs(e.height);return t.x>=n&&t.x<=n+s&&t.y>=i&&t.y<=i+a}function e(t,e){if(e.length<3)return!1;let n=!1;for(let i=0,s=e.length-1;i<e.length;s=i++){const a=e[i].point.x,o=e[i].point.y,r=e[s].point.x,h=e[s].point.y;o>t.y!=h>t.y&&t.x<(r-a)*(t.y-o)/(h-o)+a&&(n=!n)}return n}function n(t){try{const e=new URL(t).pathname.toLowerCase();return e.endsWith(".png")?"png":e.endsWith(".jpg")?"jpg":e.endsWith(".jpeg")?"jpeg":e.endsWith(".webp")?"webp":e.endsWith(".gif")?"gif":e.endsWith(".bmp")?"bmp":e.endsWith(".svg")?"svg":"jpeg"}catch(t){return"jpeg"}}function i(t,e){const n=t.split(";base64,"),i=n[0].split(":")[1],s=window.atob(n[1]),a=s.length,o=new Uint8Array(a);for(let t=0;t<a;++t)o[t]=s.charCodeAt(t);const r=new Blob([o],{type:i});return new File([r],e,{type:i})}function s(t){return new Promise((e,n)=>{const i=t.split(";base64,");if(i.length<2)return void n(new Error("Invalid base64 string"));const s=i[0].split(":")[1],a=atob(i[1]),o=new ArrayBuffer(a.length),r=new Uint8Array(o);for(let t=0;t<a.length;t++)r[t]=a.charCodeAt(t);e(new Blob([o],{type:s}))})}function a(t,e){return t<2?e?.1:-.1:t<5?e?.05:-.05:e?.02:-.02}class o{constructor(){this.width=0,this.height=0,this.originalWidth=0,this.originalHeight=0,this.scale=1,this.minScale=1,this.maxScale=10,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}setSize(t,e){this.width=t,this.height=e}setOriginalSize(t,e){this.originalWidth=t,this.originalHeight=e}calculateInitialView(){if(0===this.originalWidth||0===this.originalHeight)return;const t=this.width/this.originalWidth,e=this.height/this.originalHeight;this.scale=Math.min(t,e),this.initialScale=this.scale,this.minScale=this.initialScale,this.offset={x:(this.width-this.originalWidth*this.scale)/2,y:(this.height-this.originalHeight*this.scale)/2},this.initialOffset=Object.assign({},this.offset),this.calculateBoundaries(),this.isInitialScale=!0}calculateBoundaries(){const t=this.originalWidth*this.scale,e=this.originalHeight*this.scale;this.maxOffsetX=0,this.maxOffsetY=0,this.minOffsetX=this.width-t,this.minOffsetY=this.height-e,this.minOffsetX>this.maxOffsetX&&([this.minOffsetX,this.maxOffsetX]=[this.maxOffsetX,this.minOffsetX]),this.minOffsetY>this.maxOffsetY&&([this.minOffsetY,this.maxOffsetY]=[this.maxOffsetY,this.minOffsetY])}constrainViewport(){this.offset.x>this.maxOffsetX?this.offset.x=this.maxOffsetX:this.offset.x<this.minOffsetX&&(this.offset.x=this.minOffsetX),this.offset.y>this.maxOffsetY?this.offset.y=this.maxOffsetY:this.offset.y<this.minOffsetY&&(this.offset.y=this.minOffsetY)}toImageCoordinates(t,e){return{x:(t-this.offset.x)/this.scale,y:(e-this.offset.y)/this.scale}}toCanvasCoordinates(t,e){return{x:this.offset.x+t*this.scale,y:this.offset.y+e*this.scale}}updateScale(t,e,n){const i=this.scale,s=(e-this.offset.x)/i,a=(n-this.offset.y)/i;this.scale=Math.max(this.minScale,Math.min(t,this.maxScale));const o=s*this.scale+this.offset.x,r=a*this.scale+this.offset.y;this.offset.x+=e-o,this.offset.y+=n-r,this.calculateBoundaries(),this.constrainViewport(),this.isInitialScale=this.scale===this.initialScale}resetToInitial(){this.scale=this.initialScale,this.offset=Object.assign({},this.initialOffset),this.calculateBoundaries(),this.isInitialScale=!0}updateOffset(t,e){this.offset.x+=t,this.offset.y+=e,this.constrainViewport()}reset(){this.scale=1,this.minScale=1,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}}class r{constructor(t){this.viewport=t,this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.drawStartPoint={x:0,y:0},this.tempPolygonPoint=null,this.selectedAnnotation=null,this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.annotationMoveStart={x:0,y:0},this.originalRect=null,this.originalPolygon=null,this.deleteHistory=[],this.strokeStyle="red",this.lineWidth=5,this.lineStyle="solid",this.vertexStyle={size:8,fillColor:"red",strokeColor:"white",strokeWidth:2,shape:"circle"},this.selectionStyle={strokeColor:"#00D9FF",fillColor:"rgba(0,217,255,0.15)",handleSize:12,handleColor:"#00D9FF"},this.colorConfig={rect:"red",polygon:"red",default:"red"},this.applyColorConfig()}setColorConfig(t){this.colorConfig="string"==typeof t?{rect:t,polygon:t,default:t}:Object.assign(Object.assign({},this.colorConfig),t),this.applyColorConfig()}getColorConfig(){return Object.assign({},this.colorConfig)}applyColorConfig(){this.strokeStyle=this.colorConfig.default||"red"}getColorForType(t){return this.colorConfig[t]||this.colorConfig.default||"red"}getCurrentStyle(){return{strokeColor:this.strokeStyle,lineWidth:this.lineWidth,lineStyle:this.lineStyle,vertexStyle:Object.assign({},this.vertexStyle)}}setLineStyle(t){this.lineStyle=t}setVertexStyle(t){this.vertexStyle=Object.assign(Object.assign({},this.vertexStyle),t),t.fillColor&&(this.strokeStyle=t.fillColor)}getLineStyle(){return this.lineStyle}getVertexStyle(){return Object.assign({},this.vertexStyle)}getAnnotationStyle(t){return t.style||this.getCurrentStyle()}startRectDrawing(t){this.isDrawing=!0,this.drawStartPoint=t,this.operate={type:"rect",data:[{start:Object.assign({},t),width:0,height:0}],status:"pending"}}updateRectDrawing(t){if(!this.isDrawing||"rect"!==this.operate.type)return;const e=this.operate.data[0];e.width=t.x-this.drawStartPoint.x,e.height=t.y-this.drawStartPoint.y}finishRectDrawing(){if(!this.isDrawing||"rect"!==this.operate.type)return!1;const t=this.operate.data[0];if(Math.abs(t.width)>5&&Math.abs(t.height)>5){const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[]}return this.operate.data=[],this.isDrawing=!1,!0}startPolygonDrawing(t){this.isDrawing=!0,this.operate={type:"polygon",data:[{point:t}],status:"pending"},this.tempPolygonPoint=t}addPolygonPoint(t){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;const e=this.operate.data.length>0?this.operate.data[this.operate.data.length-1]:null;return!(e&&Math.abs(e.point.x-t.x)<=5&&Math.abs(e.point.y-t.y)<=5)&&(this.operate.data.push({point:t}),!0)}updatePolygonTempPoint(t){this.tempPolygonPoint=t}finishPolygonDrawing(){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;if(this.operate.data.length>=3){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[]}return this.operate={type:"polygon",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,!0}cancelDrawing(){if(this.isDrawing&&"polygon"===this.operate.type&&this.operate.data.length>=2){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t)}this.operate.data=[],this.isDrawing=!1,this.tempPolygonPoint=null}withdraw(){if(this.operate.data.length>0)return"polygon"===this.operate.type?(this.operate.data.pop(),0===this.operate.data.length&&(this.isDrawing=!1)):(this.operate.data=[],this.isDrawing=!1),!0;if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.recordList.splice(e,0,t),!0}return this.recordList.length>0&&(this.recordList.pop(),!0)}selectAnnotation(t){if(t<0||t>=this.recordList.length)return this.deselectAnnotation(),!1;const e=this.recordList[t];return this.selectedAnnotation={index:t,type:e.type},!0}deselectAnnotation(){this.selectedAnnotation=null,this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}deleteSelectedAnnotation(){if(!this.selectedAnnotation)return!1;const t=this.selectedAnnotation.index,e=this.recordList[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.recordList.splice(t,1),this.deselectAnnotation(),!0}startMovingAnnotation(t){return!!this.selectedAnnotation&&(this.isMovingAnnotation=!0,this.annotationMoveStart={x:t.clientX,y:t.clientY},!0)}moveSelectedAnnotation(t,e){if(!this.selectedAnnotation)return!1;const n=this.recordList[this.selectedAnnotation.index];if(!n)return!1;if("rect"===n.type){const i=n.data[0];i.start.x+=t,i.start.y+=e}else if("polygon"===n.type){n.data.forEach(n=>{n.point.x+=t,n.point.y+=e})}return!0}finishMovingAnnotation(){this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}startResizing(t,e){if(!this.selectedAnnotation)return!1;this.activeHandle=t,this.isResizing=!0;const n=this.recordList[this.selectedAnnotation.index];return"rect"===n.type?this.originalRect=Object.assign({},n.data[0]):"polygon"===n.type&&(this.originalPolygon=n.data.map(t=>({point:Object.assign({},t.point)}))),!0}resizeRect(t){if(!this.selectedAnnotation||"rect"!==this.selectedAnnotation.type||!this.originalRect||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data[0],n=this.originalRect,i=n.start.x,s=n.start.x+n.width,a=n.start.y,o=n.start.y+n.height;let r,h;switch(this.activeHandle.index){case 0:r=s,h=o;break;case 1:r=i,h=o;break;case 2:r=s,h=a;break;case 3:r=i,h=a;break;default:return!1}const l=Math.min(t.x,r),c=Math.max(t.x,r),d=Math.min(t.y,h),g=Math.max(t.y,h);e.start.x=l,e.start.y=d,e.width=c-l,e.height=g-d;const x=t.x<r,f=t.y<h;return 0===this.activeHandle.index?x||f?!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2):this.activeHandle.index=3:1===this.activeHandle.index?x&&!f?this.activeHandle.index=2:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):2===this.activeHandle.index?!x&&f?this.activeHandle.index=1:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):3===this.activeHandle.index&&(x&&f?this.activeHandle.index=0:!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2)),this.originalRect=Object.assign({},e),!0}resizePolygon(t){if(!this.selectedAnnotation||"polygon"!==this.selectedAnnotation.type||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data,n=this.activeHandle.index;return n>=0&&n<e.length&&(e[n].point.x=t.x,e[n].point.y=t.y,!0)}getAnnotationAtPoint(n){for(let i=this.recordList.length-1;i>=0;i--){const s=this.recordList[i];if("rect"===s.type){if(t(n,s.data[0]))return{index:i,type:"rect"}}else if("polygon"===s.type){if(e(n,s.data))return{index:i,type:"polygon"}}}return null}getHandleAtPoint(t,e){if(!this.selectedAnnotation)return null;const n=this.recordList[this.selectedAnnotation.index],i=this.selectionStyle.handleSize/2;if("rect"===n.type){const s=n.data[0],a=this.viewport.offset.x+s.start.x*this.viewport.scale,o=this.viewport.offset.y+s.start.y*this.viewport.scale,r=s.width*this.viewport.scale,h=s.height*this.viewport.scale,l=[{x:a,y:o,index:0},{x:a+r,y:o,index:1},{x:a,y:o+h,index:2},{x:a+r,y:o+h,index:3}];for(const n of l)if(t>=n.x-i&&t<=n.x+i&&e>=n.y-i&&e<=n.y+i)return{type:"rect-corner",index:n.index}}else if("polygon"===n.type){const s=n.data;for(let n=0;n<s.length;n++){const a=s[n],o=this.viewport.offset.x+a.point.x*this.viewport.scale,r=this.viewport.offset.y+a.point.y*this.viewport.scale;if(t>=o-i&&t<=o+i&&e>=r-i&&e<=r+i)return{type:"polygon-vertex",index:n}}}return null}clear(){this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,this.deselectAnnotation(),this.deleteHistory=[]}getAnnotations(){return[...this.recordList]}getSelectedAnnotation(){if(!this.selectedAnnotation)return null;const t=this.recordList[this.selectedAnnotation.index];return t?{index:this.selectedAnnotation.index,type:this.selectedAnnotation.type,data:t}:null}}class h{constructor(t,e,n,i){this.viewport=t,this.container=e,this.ctx=n,this.renderCallback=i,this.textAnnotations=[],this.editingTextIndex=null,this.currentEditingIndex=null,this.isTextMoving=!1,this.textMoveStart={x:0,y:0},this.textBeforeEditing="",this.selectedTextIndex=null,this.textInput=null,this.deleteHistory=[],this.defaultInputStyle={border:"2px solid #00D9FF",borderRadius:"6px",padding:"6px 10px",fontSize:"16px",fontFamily:"Arial, sans-serif",backgroundColor:"#ffffff",color:"#333",boxShadow:"0 4px 12px rgba(0,0,0,0.3)",minWidth:"60px",maxWidth:"200px"},this.textStyle={font:"16px Arial",color:"#FFD700",padding:6,backgroundColor:"rgba(0,0,0,0.6)",borderRadius:4,selectedBorderColor:"#00D9FF",selectedBackgroundColor:"rgba(0,217,255,0.15)",inputStyle:Object.assign({},this.defaultInputStyle)},this.createTextInput()}createTextInput(){this.textInput=document.createElement("input"),this.textInput.type="text",this.textInput.style.position="absolute",this.textInput.style.zIndex="99999",this.textInput.style.display="none",this.textInput.style.outline="none",this.textInput.style.width="fit-content",this.textInput.placeholder="输入文字...",this.applyInputStyle(),this.textInput.addEventListener("blur",()=>{this.finishEditing(),this.renderCallback&&this.renderCallback()}),this.textInput.addEventListener("keydown",t=>{t.stopPropagation(),"Enter"===t.key?(this.finishEditing(),this.renderCallback&&this.renderCallback()):"Escape"===t.key?(t.preventDefault(),this.cancelEditing()):"Delete"===t.key&&""===this.textInput.value&&(t.preventDefault(),this.deleteEditingAnnotation())}),this.textInput.addEventListener("input",()=>{this.adjustInputWidth()}),this.container.appendChild(this.textInput)}applyInputStyle(){if(!this.textInput)return;const t=Object.assign(Object.assign({},this.defaultInputStyle),this.textStyle.inputStyle);this.textInput.style.border=t.border,this.textInput.style.borderRadius=t.borderRadius,this.textInput.style.padding=t.padding,this.textInput.style.fontSize=t.fontSize,this.textInput.style.fontFamily=t.fontFamily,this.textInput.style.backgroundColor=t.backgroundColor,this.textInput.style.color=t.color,this.textInput.style.boxShadow=t.boxShadow,this.textInput.style.minWidth=t.minWidth,this.textInput.style.maxWidth=t.maxWidth}setTextStyle(t){this.textStyle=Object.assign(Object.assign({},this.textStyle),t),this.applyInputStyle()}setInputStyle(t){this.textStyle.inputStyle=Object.assign(Object.assign({},this.textStyle.inputStyle),t),this.applyInputStyle()}setSelectionStyle(t){void 0!==t.selectedBorderColor&&(this.textStyle.selectedBorderColor=t.selectedBorderColor),void 0!==t.selectedBackgroundColor&&(this.textStyle.selectedBackgroundColor=t.selectedBackgroundColor)}getCurrentStyle(){return{font:this.textStyle.font,color:this.textStyle.color,backgroundColor:this.textStyle.backgroundColor}}addTextAnnotation(t,e,n=""){var i;this.ctx.font=this.textStyle.font;const s=n||"输入文字...",a=this.ctx.measureText(s);let o;if(a.actualBoundingBoxAscent&&a.actualBoundingBoxDescent)o=a.actualBoundingBoxAscent+a.actualBoundingBoxDescent;else{o=1.2*parseInt((null===(i=this.textStyle.font.match(/\d+/))||void 0===i?void 0:i[0])||"16")}const r={position:{x:t,y:e},text:n,style:this.getCurrentStyle(),width:Math.max(a.width,60),height:o};this.textAnnotations.push(r);const h=this.textAnnotations.length-1;return this.deleteHistory=[],this.startEditing(h),h}updateTextAnnotation(t,e){if(t<0||t>=this.textAnnotations.length)return!1;const n=this.textAnnotations[t];n.text=e,this.ctx.font=this.textStyle.font;const i=this.ctx.measureText(e);return n.width=i.width,n.height=1.2*parseInt(this.textStyle.font),!0}moveTextAnnotation(t,e,n){return!(t<0||t>=this.textAnnotations.length)&&(this.textAnnotations[t].position={x:e,y:n},!0)}removeTextAnnotation(t){if(t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.textAnnotations.splice(t,1),this.editingTextIndex===t?this.cancelEditing():null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,!0}clearTextAnnotations(){this.textAnnotations=[],this.selectedTextIndex=null,this.cancelEditing(),this.deleteHistory=[]}startEditing(t){if(!this.textInput||t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];this.editingTextIndex=t,this.currentEditingIndex=t,this.textBeforeEditing=e.text;const n=this.viewport.offset.x+e.position.x*this.viewport.scale,i=this.viewport.offset.y+e.position.y*this.viewport.scale;return this.textInput.value=e.text,this.textInput.style.left=n-this.textStyle.padding+"px",this.textInput.style.top=i-this.textStyle.padding+"px",this.textInput.style.display="block",this.adjustInputWidth(),setTimeout(()=>{this.textInput&&(this.textInput.focus(),this.textInput.select())},10),!0}finishEditing(){if(!this.textInput)return!1;const t=this.currentEditingIndex,e=this.textInput.value.trim();if(null===t||t<0||t>=this.textAnnotations.length)return this.resetEditingState(),!1;if(""===e)this.textAnnotations.splice(t,1);else{const n=this.textAnnotations[t];n.text=e,this.ctx.font=this.textStyle.font;const i=this.ctx.measureText(n.text);n.width=i.width,n.height=1.2*parseInt(this.textStyle.font)}return this.resetEditingState(),!0}cancelEditing(){if(!this.textInput||null===this.editingTextIndex)return!1;this.textInput.value=this.textBeforeEditing;const t=this.editingTextIndex;if(t>=0&&t<this.textAnnotations.length){""===this.textAnnotations[t].text&&""===this.textBeforeEditing&&this.textAnnotations.splice(t,1)}return this.resetEditingState(),!0}deleteEditingAnnotation(){if(null===this.editingTextIndex)return!1;const t=this.editingTextIndex;return this.textInput&&(this.textInput.style.display="none"),t>=0&&t<this.textAnnotations.length&&this.textAnnotations.splice(t,1),this.resetEditingState(),!0}resetEditingState(){this.textInput&&(this.textInput.style.display="none"),this.editingTextIndex=null,this.currentEditingIndex=null,this.textBeforeEditing=""}adjustInputWidth(){if(!this.textInput||null===this.editingTextIndex)return;this.ctx.font=this.textStyle.font;const t=this.textInput.value||this.textInput.placeholder||"",e=this.ctx.measureText(t).width,n=Math.min(Math.max(e+24,60),200);this.textInput.style.width=`${n}px`}startMoving(t,e){return!(e<0||e>=this.textAnnotations.length)&&(this.editingTextIndex=e,this.isTextMoving=!0,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}moveAnnotation(t){if(!this.isTextMoving||null===this.editingTextIndex)return!1;const e=t.clientX-this.textMoveStart.x,n=t.clientY-this.textMoveStart.y,i=this.textAnnotations[this.editingTextIndex];return!!i&&(i.position.x+=e/this.viewport.scale,i.position.y+=n/this.viewport.scale,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}finishMoving(){this.isTextMoving=!1}checkTextClick(t,e){for(let n=this.textAnnotations.length-1;n>=0;n--){const i=this.textAnnotations[n],s=this.viewport.offset.x+i.position.x*this.viewport.scale,a=this.viewport.offset.y+i.position.y*this.viewport.scale;if(t>=s-this.textStyle.padding&&t<=s+i.width+this.textStyle.padding&&e>=a-this.textStyle.padding&&e<=a+i.height+this.textStyle.padding)return n}return null}checkTextClickForMove(t){const e=this.checkTextClick(t.offsetX,t.offsetY);return null!==e?(this.startMoving(t,e),{index:e,handled:!0}):{index:-1,handled:!1}}getTextAnnotations(){return[...this.textAnnotations]}withdraw(){if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.textAnnotations.splice(e,0,t),!0}return this.textAnnotations.length>0&&(this.textAnnotations.pop(),!0)}selectTextAnnotation(t){return t<0||t>=this.textAnnotations.length?(this.deselectTextAnnotation(),!1):(this.selectedTextIndex=t,null!==this.editingTextIndex&&this.finishEditing(),!0)}deselectTextAnnotation(){this.selectedTextIndex=null}deleteSelectedTextAnnotation(){if(null===this.selectedTextIndex)return!1;const t=this.selectedTextIndex,e=this.textAnnotations[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.textAnnotations.splice(t,1),this.selectedTextIndex=null,null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,!0}getSelectedTextAnnotation(){if(null===this.selectedTextIndex)return null;const t=this.textAnnotations[this.selectedTextIndex];return t?{index:this.selectedTextIndex,data:t}:null}destroy(){this.textInput&&this.textInput.parentNode&&this.textInput.parentNode.removeChild(this.textInput)}}class l{constructor(t,e,n,i,s){this.ctx=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.canvas=s}render(t){this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.drawBackgroundImage(t),this.drawAnnotations(),this.drawTextAnnotations()}drawBackgroundImage(t){this.ctx.drawImage(t,this.viewport.offset.x,this.viewport.offset.y,this.viewport.originalWidth*this.viewport.scale,this.viewport.originalHeight*this.viewport.scale)}drawAnnotations(){this.annotationManager.recordList.forEach((t,e)=>{var n;const i=this.annotationManager.getAnnotationStyle(t);this.ctx.strokeStyle=i.strokeColor,this.ctx.lineWidth=i.lineWidth,this.setLineDash(i.lineStyle||"solid"),this.ctx.fillStyle=this.ctx.strokeStyle;const s=(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.index)===e;if("rect"===t.type)this.drawRect(t.data[0],s);else if("polygon"===t.type){const e=i.vertexStyle||this.annotationManager.getVertexStyle();this.drawPolygon(t.data,"fullfilled"===t.status,e)}}),this.annotationManager.operate.data.length>0&&(this.ctx.strokeStyle=this.annotationManager.strokeStyle,this.ctx.lineWidth=this.annotationManager.lineWidth,this.ctx.fillStyle=this.ctx.strokeStyle,this.setLineDash(this.annotationManager.lineStyle),"rect"===this.annotationManager.operate.type?this.drawRect(this.annotationManager.operate.data[0],!1):"polygon"===this.annotationManager.operate.type&&this.drawCurrentPolygon()),this.ctx.setLineDash([]),this.drawSelectionHighlight()}setLineDash(t){switch(t){case"dashed":this.ctx.setLineDash([10,5]);break;case"dotted":this.ctx.setLineDash([2,4]);break;default:this.ctx.setLineDash([])}}drawRect(t,e=!1){this.ctx.strokeRect(this.viewport.offset.x+t.start.x*this.viewport.scale,this.viewport.offset.y+t.start.y*this.viewport.scale,t.width*this.viewport.scale,t.height*this.viewport.scale)}drawPolygon(t,e,n){if(0!==t.length){if(this.ctx.beginPath(),t.forEach((t,e)=>{const n=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(n,i):this.ctx.lineTo(n,i)}),e&&t.length>1){const e=t[0];this.ctx.lineTo(this.viewport.offset.x+e.point.x*this.viewport.scale,this.viewport.offset.y+e.point.y*this.viewport.scale)}this.ctx.stroke(),this.drawPolygonVertices(t,n)}}drawPolygonVertices(t,e){const n=e||this.annotationManager.getVertexStyle(),i=n.size/2;t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),s=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);switch(this.ctx.fillStyle=n.fillColor,this.ctx.strokeStyle=n.strokeColor,this.ctx.lineWidth=n.strokeWidth,this.ctx.beginPath(),n.shape){case"square":this.ctx.rect(e-i,s-i,2*i,2*i);break;case"diamond":this.ctx.moveTo(e,s-i),this.ctx.lineTo(e+i,s),this.ctx.lineTo(e,s+i),this.ctx.lineTo(e-i,s),this.ctx.closePath();break;default:this.ctx.arc(e,s,i,0,2*Math.PI)}this.ctx.fill(),n.strokeWidth>0&&this.ctx.stroke()})}drawCurrentPolygon(){const t=this.annotationManager.operate.data,e=this.annotationManager.tempPolygonPoint;if(this.ctx.beginPath(),t.forEach((t,e)=>{const n=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(n,i):this.ctx.lineTo(n,i)}),e){const t=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+e.y*this.viewport.scale);this.ctx.lineTo(t,n)}if(this.ctx.stroke(),this.drawPolygonVertices(t,this.annotationManager.getVertexStyle()),e){const t=this.annotationManager.getVertexStyle(),n=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+e.y*this.viewport.scale),s=t.size/2;switch(this.ctx.fillStyle=t.fillColor,this.ctx.strokeStyle=t.strokeColor,this.ctx.lineWidth=t.strokeWidth,this.ctx.beginPath(),t.shape){case"square":this.ctx.rect(n-s,i-s,2*s,2*s);break;case"diamond":this.ctx.moveTo(n,i-s),this.ctx.lineTo(n+s,i),this.ctx.lineTo(n,i+s),this.ctx.lineTo(n-s,i),this.ctx.closePath();break;default:this.ctx.arc(n,i,s,0,2*Math.PI)}this.ctx.fill(),t.strokeWidth>0&&this.ctx.stroke()}}drawSelectionHighlight(){const t=this.annotationManager.selectedAnnotation;if(!t)return;const e=this.annotationManager.recordList[t.index];if(!e)return;const n=this.annotationManager.selectionStyle;this.ctx.save(),"rect"===e.type?this.drawRectSelectionHighlight(e.data[0],n):"polygon"===e.type&&this.drawPolygonSelectionHighlight(e.data,n),this.ctx.restore()}drawRectSelectionHighlight(t,e){const n=this.viewport.offset.x+t.start.x*this.viewport.scale,i=this.viewport.offset.y+t.start.y*this.viewport.scale,s=t.width*this.viewport.scale,a=t.height*this.viewport.scale;this.ctx.fillStyle=e.fillColor,this.ctx.fillRect(n,i,s,a),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.strokeRect(n,i,s,a);const o=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),this.ctx.fillRect(n-o/2,i-o/2,o,o),this.ctx.fillRect(n+s-o/2,i-o/2,o,o),this.ctx.fillRect(n-o/2,i+a-o/2,o,o),this.ctx.fillRect(n+s-o/2,i+a-o/2,o,o)}drawPolygonSelectionHighlight(t,e){this.ctx.beginPath(),t.forEach((t,e)=>{const n=this.viewport.offset.x+t.point.x*this.viewport.scale,i=this.viewport.offset.y+t.point.y*this.viewport.scale;0===e?this.ctx.moveTo(n,i):this.ctx.lineTo(n,i)}),this.ctx.closePath(),this.ctx.fillStyle=e.fillColor,this.ctx.fill(),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.stroke();const n=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);this.ctx.fillRect(e-n/2,i-n/2,n,n)})}drawTextAnnotations(){const t=this.textManager.textStyle;this.textManager.textAnnotations.forEach((e,n)=>{if(this.textManager.editingTextIndex===n&&this.textManager.textInput&&"none"!==this.textManager.textInput.style.display)return;if(!e.text)return;const i=e.style||{font:t.font,color:t.color,backgroundColor:t.backgroundColor},s=this.viewport.offset.x+e.position.x*this.viewport.scale,a=this.viewport.offset.y+e.position.y*this.viewport.scale,o=this.textManager.selectedTextIndex===n;this.ctx.font=i.font;const r=this.ctx.measureText(e.text),h=r.actualBoundingBoxAscent||.8*e.height,l=h+(r.actualBoundingBoxDescent||.2*e.height),c=t.borderRadius,d=s-t.padding,g=e.width+2*t.padding,x=l+2*t.padding,f=a-h-t.padding;this.ctx.fillStyle=i.backgroundColor,this.ctx.beginPath(),this.ctx.roundRect(d,f,g,x,c),this.ctx.fill(),o&&(this.ctx.strokeStyle=t.selectedBorderColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.beginPath(),this.ctx.roundRect(d,f,g,x,c),this.ctx.stroke(),this.ctx.setLineDash([])),this.ctx.fillStyle=i.color,this.ctx.fillText(e.text,s,a)})}drawForExport(t,e,n,i){t.drawImage(e,0,0,n,i),this.annotationManager.recordList.forEach(e=>{const n=this.annotationManager.getAnnotationStyle(e);if(t.strokeStyle=n.strokeColor,t.lineWidth=n.lineWidth,"rect"===e.type){const n=e.data[0];t.strokeRect(n.start.x,n.start.y,n.width,n.height)}else if("polygon"===e.type&&"fullfilled"===e.status){t.beginPath(),e.data.forEach((e,n)=>{0===n?t.moveTo(e.point.x,e.point.y):t.lineTo(e.point.x,e.point.y)});const i=e.data[0];t.lineTo(i.point.x,i.point.y),t.stroke(),e.data.forEach(e=>{t.beginPath(),t.arc(e.point.x,e.point.y,4,0,2*Math.PI),t.fillStyle=n.strokeColor,t.fill()})}}),this.textManager.textAnnotations.forEach(e=>{const n=this.textManager.textStyle,i=e.style||{font:n.font,color:n.color,backgroundColor:n.backgroundColor};t.font=i.font;const s=t.measureText(e.text),a=s.actualBoundingBoxAscent||.8*e.height,o=a+(s.actualBoundingBoxDescent||.2*e.height),r=e.position.x-n.padding,h=e.width+2*n.padding,l=o+2*n.padding,c=e.position.y-a-n.padding,d=n.borderRadius;t.fillStyle=i.backgroundColor,t.roundRect?(t.roundRect(r,c,h,l,d),t.fill()):t.fillRect(r,c,h,l),t.fillStyle=i.color,t.fillText(e.text,e.position.x,e.position.y)})}}class c{constructor(t,e,n,i,s,a,o,r,h){this.canvas=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.renderer=s,this.getDrawType=a,this.getBgImage=o,this.renderCallback=r,this.setDrawTypeCallback=h,this.isDragging=!1,this.dragStart={x:0,y:0},this.justFinishedMove=!1,this.justDeselected=!1}handleWheel(t){if(t.preventDefault(),!this.getBgImage())return;const e=t.deltaY>0?-.02:.02,n=this.viewport.scale,i=Math.max(this.viewport.minScale,Math.min(n+e,this.viewport.maxScale)),s=this.canvas.getBoundingClientRect(),a=t.clientX-s.left,o=t.clientY-s.top,r=(a-this.viewport.offset.x)/n,h=(o-this.viewport.offset.y)/n;this.viewport.scale=i;const l=r*i+this.viewport.offset.x,c=h*i+this.viewport.offset.y;this.viewport.offset.x+=a-l,this.viewport.offset.y+=o-c,this.viewport.calculateBoundaries(),this.viewport.constrainViewport(),this.viewport.isInitialScale=this.viewport.scale===this.viewport.initialScale,this.renderCallback()}handleMouseDown(t){var e,n;if(0!==t.button)return;const i=this.getDrawType(),s=this.getBgImage();if(this.annotationManager.selectedAnnotation&&s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(n)return this.annotationManager.startResizing(n,e),void this.renderCallback()}if("text"===i){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);if("rect"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(e);if("polygon"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();if(this.annotationManager.selectedAnnotation)return this.annotationManager.deselectAnnotation(),void this.renderCallback()}return null!==this.textManager.selectedTextIndex?(this.textManager.deselectTextAnnotation(),void this.renderCallback()):void this.handleTextModeClick(t)}if(!s)return;const a=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if("rect"===i){if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return this.annotationManager.startResizing(e,a),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(a);return n&&"rect"===n.type?(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const n=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==n)return this.textManager.selectedTextIndex===n?this.textManager.startMoving(t,n):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(n)),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(a);if("polygon"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const s=this.annotationManager.getAnnotationAtPoint(a);if("rect"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.startRectDrawing(a)}else if("polygon"===i){if("polygon"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e&&"polygon-vertex"===e.type)return this.annotationManager.startResizing(e,a),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(a);return n&&"polygon"===n.type?(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(a);if("rect"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const s=this.annotationManager.getAnnotationAtPoint(a);if("polygon"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.isDrawing?this.checkPolygonPointValid(a)&&this.annotationManager.addPolygonPoint(a):this.annotationManager.startPolygonDrawing(a),this.annotationManager.updatePolygonTempPoint(a),this.renderCallback()}else if("drag"===i){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return this.annotationManager.startResizing(e,a),void this.renderCallback()}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(this.handleRectModeClick(t,a))return;if(this.handlePolygonModeClick(t,a))return;this.isDragging=!0,this.dragStart={x:t.clientX,y:t.clientY},this.canvas.style.cursor="grabbing"}else""===i&&this.handleNoModeClick(t,a)}checkTextClickInDragMode(t){return!!this.textManager.checkTextClickForMove(t).handled&&(this.canvas.style.cursor="grabbing",!0)}handleTextModeClick(t){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.startMoving(t,e),this.canvas.style.cursor="grabbing",this.renderCallback(),!0;const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return this.textManager.addTextAnnotation(n.x,n.y),!0}handleRectModeClick(t,e){var n,i;if("rect"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)){const n=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(n)return this.annotationManager.startResizing(n,e),this.renderCallback(),!0}const s=this.annotationManager.getAnnotationAtPoint(e);return s&&"rect"===s.type?(this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0):"rect"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handlePolygonModeClick(t,e){var n,i;if("polygon"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)){const n=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(n&&"polygon-vertex"===n.type)return this.annotationManager.startResizing(n,e),this.renderCallback(),!0}const s=this.annotationManager.getAnnotationAtPoint(e);return s&&"polygon"===s.type?(this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0):"polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handleRectModeClickForMove(t,e){const n=this.annotationManager.getAnnotationAtPoint(e);return!(!n||"rect"!==n.type)&&(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handlePolygonModeClickForMove(t,e){const n=this.annotationManager.getAnnotationAtPoint(e);return!(!n||"polygon"!==n.type)&&(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handleNoModeClick(t,e){const n=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==n)return this.textManager.selectedTextIndex===n?this.textManager.startMoving(t,n):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(n)),void this.renderCallback();this.textManager.deselectTextAnnotation();const i=this.annotationManager.getAnnotationAtPoint(e);i?(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback()):this.annotationManager.deselectAnnotation()}checkPolygonPointValid(t){const e=this.annotationManager.operate.data.length>0?this.annotationManager.operate.data[this.annotationManager.operate.data.length-1]:null;return!e||Math.abs(e.point.x-t.x)>5||Math.abs(e.point.y-t.y)>5}handleMouseMove(t){if(!this.getBgImage())return;const e=this.getDrawType();if(this.isDragging&&"drag"===e){const e=t.clientX-this.dragStart.x,n=t.clientY-this.dragStart.y;return this.viewport.updateOffset(e,n),this.dragStart={x:t.clientX,y:t.clientY},void this.renderCallback()}if(this.textManager.isTextMoving&&null!==this.textManager.editingTextIndex)this.textManager.moveAnnotation(t)&&this.renderCallback();else if((this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&this.annotationManager.selectedAnnotation)this.handleAnnotationMove(t);else{if(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving||this.updateCursor(t),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updateRectDrawing(e),this.renderCallback()}if("polygon"===e&&this.annotationManager.isDrawing){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updatePolygonTempPoint(e),this.renderCallback()}}}handleAnnotationMove(t){var e,n;if(this.annotationManager.isResizing&&this.annotationManager.activeHandle){const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return"rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)?this.annotationManager.resizeRect(i):"polygon"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)&&this.annotationManager.resizePolygon(i),void this.renderCallback()}if(!this.annotationManager.isMovingAnnotation||!this.annotationManager.selectedAnnotation)return;const i=(t.clientX-this.annotationManager.annotationMoveStart.x)/this.viewport.scale,s=(t.clientY-this.annotationManager.annotationMoveStart.y)/this.viewport.scale;this.annotationManager.moveSelectedAnnotation(i,s),this.annotationManager.annotationMoveStart={x:t.clientX,y:t.clientY},this.renderCallback()}updateCursor(t){const e=this.getDrawType();if("text"===e){if(this.getBgImage()){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(this.annotationManager.getAnnotationAtPoint(e))return void(this.canvas.style.cursor="move")}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);return void(this.canvas.style.cursor=null!==e?"move":"crosshair")}"rect"!==e?"polygon"!==e?"drag"!==e?""!==e?this.canvas.style.cursor="default":this.updateNoModeCursor(t):this.updateDragModeCursor(t):this.updatePolygonModeCursor(t):this.updateRectModeCursor(t)}updateRectModeCursor(t){var e;if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void(this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize")}const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(n)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updatePolygonModeCursor(t){var e;if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){if(this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="crosshair")}const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(n)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updateDragModeCursor(t){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(null!==this.textManager.checkTextClick(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="move");const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=n?"move":"grab"}updateNoModeCursor(t){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(null!==this.textManager.checkTextClick(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="move");const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=n?"move":"default"}handleMouseUp(t){if(this.isDragging){this.isDragging=!1;const t=this.getDrawType();return void(this.canvas.style.cursor="drag"===t?"grab":"default")}if(this.textManager.isTextMoving){this.justFinishedMove=!0,this.textManager.finishMoving();const t=this.getDrawType();"drag"===t?this.canvas.style.cursor="grab":""===t?this.canvas.style.cursor="move":(this.textManager.editingTextIndex=null,this.canvas.style.cursor="default")}(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&(this.justFinishedMove=!0,this.annotationManager.finishMovingAnnotation(),this.canvas.style.cursor=this.annotationManager.selectedAnnotation?"move":"default"),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type&&(this.annotationManager.finishRectDrawing(),this.renderCallback())}handleMouseLeave(t){(this.isDragging||this.textManager.isTextMoving||this.annotationManager.isResizing||this.annotationManager.isMovingAnnotation)&&this.handleMouseUp(t)}handleDoubleClick(t){if(!this.getBgImage())return;this.justFinishedMove=!1;const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return void this.textManager.startEditing(e);if("polygon"===this.getDrawType()){if(this.annotationManager.isDrawing&&this.annotationManager.operate.data.length<=2)return;this.annotationManager.finishPolygonDrawing(),this.renderCallback()}}handleClick(t){var e;const n=this.getDrawType();if(!this.getBgImage()||"polygon"!==n||this.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;if(this.justDeselected)return void(this.justDeselected=!1);if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type))return;const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.checkPolygonPointValid(i)&&(this.annotationManager.isDrawing?this.annotationManager.addPolygonPoint(i):this.annotationManager.startPolygonDrawing(i)),this.annotationManager.updatePolygonTempPoint(i),this.renderCallback()}handleKeyDown(t){if("z"===t.key&&(t.ctrlKey||t.metaKey))return this.annotationManager.withdraw()||this.textManager.withdraw(),void this.renderCallback();if(" "===t.key)return this.viewport.resetToInitial(),void this.renderCallback();if("Escape"!==t.key){if("Delete"===t.key||"Backspace"===t.key){if(null!==this.textManager.editingTextIndex)return this.textManager.removeTextAnnotation(this.textManager.editingTextIndex),void this.renderCallback();if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.renderCallback();this.annotationManager.selectedAnnotation&&(this.annotationManager.deleteSelectedAnnotation(),this.renderCallback())}}else this.annotationManager.isDrawing?(this.annotationManager.cancelDrawing(),this.renderCallback()):this.annotationManager.selectedAnnotation&&(this.annotationManager.deselectAnnotation(),this.renderCallback())}}class d{constructor(t){this.canvas=document.createElement("canvas"),this.bgImage=null,this.bgImageSrc="",this.bgImageExt="jpeg",this.drawType="";const{drawType:e,useEvents:n=!0,id:i="container",annotationColor:s,lineStyle:a,vertexStyle:d,textStyle:g}=t,x=document.getElementById(i);if(!x)throw new Error(`Container with id "${i}" not found`);this.container=x,"absolute"!==x.style.position&&"fixed"!==x.style.position&&"relative"!==x.style.position&&(x.style.position="relative"),this.ctx=this.canvas.getContext("2d"),this.viewport=new o,this.viewport.setSize(x.clientWidth,x.clientHeight),this.canvas.width=this.viewport.width,this.canvas.height=this.viewport.height,this.canvas.style.width=`${this.viewport.width}px`,this.canvas.style.height=`${this.viewport.height}px`,this.canvas.style.cursor="default",this.canvas.style.display="block",x.appendChild(this.canvas),this.annotationManager=new r(this.viewport),s&&this.annotationManager.setColorConfig(s),a&&this.annotationManager.setLineStyle(a),d&&this.annotationManager.setVertexStyle(d),this.textManager=new h(this.viewport,this.container,this.ctx,()=>this.render()),g&&this.textManager.setTextStyle(g),this.renderer=new l(this.ctx,this.viewport,this.annotationManager,this.textManager,this.canvas),this.eventHandler=new c(this.canvas,this.viewport,this.annotationManager,this.textManager,this.renderer,()=>this.drawType,()=>this.bgImage,()=>this.render(),t=>this.setDrawType(t)),this.events={wheel:t=>this.eventHandler.handleWheel(t),mousedown:t=>this.eventHandler.handleMouseDown(t),mousemove:t=>this.eventHandler.handleMouseMove(t),mouseup:t=>this.eventHandler.handleMouseUp(t),mouseleave:t=>this.eventHandler.handleMouseLeave(t),dblclick:t=>this.eventHandler.handleDoubleClick(t),click:t=>this.eventHandler.handleClick(t),keydown:t=>this.eventHandler.handleKeyDown(t)},this.setDrawType(e||""),n&&this.addEventListeners()}setDrawType(t){"polygon"===this.drawType&&this.annotationManager.isDrawing&&this.annotationManager.operate.data.length>0?console.warn("Cannot switch mode while polygon is being drawn. Please complete or cancel the polygon first."):this.drawType!==t&&(this.annotationManager.operate.data=[],this.annotationManager.isDrawing=!1,this.annotationManager.tempPolygonPoint=null,""!==t&&this.deselectAnnotation(),this.annotationManager.operate.type=t,this.drawType=t,this.canvas.style.cursor="drag"===t?"grab":"text"===t?"text":"default")}drawImage(t){this.bgImageSrc=t,this.bgImageExt=n(t);const e=new Image;e.crossOrigin="anonymous",e.src=t,e.onload=()=>{this.bgImage=e,this.viewport.setOriginalSize(e.width,e.height),this.viewport.calculateInitialView(),this.render()}}render(){this.renderer.render(this.bgImage)}clear(t=""){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.setDrawType(t),this.render()}withdraw(){const t=this.annotationManager.withdraw(),e=this.textManager.withdraw();(t||e)&&this.render()}addEventListeners(){this.canvas.addEventListener("mousedown",this.events.mousedown),this.canvas.addEventListener("mousemove",this.events.mousemove),this.canvas.addEventListener("mouseup",this.events.mouseup),this.canvas.addEventListener("mouseleave",this.events.mouseleave),this.canvas.addEventListener("wheel",this.events.wheel),this.canvas.addEventListener("contextmenu",t=>t.preventDefault()),document.addEventListener("keydown",this.events.keydown),this.handleClickEventListener()}handleClickEventListener(){let t=null,e=0;this.canvas.addEventListener("click",n=>{if(this.eventHandler.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;const i=this.eventHandler.justFinishedMove;i&&(this.eventHandler.justFinishedMove=!1),e++,1===e?t=window.setTimeout(()=>{1!==e||i||this.events.click(n),e=0,t=null},300):2===e&&(this.eventHandler.justFinishedMove=!1,this.events.dblclick(n),e=0,null!==t&&(clearTimeout(t),t=null))})}changeScale(t){if(!this.bgImage)return;const e=a(this.viewport.scale,t),n=this.viewport.width/2,i=this.viewport.height/2,s=this.viewport.scale+e;this.viewport.updateScale(s,n,i),this.render()}clearCanvas(t=!1,e=!0){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.textManager.deselectTextAnnotation(),!t&&e&&(this.bgImage=null,this.bgImageSrc="",this.viewport.setOriginalSize(0,0),this.viewport.reset()),this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.bgImage&&this.render(),"drag"===this.drawType&&(this.canvas.style.cursor="default")}clearAnnotations(){this.clearCanvas(!0,!1)}getAnnotations(){return this.annotationManager.getAnnotations()}getTextAnnotations(){return this.textManager.getTextAnnotations()}exportAnnotationImage(){return new Promise((t,e)=>{if(!this.bgImage)return void e(new Error("No background image loaded"));const n=document.createElement("canvas");n.width=this.viewport.originalWidth,n.height=this.viewport.originalHeight;const i=n.getContext("2d");if(!i)return void e(new Error("Could not create offscreen canvas context"));const s=new Image;s.src=this.bgImageSrc,s.crossOrigin="anonymous",s.onload=()=>{try{this.renderer.drawForExport(i,s,this.viewport.originalWidth,this.viewport.originalHeight);const e=n.toDataURL(`image/${this.bgImageExt}`,.7);t(e)}catch(n){this.exportCurrentViewImage().then(t).catch(t=>e(new Error(`Both methods failed: ${t.message}`)))}},s.onerror=()=>{e(new Error("Failed to load image for export"))}})}exportCurrentViewImage(){return new Promise((t,e)=>{try{t(this.canvas.toDataURL(`image/${this.bgImageExt}`))}catch(t){e(new Error(`Failed to export current view: ${t.message}`))}})}base64ToFile(t,e){return i(t,e)}static base64ToBlob(t){return s(t)}addTextAnnotation(t,e,n=""){this.textManager.addTextAnnotation(t,e,n),this.render()}updateTextAnnotation(t,e){this.textManager.updateTextAnnotation(t,e)&&this.render()}moveTextAnnotation(t,e,n){this.textManager.moveTextAnnotation(t,e,n)&&this.render()}removeTextAnnotation(t){this.textManager.removeTextAnnotation(t)&&this.render()}clearTextAnnotations(){this.textManager.clearTextAnnotations(),this.render()}selectAnnotation(t){this.annotationManager.selectAnnotation(t)&&this.render()}deselectAnnotation(){this.annotationManager.deselectAnnotation(),this.textManager.deselectTextAnnotation(),this.textManager.editingTextIndex=null,this.render()}getSelectedAnnotation(){const t=this.annotationManager.getSelectedAnnotation();if(t)return t;const e=this.textManager.getSelectedTextAnnotation();return e?{index:e.index,type:"text",data:e.data}:null}deleteSelectedAnnotation(){if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.render();this.annotationManager.deleteSelectedAnnotation()&&this.render()}moveSelectedAnnotation(t,e){this.annotationManager.moveSelectedAnnotation(t,e)&&this.render()}setAnnotationColor(t){this.annotationManager.setColorConfig(t),this.render()}getAnnotationColor(){return this.annotationManager.getColorConfig()}updateSelectedAnnotationStyle(){const t=this.annotationManager.selectedAnnotation;if(!t)return!1;const e=this.annotationManager.recordList[t.index];return!!e&&(e.style=this.annotationManager.getCurrentStyle(),this.render(),!0)}setLineStyle(t){this.annotationManager.setLineStyle(t),this.render()}getLineStyle(){return this.annotationManager.getLineStyle()}setVertexStyle(t){this.annotationManager.setVertexStyle(t),this.render()}getVertexStyle(){return this.annotationManager.getVertexStyle()}setTextStyle(t){this.textManager.setTextStyle(t),this.render()}setTextInputStyle(t){this.textManager.setInputStyle(t)}setTextSelectionStyle(t){this.textManager.setSelectionStyle(t),this.render()}destroy(){this.textManager.destroy(),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}export{r as AnnotationManager,d as Drawer,c as EventHandler,l as Renderer,h as TextAnnotationManager,o as ViewportManager,s as base64ToBlob,i as base64ToFile,d as default,n as getImageTypeFromUrl,a as getZoomDelta,e as isPointInPolygon,t as isPointInRect};
1
+ function t(t,e){const n=e.width>=0?e.start.x:e.start.x+e.width,i=e.height>=0?e.start.y:e.start.y+e.height,s=Math.abs(e.width),a=Math.abs(e.height);return t.x>=n&&t.x<=n+s&&t.y>=i&&t.y<=i+a}function e(t,e){if(e.length<3)return!1;let n=!1;for(let i=0,s=e.length-1;i<e.length;s=i++){const a=e[i].point.x,o=e[i].point.y,r=e[s].point.x,h=e[s].point.y;o>t.y!=h>t.y&&t.x<(r-a)*(t.y-o)/(h-o)+a&&(n=!n)}return n}function n(t){try{const e=new URL(t).pathname.toLowerCase();return e.endsWith(".png")?"png":e.endsWith(".jpg")?"jpg":e.endsWith(".jpeg")?"jpeg":e.endsWith(".webp")?"webp":e.endsWith(".gif")?"gif":e.endsWith(".bmp")?"bmp":e.endsWith(".svg")?"svg":"jpeg"}catch(t){return"jpeg"}}function i(t,e){const n=t.split(";base64,"),i=n[0].split(":")[1],s=window.atob(n[1]),a=s.length,o=new Uint8Array(a);for(let t=0;t<a;++t)o[t]=s.charCodeAt(t);const r=new Blob([o],{type:i});return new File([r],e,{type:i})}function s(t){return new Promise((e,n)=>{const i=t.split(";base64,");if(i.length<2)return void n(new Error("Invalid base64 string"));const s=i[0].split(":")[1],a=atob(i[1]),o=new ArrayBuffer(a.length),r=new Uint8Array(o);for(let t=0;t<a.length;t++)r[t]=a.charCodeAt(t);e(new Blob([o],{type:s}))})}function a(t,e){return t<2?e?.1:-.1:t<5?e?.05:-.05:e?.02:-.02}class o{constructor(){this.width=0,this.height=0,this.originalWidth=0,this.originalHeight=0,this.scale=1,this.minScale=1,this.maxScale=10,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}setSize(t,e){this.width=t,this.height=e}setOriginalSize(t,e){this.originalWidth=t,this.originalHeight=e}calculateInitialView(){if(0===this.originalWidth||0===this.originalHeight)return;const t=this.width/this.originalWidth,e=this.height/this.originalHeight;this.scale=Math.min(t,e),this.initialScale=this.scale,this.minScale=this.initialScale,this.offset={x:(this.width-this.originalWidth*this.scale)/2,y:(this.height-this.originalHeight*this.scale)/2},this.initialOffset=Object.assign({},this.offset),this.calculateBoundaries(),this.isInitialScale=!0}calculateBoundaries(){const t=this.originalWidth*this.scale,e=this.originalHeight*this.scale;this.maxOffsetX=0,this.maxOffsetY=0,this.minOffsetX=this.width-t,this.minOffsetY=this.height-e,this.minOffsetX>this.maxOffsetX&&([this.minOffsetX,this.maxOffsetX]=[this.maxOffsetX,this.minOffsetX]),this.minOffsetY>this.maxOffsetY&&([this.minOffsetY,this.maxOffsetY]=[this.maxOffsetY,this.minOffsetY])}constrainViewport(){this.offset.x>this.maxOffsetX?this.offset.x=this.maxOffsetX:this.offset.x<this.minOffsetX&&(this.offset.x=this.minOffsetX),this.offset.y>this.maxOffsetY?this.offset.y=this.maxOffsetY:this.offset.y<this.minOffsetY&&(this.offset.y=this.minOffsetY)}toImageCoordinates(t,e){return{x:(t-this.offset.x)/this.scale,y:(e-this.offset.y)/this.scale}}toCanvasCoordinates(t,e){return{x:this.offset.x+t*this.scale,y:this.offset.y+e*this.scale}}updateScale(t,e,n){const i=this.scale,s=(e-this.offset.x)/i,a=(n-this.offset.y)/i;this.scale=Math.max(this.minScale,Math.min(t,this.maxScale));const o=s*this.scale+this.offset.x,r=a*this.scale+this.offset.y;this.offset.x+=e-o,this.offset.y+=n-r,this.calculateBoundaries(),this.constrainViewport(),this.isInitialScale=this.scale===this.initialScale}resetToInitial(){this.scale=this.initialScale,this.offset=Object.assign({},this.initialOffset),this.calculateBoundaries(),this.isInitialScale=!0}updateOffset(t,e){this.offset.x+=t,this.offset.y+=e,this.constrainViewport()}reset(){this.scale=1,this.minScale=1,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}}class r{constructor(t){this.viewport=t,this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.drawStartPoint={x:0,y:0},this.tempPolygonPoint=null,this.selectedAnnotation=null,this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.annotationMoveStart={x:0,y:0},this.originalRect=null,this.originalPolygon=null,this.deleteHistory=[],this.strokeStyle="red",this.lineWidth=5,this.lineStyle="solid",this.vertexStyle={size:8,fillColor:"red",strokeColor:"white",strokeWidth:2,shape:"circle"},this.selectionStyle={strokeColor:"#00D9FF",fillColor:"rgba(0,217,255,0.15)",handleSize:12,handleColor:"#00D9FF"},this.colorConfig={rect:"red",polygon:"red",default:"red"},this.applyColorConfig()}setColorConfig(t){this.colorConfig="string"==typeof t?{rect:t,polygon:t,default:t}:Object.assign(Object.assign({},this.colorConfig),t),this.applyColorConfig()}getColorConfig(){return Object.assign({},this.colorConfig)}applyColorConfig(){this.strokeStyle=this.colorConfig.default||"red"}getColorForType(t){return this.colorConfig[t]||this.colorConfig.default||"red"}getCurrentStyle(){return{strokeColor:this.strokeStyle,lineWidth:this.lineWidth,lineStyle:this.lineStyle,vertexStyle:Object.assign({},this.vertexStyle)}}setLineStyle(t){this.lineStyle=t}setVertexStyle(t){this.vertexStyle=Object.assign(Object.assign({},this.vertexStyle),t),t.fillColor&&(this.strokeStyle=t.fillColor)}getLineStyle(){return this.lineStyle}getVertexStyle(){return Object.assign({},this.vertexStyle)}getAnnotationStyle(t){return t.style||this.getCurrentStyle()}startRectDrawing(t){this.isDrawing=!0,this.drawStartPoint=t,this.operate={type:"rect",data:[{start:Object.assign({},t),width:0,height:0}],status:"pending"}}updateRectDrawing(t){if(!this.isDrawing||"rect"!==this.operate.type)return;const e=this.operate.data[0];e.width=t.x-this.drawStartPoint.x,e.height=t.y-this.drawStartPoint.y}finishRectDrawing(){if(!this.isDrawing||"rect"!==this.operate.type)return!1;const t=this.operate.data[0];if(Math.abs(t.width)>5&&Math.abs(t.height)>5){const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[]}return this.operate.data=[],this.isDrawing=!1,!0}startPolygonDrawing(t){this.isDrawing=!0,this.operate={type:"polygon",data:[{point:t}],status:"pending"},this.tempPolygonPoint=t}addPolygonPoint(t){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;const e=this.operate.data.length>0?this.operate.data[this.operate.data.length-1]:null;return!(e&&Math.abs(e.point.x-t.x)<=5&&Math.abs(e.point.y-t.y)<=5)&&(this.operate.data.push({point:t}),!0)}updatePolygonTempPoint(t){this.tempPolygonPoint=t}finishPolygonDrawing(){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;if(this.operate.data.length>=3){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[]}return this.operate={type:"polygon",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,!0}cancelDrawing(){if(this.isDrawing&&"polygon"===this.operate.type&&this.operate.data.length>=2){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t)}this.operate.data=[],this.isDrawing=!1,this.tempPolygonPoint=null}withdraw(){if(this.operate.data.length>0)return"polygon"===this.operate.type?(this.operate.data.pop(),0===this.operate.data.length&&(this.isDrawing=!1)):(this.operate.data=[],this.isDrawing=!1),!0;if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.recordList.splice(e,0,t),!0}return this.recordList.length>0&&(this.recordList.pop(),!0)}selectAnnotation(t){if(t<0||t>=this.recordList.length)return this.deselectAnnotation(),!1;const e=this.recordList[t];return this.selectedAnnotation={index:t,type:e.type},!0}deselectAnnotation(){this.selectedAnnotation=null,this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}deleteSelectedAnnotation(){if(!this.selectedAnnotation)return!1;const t=this.selectedAnnotation.index,e=this.recordList[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.recordList.splice(t,1),this.deselectAnnotation(),!0}startMovingAnnotation(t){return!!this.selectedAnnotation&&(this.isMovingAnnotation=!0,this.annotationMoveStart={x:t.clientX,y:t.clientY},!0)}moveSelectedAnnotation(t,e){if(!this.selectedAnnotation)return!1;const n=this.recordList[this.selectedAnnotation.index];if(!n)return!1;if("rect"===n.type){const i=n.data[0];i.start.x+=t,i.start.y+=e}else if("polygon"===n.type){n.data.forEach(n=>{n.point.x+=t,n.point.y+=e})}return!0}finishMovingAnnotation(){this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}startResizing(t,e){if(!this.selectedAnnotation)return!1;this.activeHandle=t,this.isResizing=!0;const n=this.recordList[this.selectedAnnotation.index];return"rect"===n.type?this.originalRect=Object.assign({},n.data[0]):"polygon"===n.type&&(this.originalPolygon=n.data.map(t=>({point:Object.assign({},t.point)}))),!0}resizeRect(t){if(!this.selectedAnnotation||"rect"!==this.selectedAnnotation.type||!this.originalRect||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data[0],n=this.originalRect,i=n.start.x,s=n.start.x+n.width,a=n.start.y,o=n.start.y+n.height;let r,h;switch(this.activeHandle.index){case 0:r=s,h=o;break;case 1:r=i,h=o;break;case 2:r=s,h=a;break;case 3:r=i,h=a;break;default:return!1}const l=Math.min(t.x,r),c=Math.max(t.x,r),d=Math.min(t.y,h),g=Math.max(t.y,h);e.start.x=l,e.start.y=d,e.width=c-l,e.height=g-d;const x=t.x<r,f=t.y<h;return 0===this.activeHandle.index?x||f?!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2):this.activeHandle.index=3:1===this.activeHandle.index?x&&!f?this.activeHandle.index=2:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):2===this.activeHandle.index?!x&&f?this.activeHandle.index=1:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):3===this.activeHandle.index&&(x&&f?this.activeHandle.index=0:!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2)),this.originalRect=Object.assign({},e),!0}resizePolygon(t){if(!this.selectedAnnotation||"polygon"!==this.selectedAnnotation.type||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data,n=this.activeHandle.index;return n>=0&&n<e.length&&(e[n].point.x=t.x,e[n].point.y=t.y,!0)}getAnnotationAtPoint(n){for(let i=this.recordList.length-1;i>=0;i--){const s=this.recordList[i];if("rect"===s.type){if(t(n,s.data[0]))return{index:i,type:"rect"}}else if("polygon"===s.type){if(e(n,s.data))return{index:i,type:"polygon"}}}return null}getHandleAtPoint(t,e){if(!this.selectedAnnotation)return null;const n=this.recordList[this.selectedAnnotation.index],i=this.selectionStyle.handleSize/2;if("rect"===n.type){const s=n.data[0],a=this.viewport.offset.x+s.start.x*this.viewport.scale,o=this.viewport.offset.y+s.start.y*this.viewport.scale,r=s.width*this.viewport.scale,h=s.height*this.viewport.scale,l=[{x:a,y:o,index:0},{x:a+r,y:o,index:1},{x:a,y:o+h,index:2},{x:a+r,y:o+h,index:3}];for(const n of l)if(t>=n.x-i&&t<=n.x+i&&e>=n.y-i&&e<=n.y+i)return{type:"rect-corner",index:n.index}}else if("polygon"===n.type){const s=n.data;for(let n=0;n<s.length;n++){const a=s[n],o=this.viewport.offset.x+a.point.x*this.viewport.scale,r=this.viewport.offset.y+a.point.y*this.viewport.scale;if(t>=o-i&&t<=o+i&&e>=r-i&&e<=r+i)return{type:"polygon-vertex",index:n}}}return null}clear(){this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,this.deselectAnnotation(),this.deleteHistory=[]}getAnnotations(){return[...this.recordList]}getSelectedAnnotation(){if(!this.selectedAnnotation)return null;const t=this.recordList[this.selectedAnnotation.index];return t?{index:this.selectedAnnotation.index,type:this.selectedAnnotation.type,data:t}:null}}class h{constructor(t,e,n,i){this.viewport=t,this.container=e,this.ctx=n,this.renderCallback=i,this.textAnnotations=[],this.editingTextIndex=null,this.currentEditingIndex=null,this.isTextMoving=!1,this.textMoveStart={x:0,y:0},this.textBeforeEditing="",this.selectedTextIndex=null,this.textInput=null,this.deleteHistory=[],this.defaultInputStyle={border:"2px solid #00D9FF",borderRadius:"6px",padding:"6px 10px",fontSize:"16px",fontFamily:"Arial, sans-serif",backgroundColor:"#ffffff",color:"#333",boxShadow:"0 4px 12px rgba(0,0,0,0.3)",minWidth:"60px",maxWidth:"200px"},this.textStyle={font:"16px Arial",color:"#FFD700",padding:6,backgroundColor:"rgba(0,0,0,0.6)",borderRadius:4,selectedBorderColor:"#00D9FF",selectedBackgroundColor:"rgba(0,217,255,0.15)",inputStyle:Object.assign({},this.defaultInputStyle)},this.createTextInput()}createTextInput(){this.textInput=document.createElement("input"),this.textInput.type="text",this.textInput.style.position="absolute",this.textInput.style.zIndex="99999",this.textInput.style.display="none",this.textInput.style.outline="none",this.textInput.style.width="fit-content",this.textInput.placeholder="输入文字...",this.applyInputStyle(),this.textInput.addEventListener("blur",()=>{this.finishEditing(),this.renderCallback&&this.renderCallback()}),this.textInput.addEventListener("keydown",t=>{t.stopPropagation(),"Enter"===t.key?(this.finishEditing(),this.renderCallback&&this.renderCallback()):"Escape"===t.key?(t.preventDefault(),this.cancelEditing()):"Delete"===t.key&&""===this.textInput.value&&(t.preventDefault(),this.deleteEditingAnnotation())}),this.textInput.addEventListener("input",()=>{this.adjustInputWidth()}),this.container.appendChild(this.textInput)}applyInputStyle(){if(!this.textInput)return;const t=Object.assign(Object.assign({},this.defaultInputStyle),this.textStyle.inputStyle);this.textInput.style.border=t.border,this.textInput.style.borderRadius=t.borderRadius,this.textInput.style.padding=t.padding,this.textInput.style.fontSize=t.fontSize,this.textInput.style.fontFamily=t.fontFamily,this.textInput.style.backgroundColor=t.backgroundColor,this.textInput.style.color=t.color,this.textInput.style.boxShadow=t.boxShadow,this.textInput.style.minWidth=t.minWidth,this.textInput.style.maxWidth=t.maxWidth}setTextStyle(t){this.textStyle=Object.assign(Object.assign({},this.textStyle),t),this.applyInputStyle()}setInputStyle(t){this.textStyle.inputStyle=Object.assign(Object.assign({},this.textStyle.inputStyle),t),this.applyInputStyle()}setSelectionStyle(t){void 0!==t.selectedBorderColor&&(this.textStyle.selectedBorderColor=t.selectedBorderColor),void 0!==t.selectedBackgroundColor&&(this.textStyle.selectedBackgroundColor=t.selectedBackgroundColor)}getCurrentStyle(){return{font:this.textStyle.font,color:this.textStyle.color,backgroundColor:this.textStyle.backgroundColor}}addTextAnnotation(t,e,n=""){var i;this.ctx.font=this.textStyle.font;const s=n||"输入文字...",a=this.ctx.measureText(s);let o;if(a.actualBoundingBoxAscent&&a.actualBoundingBoxDescent)o=a.actualBoundingBoxAscent+a.actualBoundingBoxDescent;else{o=1.2*parseInt((null===(i=this.textStyle.font.match(/\d+/))||void 0===i?void 0:i[0])||"16")}const r={position:{x:t,y:e},text:n,style:this.getCurrentStyle(),width:Math.max(a.width,60),height:o};this.textAnnotations.push(r);const h=this.textAnnotations.length-1;return this.deleteHistory=[],this.startEditing(h),h}updateTextAnnotation(t,e){if(t<0||t>=this.textAnnotations.length)return!1;const n=this.textAnnotations[t];n.text=e,this.ctx.font=this.textStyle.font;const i=this.ctx.measureText(e);return n.width=i.width,n.height=1.2*parseInt(this.textStyle.font),!0}moveTextAnnotation(t,e,n){return!(t<0||t>=this.textAnnotations.length)&&(this.textAnnotations[t].position={x:e,y:n},!0)}removeTextAnnotation(t){if(t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.textAnnotations.splice(t,1),this.editingTextIndex===t?this.cancelEditing():null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,!0}clearTextAnnotations(){this.textAnnotations=[],this.selectedTextIndex=null,this.cancelEditing(),this.deleteHistory=[]}startEditing(t){if(!this.textInput||t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];this.editingTextIndex=t,this.currentEditingIndex=t,this.textBeforeEditing=e.text;const n=this.viewport.offset.x+e.position.x*this.viewport.scale,i=this.viewport.offset.y+e.position.y*this.viewport.scale;return this.textInput.value=e.text,this.textInput.style.left=n-this.textStyle.padding+"px",this.textInput.style.top=i-this.textStyle.padding+"px",this.textInput.style.display="block",this.adjustInputWidth(),setTimeout(()=>{this.textInput&&(this.textInput.focus(),this.textInput.select())},10),!0}finishEditing(){if(!this.textInput)return!1;const t=this.currentEditingIndex,e=this.textInput.value.trim();if(null===t||t<0||t>=this.textAnnotations.length)return this.resetEditingState(),!1;if(""===e)this.textAnnotations.splice(t,1);else{const n=this.textAnnotations[t];n.text=e,this.ctx.font=this.textStyle.font;const i=this.ctx.measureText(n.text);n.width=i.width,n.height=1.2*parseInt(this.textStyle.font)}return this.resetEditingState(),!0}cancelEditing(){if(!this.textInput||null===this.editingTextIndex)return!1;this.textInput.value=this.textBeforeEditing;const t=this.editingTextIndex;if(t>=0&&t<this.textAnnotations.length){""===this.textAnnotations[t].text&&""===this.textBeforeEditing&&this.textAnnotations.splice(t,1)}return this.resetEditingState(),!0}deleteEditingAnnotation(){if(null===this.editingTextIndex)return!1;const t=this.editingTextIndex;return this.textInput&&(this.textInput.style.display="none"),t>=0&&t<this.textAnnotations.length&&this.textAnnotations.splice(t,1),this.resetEditingState(),!0}resetEditingState(){this.textInput&&(this.textInput.style.display="none"),this.editingTextIndex=null,this.currentEditingIndex=null,this.textBeforeEditing=""}adjustInputWidth(){if(!this.textInput||null===this.editingTextIndex)return;this.ctx.font=this.textStyle.font;const t=this.textInput.value||this.textInput.placeholder||"",e=this.ctx.measureText(t).width,n=Math.min(Math.max(e+24,60),200);this.textInput.style.width=`${n}px`}startMoving(t,e){return!(e<0||e>=this.textAnnotations.length)&&(this.editingTextIndex=e,this.isTextMoving=!0,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}moveAnnotation(t){if(!this.isTextMoving||null===this.editingTextIndex)return!1;const e=t.clientX-this.textMoveStart.x,n=t.clientY-this.textMoveStart.y,i=this.textAnnotations[this.editingTextIndex];return!!i&&(i.position.x+=e/this.viewport.scale,i.position.y+=n/this.viewport.scale,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}finishMoving(){this.isTextMoving=!1}checkTextClick(t,e){for(let n=this.textAnnotations.length-1;n>=0;n--){const i=this.textAnnotations[n],s=this.viewport.offset.x+i.position.x*this.viewport.scale,a=this.viewport.offset.y+i.position.y*this.viewport.scale;if(t>=s-this.textStyle.padding&&t<=s+i.width+this.textStyle.padding&&e>=a-this.textStyle.padding&&e<=a+i.height+this.textStyle.padding)return n}return null}checkTextClickForMove(t){const e=this.checkTextClick(t.offsetX,t.offsetY);return null!==e?(this.startMoving(t,e),{index:e,handled:!0}):{index:-1,handled:!1}}getTextAnnotations(){return[...this.textAnnotations]}withdraw(){if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.textAnnotations.splice(e,0,t),!0}return this.textAnnotations.length>0&&(this.textAnnotations.pop(),!0)}selectTextAnnotation(t){return t<0||t>=this.textAnnotations.length?(this.deselectTextAnnotation(),!1):(this.selectedTextIndex=t,null!==this.editingTextIndex&&this.finishEditing(),!0)}deselectTextAnnotation(){this.selectedTextIndex=null}deleteSelectedTextAnnotation(){if(null===this.selectedTextIndex)return!1;const t=this.selectedTextIndex,e=this.textAnnotations[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.textAnnotations.splice(t,1),this.selectedTextIndex=null,null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,!0}getSelectedTextAnnotation(){if(null===this.selectedTextIndex)return null;const t=this.textAnnotations[this.selectedTextIndex];return t?{index:this.selectedTextIndex,data:t}:null}destroy(){this.textInput&&this.textInput.parentNode&&this.textInput.parentNode.removeChild(this.textInput)}}class l{constructor(t,e,n,i,s){this.ctx=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.canvas=s}render(t){this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.drawBackgroundImage(t),this.drawAnnotations(),this.drawTextAnnotations()}drawBackgroundImage(t){this.ctx.drawImage(t,this.viewport.offset.x,this.viewport.offset.y,this.viewport.originalWidth*this.viewport.scale,this.viewport.originalHeight*this.viewport.scale)}drawAnnotations(){this.annotationManager.recordList.forEach((t,e)=>{var n;const i=this.annotationManager.getAnnotationStyle(t);this.ctx.strokeStyle=i.strokeColor,this.ctx.lineWidth=i.lineWidth,this.setLineDash(i.lineStyle||"solid"),this.ctx.fillStyle=this.ctx.strokeStyle;const s=(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.index)===e;if("rect"===t.type)this.drawRect(t.data[0],s);else if("polygon"===t.type){const e=i.vertexStyle||this.annotationManager.getVertexStyle();this.drawPolygon(t.data,"fullfilled"===t.status,e)}}),this.annotationManager.operate.data.length>0&&(this.ctx.strokeStyle=this.annotationManager.strokeStyle,this.ctx.lineWidth=this.annotationManager.lineWidth,this.ctx.fillStyle=this.ctx.strokeStyle,this.setLineDash(this.annotationManager.lineStyle),"rect"===this.annotationManager.operate.type?this.drawRect(this.annotationManager.operate.data[0],!1):"polygon"===this.annotationManager.operate.type&&this.drawCurrentPolygon()),this.ctx.setLineDash([]),this.drawSelectionHighlight()}setLineDash(t){switch(t){case"dashed":this.ctx.setLineDash([10,5]);break;case"dotted":this.ctx.setLineDash([2,4]);break;default:this.ctx.setLineDash([])}}drawRect(t,e=!1){this.ctx.strokeRect(this.viewport.offset.x+t.start.x*this.viewport.scale,this.viewport.offset.y+t.start.y*this.viewport.scale,t.width*this.viewport.scale,t.height*this.viewport.scale)}drawPolygon(t,e,n){if(0!==t.length){if(this.ctx.beginPath(),t.forEach((t,e)=>{const n=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(n,i):this.ctx.lineTo(n,i)}),e&&t.length>1){const e=t[0];this.ctx.lineTo(this.viewport.offset.x+e.point.x*this.viewport.scale,this.viewport.offset.y+e.point.y*this.viewport.scale)}this.ctx.stroke(),this.drawPolygonVertices(t,n)}}drawPolygonVertices(t,e){const n=e||this.annotationManager.getVertexStyle(),i=n.size/2;t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),s=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);switch(this.ctx.fillStyle=n.fillColor,this.ctx.strokeStyle=n.strokeColor,this.ctx.lineWidth=n.strokeWidth,this.ctx.beginPath(),n.shape){case"square":this.ctx.rect(e-i,s-i,2*i,2*i);break;case"diamond":this.ctx.moveTo(e,s-i),this.ctx.lineTo(e+i,s),this.ctx.lineTo(e,s+i),this.ctx.lineTo(e-i,s),this.ctx.closePath();break;default:this.ctx.arc(e,s,i,0,2*Math.PI)}this.ctx.fill(),n.strokeWidth>0&&this.ctx.stroke()})}drawCurrentPolygon(){const t=this.annotationManager.operate.data,e=this.annotationManager.tempPolygonPoint;if(this.ctx.beginPath(),t.forEach((t,e)=>{const n=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(n,i):this.ctx.lineTo(n,i)}),e){const t=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+e.y*this.viewport.scale);this.ctx.lineTo(t,n)}if(this.ctx.stroke(),this.drawPolygonVertices(t,this.annotationManager.getVertexStyle()),e){const t=this.annotationManager.getVertexStyle(),n=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+e.y*this.viewport.scale),s=t.size/2;switch(this.ctx.fillStyle=t.fillColor,this.ctx.strokeStyle=t.strokeColor,this.ctx.lineWidth=t.strokeWidth,this.ctx.beginPath(),t.shape){case"square":this.ctx.rect(n-s,i-s,2*s,2*s);break;case"diamond":this.ctx.moveTo(n,i-s),this.ctx.lineTo(n+s,i),this.ctx.lineTo(n,i+s),this.ctx.lineTo(n-s,i),this.ctx.closePath();break;default:this.ctx.arc(n,i,s,0,2*Math.PI)}this.ctx.fill(),t.strokeWidth>0&&this.ctx.stroke()}}drawSelectionHighlight(){const t=this.annotationManager.selectedAnnotation;if(!t)return;const e=this.annotationManager.recordList[t.index];if(!e)return;const n=this.annotationManager.selectionStyle;this.ctx.save(),"rect"===e.type?this.drawRectSelectionHighlight(e.data[0],n):"polygon"===e.type&&this.drawPolygonSelectionHighlight(e.data,n),this.ctx.restore()}drawRectSelectionHighlight(t,e){const n=this.viewport.offset.x+t.start.x*this.viewport.scale,i=this.viewport.offset.y+t.start.y*this.viewport.scale,s=t.width*this.viewport.scale,a=t.height*this.viewport.scale;this.ctx.fillStyle=e.fillColor,this.ctx.fillRect(n,i,s,a),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.strokeRect(n,i,s,a);const o=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),this.ctx.fillRect(n-o/2,i-o/2,o,o),this.ctx.fillRect(n+s-o/2,i-o/2,o,o),this.ctx.fillRect(n-o/2,i+a-o/2,o,o),this.ctx.fillRect(n+s-o/2,i+a-o/2,o,o)}drawPolygonSelectionHighlight(t,e){this.ctx.beginPath(),t.forEach((t,e)=>{const n=this.viewport.offset.x+t.point.x*this.viewport.scale,i=this.viewport.offset.y+t.point.y*this.viewport.scale;0===e?this.ctx.moveTo(n,i):this.ctx.lineTo(n,i)}),this.ctx.closePath(),this.ctx.fillStyle=e.fillColor,this.ctx.fill(),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.stroke();const n=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);this.ctx.fillRect(e-n/2,i-n/2,n,n)})}drawTextAnnotations(){const t=this.textManager.textStyle;this.textManager.textAnnotations.forEach((e,n)=>{if(this.textManager.editingTextIndex===n&&this.textManager.textInput&&"none"!==this.textManager.textInput.style.display)return;if(!e.text)return;const i=e.style||{font:t.font,color:t.color,backgroundColor:t.backgroundColor},s=this.viewport.offset.x+e.position.x*this.viewport.scale,a=this.viewport.offset.y+e.position.y*this.viewport.scale,o=this.textManager.selectedTextIndex===n;this.ctx.font=i.font;const r=this.ctx.measureText(e.text),h=r.actualBoundingBoxAscent||.8*e.height,l=h+(r.actualBoundingBoxDescent||.2*e.height),c=t.borderRadius,d=s-t.padding,g=e.width+2*t.padding,x=l+2*t.padding,f=a-h-t.padding;this.ctx.fillStyle=i.backgroundColor,this.ctx.beginPath(),this.ctx.roundRect(d,f,g,x,c),this.ctx.fill(),o&&(this.ctx.strokeStyle=t.selectedBorderColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.beginPath(),this.ctx.roundRect(d,f,g,x,c),this.ctx.stroke(),this.ctx.setLineDash([])),this.ctx.fillStyle=i.color,this.ctx.fillText(e.text,s,a)})}drawForExport(t,e,n,i){t.drawImage(e,0,0,n,i),this.annotationManager.recordList.forEach(e=>{const n=this.annotationManager.getAnnotationStyle(e);if(t.strokeStyle=n.strokeColor,t.lineWidth=n.lineWidth,"rect"===e.type){const n=e.data[0];t.strokeRect(n.start.x,n.start.y,n.width,n.height)}else if("polygon"===e.type&&"fullfilled"===e.status){t.beginPath(),e.data.forEach((e,n)=>{0===n?t.moveTo(e.point.x,e.point.y):t.lineTo(e.point.x,e.point.y)});const i=e.data[0];t.lineTo(i.point.x,i.point.y),t.stroke(),e.data.forEach(e=>{t.beginPath(),t.arc(e.point.x,e.point.y,4,0,2*Math.PI),t.fillStyle=n.strokeColor,t.fill()})}}),this.textManager.textAnnotations.forEach(e=>{const n=this.textManager.textStyle,i=e.style||{font:n.font,color:n.color,backgroundColor:n.backgroundColor};t.font=i.font;const s=t.measureText(e.text),a=s.actualBoundingBoxAscent||.8*e.height,o=a+(s.actualBoundingBoxDescent||.2*e.height),r=e.position.x-n.padding,h=e.width+2*n.padding,l=o+2*n.padding,c=e.position.y-a-n.padding,d=n.borderRadius;t.fillStyle=i.backgroundColor,t.roundRect?(t.roundRect(r,c,h,l,d),t.fill()):t.fillRect(r,c,h,l),t.fillStyle=i.color,t.fillText(e.text,e.position.x,e.position.y)})}}class c{constructor(t,e,n,i,s,a,o,r,h){this.canvas=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.renderer=s,this.getDrawType=a,this.getBgImage=o,this.renderCallback=r,this.setDrawTypeCallback=h,this.isDragging=!1,this.dragStart={x:0,y:0},this.justFinishedMove=!1,this.justDeselected=!1}handleWheel(t){if(t.preventDefault(),!this.getBgImage())return;const e=t.deltaY>0?-.02:.02,n=this.viewport.scale,i=Math.max(this.viewport.minScale,Math.min(n+e,this.viewport.maxScale)),s=this.canvas.getBoundingClientRect(),a=t.clientX-s.left,o=t.clientY-s.top,r=(a-this.viewport.offset.x)/n,h=(o-this.viewport.offset.y)/n;this.viewport.scale=i;const l=r*i+this.viewport.offset.x,c=h*i+this.viewport.offset.y;this.viewport.offset.x+=a-l,this.viewport.offset.y+=o-c,this.viewport.calculateBoundaries(),this.viewport.constrainViewport(),this.viewport.isInitialScale=this.viewport.scale===this.viewport.initialScale,this.renderCallback()}handleMouseDown(t){var e,n;if(0!==t.button)return;const i=this.getDrawType(),s=this.getBgImage();if(this.annotationManager.selectedAnnotation&&s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(n)return this.annotationManager.startResizing(n,e),void this.renderCallback()}if("text"===i){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);if("rect"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(e);if("polygon"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();if(this.annotationManager.selectedAnnotation)return this.annotationManager.deselectAnnotation(),void this.renderCallback()}return null!==this.textManager.selectedTextIndex?(this.textManager.deselectTextAnnotation(),void this.renderCallback()):void this.handleTextModeClick(t)}if(!s)return;const a=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if("rect"===i){if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return this.annotationManager.startResizing(e,a),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(a);return n&&"rect"===n.type?(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const n=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==n)return this.textManager.selectedTextIndex===n?this.textManager.startMoving(t,n):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(n)),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(a);if("polygon"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const s=this.annotationManager.getAnnotationAtPoint(a);if("rect"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.startRectDrawing(a)}else if("polygon"===i){if("polygon"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e&&"polygon-vertex"===e.type)return this.annotationManager.startResizing(e,a),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(a);return n&&"polygon"===n.type?(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(a);if("rect"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const s=this.annotationManager.getAnnotationAtPoint(a);if("polygon"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.isDrawing?this.checkPolygonPointValid(a)&&this.annotationManager.addPolygonPoint(a):this.annotationManager.startPolygonDrawing(a),this.annotationManager.updatePolygonTempPoint(a),this.renderCallback()}else if("drag"===i){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return this.annotationManager.startResizing(e,a),void this.renderCallback()}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(this.handleRectModeClick(t,a))return;if(this.handlePolygonModeClick(t,a))return;this.isDragging=!0,this.dragStart={x:t.clientX,y:t.clientY},this.canvas.style.cursor="grabbing"}else""===i&&this.handleNoModeClick(t,a)}checkTextClickInDragMode(t){return!!this.textManager.checkTextClickForMove(t).handled&&(this.canvas.style.cursor="grabbing",!0)}handleTextModeClick(t){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.startMoving(t,e),this.canvas.style.cursor="grabbing",this.renderCallback(),!0;const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return this.textManager.addTextAnnotation(n.x,n.y),!0}handleRectModeClick(t,e){var n,i;if("rect"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)){const n=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(n)return this.annotationManager.startResizing(n,e),this.renderCallback(),!0}const s=this.annotationManager.getAnnotationAtPoint(e);return s&&"rect"===s.type?(this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0):"rect"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handlePolygonModeClick(t,e){var n,i;if("polygon"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)){const n=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(n&&"polygon-vertex"===n.type)return this.annotationManager.startResizing(n,e),this.renderCallback(),!0}const s=this.annotationManager.getAnnotationAtPoint(e);return s&&"polygon"===s.type?(this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0):"polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handleRectModeClickForMove(t,e){const n=this.annotationManager.getAnnotationAtPoint(e);return!(!n||"rect"!==n.type)&&(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handlePolygonModeClickForMove(t,e){const n=this.annotationManager.getAnnotationAtPoint(e);return!(!n||"polygon"!==n.type)&&(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handleNoModeClick(t,e){const n=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==n)return this.textManager.selectedTextIndex===n?this.textManager.startMoving(t,n):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(n)),void this.renderCallback();this.textManager.deselectTextAnnotation();const i=this.annotationManager.getAnnotationAtPoint(e);i?(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback()):this.annotationManager.deselectAnnotation()}checkPolygonPointValid(t){const e=this.annotationManager.operate.data.length>0?this.annotationManager.operate.data[this.annotationManager.operate.data.length-1]:null;return!e||Math.abs(e.point.x-t.x)>5||Math.abs(e.point.y-t.y)>5}handleMouseMove(t){if(!this.getBgImage())return;const e=this.getDrawType();if(this.isDragging&&"drag"===e){const e=t.clientX-this.dragStart.x,n=t.clientY-this.dragStart.y;return this.viewport.updateOffset(e,n),this.dragStart={x:t.clientX,y:t.clientY},void this.renderCallback()}if(this.textManager.isTextMoving&&null!==this.textManager.editingTextIndex)this.textManager.moveAnnotation(t)&&this.renderCallback();else if((this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&this.annotationManager.selectedAnnotation)this.handleAnnotationMove(t);else{if(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving||this.updateCursor(t),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updateRectDrawing(e),this.renderCallback()}if("polygon"===e&&this.annotationManager.isDrawing){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updatePolygonTempPoint(e),this.renderCallback()}}}handleAnnotationMove(t){var e,n;if(this.annotationManager.isResizing&&this.annotationManager.activeHandle){const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return"rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)?this.annotationManager.resizeRect(i):"polygon"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)&&this.annotationManager.resizePolygon(i),void this.renderCallback()}if(!this.annotationManager.isMovingAnnotation||!this.annotationManager.selectedAnnotation)return;const i=(t.clientX-this.annotationManager.annotationMoveStart.x)/this.viewport.scale,s=(t.clientY-this.annotationManager.annotationMoveStart.y)/this.viewport.scale;this.annotationManager.moveSelectedAnnotation(i,s),this.annotationManager.annotationMoveStart={x:t.clientX,y:t.clientY},this.renderCallback()}updateCursor(t){const e=this.getDrawType();if("text"===e){if(this.getBgImage()){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(this.annotationManager.getAnnotationAtPoint(e))return void(this.canvas.style.cursor="move")}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);return void(this.canvas.style.cursor=null!==e?"move":"crosshair")}"rect"!==e?"polygon"!==e?"drag"!==e?""!==e?this.canvas.style.cursor="default":this.updateNoModeCursor(t):this.updateDragModeCursor(t):this.updatePolygonModeCursor(t):this.updateRectModeCursor(t)}updateRectModeCursor(t){var e;if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void(this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize")}const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(n)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updatePolygonModeCursor(t){var e;if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){if(this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="crosshair")}const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(n)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updateDragModeCursor(t){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(null!==this.textManager.checkTextClick(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="move");const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=n?"move":"grab"}updateNoModeCursor(t){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(null!==this.textManager.checkTextClick(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="move");const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=n?"move":"default"}handleMouseUp(t){if(this.isDragging){this.isDragging=!1;const t=this.getDrawType();return void(this.canvas.style.cursor="drag"===t?"grab":"default")}if(this.textManager.isTextMoving){this.justFinishedMove=!0,this.textManager.finishMoving();const t=this.getDrawType();"drag"===t?this.canvas.style.cursor="grab":""===t?this.canvas.style.cursor="move":(this.textManager.editingTextIndex=null,this.canvas.style.cursor="default")}(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&(this.justFinishedMove=!0,this.annotationManager.finishMovingAnnotation(),this.canvas.style.cursor=this.annotationManager.selectedAnnotation?"move":"default"),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type&&(this.annotationManager.finishRectDrawing(),this.renderCallback())}handleMouseLeave(t){(this.isDragging||this.textManager.isTextMoving||this.annotationManager.isResizing||this.annotationManager.isMovingAnnotation)&&this.handleMouseUp(t)}handleDoubleClick(t){if(!this.getBgImage())return;this.justFinishedMove=!1;const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return void this.textManager.startEditing(e);if("polygon"===this.getDrawType()){if(this.annotationManager.isDrawing&&this.annotationManager.operate.data.length<=2)return;this.annotationManager.finishPolygonDrawing(),this.renderCallback()}}handleClick(t){var e;const n=this.getDrawType();if(!this.getBgImage()||"polygon"!==n||this.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;if(this.justDeselected)return void(this.justDeselected=!1);if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type))return;const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.checkPolygonPointValid(i)&&(this.annotationManager.isDrawing?this.annotationManager.addPolygonPoint(i):this.annotationManager.startPolygonDrawing(i)),this.annotationManager.updatePolygonTempPoint(i),this.renderCallback()}handleKeyDown(t){if("z"===t.key&&(t.ctrlKey||t.metaKey))return this.annotationManager.withdraw()||this.textManager.withdraw(),void this.renderCallback();if(" "===t.key)return this.viewport.resetToInitial(),void this.renderCallback();if("Escape"!==t.key){if("Delete"===t.key||"Backspace"===t.key){if(null!==this.textManager.editingTextIndex)return this.textManager.removeTextAnnotation(this.textManager.editingTextIndex),void this.renderCallback();if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.renderCallback();this.annotationManager.selectedAnnotation&&(this.annotationManager.deleteSelectedAnnotation(),this.renderCallback())}}else this.annotationManager.isDrawing?(this.annotationManager.cancelDrawing(),this.renderCallback()):this.annotationManager.selectedAnnotation&&(this.annotationManager.deselectAnnotation(),this.renderCallback())}}class d{constructor(t){this.canvas=document.createElement("canvas"),this.bgImage=null,this.bgImageSrc="",this.bgImageExt="jpeg",this.drawType="";const{drawType:e,useEvents:n=!0,id:i="container",annotationColor:s,lineStyle:a,vertexStyle:d,textStyle:g}=t,x=document.getElementById(i);if(!x)throw new Error(`Container with id "${i}" not found`);this.container=x,"absolute"!==x.style.position&&"fixed"!==x.style.position&&"relative"!==x.style.position&&(x.style.position="relative"),this.ctx=this.canvas.getContext("2d"),this.viewport=new o,this.viewport.setSize(x.clientWidth,x.clientHeight),this.canvas.width=this.viewport.width,this.canvas.height=this.viewport.height,this.canvas.style.width=`${this.viewport.width}px`,this.canvas.style.height=`${this.viewport.height}px`,this.canvas.style.cursor="default",this.canvas.style.display="block",x.appendChild(this.canvas),this.annotationManager=new r(this.viewport),s&&this.annotationManager.setColorConfig(s),a&&this.annotationManager.setLineStyle(a),d&&this.annotationManager.setVertexStyle(d),this.textManager=new h(this.viewport,this.container,this.ctx,()=>this.render()),g&&this.textManager.setTextStyle(g),this.renderer=new l(this.ctx,this.viewport,this.annotationManager,this.textManager,this.canvas),this.eventHandler=new c(this.canvas,this.viewport,this.annotationManager,this.textManager,this.renderer,()=>this.drawType,()=>this.bgImage,()=>this.render(),t=>this.setDrawType(t)),this.events={wheel:t=>this.eventHandler.handleWheel(t),mousedown:t=>this.eventHandler.handleMouseDown(t),mousemove:t=>this.eventHandler.handleMouseMove(t),mouseup:t=>this.eventHandler.handleMouseUp(t),mouseleave:t=>this.eventHandler.handleMouseLeave(t),dblclick:t=>this.eventHandler.handleDoubleClick(t),click:t=>this.eventHandler.handleClick(t),keydown:t=>this.eventHandler.handleKeyDown(t)},this.setDrawType(e||""),n&&this.addEventListeners()}setDrawType(t){"polygon"===this.drawType&&this.annotationManager.isDrawing&&this.annotationManager.operate.data.length>0?console.warn("Cannot switch mode while polygon is being drawn. Please complete or cancel the polygon first."):this.drawType!==t&&(this.annotationManager.operate.data=[],this.annotationManager.isDrawing=!1,this.annotationManager.tempPolygonPoint=null,""!==t&&this.deselectAnnotation(),this.annotationManager.operate.type=t,this.drawType=t,this.canvas.style.cursor="drag"===t?"grab":"text"===t?"text":"default")}drawImage(t){this.bgImageSrc=t,this.bgImageExt=n(t);const e=new Image;e.crossOrigin="anonymous",e.src=t,e.onload=()=>{this.bgImage=e,this.viewport.setOriginalSize(e.width,e.height),this.viewport.calculateInitialView(),this.render()}}render(){this.renderer.render(this.bgImage)}clear(t=""){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.setDrawType(t),this.render()}withdraw(){const t=this.annotationManager.withdraw(),e=this.textManager.withdraw();(t||e)&&this.render()}resize(){const t=this.canvas.parentElement;t&&(this.viewport.setSize(t.clientWidth,t.clientHeight),this.canvas.width=this.viewport.width,this.canvas.height=this.viewport.height,this.canvas.style.width=`${this.viewport.width}px`,this.canvas.style.height=`${this.viewport.height}px`,this.render())}addEventListeners(){this.canvas.addEventListener("mousedown",this.events.mousedown),this.canvas.addEventListener("mousemove",this.events.mousemove),this.canvas.addEventListener("mouseup",this.events.mouseup),this.canvas.addEventListener("mouseleave",this.events.mouseleave),this.canvas.addEventListener("wheel",this.events.wheel),this.canvas.addEventListener("contextmenu",t=>t.preventDefault()),document.addEventListener("keydown",this.events.keydown),this.handleClickEventListener()}handleClickEventListener(){let t=null,e=0;this.canvas.addEventListener("click",n=>{if(this.eventHandler.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;const i=this.eventHandler.justFinishedMove;i&&(this.eventHandler.justFinishedMove=!1),e++,1===e?t=window.setTimeout(()=>{1!==e||i||this.events.click(n),e=0,t=null},300):2===e&&(this.eventHandler.justFinishedMove=!1,this.events.dblclick(n),e=0,null!==t&&(clearTimeout(t),t=null))})}changeScale(t){if(!this.bgImage)return;const e=a(this.viewport.scale,t),n=this.viewport.width/2,i=this.viewport.height/2,s=this.viewport.scale+e;this.viewport.updateScale(s,n,i),this.render()}clearCanvas(t=!1,e=!0){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.textManager.deselectTextAnnotation(),!t&&e&&(this.bgImage=null,this.bgImageSrc="",this.viewport.setOriginalSize(0,0),this.viewport.reset()),this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.bgImage&&this.render(),"drag"===this.drawType&&(this.canvas.style.cursor="default")}clearAnnotations(){this.clearCanvas(!0,!1)}getAnnotations(){return this.annotationManager.getAnnotations()}getTextAnnotations(){return this.textManager.getTextAnnotations()}exportAnnotationImage(){return new Promise((t,e)=>{if(!this.bgImage)return void e(new Error("No background image loaded"));const n=document.createElement("canvas");n.width=this.viewport.originalWidth,n.height=this.viewport.originalHeight;const i=n.getContext("2d");if(!i)return void e(new Error("Could not create offscreen canvas context"));const s=new Image;s.src=this.bgImageSrc,s.crossOrigin="anonymous",s.onload=()=>{try{this.renderer.drawForExport(i,s,this.viewport.originalWidth,this.viewport.originalHeight);const e=n.toDataURL(`image/${this.bgImageExt}`,.7);t(e)}catch(n){this.exportCurrentViewImage().then(t).catch(t=>e(new Error(`Both methods failed: ${t.message}`)))}},s.onerror=()=>{e(new Error("Failed to load image for export"))}})}exportCurrentViewImage(){return new Promise((t,e)=>{try{t(this.canvas.toDataURL(`image/${this.bgImageExt}`))}catch(t){e(new Error(`Failed to export current view: ${t.message}`))}})}base64ToFile(t,e){return i(t,e)}static base64ToBlob(t){return s(t)}addTextAnnotation(t,e,n=""){this.textManager.addTextAnnotation(t,e,n),this.render()}updateTextAnnotation(t,e){this.textManager.updateTextAnnotation(t,e)&&this.render()}moveTextAnnotation(t,e,n){this.textManager.moveTextAnnotation(t,e,n)&&this.render()}removeTextAnnotation(t){this.textManager.removeTextAnnotation(t)&&this.render()}clearTextAnnotations(){this.textManager.clearTextAnnotations(),this.render()}selectAnnotation(t){this.annotationManager.selectAnnotation(t)&&this.render()}deselectAnnotation(){this.annotationManager.deselectAnnotation(),this.textManager.deselectTextAnnotation(),this.textManager.editingTextIndex=null,this.render()}getSelectedAnnotation(){const t=this.annotationManager.getSelectedAnnotation();if(t)return t;const e=this.textManager.getSelectedTextAnnotation();return e?{index:e.index,type:"text",data:e.data}:null}deleteSelectedAnnotation(){if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.render();this.annotationManager.deleteSelectedAnnotation()&&this.render()}moveSelectedAnnotation(t,e){this.annotationManager.moveSelectedAnnotation(t,e)&&this.render()}setAnnotationColor(t){this.annotationManager.setColorConfig(t),this.render()}getAnnotationColor(){return this.annotationManager.getColorConfig()}updateSelectedAnnotationStyle(){const t=this.annotationManager.selectedAnnotation;if(!t)return!1;const e=this.annotationManager.recordList[t.index];return!!e&&(e.style=this.annotationManager.getCurrentStyle(),this.render(),!0)}setLineStyle(t){this.annotationManager.setLineStyle(t),this.render()}getLineStyle(){return this.annotationManager.getLineStyle()}setVertexStyle(t){this.annotationManager.setVertexStyle(t),this.render()}getVertexStyle(){return this.annotationManager.getVertexStyle()}setTextStyle(t){this.textManager.setTextStyle(t),this.render()}setTextInputStyle(t){this.textManager.setInputStyle(t)}setTextSelectionStyle(t){this.textManager.setSelectionStyle(t),this.render()}destroy(){this.textManager.destroy(),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}export{r as AnnotationManager,d as Drawer,c as EventHandler,l as Renderer,h as TextAnnotationManager,o as ViewportManager,s as base64ToBlob,i as base64ToFile,d as default,n as getImageTypeFromUrl,a as getZoomDelta,e as isPointInPolygon,t as isPointInRect};
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).ImageAnnotationDrawer=t.ImageAnnotationDrawer||{})}(this,function(t){"use strict";function e(t,e){const n=e.width>=0?e.start.x:e.start.x+e.width,i=e.height>=0?e.start.y:e.start.y+e.height,s=Math.abs(e.width),a=Math.abs(e.height);return t.x>=n&&t.x<=n+s&&t.y>=i&&t.y<=i+a}function n(t,e){if(e.length<3)return!1;let n=!1;for(let i=0,s=e.length-1;i<e.length;s=i++){const a=e[i].point.x,o=e[i].point.y,r=e[s].point.x,h=e[s].point.y;o>t.y!=h>t.y&&t.x<(r-a)*(t.y-o)/(h-o)+a&&(n=!n)}return n}function i(t){try{const e=new URL(t).pathname.toLowerCase();return e.endsWith(".png")?"png":e.endsWith(".jpg")?"jpg":e.endsWith(".jpeg")?"jpeg":e.endsWith(".webp")?"webp":e.endsWith(".gif")?"gif":e.endsWith(".bmp")?"bmp":e.endsWith(".svg")?"svg":"jpeg"}catch(t){return"jpeg"}}function s(t,e){const n=t.split(";base64,"),i=n[0].split(":")[1],s=window.atob(n[1]),a=s.length,o=new Uint8Array(a);for(let t=0;t<a;++t)o[t]=s.charCodeAt(t);const r=new Blob([o],{type:i});return new File([r],e,{type:i})}function a(t){return new Promise((e,n)=>{const i=t.split(";base64,");if(i.length<2)return void n(new Error("Invalid base64 string"));const s=i[0].split(":")[1],a=atob(i[1]),o=new ArrayBuffer(a.length),r=new Uint8Array(o);for(let t=0;t<a.length;t++)r[t]=a.charCodeAt(t);e(new Blob([o],{type:s}))})}function o(t,e){return t<2?e?.1:-.1:t<5?e?.05:-.05:e?.02:-.02}class r{constructor(){this.width=0,this.height=0,this.originalWidth=0,this.originalHeight=0,this.scale=1,this.minScale=1,this.maxScale=10,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}setSize(t,e){this.width=t,this.height=e}setOriginalSize(t,e){this.originalWidth=t,this.originalHeight=e}calculateInitialView(){if(0===this.originalWidth||0===this.originalHeight)return;const t=this.width/this.originalWidth,e=this.height/this.originalHeight;this.scale=Math.min(t,e),this.initialScale=this.scale,this.minScale=this.initialScale,this.offset={x:(this.width-this.originalWidth*this.scale)/2,y:(this.height-this.originalHeight*this.scale)/2},this.initialOffset=Object.assign({},this.offset),this.calculateBoundaries(),this.isInitialScale=!0}calculateBoundaries(){const t=this.originalWidth*this.scale,e=this.originalHeight*this.scale;this.maxOffsetX=0,this.maxOffsetY=0,this.minOffsetX=this.width-t,this.minOffsetY=this.height-e,this.minOffsetX>this.maxOffsetX&&([this.minOffsetX,this.maxOffsetX]=[this.maxOffsetX,this.minOffsetX]),this.minOffsetY>this.maxOffsetY&&([this.minOffsetY,this.maxOffsetY]=[this.maxOffsetY,this.minOffsetY])}constrainViewport(){this.offset.x>this.maxOffsetX?this.offset.x=this.maxOffsetX:this.offset.x<this.minOffsetX&&(this.offset.x=this.minOffsetX),this.offset.y>this.maxOffsetY?this.offset.y=this.maxOffsetY:this.offset.y<this.minOffsetY&&(this.offset.y=this.minOffsetY)}toImageCoordinates(t,e){return{x:(t-this.offset.x)/this.scale,y:(e-this.offset.y)/this.scale}}toCanvasCoordinates(t,e){return{x:this.offset.x+t*this.scale,y:this.offset.y+e*this.scale}}updateScale(t,e,n){const i=this.scale,s=(e-this.offset.x)/i,a=(n-this.offset.y)/i;this.scale=Math.max(this.minScale,Math.min(t,this.maxScale));const o=s*this.scale+this.offset.x,r=a*this.scale+this.offset.y;this.offset.x+=e-o,this.offset.y+=n-r,this.calculateBoundaries(),this.constrainViewport(),this.isInitialScale=this.scale===this.initialScale}resetToInitial(){this.scale=this.initialScale,this.offset=Object.assign({},this.initialOffset),this.calculateBoundaries(),this.isInitialScale=!0}updateOffset(t,e){this.offset.x+=t,this.offset.y+=e,this.constrainViewport()}reset(){this.scale=1,this.minScale=1,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}}class h{constructor(t){this.viewport=t,this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.drawStartPoint={x:0,y:0},this.tempPolygonPoint=null,this.selectedAnnotation=null,this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.annotationMoveStart={x:0,y:0},this.originalRect=null,this.originalPolygon=null,this.deleteHistory=[],this.strokeStyle="red",this.lineWidth=5,this.lineStyle="solid",this.vertexStyle={size:8,fillColor:"red",strokeColor:"white",strokeWidth:2,shape:"circle"},this.selectionStyle={strokeColor:"#00D9FF",fillColor:"rgba(0,217,255,0.15)",handleSize:12,handleColor:"#00D9FF"},this.colorConfig={rect:"red",polygon:"red",default:"red"},this.applyColorConfig()}setColorConfig(t){this.colorConfig="string"==typeof t?{rect:t,polygon:t,default:t}:Object.assign(Object.assign({},this.colorConfig),t),this.applyColorConfig()}getColorConfig(){return Object.assign({},this.colorConfig)}applyColorConfig(){this.strokeStyle=this.colorConfig.default||"red"}getColorForType(t){return this.colorConfig[t]||this.colorConfig.default||"red"}getCurrentStyle(){return{strokeColor:this.strokeStyle,lineWidth:this.lineWidth,lineStyle:this.lineStyle,vertexStyle:Object.assign({},this.vertexStyle)}}setLineStyle(t){this.lineStyle=t}setVertexStyle(t){this.vertexStyle=Object.assign(Object.assign({},this.vertexStyle),t),t.fillColor&&(this.strokeStyle=t.fillColor)}getLineStyle(){return this.lineStyle}getVertexStyle(){return Object.assign({},this.vertexStyle)}getAnnotationStyle(t){return t.style||this.getCurrentStyle()}startRectDrawing(t){this.isDrawing=!0,this.drawStartPoint=t,this.operate={type:"rect",data:[{start:Object.assign({},t),width:0,height:0}],status:"pending"}}updateRectDrawing(t){if(!this.isDrawing||"rect"!==this.operate.type)return;const e=this.operate.data[0];e.width=t.x-this.drawStartPoint.x,e.height=t.y-this.drawStartPoint.y}finishRectDrawing(){if(!this.isDrawing||"rect"!==this.operate.type)return!1;const t=this.operate.data[0];if(Math.abs(t.width)>5&&Math.abs(t.height)>5){const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[]}return this.operate.data=[],this.isDrawing=!1,!0}startPolygonDrawing(t){this.isDrawing=!0,this.operate={type:"polygon",data:[{point:t}],status:"pending"},this.tempPolygonPoint=t}addPolygonPoint(t){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;const e=this.operate.data.length>0?this.operate.data[this.operate.data.length-1]:null;return!(e&&Math.abs(e.point.x-t.x)<=5&&Math.abs(e.point.y-t.y)<=5)&&(this.operate.data.push({point:t}),!0)}updatePolygonTempPoint(t){this.tempPolygonPoint=t}finishPolygonDrawing(){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;if(this.operate.data.length>=3){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[]}return this.operate={type:"polygon",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,!0}cancelDrawing(){if(this.isDrawing&&"polygon"===this.operate.type&&this.operate.data.length>=2){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t)}this.operate.data=[],this.isDrawing=!1,this.tempPolygonPoint=null}withdraw(){if(this.operate.data.length>0)return"polygon"===this.operate.type?(this.operate.data.pop(),0===this.operate.data.length&&(this.isDrawing=!1)):(this.operate.data=[],this.isDrawing=!1),!0;if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.recordList.splice(e,0,t),!0}return this.recordList.length>0&&(this.recordList.pop(),!0)}selectAnnotation(t){if(t<0||t>=this.recordList.length)return this.deselectAnnotation(),!1;const e=this.recordList[t];return this.selectedAnnotation={index:t,type:e.type},!0}deselectAnnotation(){this.selectedAnnotation=null,this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}deleteSelectedAnnotation(){if(!this.selectedAnnotation)return!1;const t=this.selectedAnnotation.index,e=this.recordList[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.recordList.splice(t,1),this.deselectAnnotation(),!0}startMovingAnnotation(t){return!!this.selectedAnnotation&&(this.isMovingAnnotation=!0,this.annotationMoveStart={x:t.clientX,y:t.clientY},!0)}moveSelectedAnnotation(t,e){if(!this.selectedAnnotation)return!1;const n=this.recordList[this.selectedAnnotation.index];if(!n)return!1;if("rect"===n.type){const i=n.data[0];i.start.x+=t,i.start.y+=e}else if("polygon"===n.type){n.data.forEach(n=>{n.point.x+=t,n.point.y+=e})}return!0}finishMovingAnnotation(){this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}startResizing(t,e){if(!this.selectedAnnotation)return!1;this.activeHandle=t,this.isResizing=!0;const n=this.recordList[this.selectedAnnotation.index];return"rect"===n.type?this.originalRect=Object.assign({},n.data[0]):"polygon"===n.type&&(this.originalPolygon=n.data.map(t=>({point:Object.assign({},t.point)}))),!0}resizeRect(t){if(!this.selectedAnnotation||"rect"!==this.selectedAnnotation.type||!this.originalRect||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data[0],n=this.originalRect,i=n.start.x,s=n.start.x+n.width,a=n.start.y,o=n.start.y+n.height;let r,h;switch(this.activeHandle.index){case 0:r=s,h=o;break;case 1:r=i,h=o;break;case 2:r=s,h=a;break;case 3:r=i,h=a;break;default:return!1}const l=Math.min(t.x,r),c=Math.max(t.x,r),d=Math.min(t.y,h),g=Math.max(t.y,h);e.start.x=l,e.start.y=d,e.width=c-l,e.height=g-d;const x=t.x<r,f=t.y<h;return 0===this.activeHandle.index?x||f?!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2):this.activeHandle.index=3:1===this.activeHandle.index?x&&!f?this.activeHandle.index=2:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):2===this.activeHandle.index?!x&&f?this.activeHandle.index=1:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):3===this.activeHandle.index&&(x&&f?this.activeHandle.index=0:!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2)),this.originalRect=Object.assign({},e),!0}resizePolygon(t){if(!this.selectedAnnotation||"polygon"!==this.selectedAnnotation.type||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data,n=this.activeHandle.index;return n>=0&&n<e.length&&(e[n].point.x=t.x,e[n].point.y=t.y,!0)}getAnnotationAtPoint(t){for(let i=this.recordList.length-1;i>=0;i--){const s=this.recordList[i];if("rect"===s.type){if(e(t,s.data[0]))return{index:i,type:"rect"}}else if("polygon"===s.type){if(n(t,s.data))return{index:i,type:"polygon"}}}return null}getHandleAtPoint(t,e){if(!this.selectedAnnotation)return null;const n=this.recordList[this.selectedAnnotation.index],i=this.selectionStyle.handleSize/2;if("rect"===n.type){const s=n.data[0],a=this.viewport.offset.x+s.start.x*this.viewport.scale,o=this.viewport.offset.y+s.start.y*this.viewport.scale,r=s.width*this.viewport.scale,h=s.height*this.viewport.scale,l=[{x:a,y:o,index:0},{x:a+r,y:o,index:1},{x:a,y:o+h,index:2},{x:a+r,y:o+h,index:3}];for(const n of l)if(t>=n.x-i&&t<=n.x+i&&e>=n.y-i&&e<=n.y+i)return{type:"rect-corner",index:n.index}}else if("polygon"===n.type){const s=n.data;for(let n=0;n<s.length;n++){const a=s[n],o=this.viewport.offset.x+a.point.x*this.viewport.scale,r=this.viewport.offset.y+a.point.y*this.viewport.scale;if(t>=o-i&&t<=o+i&&e>=r-i&&e<=r+i)return{type:"polygon-vertex",index:n}}}return null}clear(){this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,this.deselectAnnotation(),this.deleteHistory=[]}getAnnotations(){return[...this.recordList]}getSelectedAnnotation(){if(!this.selectedAnnotation)return null;const t=this.recordList[this.selectedAnnotation.index];return t?{index:this.selectedAnnotation.index,type:this.selectedAnnotation.type,data:t}:null}}class l{constructor(t,e,n,i){this.viewport=t,this.container=e,this.ctx=n,this.renderCallback=i,this.textAnnotations=[],this.editingTextIndex=null,this.currentEditingIndex=null,this.isTextMoving=!1,this.textMoveStart={x:0,y:0},this.textBeforeEditing="",this.selectedTextIndex=null,this.textInput=null,this.deleteHistory=[],this.defaultInputStyle={border:"2px solid #00D9FF",borderRadius:"6px",padding:"6px 10px",fontSize:"16px",fontFamily:"Arial, sans-serif",backgroundColor:"#ffffff",color:"#333",boxShadow:"0 4px 12px rgba(0,0,0,0.3)",minWidth:"60px",maxWidth:"200px"},this.textStyle={font:"16px Arial",color:"#FFD700",padding:6,backgroundColor:"rgba(0,0,0,0.6)",borderRadius:4,selectedBorderColor:"#00D9FF",selectedBackgroundColor:"rgba(0,217,255,0.15)",inputStyle:Object.assign({},this.defaultInputStyle)},this.createTextInput()}createTextInput(){this.textInput=document.createElement("input"),this.textInput.type="text",this.textInput.style.position="absolute",this.textInput.style.zIndex="99999",this.textInput.style.display="none",this.textInput.style.outline="none",this.textInput.style.width="fit-content",this.textInput.placeholder="输入文字...",this.applyInputStyle(),this.textInput.addEventListener("blur",()=>{this.finishEditing(),this.renderCallback&&this.renderCallback()}),this.textInput.addEventListener("keydown",t=>{t.stopPropagation(),"Enter"===t.key?(this.finishEditing(),this.renderCallback&&this.renderCallback()):"Escape"===t.key?(t.preventDefault(),this.cancelEditing()):"Delete"===t.key&&""===this.textInput.value&&(t.preventDefault(),this.deleteEditingAnnotation())}),this.textInput.addEventListener("input",()=>{this.adjustInputWidth()}),this.container.appendChild(this.textInput)}applyInputStyle(){if(!this.textInput)return;const t=Object.assign(Object.assign({},this.defaultInputStyle),this.textStyle.inputStyle);this.textInput.style.border=t.border,this.textInput.style.borderRadius=t.borderRadius,this.textInput.style.padding=t.padding,this.textInput.style.fontSize=t.fontSize,this.textInput.style.fontFamily=t.fontFamily,this.textInput.style.backgroundColor=t.backgroundColor,this.textInput.style.color=t.color,this.textInput.style.boxShadow=t.boxShadow,this.textInput.style.minWidth=t.minWidth,this.textInput.style.maxWidth=t.maxWidth}setTextStyle(t){this.textStyle=Object.assign(Object.assign({},this.textStyle),t),this.applyInputStyle()}setInputStyle(t){this.textStyle.inputStyle=Object.assign(Object.assign({},this.textStyle.inputStyle),t),this.applyInputStyle()}setSelectionStyle(t){void 0!==t.selectedBorderColor&&(this.textStyle.selectedBorderColor=t.selectedBorderColor),void 0!==t.selectedBackgroundColor&&(this.textStyle.selectedBackgroundColor=t.selectedBackgroundColor)}getCurrentStyle(){return{font:this.textStyle.font,color:this.textStyle.color,backgroundColor:this.textStyle.backgroundColor}}addTextAnnotation(t,e,n=""){var i;this.ctx.font=this.textStyle.font;const s=n||"输入文字...",a=this.ctx.measureText(s);let o;if(a.actualBoundingBoxAscent&&a.actualBoundingBoxDescent)o=a.actualBoundingBoxAscent+a.actualBoundingBoxDescent;else{o=1.2*parseInt((null===(i=this.textStyle.font.match(/\d+/))||void 0===i?void 0:i[0])||"16")}const r={position:{x:t,y:e},text:n,style:this.getCurrentStyle(),width:Math.max(a.width,60),height:o};this.textAnnotations.push(r);const h=this.textAnnotations.length-1;return this.deleteHistory=[],this.startEditing(h),h}updateTextAnnotation(t,e){if(t<0||t>=this.textAnnotations.length)return!1;const n=this.textAnnotations[t];n.text=e,this.ctx.font=this.textStyle.font;const i=this.ctx.measureText(e);return n.width=i.width,n.height=1.2*parseInt(this.textStyle.font),!0}moveTextAnnotation(t,e,n){return!(t<0||t>=this.textAnnotations.length)&&(this.textAnnotations[t].position={x:e,y:n},!0)}removeTextAnnotation(t){if(t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.textAnnotations.splice(t,1),this.editingTextIndex===t?this.cancelEditing():null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,!0}clearTextAnnotations(){this.textAnnotations=[],this.selectedTextIndex=null,this.cancelEditing(),this.deleteHistory=[]}startEditing(t){if(!this.textInput||t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];this.editingTextIndex=t,this.currentEditingIndex=t,this.textBeforeEditing=e.text;const n=this.viewport.offset.x+e.position.x*this.viewport.scale,i=this.viewport.offset.y+e.position.y*this.viewport.scale;return this.textInput.value=e.text,this.textInput.style.left=n-this.textStyle.padding+"px",this.textInput.style.top=i-this.textStyle.padding+"px",this.textInput.style.display="block",this.adjustInputWidth(),setTimeout(()=>{this.textInput&&(this.textInput.focus(),this.textInput.select())},10),!0}finishEditing(){if(!this.textInput)return!1;const t=this.currentEditingIndex,e=this.textInput.value.trim();if(null===t||t<0||t>=this.textAnnotations.length)return this.resetEditingState(),!1;if(""===e)this.textAnnotations.splice(t,1);else{const n=this.textAnnotations[t];n.text=e,this.ctx.font=this.textStyle.font;const i=this.ctx.measureText(n.text);n.width=i.width,n.height=1.2*parseInt(this.textStyle.font)}return this.resetEditingState(),!0}cancelEditing(){if(!this.textInput||null===this.editingTextIndex)return!1;this.textInput.value=this.textBeforeEditing;const t=this.editingTextIndex;if(t>=0&&t<this.textAnnotations.length){""===this.textAnnotations[t].text&&""===this.textBeforeEditing&&this.textAnnotations.splice(t,1)}return this.resetEditingState(),!0}deleteEditingAnnotation(){if(null===this.editingTextIndex)return!1;const t=this.editingTextIndex;return this.textInput&&(this.textInput.style.display="none"),t>=0&&t<this.textAnnotations.length&&this.textAnnotations.splice(t,1),this.resetEditingState(),!0}resetEditingState(){this.textInput&&(this.textInput.style.display="none"),this.editingTextIndex=null,this.currentEditingIndex=null,this.textBeforeEditing=""}adjustInputWidth(){if(!this.textInput||null===this.editingTextIndex)return;this.ctx.font=this.textStyle.font;const t=this.textInput.value||this.textInput.placeholder||"",e=this.ctx.measureText(t).width,n=Math.min(Math.max(e+24,60),200);this.textInput.style.width=`${n}px`}startMoving(t,e){return!(e<0||e>=this.textAnnotations.length)&&(this.editingTextIndex=e,this.isTextMoving=!0,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}moveAnnotation(t){if(!this.isTextMoving||null===this.editingTextIndex)return!1;const e=t.clientX-this.textMoveStart.x,n=t.clientY-this.textMoveStart.y,i=this.textAnnotations[this.editingTextIndex];return!!i&&(i.position.x+=e/this.viewport.scale,i.position.y+=n/this.viewport.scale,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}finishMoving(){this.isTextMoving=!1}checkTextClick(t,e){for(let n=this.textAnnotations.length-1;n>=0;n--){const i=this.textAnnotations[n],s=this.viewport.offset.x+i.position.x*this.viewport.scale,a=this.viewport.offset.y+i.position.y*this.viewport.scale;if(t>=s-this.textStyle.padding&&t<=s+i.width+this.textStyle.padding&&e>=a-this.textStyle.padding&&e<=a+i.height+this.textStyle.padding)return n}return null}checkTextClickForMove(t){const e=this.checkTextClick(t.offsetX,t.offsetY);return null!==e?(this.startMoving(t,e),{index:e,handled:!0}):{index:-1,handled:!1}}getTextAnnotations(){return[...this.textAnnotations]}withdraw(){if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.textAnnotations.splice(e,0,t),!0}return this.textAnnotations.length>0&&(this.textAnnotations.pop(),!0)}selectTextAnnotation(t){return t<0||t>=this.textAnnotations.length?(this.deselectTextAnnotation(),!1):(this.selectedTextIndex=t,null!==this.editingTextIndex&&this.finishEditing(),!0)}deselectTextAnnotation(){this.selectedTextIndex=null}deleteSelectedTextAnnotation(){if(null===this.selectedTextIndex)return!1;const t=this.selectedTextIndex,e=this.textAnnotations[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.textAnnotations.splice(t,1),this.selectedTextIndex=null,null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,!0}getSelectedTextAnnotation(){if(null===this.selectedTextIndex)return null;const t=this.textAnnotations[this.selectedTextIndex];return t?{index:this.selectedTextIndex,data:t}:null}destroy(){this.textInput&&this.textInput.parentNode&&this.textInput.parentNode.removeChild(this.textInput)}}class c{constructor(t,e,n,i,s){this.ctx=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.canvas=s}render(t){this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.drawBackgroundImage(t),this.drawAnnotations(),this.drawTextAnnotations()}drawBackgroundImage(t){this.ctx.drawImage(t,this.viewport.offset.x,this.viewport.offset.y,this.viewport.originalWidth*this.viewport.scale,this.viewport.originalHeight*this.viewport.scale)}drawAnnotations(){this.annotationManager.recordList.forEach((t,e)=>{var n;const i=this.annotationManager.getAnnotationStyle(t);this.ctx.strokeStyle=i.strokeColor,this.ctx.lineWidth=i.lineWidth,this.setLineDash(i.lineStyle||"solid"),this.ctx.fillStyle=this.ctx.strokeStyle;const s=(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.index)===e;if("rect"===t.type)this.drawRect(t.data[0],s);else if("polygon"===t.type){const e=i.vertexStyle||this.annotationManager.getVertexStyle();this.drawPolygon(t.data,"fullfilled"===t.status,e)}}),this.annotationManager.operate.data.length>0&&(this.ctx.strokeStyle=this.annotationManager.strokeStyle,this.ctx.lineWidth=this.annotationManager.lineWidth,this.ctx.fillStyle=this.ctx.strokeStyle,this.setLineDash(this.annotationManager.lineStyle),"rect"===this.annotationManager.operate.type?this.drawRect(this.annotationManager.operate.data[0],!1):"polygon"===this.annotationManager.operate.type&&this.drawCurrentPolygon()),this.ctx.setLineDash([]),this.drawSelectionHighlight()}setLineDash(t){switch(t){case"dashed":this.ctx.setLineDash([10,5]);break;case"dotted":this.ctx.setLineDash([2,4]);break;default:this.ctx.setLineDash([])}}drawRect(t,e=!1){this.ctx.strokeRect(this.viewport.offset.x+t.start.x*this.viewport.scale,this.viewport.offset.y+t.start.y*this.viewport.scale,t.width*this.viewport.scale,t.height*this.viewport.scale)}drawPolygon(t,e,n){if(0!==t.length){if(this.ctx.beginPath(),t.forEach((t,e)=>{const n=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(n,i):this.ctx.lineTo(n,i)}),e&&t.length>1){const e=t[0];this.ctx.lineTo(this.viewport.offset.x+e.point.x*this.viewport.scale,this.viewport.offset.y+e.point.y*this.viewport.scale)}this.ctx.stroke(),this.drawPolygonVertices(t,n)}}drawPolygonVertices(t,e){const n=e||this.annotationManager.getVertexStyle(),i=n.size/2;t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),s=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);switch(this.ctx.fillStyle=n.fillColor,this.ctx.strokeStyle=n.strokeColor,this.ctx.lineWidth=n.strokeWidth,this.ctx.beginPath(),n.shape){case"square":this.ctx.rect(e-i,s-i,2*i,2*i);break;case"diamond":this.ctx.moveTo(e,s-i),this.ctx.lineTo(e+i,s),this.ctx.lineTo(e,s+i),this.ctx.lineTo(e-i,s),this.ctx.closePath();break;default:this.ctx.arc(e,s,i,0,2*Math.PI)}this.ctx.fill(),n.strokeWidth>0&&this.ctx.stroke()})}drawCurrentPolygon(){const t=this.annotationManager.operate.data,e=this.annotationManager.tempPolygonPoint;if(this.ctx.beginPath(),t.forEach((t,e)=>{const n=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(n,i):this.ctx.lineTo(n,i)}),e){const t=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+e.y*this.viewport.scale);this.ctx.lineTo(t,n)}if(this.ctx.stroke(),this.drawPolygonVertices(t,this.annotationManager.getVertexStyle()),e){const t=this.annotationManager.getVertexStyle(),n=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+e.y*this.viewport.scale),s=t.size/2;switch(this.ctx.fillStyle=t.fillColor,this.ctx.strokeStyle=t.strokeColor,this.ctx.lineWidth=t.strokeWidth,this.ctx.beginPath(),t.shape){case"square":this.ctx.rect(n-s,i-s,2*s,2*s);break;case"diamond":this.ctx.moveTo(n,i-s),this.ctx.lineTo(n+s,i),this.ctx.lineTo(n,i+s),this.ctx.lineTo(n-s,i),this.ctx.closePath();break;default:this.ctx.arc(n,i,s,0,2*Math.PI)}this.ctx.fill(),t.strokeWidth>0&&this.ctx.stroke()}}drawSelectionHighlight(){const t=this.annotationManager.selectedAnnotation;if(!t)return;const e=this.annotationManager.recordList[t.index];if(!e)return;const n=this.annotationManager.selectionStyle;this.ctx.save(),"rect"===e.type?this.drawRectSelectionHighlight(e.data[0],n):"polygon"===e.type&&this.drawPolygonSelectionHighlight(e.data,n),this.ctx.restore()}drawRectSelectionHighlight(t,e){const n=this.viewport.offset.x+t.start.x*this.viewport.scale,i=this.viewport.offset.y+t.start.y*this.viewport.scale,s=t.width*this.viewport.scale,a=t.height*this.viewport.scale;this.ctx.fillStyle=e.fillColor,this.ctx.fillRect(n,i,s,a),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.strokeRect(n,i,s,a);const o=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),this.ctx.fillRect(n-o/2,i-o/2,o,o),this.ctx.fillRect(n+s-o/2,i-o/2,o,o),this.ctx.fillRect(n-o/2,i+a-o/2,o,o),this.ctx.fillRect(n+s-o/2,i+a-o/2,o,o)}drawPolygonSelectionHighlight(t,e){this.ctx.beginPath(),t.forEach((t,e)=>{const n=this.viewport.offset.x+t.point.x*this.viewport.scale,i=this.viewport.offset.y+t.point.y*this.viewport.scale;0===e?this.ctx.moveTo(n,i):this.ctx.lineTo(n,i)}),this.ctx.closePath(),this.ctx.fillStyle=e.fillColor,this.ctx.fill(),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.stroke();const n=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);this.ctx.fillRect(e-n/2,i-n/2,n,n)})}drawTextAnnotations(){const t=this.textManager.textStyle;this.textManager.textAnnotations.forEach((e,n)=>{if(this.textManager.editingTextIndex===n&&this.textManager.textInput&&"none"!==this.textManager.textInput.style.display)return;if(!e.text)return;const i=e.style||{font:t.font,color:t.color,backgroundColor:t.backgroundColor},s=this.viewport.offset.x+e.position.x*this.viewport.scale,a=this.viewport.offset.y+e.position.y*this.viewport.scale,o=this.textManager.selectedTextIndex===n;this.ctx.font=i.font;const r=this.ctx.measureText(e.text),h=r.actualBoundingBoxAscent||.8*e.height,l=h+(r.actualBoundingBoxDescent||.2*e.height),c=t.borderRadius,d=s-t.padding,g=e.width+2*t.padding,x=l+2*t.padding,f=a-h-t.padding;this.ctx.fillStyle=i.backgroundColor,this.ctx.beginPath(),this.ctx.roundRect(d,f,g,x,c),this.ctx.fill(),o&&(this.ctx.strokeStyle=t.selectedBorderColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.beginPath(),this.ctx.roundRect(d,f,g,x,c),this.ctx.stroke(),this.ctx.setLineDash([])),this.ctx.fillStyle=i.color,this.ctx.fillText(e.text,s,a)})}drawForExport(t,e,n,i){t.drawImage(e,0,0,n,i),this.annotationManager.recordList.forEach(e=>{const n=this.annotationManager.getAnnotationStyle(e);if(t.strokeStyle=n.strokeColor,t.lineWidth=n.lineWidth,"rect"===e.type){const n=e.data[0];t.strokeRect(n.start.x,n.start.y,n.width,n.height)}else if("polygon"===e.type&&"fullfilled"===e.status){t.beginPath(),e.data.forEach((e,n)=>{0===n?t.moveTo(e.point.x,e.point.y):t.lineTo(e.point.x,e.point.y)});const i=e.data[0];t.lineTo(i.point.x,i.point.y),t.stroke(),e.data.forEach(e=>{t.beginPath(),t.arc(e.point.x,e.point.y,4,0,2*Math.PI),t.fillStyle=n.strokeColor,t.fill()})}}),this.textManager.textAnnotations.forEach(e=>{const n=this.textManager.textStyle,i=e.style||{font:n.font,color:n.color,backgroundColor:n.backgroundColor};t.font=i.font;const s=t.measureText(e.text),a=s.actualBoundingBoxAscent||.8*e.height,o=a+(s.actualBoundingBoxDescent||.2*e.height),r=e.position.x-n.padding,h=e.width+2*n.padding,l=o+2*n.padding,c=e.position.y-a-n.padding,d=n.borderRadius;t.fillStyle=i.backgroundColor,t.roundRect?(t.roundRect(r,c,h,l,d),t.fill()):t.fillRect(r,c,h,l),t.fillStyle=i.color,t.fillText(e.text,e.position.x,e.position.y)})}}class d{constructor(t,e,n,i,s,a,o,r,h){this.canvas=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.renderer=s,this.getDrawType=a,this.getBgImage=o,this.renderCallback=r,this.setDrawTypeCallback=h,this.isDragging=!1,this.dragStart={x:0,y:0},this.justFinishedMove=!1,this.justDeselected=!1}handleWheel(t){if(t.preventDefault(),!this.getBgImage())return;const e=t.deltaY>0?-.02:.02,n=this.viewport.scale,i=Math.max(this.viewport.minScale,Math.min(n+e,this.viewport.maxScale)),s=this.canvas.getBoundingClientRect(),a=t.clientX-s.left,o=t.clientY-s.top,r=(a-this.viewport.offset.x)/n,h=(o-this.viewport.offset.y)/n;this.viewport.scale=i;const l=r*i+this.viewport.offset.x,c=h*i+this.viewport.offset.y;this.viewport.offset.x+=a-l,this.viewport.offset.y+=o-c,this.viewport.calculateBoundaries(),this.viewport.constrainViewport(),this.viewport.isInitialScale=this.viewport.scale===this.viewport.initialScale,this.renderCallback()}handleMouseDown(t){var e,n;if(0!==t.button)return;const i=this.getDrawType(),s=this.getBgImage();if(this.annotationManager.selectedAnnotation&&s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(n)return this.annotationManager.startResizing(n,e),void this.renderCallback()}if("text"===i){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);if("rect"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(e);if("polygon"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();if(this.annotationManager.selectedAnnotation)return this.annotationManager.deselectAnnotation(),void this.renderCallback()}return null!==this.textManager.selectedTextIndex?(this.textManager.deselectTextAnnotation(),void this.renderCallback()):void this.handleTextModeClick(t)}if(!s)return;const a=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if("rect"===i){if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return this.annotationManager.startResizing(e,a),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(a);return n&&"rect"===n.type?(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const n=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==n)return this.textManager.selectedTextIndex===n?this.textManager.startMoving(t,n):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(n)),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(a);if("polygon"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const s=this.annotationManager.getAnnotationAtPoint(a);if("rect"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.startRectDrawing(a)}else if("polygon"===i){if("polygon"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e&&"polygon-vertex"===e.type)return this.annotationManager.startResizing(e,a),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(a);return n&&"polygon"===n.type?(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(a);if("rect"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const s=this.annotationManager.getAnnotationAtPoint(a);if("polygon"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.isDrawing?this.checkPolygonPointValid(a)&&this.annotationManager.addPolygonPoint(a):this.annotationManager.startPolygonDrawing(a),this.annotationManager.updatePolygonTempPoint(a),this.renderCallback()}else if("drag"===i){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return this.annotationManager.startResizing(e,a),void this.renderCallback()}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(this.handleRectModeClick(t,a))return;if(this.handlePolygonModeClick(t,a))return;this.isDragging=!0,this.dragStart={x:t.clientX,y:t.clientY},this.canvas.style.cursor="grabbing"}else""===i&&this.handleNoModeClick(t,a)}checkTextClickInDragMode(t){return!!this.textManager.checkTextClickForMove(t).handled&&(this.canvas.style.cursor="grabbing",!0)}handleTextModeClick(t){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.startMoving(t,e),this.canvas.style.cursor="grabbing",this.renderCallback(),!0;const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return this.textManager.addTextAnnotation(n.x,n.y),!0}handleRectModeClick(t,e){var n,i;if("rect"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)){const n=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(n)return this.annotationManager.startResizing(n,e),this.renderCallback(),!0}const s=this.annotationManager.getAnnotationAtPoint(e);return s&&"rect"===s.type?(this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0):"rect"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handlePolygonModeClick(t,e){var n,i;if("polygon"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)){const n=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(n&&"polygon-vertex"===n.type)return this.annotationManager.startResizing(n,e),this.renderCallback(),!0}const s=this.annotationManager.getAnnotationAtPoint(e);return s&&"polygon"===s.type?(this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0):"polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handleRectModeClickForMove(t,e){const n=this.annotationManager.getAnnotationAtPoint(e);return!(!n||"rect"!==n.type)&&(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handlePolygonModeClickForMove(t,e){const n=this.annotationManager.getAnnotationAtPoint(e);return!(!n||"polygon"!==n.type)&&(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handleNoModeClick(t,e){const n=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==n)return this.textManager.selectedTextIndex===n?this.textManager.startMoving(t,n):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(n)),void this.renderCallback();this.textManager.deselectTextAnnotation();const i=this.annotationManager.getAnnotationAtPoint(e);i?(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback()):this.annotationManager.deselectAnnotation()}checkPolygonPointValid(t){const e=this.annotationManager.operate.data.length>0?this.annotationManager.operate.data[this.annotationManager.operate.data.length-1]:null;return!e||Math.abs(e.point.x-t.x)>5||Math.abs(e.point.y-t.y)>5}handleMouseMove(t){if(!this.getBgImage())return;const e=this.getDrawType();if(this.isDragging&&"drag"===e){const e=t.clientX-this.dragStart.x,n=t.clientY-this.dragStart.y;return this.viewport.updateOffset(e,n),this.dragStart={x:t.clientX,y:t.clientY},void this.renderCallback()}if(this.textManager.isTextMoving&&null!==this.textManager.editingTextIndex)this.textManager.moveAnnotation(t)&&this.renderCallback();else if((this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&this.annotationManager.selectedAnnotation)this.handleAnnotationMove(t);else{if(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving||this.updateCursor(t),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updateRectDrawing(e),this.renderCallback()}if("polygon"===e&&this.annotationManager.isDrawing){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updatePolygonTempPoint(e),this.renderCallback()}}}handleAnnotationMove(t){var e,n;if(this.annotationManager.isResizing&&this.annotationManager.activeHandle){const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return"rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)?this.annotationManager.resizeRect(i):"polygon"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)&&this.annotationManager.resizePolygon(i),void this.renderCallback()}if(!this.annotationManager.isMovingAnnotation||!this.annotationManager.selectedAnnotation)return;const i=(t.clientX-this.annotationManager.annotationMoveStart.x)/this.viewport.scale,s=(t.clientY-this.annotationManager.annotationMoveStart.y)/this.viewport.scale;this.annotationManager.moveSelectedAnnotation(i,s),this.annotationManager.annotationMoveStart={x:t.clientX,y:t.clientY},this.renderCallback()}updateCursor(t){const e=this.getDrawType();if("text"===e){if(this.getBgImage()){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(this.annotationManager.getAnnotationAtPoint(e))return void(this.canvas.style.cursor="move")}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);return void(this.canvas.style.cursor=null!==e?"move":"crosshair")}"rect"!==e?"polygon"!==e?"drag"!==e?""!==e?this.canvas.style.cursor="default":this.updateNoModeCursor(t):this.updateDragModeCursor(t):this.updatePolygonModeCursor(t):this.updateRectModeCursor(t)}updateRectModeCursor(t){var e;if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void(this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize")}const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(n)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updatePolygonModeCursor(t){var e;if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){if(this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="crosshair")}const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(n)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updateDragModeCursor(t){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(null!==this.textManager.checkTextClick(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="move");const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=n?"move":"grab"}updateNoModeCursor(t){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(null!==this.textManager.checkTextClick(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="move");const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=n?"move":"default"}handleMouseUp(t){if(this.isDragging){this.isDragging=!1;const t=this.getDrawType();return void(this.canvas.style.cursor="drag"===t?"grab":"default")}if(this.textManager.isTextMoving){this.justFinishedMove=!0,this.textManager.finishMoving();const t=this.getDrawType();"drag"===t?this.canvas.style.cursor="grab":""===t?this.canvas.style.cursor="move":(this.textManager.editingTextIndex=null,this.canvas.style.cursor="default")}(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&(this.justFinishedMove=!0,this.annotationManager.finishMovingAnnotation(),this.canvas.style.cursor=this.annotationManager.selectedAnnotation?"move":"default"),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type&&(this.annotationManager.finishRectDrawing(),this.renderCallback())}handleMouseLeave(t){(this.isDragging||this.textManager.isTextMoving||this.annotationManager.isResizing||this.annotationManager.isMovingAnnotation)&&this.handleMouseUp(t)}handleDoubleClick(t){if(!this.getBgImage())return;this.justFinishedMove=!1;const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return void this.textManager.startEditing(e);if("polygon"===this.getDrawType()){if(this.annotationManager.isDrawing&&this.annotationManager.operate.data.length<=2)return;this.annotationManager.finishPolygonDrawing(),this.renderCallback()}}handleClick(t){var e;const n=this.getDrawType();if(!this.getBgImage()||"polygon"!==n||this.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;if(this.justDeselected)return void(this.justDeselected=!1);if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type))return;const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.checkPolygonPointValid(i)&&(this.annotationManager.isDrawing?this.annotationManager.addPolygonPoint(i):this.annotationManager.startPolygonDrawing(i)),this.annotationManager.updatePolygonTempPoint(i),this.renderCallback()}handleKeyDown(t){if("z"===t.key&&(t.ctrlKey||t.metaKey))return this.annotationManager.withdraw()||this.textManager.withdraw(),void this.renderCallback();if(" "===t.key)return this.viewport.resetToInitial(),void this.renderCallback();if("Escape"!==t.key){if("Delete"===t.key||"Backspace"===t.key){if(null!==this.textManager.editingTextIndex)return this.textManager.removeTextAnnotation(this.textManager.editingTextIndex),void this.renderCallback();if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.renderCallback();this.annotationManager.selectedAnnotation&&(this.annotationManager.deleteSelectedAnnotation(),this.renderCallback())}}else this.annotationManager.isDrawing?(this.annotationManager.cancelDrawing(),this.renderCallback()):this.annotationManager.selectedAnnotation&&(this.annotationManager.deselectAnnotation(),this.renderCallback())}}class g{constructor(t){this.canvas=document.createElement("canvas"),this.bgImage=null,this.bgImageSrc="",this.bgImageExt="jpeg",this.drawType="";const{drawType:e,useEvents:n=!0,id:i="container",annotationColor:s,lineStyle:a,vertexStyle:o,textStyle:g}=t,x=document.getElementById(i);if(!x)throw new Error(`Container with id "${i}" not found`);this.container=x,"absolute"!==x.style.position&&"fixed"!==x.style.position&&"relative"!==x.style.position&&(x.style.position="relative"),this.ctx=this.canvas.getContext("2d"),this.viewport=new r,this.viewport.setSize(x.clientWidth,x.clientHeight),this.canvas.width=this.viewport.width,this.canvas.height=this.viewport.height,this.canvas.style.width=`${this.viewport.width}px`,this.canvas.style.height=`${this.viewport.height}px`,this.canvas.style.cursor="default",this.canvas.style.display="block",x.appendChild(this.canvas),this.annotationManager=new h(this.viewport),s&&this.annotationManager.setColorConfig(s),a&&this.annotationManager.setLineStyle(a),o&&this.annotationManager.setVertexStyle(o),this.textManager=new l(this.viewport,this.container,this.ctx,()=>this.render()),g&&this.textManager.setTextStyle(g),this.renderer=new c(this.ctx,this.viewport,this.annotationManager,this.textManager,this.canvas),this.eventHandler=new d(this.canvas,this.viewport,this.annotationManager,this.textManager,this.renderer,()=>this.drawType,()=>this.bgImage,()=>this.render(),t=>this.setDrawType(t)),this.events={wheel:t=>this.eventHandler.handleWheel(t),mousedown:t=>this.eventHandler.handleMouseDown(t),mousemove:t=>this.eventHandler.handleMouseMove(t),mouseup:t=>this.eventHandler.handleMouseUp(t),mouseleave:t=>this.eventHandler.handleMouseLeave(t),dblclick:t=>this.eventHandler.handleDoubleClick(t),click:t=>this.eventHandler.handleClick(t),keydown:t=>this.eventHandler.handleKeyDown(t)},this.setDrawType(e||""),n&&this.addEventListeners()}setDrawType(t){"polygon"===this.drawType&&this.annotationManager.isDrawing&&this.annotationManager.operate.data.length>0?console.warn("Cannot switch mode while polygon is being drawn. Please complete or cancel the polygon first."):this.drawType!==t&&(this.annotationManager.operate.data=[],this.annotationManager.isDrawing=!1,this.annotationManager.tempPolygonPoint=null,""!==t&&this.deselectAnnotation(),this.annotationManager.operate.type=t,this.drawType=t,this.canvas.style.cursor="drag"===t?"grab":"text"===t?"text":"default")}drawImage(t){this.bgImageSrc=t,this.bgImageExt=i(t);const e=new Image;e.crossOrigin="anonymous",e.src=t,e.onload=()=>{this.bgImage=e,this.viewport.setOriginalSize(e.width,e.height),this.viewport.calculateInitialView(),this.render()}}render(){this.renderer.render(this.bgImage)}clear(t=""){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.setDrawType(t),this.render()}withdraw(){const t=this.annotationManager.withdraw(),e=this.textManager.withdraw();(t||e)&&this.render()}addEventListeners(){this.canvas.addEventListener("mousedown",this.events.mousedown),this.canvas.addEventListener("mousemove",this.events.mousemove),this.canvas.addEventListener("mouseup",this.events.mouseup),this.canvas.addEventListener("mouseleave",this.events.mouseleave),this.canvas.addEventListener("wheel",this.events.wheel),this.canvas.addEventListener("contextmenu",t=>t.preventDefault()),document.addEventListener("keydown",this.events.keydown),this.handleClickEventListener()}handleClickEventListener(){let t=null,e=0;this.canvas.addEventListener("click",n=>{if(this.eventHandler.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;const i=this.eventHandler.justFinishedMove;i&&(this.eventHandler.justFinishedMove=!1),e++,1===e?t=window.setTimeout(()=>{1!==e||i||this.events.click(n),e=0,t=null},300):2===e&&(this.eventHandler.justFinishedMove=!1,this.events.dblclick(n),e=0,null!==t&&(clearTimeout(t),t=null))})}changeScale(t){if(!this.bgImage)return;const e=o(this.viewport.scale,t),n=this.viewport.width/2,i=this.viewport.height/2,s=this.viewport.scale+e;this.viewport.updateScale(s,n,i),this.render()}clearCanvas(t=!1,e=!0){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.textManager.deselectTextAnnotation(),!t&&e&&(this.bgImage=null,this.bgImageSrc="",this.viewport.setOriginalSize(0,0),this.viewport.reset()),this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.bgImage&&this.render(),"drag"===this.drawType&&(this.canvas.style.cursor="default")}clearAnnotations(){this.clearCanvas(!0,!1)}getAnnotations(){return this.annotationManager.getAnnotations()}getTextAnnotations(){return this.textManager.getTextAnnotations()}exportAnnotationImage(){return new Promise((t,e)=>{if(!this.bgImage)return void e(new Error("No background image loaded"));const n=document.createElement("canvas");n.width=this.viewport.originalWidth,n.height=this.viewport.originalHeight;const i=n.getContext("2d");if(!i)return void e(new Error("Could not create offscreen canvas context"));const s=new Image;s.src=this.bgImageSrc,s.crossOrigin="anonymous",s.onload=()=>{try{this.renderer.drawForExport(i,s,this.viewport.originalWidth,this.viewport.originalHeight);const e=n.toDataURL(`image/${this.bgImageExt}`,.7);t(e)}catch(n){this.exportCurrentViewImage().then(t).catch(t=>e(new Error(`Both methods failed: ${t.message}`)))}},s.onerror=()=>{e(new Error("Failed to load image for export"))}})}exportCurrentViewImage(){return new Promise((t,e)=>{try{t(this.canvas.toDataURL(`image/${this.bgImageExt}`))}catch(t){e(new Error(`Failed to export current view: ${t.message}`))}})}base64ToFile(t,e){return s(t,e)}static base64ToBlob(t){return a(t)}addTextAnnotation(t,e,n=""){this.textManager.addTextAnnotation(t,e,n),this.render()}updateTextAnnotation(t,e){this.textManager.updateTextAnnotation(t,e)&&this.render()}moveTextAnnotation(t,e,n){this.textManager.moveTextAnnotation(t,e,n)&&this.render()}removeTextAnnotation(t){this.textManager.removeTextAnnotation(t)&&this.render()}clearTextAnnotations(){this.textManager.clearTextAnnotations(),this.render()}selectAnnotation(t){this.annotationManager.selectAnnotation(t)&&this.render()}deselectAnnotation(){this.annotationManager.deselectAnnotation(),this.textManager.deselectTextAnnotation(),this.textManager.editingTextIndex=null,this.render()}getSelectedAnnotation(){const t=this.annotationManager.getSelectedAnnotation();if(t)return t;const e=this.textManager.getSelectedTextAnnotation();return e?{index:e.index,type:"text",data:e.data}:null}deleteSelectedAnnotation(){if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.render();this.annotationManager.deleteSelectedAnnotation()&&this.render()}moveSelectedAnnotation(t,e){this.annotationManager.moveSelectedAnnotation(t,e)&&this.render()}setAnnotationColor(t){this.annotationManager.setColorConfig(t),this.render()}getAnnotationColor(){return this.annotationManager.getColorConfig()}updateSelectedAnnotationStyle(){const t=this.annotationManager.selectedAnnotation;if(!t)return!1;const e=this.annotationManager.recordList[t.index];return!!e&&(e.style=this.annotationManager.getCurrentStyle(),this.render(),!0)}setLineStyle(t){this.annotationManager.setLineStyle(t),this.render()}getLineStyle(){return this.annotationManager.getLineStyle()}setVertexStyle(t){this.annotationManager.setVertexStyle(t),this.render()}getVertexStyle(){return this.annotationManager.getVertexStyle()}setTextStyle(t){this.textManager.setTextStyle(t),this.render()}setTextInputStyle(t){this.textManager.setInputStyle(t)}setTextSelectionStyle(t){this.textManager.setSelectionStyle(t),this.render()}destroy(){this.textManager.destroy(),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}t.AnnotationManager=h,t.Drawer=g,t.EventHandler=d,t.Renderer=c,t.TextAnnotationManager=l,t.ViewportManager=r,t.base64ToBlob=a,t.base64ToFile=s,t.default=g,t.getImageTypeFromUrl=i,t.getZoomDelta=o,t.isPointInPolygon=n,t.isPointInRect=e,Object.defineProperty(t,"__esModule",{value:!0})}),"undefined"!=typeof ImageAnnotationDrawer&&ImageAnnotationDrawer.default&&(ImageAnnotationDrawer=ImageAnnotationDrawer.default);
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).ImageAnnotationDrawer=t.ImageAnnotationDrawer||{})}(this,function(t){"use strict";function e(t,e){const n=e.width>=0?e.start.x:e.start.x+e.width,i=e.height>=0?e.start.y:e.start.y+e.height,s=Math.abs(e.width),a=Math.abs(e.height);return t.x>=n&&t.x<=n+s&&t.y>=i&&t.y<=i+a}function n(t,e){if(e.length<3)return!1;let n=!1;for(let i=0,s=e.length-1;i<e.length;s=i++){const a=e[i].point.x,o=e[i].point.y,r=e[s].point.x,h=e[s].point.y;o>t.y!=h>t.y&&t.x<(r-a)*(t.y-o)/(h-o)+a&&(n=!n)}return n}function i(t){try{const e=new URL(t).pathname.toLowerCase();return e.endsWith(".png")?"png":e.endsWith(".jpg")?"jpg":e.endsWith(".jpeg")?"jpeg":e.endsWith(".webp")?"webp":e.endsWith(".gif")?"gif":e.endsWith(".bmp")?"bmp":e.endsWith(".svg")?"svg":"jpeg"}catch(t){return"jpeg"}}function s(t,e){const n=t.split(";base64,"),i=n[0].split(":")[1],s=window.atob(n[1]),a=s.length,o=new Uint8Array(a);for(let t=0;t<a;++t)o[t]=s.charCodeAt(t);const r=new Blob([o],{type:i});return new File([r],e,{type:i})}function a(t){return new Promise((e,n)=>{const i=t.split(";base64,");if(i.length<2)return void n(new Error("Invalid base64 string"));const s=i[0].split(":")[1],a=atob(i[1]),o=new ArrayBuffer(a.length),r=new Uint8Array(o);for(let t=0;t<a.length;t++)r[t]=a.charCodeAt(t);e(new Blob([o],{type:s}))})}function o(t,e){return t<2?e?.1:-.1:t<5?e?.05:-.05:e?.02:-.02}class r{constructor(){this.width=0,this.height=0,this.originalWidth=0,this.originalHeight=0,this.scale=1,this.minScale=1,this.maxScale=10,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}setSize(t,e){this.width=t,this.height=e}setOriginalSize(t,e){this.originalWidth=t,this.originalHeight=e}calculateInitialView(){if(0===this.originalWidth||0===this.originalHeight)return;const t=this.width/this.originalWidth,e=this.height/this.originalHeight;this.scale=Math.min(t,e),this.initialScale=this.scale,this.minScale=this.initialScale,this.offset={x:(this.width-this.originalWidth*this.scale)/2,y:(this.height-this.originalHeight*this.scale)/2},this.initialOffset=Object.assign({},this.offset),this.calculateBoundaries(),this.isInitialScale=!0}calculateBoundaries(){const t=this.originalWidth*this.scale,e=this.originalHeight*this.scale;this.maxOffsetX=0,this.maxOffsetY=0,this.minOffsetX=this.width-t,this.minOffsetY=this.height-e,this.minOffsetX>this.maxOffsetX&&([this.minOffsetX,this.maxOffsetX]=[this.maxOffsetX,this.minOffsetX]),this.minOffsetY>this.maxOffsetY&&([this.minOffsetY,this.maxOffsetY]=[this.maxOffsetY,this.minOffsetY])}constrainViewport(){this.offset.x>this.maxOffsetX?this.offset.x=this.maxOffsetX:this.offset.x<this.minOffsetX&&(this.offset.x=this.minOffsetX),this.offset.y>this.maxOffsetY?this.offset.y=this.maxOffsetY:this.offset.y<this.minOffsetY&&(this.offset.y=this.minOffsetY)}toImageCoordinates(t,e){return{x:(t-this.offset.x)/this.scale,y:(e-this.offset.y)/this.scale}}toCanvasCoordinates(t,e){return{x:this.offset.x+t*this.scale,y:this.offset.y+e*this.scale}}updateScale(t,e,n){const i=this.scale,s=(e-this.offset.x)/i,a=(n-this.offset.y)/i;this.scale=Math.max(this.minScale,Math.min(t,this.maxScale));const o=s*this.scale+this.offset.x,r=a*this.scale+this.offset.y;this.offset.x+=e-o,this.offset.y+=n-r,this.calculateBoundaries(),this.constrainViewport(),this.isInitialScale=this.scale===this.initialScale}resetToInitial(){this.scale=this.initialScale,this.offset=Object.assign({},this.initialOffset),this.calculateBoundaries(),this.isInitialScale=!0}updateOffset(t,e){this.offset.x+=t,this.offset.y+=e,this.constrainViewport()}reset(){this.scale=1,this.minScale=1,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}}class h{constructor(t){this.viewport=t,this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.drawStartPoint={x:0,y:0},this.tempPolygonPoint=null,this.selectedAnnotation=null,this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.annotationMoveStart={x:0,y:0},this.originalRect=null,this.originalPolygon=null,this.deleteHistory=[],this.strokeStyle="red",this.lineWidth=5,this.lineStyle="solid",this.vertexStyle={size:8,fillColor:"red",strokeColor:"white",strokeWidth:2,shape:"circle"},this.selectionStyle={strokeColor:"#00D9FF",fillColor:"rgba(0,217,255,0.15)",handleSize:12,handleColor:"#00D9FF"},this.colorConfig={rect:"red",polygon:"red",default:"red"},this.applyColorConfig()}setColorConfig(t){this.colorConfig="string"==typeof t?{rect:t,polygon:t,default:t}:Object.assign(Object.assign({},this.colorConfig),t),this.applyColorConfig()}getColorConfig(){return Object.assign({},this.colorConfig)}applyColorConfig(){this.strokeStyle=this.colorConfig.default||"red"}getColorForType(t){return this.colorConfig[t]||this.colorConfig.default||"red"}getCurrentStyle(){return{strokeColor:this.strokeStyle,lineWidth:this.lineWidth,lineStyle:this.lineStyle,vertexStyle:Object.assign({},this.vertexStyle)}}setLineStyle(t){this.lineStyle=t}setVertexStyle(t){this.vertexStyle=Object.assign(Object.assign({},this.vertexStyle),t),t.fillColor&&(this.strokeStyle=t.fillColor)}getLineStyle(){return this.lineStyle}getVertexStyle(){return Object.assign({},this.vertexStyle)}getAnnotationStyle(t){return t.style||this.getCurrentStyle()}startRectDrawing(t){this.isDrawing=!0,this.drawStartPoint=t,this.operate={type:"rect",data:[{start:Object.assign({},t),width:0,height:0}],status:"pending"}}updateRectDrawing(t){if(!this.isDrawing||"rect"!==this.operate.type)return;const e=this.operate.data[0];e.width=t.x-this.drawStartPoint.x,e.height=t.y-this.drawStartPoint.y}finishRectDrawing(){if(!this.isDrawing||"rect"!==this.operate.type)return!1;const t=this.operate.data[0];if(Math.abs(t.width)>5&&Math.abs(t.height)>5){const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[]}return this.operate.data=[],this.isDrawing=!1,!0}startPolygonDrawing(t){this.isDrawing=!0,this.operate={type:"polygon",data:[{point:t}],status:"pending"},this.tempPolygonPoint=t}addPolygonPoint(t){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;const e=this.operate.data.length>0?this.operate.data[this.operate.data.length-1]:null;return!(e&&Math.abs(e.point.x-t.x)<=5&&Math.abs(e.point.y-t.y)<=5)&&(this.operate.data.push({point:t}),!0)}updatePolygonTempPoint(t){this.tempPolygonPoint=t}finishPolygonDrawing(){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;if(this.operate.data.length>=3){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[]}return this.operate={type:"polygon",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,!0}cancelDrawing(){if(this.isDrawing&&"polygon"===this.operate.type&&this.operate.data.length>=2){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t)}this.operate.data=[],this.isDrawing=!1,this.tempPolygonPoint=null}withdraw(){if(this.operate.data.length>0)return"polygon"===this.operate.type?(this.operate.data.pop(),0===this.operate.data.length&&(this.isDrawing=!1)):(this.operate.data=[],this.isDrawing=!1),!0;if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.recordList.splice(e,0,t),!0}return this.recordList.length>0&&(this.recordList.pop(),!0)}selectAnnotation(t){if(t<0||t>=this.recordList.length)return this.deselectAnnotation(),!1;const e=this.recordList[t];return this.selectedAnnotation={index:t,type:e.type},!0}deselectAnnotation(){this.selectedAnnotation=null,this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}deleteSelectedAnnotation(){if(!this.selectedAnnotation)return!1;const t=this.selectedAnnotation.index,e=this.recordList[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.recordList.splice(t,1),this.deselectAnnotation(),!0}startMovingAnnotation(t){return!!this.selectedAnnotation&&(this.isMovingAnnotation=!0,this.annotationMoveStart={x:t.clientX,y:t.clientY},!0)}moveSelectedAnnotation(t,e){if(!this.selectedAnnotation)return!1;const n=this.recordList[this.selectedAnnotation.index];if(!n)return!1;if("rect"===n.type){const i=n.data[0];i.start.x+=t,i.start.y+=e}else if("polygon"===n.type){n.data.forEach(n=>{n.point.x+=t,n.point.y+=e})}return!0}finishMovingAnnotation(){this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}startResizing(t,e){if(!this.selectedAnnotation)return!1;this.activeHandle=t,this.isResizing=!0;const n=this.recordList[this.selectedAnnotation.index];return"rect"===n.type?this.originalRect=Object.assign({},n.data[0]):"polygon"===n.type&&(this.originalPolygon=n.data.map(t=>({point:Object.assign({},t.point)}))),!0}resizeRect(t){if(!this.selectedAnnotation||"rect"!==this.selectedAnnotation.type||!this.originalRect||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data[0],n=this.originalRect,i=n.start.x,s=n.start.x+n.width,a=n.start.y,o=n.start.y+n.height;let r,h;switch(this.activeHandle.index){case 0:r=s,h=o;break;case 1:r=i,h=o;break;case 2:r=s,h=a;break;case 3:r=i,h=a;break;default:return!1}const l=Math.min(t.x,r),c=Math.max(t.x,r),d=Math.min(t.y,h),g=Math.max(t.y,h);e.start.x=l,e.start.y=d,e.width=c-l,e.height=g-d;const x=t.x<r,f=t.y<h;return 0===this.activeHandle.index?x||f?!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2):this.activeHandle.index=3:1===this.activeHandle.index?x&&!f?this.activeHandle.index=2:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):2===this.activeHandle.index?!x&&f?this.activeHandle.index=1:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):3===this.activeHandle.index&&(x&&f?this.activeHandle.index=0:!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2)),this.originalRect=Object.assign({},e),!0}resizePolygon(t){if(!this.selectedAnnotation||"polygon"!==this.selectedAnnotation.type||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data,n=this.activeHandle.index;return n>=0&&n<e.length&&(e[n].point.x=t.x,e[n].point.y=t.y,!0)}getAnnotationAtPoint(t){for(let i=this.recordList.length-1;i>=0;i--){const s=this.recordList[i];if("rect"===s.type){if(e(t,s.data[0]))return{index:i,type:"rect"}}else if("polygon"===s.type){if(n(t,s.data))return{index:i,type:"polygon"}}}return null}getHandleAtPoint(t,e){if(!this.selectedAnnotation)return null;const n=this.recordList[this.selectedAnnotation.index],i=this.selectionStyle.handleSize/2;if("rect"===n.type){const s=n.data[0],a=this.viewport.offset.x+s.start.x*this.viewport.scale,o=this.viewport.offset.y+s.start.y*this.viewport.scale,r=s.width*this.viewport.scale,h=s.height*this.viewport.scale,l=[{x:a,y:o,index:0},{x:a+r,y:o,index:1},{x:a,y:o+h,index:2},{x:a+r,y:o+h,index:3}];for(const n of l)if(t>=n.x-i&&t<=n.x+i&&e>=n.y-i&&e<=n.y+i)return{type:"rect-corner",index:n.index}}else if("polygon"===n.type){const s=n.data;for(let n=0;n<s.length;n++){const a=s[n],o=this.viewport.offset.x+a.point.x*this.viewport.scale,r=this.viewport.offset.y+a.point.y*this.viewport.scale;if(t>=o-i&&t<=o+i&&e>=r-i&&e<=r+i)return{type:"polygon-vertex",index:n}}}return null}clear(){this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,this.deselectAnnotation(),this.deleteHistory=[]}getAnnotations(){return[...this.recordList]}getSelectedAnnotation(){if(!this.selectedAnnotation)return null;const t=this.recordList[this.selectedAnnotation.index];return t?{index:this.selectedAnnotation.index,type:this.selectedAnnotation.type,data:t}:null}}class l{constructor(t,e,n,i){this.viewport=t,this.container=e,this.ctx=n,this.renderCallback=i,this.textAnnotations=[],this.editingTextIndex=null,this.currentEditingIndex=null,this.isTextMoving=!1,this.textMoveStart={x:0,y:0},this.textBeforeEditing="",this.selectedTextIndex=null,this.textInput=null,this.deleteHistory=[],this.defaultInputStyle={border:"2px solid #00D9FF",borderRadius:"6px",padding:"6px 10px",fontSize:"16px",fontFamily:"Arial, sans-serif",backgroundColor:"#ffffff",color:"#333",boxShadow:"0 4px 12px rgba(0,0,0,0.3)",minWidth:"60px",maxWidth:"200px"},this.textStyle={font:"16px Arial",color:"#FFD700",padding:6,backgroundColor:"rgba(0,0,0,0.6)",borderRadius:4,selectedBorderColor:"#00D9FF",selectedBackgroundColor:"rgba(0,217,255,0.15)",inputStyle:Object.assign({},this.defaultInputStyle)},this.createTextInput()}createTextInput(){this.textInput=document.createElement("input"),this.textInput.type="text",this.textInput.style.position="absolute",this.textInput.style.zIndex="99999",this.textInput.style.display="none",this.textInput.style.outline="none",this.textInput.style.width="fit-content",this.textInput.placeholder="输入文字...",this.applyInputStyle(),this.textInput.addEventListener("blur",()=>{this.finishEditing(),this.renderCallback&&this.renderCallback()}),this.textInput.addEventListener("keydown",t=>{t.stopPropagation(),"Enter"===t.key?(this.finishEditing(),this.renderCallback&&this.renderCallback()):"Escape"===t.key?(t.preventDefault(),this.cancelEditing()):"Delete"===t.key&&""===this.textInput.value&&(t.preventDefault(),this.deleteEditingAnnotation())}),this.textInput.addEventListener("input",()=>{this.adjustInputWidth()}),this.container.appendChild(this.textInput)}applyInputStyle(){if(!this.textInput)return;const t=Object.assign(Object.assign({},this.defaultInputStyle),this.textStyle.inputStyle);this.textInput.style.border=t.border,this.textInput.style.borderRadius=t.borderRadius,this.textInput.style.padding=t.padding,this.textInput.style.fontSize=t.fontSize,this.textInput.style.fontFamily=t.fontFamily,this.textInput.style.backgroundColor=t.backgroundColor,this.textInput.style.color=t.color,this.textInput.style.boxShadow=t.boxShadow,this.textInput.style.minWidth=t.minWidth,this.textInput.style.maxWidth=t.maxWidth}setTextStyle(t){this.textStyle=Object.assign(Object.assign({},this.textStyle),t),this.applyInputStyle()}setInputStyle(t){this.textStyle.inputStyle=Object.assign(Object.assign({},this.textStyle.inputStyle),t),this.applyInputStyle()}setSelectionStyle(t){void 0!==t.selectedBorderColor&&(this.textStyle.selectedBorderColor=t.selectedBorderColor),void 0!==t.selectedBackgroundColor&&(this.textStyle.selectedBackgroundColor=t.selectedBackgroundColor)}getCurrentStyle(){return{font:this.textStyle.font,color:this.textStyle.color,backgroundColor:this.textStyle.backgroundColor}}addTextAnnotation(t,e,n=""){var i;this.ctx.font=this.textStyle.font;const s=n||"输入文字...",a=this.ctx.measureText(s);let o;if(a.actualBoundingBoxAscent&&a.actualBoundingBoxDescent)o=a.actualBoundingBoxAscent+a.actualBoundingBoxDescent;else{o=1.2*parseInt((null===(i=this.textStyle.font.match(/\d+/))||void 0===i?void 0:i[0])||"16")}const r={position:{x:t,y:e},text:n,style:this.getCurrentStyle(),width:Math.max(a.width,60),height:o};this.textAnnotations.push(r);const h=this.textAnnotations.length-1;return this.deleteHistory=[],this.startEditing(h),h}updateTextAnnotation(t,e){if(t<0||t>=this.textAnnotations.length)return!1;const n=this.textAnnotations[t];n.text=e,this.ctx.font=this.textStyle.font;const i=this.ctx.measureText(e);return n.width=i.width,n.height=1.2*parseInt(this.textStyle.font),!0}moveTextAnnotation(t,e,n){return!(t<0||t>=this.textAnnotations.length)&&(this.textAnnotations[t].position={x:e,y:n},!0)}removeTextAnnotation(t){if(t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.textAnnotations.splice(t,1),this.editingTextIndex===t?this.cancelEditing():null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,!0}clearTextAnnotations(){this.textAnnotations=[],this.selectedTextIndex=null,this.cancelEditing(),this.deleteHistory=[]}startEditing(t){if(!this.textInput||t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];this.editingTextIndex=t,this.currentEditingIndex=t,this.textBeforeEditing=e.text;const n=this.viewport.offset.x+e.position.x*this.viewport.scale,i=this.viewport.offset.y+e.position.y*this.viewport.scale;return this.textInput.value=e.text,this.textInput.style.left=n-this.textStyle.padding+"px",this.textInput.style.top=i-this.textStyle.padding+"px",this.textInput.style.display="block",this.adjustInputWidth(),setTimeout(()=>{this.textInput&&(this.textInput.focus(),this.textInput.select())},10),!0}finishEditing(){if(!this.textInput)return!1;const t=this.currentEditingIndex,e=this.textInput.value.trim();if(null===t||t<0||t>=this.textAnnotations.length)return this.resetEditingState(),!1;if(""===e)this.textAnnotations.splice(t,1);else{const n=this.textAnnotations[t];n.text=e,this.ctx.font=this.textStyle.font;const i=this.ctx.measureText(n.text);n.width=i.width,n.height=1.2*parseInt(this.textStyle.font)}return this.resetEditingState(),!0}cancelEditing(){if(!this.textInput||null===this.editingTextIndex)return!1;this.textInput.value=this.textBeforeEditing;const t=this.editingTextIndex;if(t>=0&&t<this.textAnnotations.length){""===this.textAnnotations[t].text&&""===this.textBeforeEditing&&this.textAnnotations.splice(t,1)}return this.resetEditingState(),!0}deleteEditingAnnotation(){if(null===this.editingTextIndex)return!1;const t=this.editingTextIndex;return this.textInput&&(this.textInput.style.display="none"),t>=0&&t<this.textAnnotations.length&&this.textAnnotations.splice(t,1),this.resetEditingState(),!0}resetEditingState(){this.textInput&&(this.textInput.style.display="none"),this.editingTextIndex=null,this.currentEditingIndex=null,this.textBeforeEditing=""}adjustInputWidth(){if(!this.textInput||null===this.editingTextIndex)return;this.ctx.font=this.textStyle.font;const t=this.textInput.value||this.textInput.placeholder||"",e=this.ctx.measureText(t).width,n=Math.min(Math.max(e+24,60),200);this.textInput.style.width=`${n}px`}startMoving(t,e){return!(e<0||e>=this.textAnnotations.length)&&(this.editingTextIndex=e,this.isTextMoving=!0,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}moveAnnotation(t){if(!this.isTextMoving||null===this.editingTextIndex)return!1;const e=t.clientX-this.textMoveStart.x,n=t.clientY-this.textMoveStart.y,i=this.textAnnotations[this.editingTextIndex];return!!i&&(i.position.x+=e/this.viewport.scale,i.position.y+=n/this.viewport.scale,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}finishMoving(){this.isTextMoving=!1}checkTextClick(t,e){for(let n=this.textAnnotations.length-1;n>=0;n--){const i=this.textAnnotations[n],s=this.viewport.offset.x+i.position.x*this.viewport.scale,a=this.viewport.offset.y+i.position.y*this.viewport.scale;if(t>=s-this.textStyle.padding&&t<=s+i.width+this.textStyle.padding&&e>=a-this.textStyle.padding&&e<=a+i.height+this.textStyle.padding)return n}return null}checkTextClickForMove(t){const e=this.checkTextClick(t.offsetX,t.offsetY);return null!==e?(this.startMoving(t,e),{index:e,handled:!0}):{index:-1,handled:!1}}getTextAnnotations(){return[...this.textAnnotations]}withdraw(){if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.textAnnotations.splice(e,0,t),!0}return this.textAnnotations.length>0&&(this.textAnnotations.pop(),!0)}selectTextAnnotation(t){return t<0||t>=this.textAnnotations.length?(this.deselectTextAnnotation(),!1):(this.selectedTextIndex=t,null!==this.editingTextIndex&&this.finishEditing(),!0)}deselectTextAnnotation(){this.selectedTextIndex=null}deleteSelectedTextAnnotation(){if(null===this.selectedTextIndex)return!1;const t=this.selectedTextIndex,e=this.textAnnotations[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.textAnnotations.splice(t,1),this.selectedTextIndex=null,null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,!0}getSelectedTextAnnotation(){if(null===this.selectedTextIndex)return null;const t=this.textAnnotations[this.selectedTextIndex];return t?{index:this.selectedTextIndex,data:t}:null}destroy(){this.textInput&&this.textInput.parentNode&&this.textInput.parentNode.removeChild(this.textInput)}}class c{constructor(t,e,n,i,s){this.ctx=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.canvas=s}render(t){this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.drawBackgroundImage(t),this.drawAnnotations(),this.drawTextAnnotations()}drawBackgroundImage(t){this.ctx.drawImage(t,this.viewport.offset.x,this.viewport.offset.y,this.viewport.originalWidth*this.viewport.scale,this.viewport.originalHeight*this.viewport.scale)}drawAnnotations(){this.annotationManager.recordList.forEach((t,e)=>{var n;const i=this.annotationManager.getAnnotationStyle(t);this.ctx.strokeStyle=i.strokeColor,this.ctx.lineWidth=i.lineWidth,this.setLineDash(i.lineStyle||"solid"),this.ctx.fillStyle=this.ctx.strokeStyle;const s=(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.index)===e;if("rect"===t.type)this.drawRect(t.data[0],s);else if("polygon"===t.type){const e=i.vertexStyle||this.annotationManager.getVertexStyle();this.drawPolygon(t.data,"fullfilled"===t.status,e)}}),this.annotationManager.operate.data.length>0&&(this.ctx.strokeStyle=this.annotationManager.strokeStyle,this.ctx.lineWidth=this.annotationManager.lineWidth,this.ctx.fillStyle=this.ctx.strokeStyle,this.setLineDash(this.annotationManager.lineStyle),"rect"===this.annotationManager.operate.type?this.drawRect(this.annotationManager.operate.data[0],!1):"polygon"===this.annotationManager.operate.type&&this.drawCurrentPolygon()),this.ctx.setLineDash([]),this.drawSelectionHighlight()}setLineDash(t){switch(t){case"dashed":this.ctx.setLineDash([10,5]);break;case"dotted":this.ctx.setLineDash([2,4]);break;default:this.ctx.setLineDash([])}}drawRect(t,e=!1){this.ctx.strokeRect(this.viewport.offset.x+t.start.x*this.viewport.scale,this.viewport.offset.y+t.start.y*this.viewport.scale,t.width*this.viewport.scale,t.height*this.viewport.scale)}drawPolygon(t,e,n){if(0!==t.length){if(this.ctx.beginPath(),t.forEach((t,e)=>{const n=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(n,i):this.ctx.lineTo(n,i)}),e&&t.length>1){const e=t[0];this.ctx.lineTo(this.viewport.offset.x+e.point.x*this.viewport.scale,this.viewport.offset.y+e.point.y*this.viewport.scale)}this.ctx.stroke(),this.drawPolygonVertices(t,n)}}drawPolygonVertices(t,e){const n=e||this.annotationManager.getVertexStyle(),i=n.size/2;t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),s=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);switch(this.ctx.fillStyle=n.fillColor,this.ctx.strokeStyle=n.strokeColor,this.ctx.lineWidth=n.strokeWidth,this.ctx.beginPath(),n.shape){case"square":this.ctx.rect(e-i,s-i,2*i,2*i);break;case"diamond":this.ctx.moveTo(e,s-i),this.ctx.lineTo(e+i,s),this.ctx.lineTo(e,s+i),this.ctx.lineTo(e-i,s),this.ctx.closePath();break;default:this.ctx.arc(e,s,i,0,2*Math.PI)}this.ctx.fill(),n.strokeWidth>0&&this.ctx.stroke()})}drawCurrentPolygon(){const t=this.annotationManager.operate.data,e=this.annotationManager.tempPolygonPoint;if(this.ctx.beginPath(),t.forEach((t,e)=>{const n=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(n,i):this.ctx.lineTo(n,i)}),e){const t=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+e.y*this.viewport.scale);this.ctx.lineTo(t,n)}if(this.ctx.stroke(),this.drawPolygonVertices(t,this.annotationManager.getVertexStyle()),e){const t=this.annotationManager.getVertexStyle(),n=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+e.y*this.viewport.scale),s=t.size/2;switch(this.ctx.fillStyle=t.fillColor,this.ctx.strokeStyle=t.strokeColor,this.ctx.lineWidth=t.strokeWidth,this.ctx.beginPath(),t.shape){case"square":this.ctx.rect(n-s,i-s,2*s,2*s);break;case"diamond":this.ctx.moveTo(n,i-s),this.ctx.lineTo(n+s,i),this.ctx.lineTo(n,i+s),this.ctx.lineTo(n-s,i),this.ctx.closePath();break;default:this.ctx.arc(n,i,s,0,2*Math.PI)}this.ctx.fill(),t.strokeWidth>0&&this.ctx.stroke()}}drawSelectionHighlight(){const t=this.annotationManager.selectedAnnotation;if(!t)return;const e=this.annotationManager.recordList[t.index];if(!e)return;const n=this.annotationManager.selectionStyle;this.ctx.save(),"rect"===e.type?this.drawRectSelectionHighlight(e.data[0],n):"polygon"===e.type&&this.drawPolygonSelectionHighlight(e.data,n),this.ctx.restore()}drawRectSelectionHighlight(t,e){const n=this.viewport.offset.x+t.start.x*this.viewport.scale,i=this.viewport.offset.y+t.start.y*this.viewport.scale,s=t.width*this.viewport.scale,a=t.height*this.viewport.scale;this.ctx.fillStyle=e.fillColor,this.ctx.fillRect(n,i,s,a),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.strokeRect(n,i,s,a);const o=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),this.ctx.fillRect(n-o/2,i-o/2,o,o),this.ctx.fillRect(n+s-o/2,i-o/2,o,o),this.ctx.fillRect(n-o/2,i+a-o/2,o,o),this.ctx.fillRect(n+s-o/2,i+a-o/2,o,o)}drawPolygonSelectionHighlight(t,e){this.ctx.beginPath(),t.forEach((t,e)=>{const n=this.viewport.offset.x+t.point.x*this.viewport.scale,i=this.viewport.offset.y+t.point.y*this.viewport.scale;0===e?this.ctx.moveTo(n,i):this.ctx.lineTo(n,i)}),this.ctx.closePath(),this.ctx.fillStyle=e.fillColor,this.ctx.fill(),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.stroke();const n=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);this.ctx.fillRect(e-n/2,i-n/2,n,n)})}drawTextAnnotations(){const t=this.textManager.textStyle;this.textManager.textAnnotations.forEach((e,n)=>{if(this.textManager.editingTextIndex===n&&this.textManager.textInput&&"none"!==this.textManager.textInput.style.display)return;if(!e.text)return;const i=e.style||{font:t.font,color:t.color,backgroundColor:t.backgroundColor},s=this.viewport.offset.x+e.position.x*this.viewport.scale,a=this.viewport.offset.y+e.position.y*this.viewport.scale,o=this.textManager.selectedTextIndex===n;this.ctx.font=i.font;const r=this.ctx.measureText(e.text),h=r.actualBoundingBoxAscent||.8*e.height,l=h+(r.actualBoundingBoxDescent||.2*e.height),c=t.borderRadius,d=s-t.padding,g=e.width+2*t.padding,x=l+2*t.padding,f=a-h-t.padding;this.ctx.fillStyle=i.backgroundColor,this.ctx.beginPath(),this.ctx.roundRect(d,f,g,x,c),this.ctx.fill(),o&&(this.ctx.strokeStyle=t.selectedBorderColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.beginPath(),this.ctx.roundRect(d,f,g,x,c),this.ctx.stroke(),this.ctx.setLineDash([])),this.ctx.fillStyle=i.color,this.ctx.fillText(e.text,s,a)})}drawForExport(t,e,n,i){t.drawImage(e,0,0,n,i),this.annotationManager.recordList.forEach(e=>{const n=this.annotationManager.getAnnotationStyle(e);if(t.strokeStyle=n.strokeColor,t.lineWidth=n.lineWidth,"rect"===e.type){const n=e.data[0];t.strokeRect(n.start.x,n.start.y,n.width,n.height)}else if("polygon"===e.type&&"fullfilled"===e.status){t.beginPath(),e.data.forEach((e,n)=>{0===n?t.moveTo(e.point.x,e.point.y):t.lineTo(e.point.x,e.point.y)});const i=e.data[0];t.lineTo(i.point.x,i.point.y),t.stroke(),e.data.forEach(e=>{t.beginPath(),t.arc(e.point.x,e.point.y,4,0,2*Math.PI),t.fillStyle=n.strokeColor,t.fill()})}}),this.textManager.textAnnotations.forEach(e=>{const n=this.textManager.textStyle,i=e.style||{font:n.font,color:n.color,backgroundColor:n.backgroundColor};t.font=i.font;const s=t.measureText(e.text),a=s.actualBoundingBoxAscent||.8*e.height,o=a+(s.actualBoundingBoxDescent||.2*e.height),r=e.position.x-n.padding,h=e.width+2*n.padding,l=o+2*n.padding,c=e.position.y-a-n.padding,d=n.borderRadius;t.fillStyle=i.backgroundColor,t.roundRect?(t.roundRect(r,c,h,l,d),t.fill()):t.fillRect(r,c,h,l),t.fillStyle=i.color,t.fillText(e.text,e.position.x,e.position.y)})}}class d{constructor(t,e,n,i,s,a,o,r,h){this.canvas=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.renderer=s,this.getDrawType=a,this.getBgImage=o,this.renderCallback=r,this.setDrawTypeCallback=h,this.isDragging=!1,this.dragStart={x:0,y:0},this.justFinishedMove=!1,this.justDeselected=!1}handleWheel(t){if(t.preventDefault(),!this.getBgImage())return;const e=t.deltaY>0?-.02:.02,n=this.viewport.scale,i=Math.max(this.viewport.minScale,Math.min(n+e,this.viewport.maxScale)),s=this.canvas.getBoundingClientRect(),a=t.clientX-s.left,o=t.clientY-s.top,r=(a-this.viewport.offset.x)/n,h=(o-this.viewport.offset.y)/n;this.viewport.scale=i;const l=r*i+this.viewport.offset.x,c=h*i+this.viewport.offset.y;this.viewport.offset.x+=a-l,this.viewport.offset.y+=o-c,this.viewport.calculateBoundaries(),this.viewport.constrainViewport(),this.viewport.isInitialScale=this.viewport.scale===this.viewport.initialScale,this.renderCallback()}handleMouseDown(t){var e,n;if(0!==t.button)return;const i=this.getDrawType(),s=this.getBgImage();if(this.annotationManager.selectedAnnotation&&s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(n)return this.annotationManager.startResizing(n,e),void this.renderCallback()}if("text"===i){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);if("rect"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(e);if("polygon"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();if(this.annotationManager.selectedAnnotation)return this.annotationManager.deselectAnnotation(),void this.renderCallback()}return null!==this.textManager.selectedTextIndex?(this.textManager.deselectTextAnnotation(),void this.renderCallback()):void this.handleTextModeClick(t)}if(!s)return;const a=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if("rect"===i){if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return this.annotationManager.startResizing(e,a),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(a);return n&&"rect"===n.type?(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const n=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==n)return this.textManager.selectedTextIndex===n?this.textManager.startMoving(t,n):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(n)),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(a);if("polygon"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const s=this.annotationManager.getAnnotationAtPoint(a);if("rect"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.startRectDrawing(a)}else if("polygon"===i){if("polygon"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e&&"polygon-vertex"===e.type)return this.annotationManager.startResizing(e,a),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(a);return n&&"polygon"===n.type?(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(a);if("rect"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const s=this.annotationManager.getAnnotationAtPoint(a);if("polygon"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.isDrawing?this.checkPolygonPointValid(a)&&this.annotationManager.addPolygonPoint(a):this.annotationManager.startPolygonDrawing(a),this.annotationManager.updatePolygonTempPoint(a),this.renderCallback()}else if("drag"===i){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return this.annotationManager.startResizing(e,a),void this.renderCallback()}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(this.handleRectModeClick(t,a))return;if(this.handlePolygonModeClick(t,a))return;this.isDragging=!0,this.dragStart={x:t.clientX,y:t.clientY},this.canvas.style.cursor="grabbing"}else""===i&&this.handleNoModeClick(t,a)}checkTextClickInDragMode(t){return!!this.textManager.checkTextClickForMove(t).handled&&(this.canvas.style.cursor="grabbing",!0)}handleTextModeClick(t){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.startMoving(t,e),this.canvas.style.cursor="grabbing",this.renderCallback(),!0;const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return this.textManager.addTextAnnotation(n.x,n.y),!0}handleRectModeClick(t,e){var n,i;if("rect"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)){const n=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(n)return this.annotationManager.startResizing(n,e),this.renderCallback(),!0}const s=this.annotationManager.getAnnotationAtPoint(e);return s&&"rect"===s.type?(this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0):"rect"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handlePolygonModeClick(t,e){var n,i;if("polygon"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)){const n=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(n&&"polygon-vertex"===n.type)return this.annotationManager.startResizing(n,e),this.renderCallback(),!0}const s=this.annotationManager.getAnnotationAtPoint(e);return s&&"polygon"===s.type?(this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0):"polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handleRectModeClickForMove(t,e){const n=this.annotationManager.getAnnotationAtPoint(e);return!(!n||"rect"!==n.type)&&(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handlePolygonModeClickForMove(t,e){const n=this.annotationManager.getAnnotationAtPoint(e);return!(!n||"polygon"!==n.type)&&(this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handleNoModeClick(t,e){const n=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==n)return this.textManager.selectedTextIndex===n?this.textManager.startMoving(t,n):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(n)),void this.renderCallback();this.textManager.deselectTextAnnotation();const i=this.annotationManager.getAnnotationAtPoint(e);i?(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback()):this.annotationManager.deselectAnnotation()}checkPolygonPointValid(t){const e=this.annotationManager.operate.data.length>0?this.annotationManager.operate.data[this.annotationManager.operate.data.length-1]:null;return!e||Math.abs(e.point.x-t.x)>5||Math.abs(e.point.y-t.y)>5}handleMouseMove(t){if(!this.getBgImage())return;const e=this.getDrawType();if(this.isDragging&&"drag"===e){const e=t.clientX-this.dragStart.x,n=t.clientY-this.dragStart.y;return this.viewport.updateOffset(e,n),this.dragStart={x:t.clientX,y:t.clientY},void this.renderCallback()}if(this.textManager.isTextMoving&&null!==this.textManager.editingTextIndex)this.textManager.moveAnnotation(t)&&this.renderCallback();else if((this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&this.annotationManager.selectedAnnotation)this.handleAnnotationMove(t);else{if(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving||this.updateCursor(t),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updateRectDrawing(e),this.renderCallback()}if("polygon"===e&&this.annotationManager.isDrawing){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updatePolygonTempPoint(e),this.renderCallback()}}}handleAnnotationMove(t){var e,n;if(this.annotationManager.isResizing&&this.annotationManager.activeHandle){const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return"rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)?this.annotationManager.resizeRect(i):"polygon"===(null===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)&&this.annotationManager.resizePolygon(i),void this.renderCallback()}if(!this.annotationManager.isMovingAnnotation||!this.annotationManager.selectedAnnotation)return;const i=(t.clientX-this.annotationManager.annotationMoveStart.x)/this.viewport.scale,s=(t.clientY-this.annotationManager.annotationMoveStart.y)/this.viewport.scale;this.annotationManager.moveSelectedAnnotation(i,s),this.annotationManager.annotationMoveStart={x:t.clientX,y:t.clientY},this.renderCallback()}updateCursor(t){const e=this.getDrawType();if("text"===e){if(this.getBgImage()){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(this.annotationManager.getAnnotationAtPoint(e))return void(this.canvas.style.cursor="move")}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);return void(this.canvas.style.cursor=null!==e?"move":"crosshair")}"rect"!==e?"polygon"!==e?"drag"!==e?""!==e?this.canvas.style.cursor="default":this.updateNoModeCursor(t):this.updateDragModeCursor(t):this.updatePolygonModeCursor(t):this.updateRectModeCursor(t)}updateRectModeCursor(t){var e;if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void(this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize")}const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(n)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updatePolygonModeCursor(t){var e;if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){if(this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="crosshair")}const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(n)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updateDragModeCursor(t){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(null!==this.textManager.checkTextClick(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="move");const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=n?"move":"grab"}updateNoModeCursor(t){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(null!==this.textManager.checkTextClick(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="move");const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=n?"move":"default"}handleMouseUp(t){if(this.isDragging){this.isDragging=!1;const t=this.getDrawType();return void(this.canvas.style.cursor="drag"===t?"grab":"default")}if(this.textManager.isTextMoving){this.justFinishedMove=!0,this.textManager.finishMoving();const t=this.getDrawType();"drag"===t?this.canvas.style.cursor="grab":""===t?this.canvas.style.cursor="move":(this.textManager.editingTextIndex=null,this.canvas.style.cursor="default")}(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&(this.justFinishedMove=!0,this.annotationManager.finishMovingAnnotation(),this.canvas.style.cursor=this.annotationManager.selectedAnnotation?"move":"default"),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type&&(this.annotationManager.finishRectDrawing(),this.renderCallback())}handleMouseLeave(t){(this.isDragging||this.textManager.isTextMoving||this.annotationManager.isResizing||this.annotationManager.isMovingAnnotation)&&this.handleMouseUp(t)}handleDoubleClick(t){if(!this.getBgImage())return;this.justFinishedMove=!1;const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return void this.textManager.startEditing(e);if("polygon"===this.getDrawType()){if(this.annotationManager.isDrawing&&this.annotationManager.operate.data.length<=2)return;this.annotationManager.finishPolygonDrawing(),this.renderCallback()}}handleClick(t){var e;const n=this.getDrawType();if(!this.getBgImage()||"polygon"!==n||this.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;if(this.justDeselected)return void(this.justDeselected=!1);if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type))return;const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.checkPolygonPointValid(i)&&(this.annotationManager.isDrawing?this.annotationManager.addPolygonPoint(i):this.annotationManager.startPolygonDrawing(i)),this.annotationManager.updatePolygonTempPoint(i),this.renderCallback()}handleKeyDown(t){if("z"===t.key&&(t.ctrlKey||t.metaKey))return this.annotationManager.withdraw()||this.textManager.withdraw(),void this.renderCallback();if(" "===t.key)return this.viewport.resetToInitial(),void this.renderCallback();if("Escape"!==t.key){if("Delete"===t.key||"Backspace"===t.key){if(null!==this.textManager.editingTextIndex)return this.textManager.removeTextAnnotation(this.textManager.editingTextIndex),void this.renderCallback();if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.renderCallback();this.annotationManager.selectedAnnotation&&(this.annotationManager.deleteSelectedAnnotation(),this.renderCallback())}}else this.annotationManager.isDrawing?(this.annotationManager.cancelDrawing(),this.renderCallback()):this.annotationManager.selectedAnnotation&&(this.annotationManager.deselectAnnotation(),this.renderCallback())}}class g{constructor(t){this.canvas=document.createElement("canvas"),this.bgImage=null,this.bgImageSrc="",this.bgImageExt="jpeg",this.drawType="";const{drawType:e,useEvents:n=!0,id:i="container",annotationColor:s,lineStyle:a,vertexStyle:o,textStyle:g}=t,x=document.getElementById(i);if(!x)throw new Error(`Container with id "${i}" not found`);this.container=x,"absolute"!==x.style.position&&"fixed"!==x.style.position&&"relative"!==x.style.position&&(x.style.position="relative"),this.ctx=this.canvas.getContext("2d"),this.viewport=new r,this.viewport.setSize(x.clientWidth,x.clientHeight),this.canvas.width=this.viewport.width,this.canvas.height=this.viewport.height,this.canvas.style.width=`${this.viewport.width}px`,this.canvas.style.height=`${this.viewport.height}px`,this.canvas.style.cursor="default",this.canvas.style.display="block",x.appendChild(this.canvas),this.annotationManager=new h(this.viewport),s&&this.annotationManager.setColorConfig(s),a&&this.annotationManager.setLineStyle(a),o&&this.annotationManager.setVertexStyle(o),this.textManager=new l(this.viewport,this.container,this.ctx,()=>this.render()),g&&this.textManager.setTextStyle(g),this.renderer=new c(this.ctx,this.viewport,this.annotationManager,this.textManager,this.canvas),this.eventHandler=new d(this.canvas,this.viewport,this.annotationManager,this.textManager,this.renderer,()=>this.drawType,()=>this.bgImage,()=>this.render(),t=>this.setDrawType(t)),this.events={wheel:t=>this.eventHandler.handleWheel(t),mousedown:t=>this.eventHandler.handleMouseDown(t),mousemove:t=>this.eventHandler.handleMouseMove(t),mouseup:t=>this.eventHandler.handleMouseUp(t),mouseleave:t=>this.eventHandler.handleMouseLeave(t),dblclick:t=>this.eventHandler.handleDoubleClick(t),click:t=>this.eventHandler.handleClick(t),keydown:t=>this.eventHandler.handleKeyDown(t)},this.setDrawType(e||""),n&&this.addEventListeners()}setDrawType(t){"polygon"===this.drawType&&this.annotationManager.isDrawing&&this.annotationManager.operate.data.length>0?console.warn("Cannot switch mode while polygon is being drawn. Please complete or cancel the polygon first."):this.drawType!==t&&(this.annotationManager.operate.data=[],this.annotationManager.isDrawing=!1,this.annotationManager.tempPolygonPoint=null,""!==t&&this.deselectAnnotation(),this.annotationManager.operate.type=t,this.drawType=t,this.canvas.style.cursor="drag"===t?"grab":"text"===t?"text":"default")}drawImage(t){this.bgImageSrc=t,this.bgImageExt=i(t);const e=new Image;e.crossOrigin="anonymous",e.src=t,e.onload=()=>{this.bgImage=e,this.viewport.setOriginalSize(e.width,e.height),this.viewport.calculateInitialView(),this.render()}}render(){this.renderer.render(this.bgImage)}clear(t=""){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.setDrawType(t),this.render()}withdraw(){const t=this.annotationManager.withdraw(),e=this.textManager.withdraw();(t||e)&&this.render()}resize(){const t=this.canvas.parentElement;t&&(this.viewport.setSize(t.clientWidth,t.clientHeight),this.canvas.width=this.viewport.width,this.canvas.height=this.viewport.height,this.canvas.style.width=`${this.viewport.width}px`,this.canvas.style.height=`${this.viewport.height}px`,this.render())}addEventListeners(){this.canvas.addEventListener("mousedown",this.events.mousedown),this.canvas.addEventListener("mousemove",this.events.mousemove),this.canvas.addEventListener("mouseup",this.events.mouseup),this.canvas.addEventListener("mouseleave",this.events.mouseleave),this.canvas.addEventListener("wheel",this.events.wheel),this.canvas.addEventListener("contextmenu",t=>t.preventDefault()),document.addEventListener("keydown",this.events.keydown),this.handleClickEventListener()}handleClickEventListener(){let t=null,e=0;this.canvas.addEventListener("click",n=>{if(this.eventHandler.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;const i=this.eventHandler.justFinishedMove;i&&(this.eventHandler.justFinishedMove=!1),e++,1===e?t=window.setTimeout(()=>{1!==e||i||this.events.click(n),e=0,t=null},300):2===e&&(this.eventHandler.justFinishedMove=!1,this.events.dblclick(n),e=0,null!==t&&(clearTimeout(t),t=null))})}changeScale(t){if(!this.bgImage)return;const e=o(this.viewport.scale,t),n=this.viewport.width/2,i=this.viewport.height/2,s=this.viewport.scale+e;this.viewport.updateScale(s,n,i),this.render()}clearCanvas(t=!1,e=!0){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.textManager.deselectTextAnnotation(),!t&&e&&(this.bgImage=null,this.bgImageSrc="",this.viewport.setOriginalSize(0,0),this.viewport.reset()),this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.bgImage&&this.render(),"drag"===this.drawType&&(this.canvas.style.cursor="default")}clearAnnotations(){this.clearCanvas(!0,!1)}getAnnotations(){return this.annotationManager.getAnnotations()}getTextAnnotations(){return this.textManager.getTextAnnotations()}exportAnnotationImage(){return new Promise((t,e)=>{if(!this.bgImage)return void e(new Error("No background image loaded"));const n=document.createElement("canvas");n.width=this.viewport.originalWidth,n.height=this.viewport.originalHeight;const i=n.getContext("2d");if(!i)return void e(new Error("Could not create offscreen canvas context"));const s=new Image;s.src=this.bgImageSrc,s.crossOrigin="anonymous",s.onload=()=>{try{this.renderer.drawForExport(i,s,this.viewport.originalWidth,this.viewport.originalHeight);const e=n.toDataURL(`image/${this.bgImageExt}`,.7);t(e)}catch(n){this.exportCurrentViewImage().then(t).catch(t=>e(new Error(`Both methods failed: ${t.message}`)))}},s.onerror=()=>{e(new Error("Failed to load image for export"))}})}exportCurrentViewImage(){return new Promise((t,e)=>{try{t(this.canvas.toDataURL(`image/${this.bgImageExt}`))}catch(t){e(new Error(`Failed to export current view: ${t.message}`))}})}base64ToFile(t,e){return s(t,e)}static base64ToBlob(t){return a(t)}addTextAnnotation(t,e,n=""){this.textManager.addTextAnnotation(t,e,n),this.render()}updateTextAnnotation(t,e){this.textManager.updateTextAnnotation(t,e)&&this.render()}moveTextAnnotation(t,e,n){this.textManager.moveTextAnnotation(t,e,n)&&this.render()}removeTextAnnotation(t){this.textManager.removeTextAnnotation(t)&&this.render()}clearTextAnnotations(){this.textManager.clearTextAnnotations(),this.render()}selectAnnotation(t){this.annotationManager.selectAnnotation(t)&&this.render()}deselectAnnotation(){this.annotationManager.deselectAnnotation(),this.textManager.deselectTextAnnotation(),this.textManager.editingTextIndex=null,this.render()}getSelectedAnnotation(){const t=this.annotationManager.getSelectedAnnotation();if(t)return t;const e=this.textManager.getSelectedTextAnnotation();return e?{index:e.index,type:"text",data:e.data}:null}deleteSelectedAnnotation(){if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.render();this.annotationManager.deleteSelectedAnnotation()&&this.render()}moveSelectedAnnotation(t,e){this.annotationManager.moveSelectedAnnotation(t,e)&&this.render()}setAnnotationColor(t){this.annotationManager.setColorConfig(t),this.render()}getAnnotationColor(){return this.annotationManager.getColorConfig()}updateSelectedAnnotationStyle(){const t=this.annotationManager.selectedAnnotation;if(!t)return!1;const e=this.annotationManager.recordList[t.index];return!!e&&(e.style=this.annotationManager.getCurrentStyle(),this.render(),!0)}setLineStyle(t){this.annotationManager.setLineStyle(t),this.render()}getLineStyle(){return this.annotationManager.getLineStyle()}setVertexStyle(t){this.annotationManager.setVertexStyle(t),this.render()}getVertexStyle(){return this.annotationManager.getVertexStyle()}setTextStyle(t){this.textManager.setTextStyle(t),this.render()}setTextInputStyle(t){this.textManager.setInputStyle(t)}setTextSelectionStyle(t){this.textManager.setSelectionStyle(t),this.render()}destroy(){this.textManager.destroy(),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}t.AnnotationManager=h,t.Drawer=g,t.EventHandler=d,t.Renderer=c,t.TextAnnotationManager=l,t.ViewportManager=r,t.base64ToBlob=a,t.base64ToFile=s,t.default=g,t.getImageTypeFromUrl=i,t.getZoomDelta=o,t.isPointInPolygon=n,t.isPointInRect=e,Object.defineProperty(t,"__esModule",{value:!0})}),"undefined"!=typeof ImageAnnotationDrawer&&ImageAnnotationDrawer.default&&(ImageAnnotationDrawer=ImageAnnotationDrawer.default);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "image-annotation-drawer",
3
3
  "type": "module",
4
- "version": "1.0.1",
4
+ "version": "1.0.2",
5
5
  "description": "A lightweight image annotation library based on HTML5 Canvas, supporting rectangles, polygons, text annotations, zoom and drag operations.",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.esm.js",