image-annotation-drawer 1.3.4 → 1.3.5

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/CHANGELOG.md CHANGED
@@ -5,6 +5,63 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.3.5] - 2026-10-15
9
+
10
+ ### Fixed - 导出图里靠前的标注标题被自己的底色反复盖住(越靠前越糊)
11
+
12
+ `drawForExport()` 在 `roundRect()` 之前**没有调用 `ctx.beginPath()`**。Canvas 的 `roundRect()`
13
+ 是**追加**到当前路径的,而 `ctx.fill()` 填充的是**整条路径**,于是路径跨轮累积:
14
+
15
+ ```
16
+ 标题1: roundRect(框1) → fill() 只填框1 → 画白字1 ✅
17
+ 标题2: roundRect(框2) → 路径 = [框1, 框2] → fill() 把框1 也重填一遍
18
+ → 框1 的半透明底色盖住了刚画的白色文字1 ❌
19
+ ```
20
+
21
+ 第 k 个标题会被后面的 `fill()` 各盖一层,残留 `(1 - 0.85)^(N-k)`。以 5 个标注为例:
22
+
23
+ | 标题序号 | 被盖次数 | 残留 | 观感 |
24
+ |---|---|---|---|
25
+ | 1 | 4 | 0.05% | 完全看不见 |
26
+ | 2 | 3 | 0.34% | 完全看不见 |
27
+ | 3 | 2 | 2.25% | 几乎看不见 |
28
+ | 4 | 1 | 15% | 明显发糊 |
29
+ | 5 | 0 | 100% | 正常 |
30
+
31
+ 即**越靠前的标注标题越糊,最后一个完好**(实测 5 个标注导出:前 4 个标题的白色文字像素为
32
+ **0**,只有第 5 个可读)。业务侧标题底色是 `rgba(255, 77, 79, 0.85)`,白字被盖一次后亮度落在
33
+ 149(框底色 131),肉眼观感就是"文字上又糊了一层红底"。
34
+
35
+ - 修复:**标题框**与**文本标注背景**两处 `roundRect()` 前补 `ctx.beginPath()`。
36
+ - 交互画布(`text-renderer.ts`)本来就正确调用了 `beginPath()`,所以弹窗内看着正常、
37
+ 只有导出糊 —— 这也是该缺陷长期没被发现的原因。
38
+ - 非 `roundRect` 分支用的 `fillRect()` 不走路径,因此无 `roundRect` 的老浏览器(Chrome < 99)
39
+ 不触发本缺陷。
40
+
41
+ ### Fixed - 文本标注样式缺字段时的兜底
42
+
43
+ `textData.style` 可能存在但**缺字段**(外部直接写入 `textManager.textAnnotations` 时):
44
+
45
+ - 缺 `font`:`scaleFont(undefined)` 会抛错,被 `exportAnnotationImage()` 的 catch **静默**降级为
46
+ `exportCurrentViewImage()`(低清交互画布)。现改为逐字段回退到全局默认。
47
+ - 缺 `color`:`ctx.fillStyle = undefined` 被 canvas 静默忽略,文字被画成**背景色** → 完全看不见。
48
+ 导出路径与交互路径(`text-renderer.ts`)均已修正。
49
+
50
+ ### Fixed - 离屏导出底图的 CORS 加载顺序
51
+
52
+ `exportAnnotationImage()` 中 `image.src` 先于 `image.crossOrigin` 赋值(与 `drawImage()` 相反)。
53
+ `src` 先赋值会让这次请求可能不带 CORS,离屏 canvas 被污染后 `toDataURL()` 抛 `SecurityError`,
54
+ 再被 catch 静默降级成低清画布。现与 `drawImage()` 对齐(先 `crossOrigin`、后 `src`)。
55
+
56
+ ### Tests
57
+
58
+ - 新增 `__tests__/renderers/export-path.test.ts`:忠实建模 canvas 路径语义(`beginPath` 清空 /
59
+ `roundRect` 追加 / `fill` 快照整条路径),断言每次 `fill()` 的路径里**有且只有 1 个矩形**。
60
+ 修复前第 2 次 `fill()` 的路径长度为 2(红),修复后恒为 1(绿)。
61
+ - 新增 `__tests__/renderers/text-renderer-style-fallback.test.ts`,并扩展
62
+ `__tests__/renderers/export-scaling.test.ts`:样式缺字段时回退全局默认、不抛错、不画成背景色。
63
+ - 新增 `__tests__/export-image.test.ts`:导出路径与主画布路径的 `crossOrigin` / `src` 顺序一致。
64
+
8
65
  ## [1.3.4] - 2026-10-15
9
66
 
10
67
  ### Fixed - 导出图里的标注文字过小
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),o=Math.abs(e.height);return t.x>=n&&t.x<=n+s&&t.y>=i&&t.y<=i+o}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 o=e[i].point.x,a=e[i].point.y,r=e[s].point.x,h=e[s].point.y;a>t.y!=h>t.y&&t.x<(r-o)*(t.y-a)/(h-a)+o&&(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]),o=s.length,a=new Uint8Array(o);for(let t=0;t<o;++t)a[t]=s.charCodeAt(t);const r=new Blob([a],{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],o=atob(i[1]),a=new ArrayBuffer(o.length),r=new Uint8Array(a);for(let t=0;t<o.length;t++)r[t]=o.charCodeAt(t);e(new Blob([a],{type:s}))})}function o(t,e){return t<2?e?.1:-.1:t<5?e?.05:-.05:e?.02:-.02}function a(t){return"function"==typeof structuredClone?structuredClone(t):JSON.parse(JSON.stringify(t))}function r(){return"undefined"!=typeof crypto&&"function"==typeof crypto.randomUUID?crypto.randomUUID():`id-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}class h{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,o=(n-this.offset.y)/i;this.scale=Math.max(this.minScale,Math.min(t,this.maxScale));const a=s*this.scale+this.offset.x,r=o*this.scale+this.offset.y;this.offset.x+=e-a,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}}const l={minX:Number.NEGATIVE_INFINITY,minY:Number.NEGATIVE_INFINITY,maxX:Number.POSITIVE_INFINITY,maxY:Number.POSITIVE_INFINITY};function d(t,e,n){return Math.min(Math.max(t,e),n)}function c(t){var e,n,i,s;const{anchor:o,boxWidth:a,boxHeight:r,position:h}=t,c=null!==(e=t.bounds)&&void 0!==e?e:l,g=null!==(n=t.gap)&&void 0!==n?n:4,x=null!==(i=h.offsetX)&&void 0!==i?i:0,u=null!==(s=h.offsetY)&&void 0!==s?s:0,f=h.align||"center";let p;switch(f){case"left":p=o.x+x;break;case"right":p=o.x+o.width-a+x;break;default:p=o.x+o.width/2-a/2+x}const y=d(p,c.minX,Math.max(c.minX,c.maxX-a)),v=x+(y-p),M=h.vertical||"top";let w,m=M;return"inside-top"===M?w=o.y+g+u:"bottom"===M?(w=o.y+o.height+g+u,w+r>c.maxY&&(m="top",w=o.y-r-g+u)):(w=o.y-r-g+u,w<c.minY&&(m="bottom",w=o.y+o.height+g+u)),w=d(w,c.minY,Math.max(c.minY,c.maxY-r)),{x:y,y:w,vertical:m,align:f,offsetX:v}}function g(t){const{x:e,y:n}=c(t);return{x:e,y:n}}function x(t,e){if("polygon"===t.type){const n=t.data;if(0===n.length)return null;let i=1/0,s=1/0,o=-1/0,a=-1/0;return n.forEach(t=>{const n=e?e.offset.x+t.point.x*e.scale:t.point.x,r=e?e.offset.y+t.point.y*e.scale:t.point.y;n<i&&(i=n),r<s&&(s=r),n>o&&(o=n),r>a&&(a=r)}),{x:i,y:s,width:o-i,height:a-s}}const n=t.data[0];return e?{x:e.offset.x+n.start.x*e.scale,y:e.offset.y+n.start.y*e.scale,width:n.width*e.scale,height:n.height*e.scale}:{x:n.start.x,y:n.start.y,width:n.width,height:n.height}}function u(t,e){return Math.round(t*e)}function f(t,e){return Math.max(1,u(t,e))}function p(t,e=12){const n=t.match(/(\d+(?:\.\d+)?)px/);return n?parseFloat(n[1]):e}function y(t,e){return t.replace(/(\d+(?:\.\d+)?)px/,(t,n)=>`${f(parseFloat(n),e)}px`)}function v(t,e,n){if(!n)return e;const{originalWidth:i,originalHeight:s}=t;return i&&s?{x:Math.max(0,Math.min(e.x,i)),y:Math.max(0,Math.min(e.y,s))}:e}function M(t,e,n,i,s){t&&s.id&&t(n,{id:s.id,type:e,index:i,data:a(s)})}const w=new class{constructor(){this.type="rect"}startDrawing(t,e){t.isDrawing=!0,t.drawStartPoint=e,t.operate={type:"rect",data:[{start:Object.assign({},e),width:0,height:0}],status:"pending"}}updateDrawing(t,e){if(!t.isDrawing||"rect"!==t.operate.type)return;const n=t.operate.data[0];n.width=e.x-t.drawStartPoint.x,n.height=e.y-t.drawStartPoint.y}addPoint(t,e){return!1}finishDrawing(t){if(!t.isDrawing||"rect"!==t.operate.type)return!1;const e=t.operate.data[0];return Math.abs(e.width)>5&&Math.abs(e.height)>5&&t.pushRecord(Object.assign({},t.operate)),t.operate.data=[],t.isDrawing=!1,!0}cancelDrawing(t){t.operate.data=[],t.isDrawing=!1,t.tempPolygonPoint=null}withdrawInProgress(t){return 0!==t.operate.data.length&&(t.operate.data=[],t.isDrawing=!1,!0)}hitTest(e,n){return t(n,e.data[0])}getHandles(t,e,n){const i=t.data[0],s=e.offset.x+i.start.x*e.scale,o=e.offset.y+i.start.y*e.scale,a=i.width*e.scale,r=i.height*e.scale;return[{x:s,y:o,index:0},{x:s+a,y:o,index:1},{x:s,y:o+r,index:2},{x:s+a,y:o+r,index:3}]}move(t,e,n){const i=t.data[0];i.start.x+=e,i.start.y+=n}snapshotForResize(t){const e=t.data[0];return{start:Object.assign({},e.start),width:e.width,height:e.height}}resize(t,e,n,i){const s=t.data[0],o=i,a=o.start.x,r=o.start.x+o.width,h=o.start.y,l=o.start.y+o.height;let d,c;switch(e){case 0:d=r,c=l;break;case 1:d=a,c=l;break;case 2:d=r,c=h;break;case 3:d=a,c=h;break;default:return}const g=Math.min(n.x,d),x=Math.max(n.x,d),u=Math.min(n.y,c),f=Math.max(n.y,c);s.start.x=g,s.start.y=u,s.width=x-g,s.height=f-u;const p=n.x<d,y=n.y<c;let v;return 0===e?p||y?!p&&y?v=1:p&&!y&&(v=2):v=3:1===e?p&&!y?v=2:p&&y?v=0:p||y||(v=3):2===e?!p&&y?v=1:p&&y?v=0:p||y||(v=3):3===e&&(p&&y?v=0:!p&&y?v=1:p&&!y&&(v=2)),o.start.x=s.start.x,o.start.y=s.start.y,o.width=s.width,o.height=s.height,v}getBounds(t){const e=t.data[0];return{x:e.start.x,y:e.start.y,width:e.width,height:e.height}}};const m=new class{constructor(){this.type="polygon"}startDrawing(t,e){t.isDrawing=!0,t.operate={type:"polygon",data:[{point:e}],status:"pending"},t.tempPolygonPoint=e}updateDrawing(t,e){t.tempPolygonPoint=e}addPoint(t,e){if(!t.isDrawing||"polygon"!==t.operate.type)return!1;const n=t.operate.data.length>0?t.operate.data[t.operate.data.length-1]:null;return!(n&&Math.abs(n.point.x-e.x)<=5&&Math.abs(n.point.y-e.y)<=5)&&(t.operate.data.push({point:e}),!0)}finishDrawing(t){return!(!t.isDrawing||"polygon"!==t.operate.type)&&(t.operate.data.length>=3&&(t.operate.status="fullfilled",t.pushRecord(Object.assign({},t.operate))),t.operate={type:"polygon",data:[],status:"pending"},t.isDrawing=!1,t.tempPolygonPoint=null,!0)}cancelDrawing(t){t.isDrawing&&"polygon"===t.operate.type&&t.operate.data.length>=2&&(t.operate.status="fullfilled",t.pushRecord(Object.assign({},t.operate))),t.operate.data=[],t.isDrawing=!1,t.tempPolygonPoint=null}withdrawInProgress(t){return 0!==t.operate.data.length&&(t.operate.data.pop(),0===t.operate.data.length&&(t.isDrawing=!1),!0)}hitTest(t,n){return e(n,t.data)}getHandles(t,e,n){const i=t.data,s=[];for(let t=0;t<i.length;t++){const n=i[t];s.push({x:e.offset.x+n.point.x*e.scale,y:e.offset.y+n.point.y*e.scale,index:t})}return s}move(t,e,n){t.data.forEach(t=>{t.point.x+=e,t.point.y+=n})}snapshotForResize(t){return t.data.map(t=>({point:Object.assign({},t.point)}))}resize(t,e,n,i){const s=t.data;e>=0&&e<s.length&&(s[e].point.x=n.x,s[e].point.y=n.y)}getBounds(t){const e=t.data;if(0===e.length)return{x:0,y:0,width:0,height:0};let n=1/0,i=1/0,s=-1/0,o=-1/0;return e.forEach(t=>{t.point.x<n&&(n=t.point.x),t.point.y<i&&(i=t.point.y),t.point.x>s&&(s=t.point.x),t.point.y>o&&(o=t.point.y)}),{x:n,y:i,width:s-n,height:o-i}}};const A=new class{constructor(){this.strategies=new Map}register(t){this.strategies.set(t.type,t)}get(t){const e=this.strategies.get(t);if(!e)throw new Error(`No strategy registered for shape type: ${t}`);return e}selectShapeExclusive(t,e,n){return"shape"===n.kind?(e.deselectTextAnnotation(),t.selectAnnotation(n.ref,{lock:n.locked})):(t.deselectAnnotation(),e.selectTextAnnotation(n.index))}deselectAll(t,e){t.deselectAnnotation(),e.deselectTextAnnotation()}withdrawAll(t,e){return t.withdraw()||e.withdraw()}};A.register(w),A.register(m);class T{constructor(t,e,n,i){this.viewport=t,this.container=e,this.renderCallback=n,this.changeCallback=i,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.editingTitleIndex=null,this.titleInput=null,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.titleStyle={font:"12px Arial",color:"#FFFFFF",backgroundColor:"rgba(0, 0, 0, 0.7)",paddingX:6,paddingY:3,borderRadius:4,placeholder:"输入标题..."},this.titlePosition={vertical:"top",align:"center",offsetX:0,offsetY:0},this.enableTitle=!1,this.clampEnabled=!0,this.applyColorConfig()}strategyOf(t){return A.get(t)}clamp(t){return v(this.viewport,t,this.clampEnabled)}clampToImageBounds(t){return v(this.viewport,t,this.clampEnabled)}clampRecordToImageBounds(t){if(!this.clampEnabled)return;const{originalWidth:e,originalHeight:n}=this.viewport;if(!e||!n)return;if("rect"===t.type){const i=t.data[0];if(!i)return;const s=Math.min(i.start.x,i.start.x+i.width),o=Math.max(i.start.x,i.start.x+i.width),a=Math.min(i.start.y,i.start.y+i.height),r=Math.max(i.start.y,i.start.y+i.height);if(s>=0&&a>=0&&o<=e&&r<=n)return;const h=Math.min(o-s,e),l=Math.min(r-a,n);return i.start.x=Math.max(0,Math.min(s,e-h)),i.start.y=Math.max(0,Math.min(a,n-l)),i.width=h,void(i.height=l)}const i=t.data;if(!i||0===i.length)return;let s=1/0,o=1/0,a=-1/0,r=-1/0;for(const t of i)s=Math.min(s,t.point.x),a=Math.max(a,t.point.x),o=Math.min(o,t.point.y),r=Math.max(r,t.point.y);let h=0,l=0;if(a-s>e||s<0?h=-s:a>e&&(h=e-a),r-o>n||o<0?l=-o:r>n&&(l=n-r),0!==h||0!==l)for(const t of i)t.point.x+=h,t.point.y+=l}pushRecord(t){const e=Object.assign(Object.assign({},t),{id:r(),style:this.getCurrentStyle()});this.recordList.push(e),this.deleteHistory=[],this.notifyChange("create",this.recordList.length-1,e)}initTitleSupport(){this.container&&this.enableTitle&&this.createTitleInput()}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)}}notifyChange(t,e,n){M(this.changeCallback,n.type,t,e,n)}notifyUpdate(t){const e=this.recordList[t];e&&this.notifyChange("update",t,e)}resolveIndex(t){return"number"==typeof t?t:this.recordList.findIndex(e=>e.id===t)}getAnnotation(t){const e=this.resolveIndex(t);if(!(e<0||e>=this.recordList.length))return a(this.recordList[e])}updateAnnotationStyle(t){const e=this.resolveIndex(t);return!(e<0||e>=this.recordList.length)&&(this.recordList[e].style=this.getCurrentStyle(),this.notifyUpdate(e),!0)}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()}withdraw(){if(this.operate.data.length>0){const t="polygon"===this.operate.type?"polygon":"rect";return this.strategyOf(t).withdrawInProgress(this),!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,e){var n;const i=this.resolveIndex(t);if(i<0||i>=this.recordList.length)return this.deselectAnnotation(),!1;const s=this.recordList[i],o=void 0!==(null==e?void 0:e.lock)?!!e.lock:(null===(n=this.selectedAnnotation)||void 0===n?void 0:n.index)===i&&!0===this.selectedAnnotation.locked;return this.selectedAnnotation={index:i,type:s.type,locked:o},!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(),this.notifyChange("delete",t,e),!0}startMovingAnnotation(t){return!(!this.selectedAnnotation||!0===this.selectedAnnotation.locked)&&(this.isMovingAnnotation=!0,this.annotationMoveStart={x:t.clientX,y:t.clientY},!0)}updateMoveStart(t){this.annotationMoveStart=t}finishMovingAnnotation(){var t;const e=this.isMovingAnnotation||this.isResizing;if(this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null,e&&this.selectedAnnotation){const e=this.recordList[this.selectedAnnotation.index];(null==e?void 0:e.title)&&this.autoAdjustTitlePosition(e,e.title),this.notifyUpdate(this.selectedAnnotation.index),null===(t=this.renderCallback)||void 0===t||t.call(this)}}clear(){this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,this.deselectAnnotation(),this.deleteHistory=[]}getAnnotations(){return this.recordList.map(t=>a(t))}getSelectedAnnotation(){if(!this.selectedAnnotation)return null;const t=this.recordList[this.selectedAnnotation.index];return t?{index:this.selectedAnnotation.index,type:this.selectedAnnotation.type,data:a(t)}:null}setTitleStyle(t){this.titleStyle=Object.assign(Object.assign({},this.titleStyle),t)}getTitleStyle(){return Object.assign({},this.titleStyle)}setTitlePosition(t){this.titlePosition=Object.assign(Object.assign({},this.titlePosition),t)}getTitlePosition(){return Object.assign({},this.titlePosition)}getEffectiveTitleStyle(t){const e=this.getAnnotationStyle(t);return Object.assign(Object.assign({},this.titleStyle),e.titleStyle||{})}getEffectiveTitlePosition(t){const e=this.getAnnotationStyle(t);return Object.assign(Object.assign({},this.titlePosition),e.titlePosition||{})}captureTitleStyleSnapshot(t){t.style||(t.style=this.getCurrentStyle()),t.style.titleStyle=Object.assign({},this.titleStyle),t.style.titlePositionExplicit||(t.style.titlePosition=Object.assign({},this.titlePosition))}autoAdjustTitlePosition(t,e){var n,i,s;if(!e||(null===(n=t.style)||void 0===n?void 0:n.titlePositionExplicit))return;const{originalWidth:o,originalHeight:a,initialScale:r,scale:h}=this.viewport;if(o<=0||a<=0)return;const l=x(t);if(!l)return;const d=r>0?r:h>0?h:1,g={x:l.x*d,y:l.y*d,width:l.width*d,height:l.height*d},u=this.getEffectiveTitleStyle(t),f=u.font||"12px Arial",y=p(f)+2*(null!==(i=u.paddingY)&&void 0!==i?i:3),v=this.measureTitleWidth,M=v?{minX:0,minY:0,maxX:o*d,maxY:a*d}:{minX:Number.NEGATIVE_INFINITY,minY:0,maxX:Number.POSITIVE_INFINITY,maxY:a*d},w=v?v(e,f)+2*(null!==(s=u.paddingX)&&void 0!==s?s:6):0,m=Object.assign({},this.titlePosition),A=c({anchor:g,boxWidth:w,boxHeight:y,position:m,bounds:M});t.style||(t.style=this.getCurrentStyle()),t.style.titlePosition=Object.assign(Object.assign({},m),{vertical:A.vertical,align:A.align,offsetX:A.offsetX})}adjustTitlePositions(){this.viewport.originalWidth<=0||this.viewport.originalHeight<=0||this.recordList.forEach(t=>{var e;t.title&&!(null===(e=t.style)||void 0===e?void 0:e.titlePositionExplicit)&&this.autoAdjustTitlePosition(t,t.title)})}setAnnotationTitleStyle(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.recordList.length)return!1;const i=this.recordList[n];return i.style||(i.style=this.getCurrentStyle()),i.style.titleStyle=Object.assign(Object.assign({},i.style.titleStyle||this.titleStyle),e),this.notifyUpdate(n),!0}setAnnotationTitlePosition(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.recordList.length)return!1;const i=this.recordList[n];return i.style||(i.style=this.getCurrentStyle()),i.style.titlePosition=Object.assign(Object.assign({},i.style.titlePosition||this.titlePosition),e),i.style.titlePositionExplicit=!0,this.notifyUpdate(n),!0}createTitleInput(){this.container&&(this.titleInput=document.createElement("input"),this.titleInput.type="text",this.titleInput.style.position="absolute",this.titleInput.style.zIndex="99998",this.titleInput.style.display="none",this.titleInput.style.outline="none",this.titleInput.style.border="1px solid #00D9FF",this.titleInput.style.borderRadius="4px",this.titleInput.style.padding="4px 8px",this.titleInput.style.fontSize="13px",this.titleInput.style.fontFamily="Arial, sans-serif",this.titleInput.style.backgroundColor="#ffffff",this.titleInput.style.color="#333",this.titleInput.style.boxShadow="0 2px 8px rgba(0,0,0,0.3)",this.titleInput.style.minWidth="80px",this.titleInput.style.maxWidth="200px",this.titleInput.placeholder=this.titleStyle.placeholder||"输入标题...",this.titleInput.addEventListener("blur",()=>{this.finishTitleEditing()}),this.titleInput.addEventListener("keydown",t=>{t.stopPropagation(),"Enter"===t.key?this.finishTitleEditing():"Escape"===t.key&&(t.preventDefault(),this.cancelTitleEditing())}),this.container.appendChild(this.titleInput))}setTitle(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.recordList.length)return!1;const i=this.recordList[n];return i.title=e||void 0,e&&(this.captureTitleStyleSnapshot(i),this.autoAdjustTitlePosition(i,e)),this.notifyUpdate(n),!0}getTitle(t){const e=this.resolveIndex(t);if(!(e<0||e>=this.recordList.length))return this.recordList[e].title}startTitleEditing(t){if(!this.enableTitle||!this.titleInput||t<0||t>=this.recordList.length)return!1;const e=this.recordList[t];let n,i;if(this.editingTitleIndex=t,this.deselectAnnotation(),"rect"===e.type){const t=e.data[0];n=this.viewport.offset.x+t.start.x*this.viewport.scale,i=this.viewport.offset.y+t.start.y*this.viewport.scale}else{const t=e.data[0];n=this.viewport.offset.x+t.point.x*this.viewport.scale,i=this.viewport.offset.y+t.point.y*this.viewport.scale}return this.titleInput.value=e.title||"",this.titleInput.placeholder=this.getEffectiveTitleStyle(e).placeholder||"输入标题...",this.titleInput.style.left=`${n}px`,this.titleInput.style.top=i-32+"px",this.titleInput.style.display="block",setTimeout(()=>{this.titleInput&&(this.titleInput.focus(),this.titleInput.select())},10),!0}finishTitleEditing(){if(!this.titleInput||null===this.editingTitleIndex)return!1;const t=this.editingTitleIndex,e=this.titleInput.value.trim();if(t>=0&&t<this.recordList.length){const n=this.recordList[t];n.title=e||void 0,e&&(this.captureTitleStyleSnapshot(n),this.autoAdjustTitlePosition(n,e)),this.notifyUpdate(t),this.selectAnnotation(t)}return this.resetTitleEditingState(),this.renderCallback&&this.renderCallback(),!0}cancelTitleEditing(){if(!this.titleInput||null===this.editingTitleIndex)return!1;const t=this.editingTitleIndex;return t>=0&&t<this.recordList.length&&this.selectAnnotation(t),this.resetTitleEditingState(),this.renderCallback&&this.renderCallback(),!0}resetTitleEditingState(){this.titleInput&&(this.titleInput.style.display="none"),this.editingTitleIndex=null}destroyTitleInput(){this.titleInput&&this.titleInput.parentNode&&(this.titleInput.parentNode.removeChild(this.titleInput),this.titleInput=null)}}class I extends T{startRectDrawing(t){t=this.clampToImageBounds(t),this.strategyOf("rect").startDrawing(this,t)}updateRectDrawing(t){this.isDrawing&&"rect"===this.operate.type&&(t=this.clampToImageBounds(t),this.strategyOf("rect").updateDrawing(this,t))}finishRectDrawing(){return this.strategyOf("rect").finishDrawing(this)}startPolygonDrawing(t){t=this.clampToImageBounds(t),this.strategyOf("polygon").startDrawing(this,t)}addPolygonPoint(t){return!(!this.isDrawing||"polygon"!==this.operate.type)&&(t=this.clampToImageBounds(t),this.strategyOf("polygon").addPoint(this,t))}updatePolygonTempPoint(t){this.strategyOf("polygon").updateDrawing(this,this.clampToImageBounds(t))}finishPolygonDrawing(){return this.strategyOf("polygon").finishDrawing(this)}cancelDrawing(){const t="polygon"===this.operate.type?"polygon":"rect";this.strategyOf(t).cancelDrawing(this)}moveSelectedAnnotation(t,e){if(!this.selectedAnnotation)return!1;const n=this.recordList[this.selectedAnnotation.index];return!!n&&(this.strategyOf(n.type).move(n,t,e),this.clampRecordToImageBounds(n),!0)}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=this.strategyOf("rect").snapshotForResize(n):"polygon"===n.type&&(this.originalPolygon=this.strategyOf("polygon").snapshotForResize(n)),!0}resizeRect(t){if(!this.selectedAnnotation||"rect"!==this.selectedAnnotation.type||!this.originalRect||!this.activeHandle)return!1;if(this.activeHandle.index<0||this.activeHandle.index>3)return!1;const e=this.recordList[this.selectedAnnotation.index],n=this.clampToImageBounds(t),i=this.strategyOf("rect").resize(e,this.activeHandle.index,n,this.originalRect);return"number"==typeof i&&(this.activeHandle.index=i),!0}resizePolygon(t){var e;if(!this.selectedAnnotation||"polygon"!==this.selectedAnnotation.type||!this.activeHandle)return!1;const n=this.recordList[this.selectedAnnotation.index],i=this.activeHandle.index,s=n.data;return!(i<0||i>=s.length)&&(this.strategyOf("polygon").resize(n,i,this.clampToImageBounds(t),null!==(e=this.originalPolygon)&&void 0!==e?e:[]),!0)}getAnnotationAtPoint(t){for(let e=this.recordList.length-1;e>=0;e--){const n=this.recordList[e],i=n.type;if(this.strategyOf(i).hitTest(n,t))return{index:e,type:i}}return null}getHandleAtPoint(t,e){if(!this.selectedAnnotation)return null;if(!0===this.selectedAnnotation.locked)return null;const n=this.recordList[this.selectedAnnotation.index],i=this.selectionStyle.handleSize,s=i/2,o=this.selectedAnnotation.type,a=this.strategyOf(o).getHandles(n,this.viewport,i);for(const n of a)if(t>=n.x-s&&t<=n.x+s&&e>=n.y-s&&e<=n.y+s)return"rect"===o?{type:"rect-corner",index:n.index}:{type:"polygon-vertex",index:n.index};return null}}class S{constructor(t,e,n,i,s){this.viewport=t,this.container=e,this.ctx=n,this.renderCallback=i,this.changeCallback=s,this.textAnnotations=[],this.editingTextIndex=null,this.currentEditingIndex=null,this.movingTextIndex=null,this.isTextMoving=!1,this.textMoveStart={x:0,y:0},this.textBeforeEditing="",this.selectedTextIndex=null,this.clampEnabled=!0,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}}notifyChange(t,e,n){M(this.changeCallback,"text",t,e,n)}resolveIndex(t){return"number"==typeof t?t:this.textAnnotations.findIndex(e=>e.id===t)}getTextAnnotation(t){const e=this.resolveIndex(t);if(!(e<0||e>=this.textAnnotations.length))return a(this.textAnnotations[e])}updateTextAnnotationStyle(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.textAnnotations.length)return!1;const i=this.textAnnotations[n];return i.style=Object.assign(Object.assign({},i.style||this.getCurrentStyle()),e),this.notifyChange("update",n,this.textAnnotations[n]),!0}clampToImageBounds(t){return v(this.viewport,t,this.clampEnabled)}addTextAnnotation(t,e,n=""){var i;const s=this.clampToImageBounds({x:t,y:e});t=s.x,e=s.y,this.ctx.font=this.textStyle.font;const o=n||"输入文字...",a=this.ctx.measureText(o);let h;if(a.actualBoundingBoxAscent&&a.actualBoundingBoxDescent)h=a.actualBoundingBoxAscent+a.actualBoundingBoxDescent;else{h=1.2*parseInt((null===(i=this.textStyle.font.match(/\d+/))||void 0===i?void 0:i[0])||"16")}const l={id:r(),position:{x:t,y:e},text:n,style:this.getCurrentStyle(),width:Math.max(a.width,60),height:h};this.textAnnotations.push(l);const d=this.textAnnotations.length-1;return this.notifyChange("create",d,l),this.deleteHistory=[],this.startEditing(d),d}updateTextAnnotation(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.textAnnotations.length)return!1;const i=this.textAnnotations[n];i.text=e,this.ctx.font=this.textStyle.font;const s=this.ctx.measureText(e);return i.width=s.width,i.height=1.2*parseInt(this.textStyle.font),this.notifyChange("update",n,this.textAnnotations[n]),!0}moveTextAnnotation(t,e,n){const i=this.resolveIndex(t);return!(i<0||i>=this.textAnnotations.length)&&(this.textAnnotations[i].position={x:e,y:n},this.notifyChange("update",i,this.textAnnotations[i]),!0)}removeTextAnnotation(t){const e=this.resolveIndex(t);if(e<0||e>=this.textAnnotations.length)return!1;const n=this.textAnnotations[e];return this.deleteHistory.push({annotation:Object.assign({},n),index:e}),this.textAnnotations.splice(e,1),this.notifyChange("delete",e,n),this.editingTextIndex===e?this.resetEditingState():null!==this.editingTextIndex&&this.editingTextIndex>e&&this.editingTextIndex--,this.movingTextIndex===e?this.endTextMoving():null!==this.movingTextIndex&&this.movingTextIndex>e&&this.movingTextIndex--,!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}px`,this.textInput.style.top=`${i}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){const e=this.textAnnotations[t];this.textAnnotations.splice(t,1),this.notifyChange("delete",t,e)}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),this.notifyChange("update",t,n)}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){if(""===this.textAnnotations[t].text&&""===this.textBeforeEditing){const e=this.textAnnotations[t];this.textAnnotations.splice(t,1),this.notifyChange("delete",t,e)}}return this.resetEditingState(),!0}deleteEditingAnnotation(){if(null===this.editingTextIndex)return!1;const t=this.editingTextIndex;if(this.textInput&&(this.textInput.style.display="none"),t>=0&&t<this.textAnnotations.length){const e=this.textAnnotations[t];this.textAnnotations.splice(t,1),this.notifyChange("delete",t,e)}return 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.movingTextIndex=e,this.isTextMoving=!0,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}moveAnnotation(t){if(!this.isTextMoving||null===this.movingTextIndex)return!1;const e=t.clientX-this.textMoveStart.x,n=t.clientY-this.textMoveStart.y,i=this.textAnnotations[this.movingTextIndex];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(){if(this.isTextMoving=!1,null!==this.movingTextIndex){const t=this.textAnnotations[this.movingTextIndex];t&&this.notifyChange("update",this.movingTextIndex,t)}this.movingTextIndex=null}endTextMoving(){this.isTextMoving=!1,this.movingTextIndex=null}isEditingVisible(){var t;return"block"===(null===(t=this.textInput)||void 0===t?void 0:t.style.display)}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,o=this.viewport.offset.y+i.position.y*this.viewport.scale,a=Math.max(i.width,60)+2*this.textStyle.padding,r=i.height+2*this.textStyle.padding;if(t>=s&&t<=s+a&&e>=o&&e<=o+r)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.map(t=>a(t))}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,this.notifyChange("delete",t,e),null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,null!==this.movingTextIndex&&this.movingTextIndex>t&&this.movingTextIndex--,!0}getSelectedTextAnnotation(){if(null===this.selectedTextIndex)return null;const t=this.textAnnotations[this.selectedTextIndex];return t?{index:this.selectedTextIndex,data:a(t)}:null}destroy(){this.textInput&&this.textInput.parentNode&&this.textInput.parentNode.removeChild(this.textInput)}}function b(t,e){switch(e){case"dashed":t.setLineDash([10,5]);break;case"dotted":t.setLineDash([2,4]);break;default:t.setLineDash([])}}class C{draw(t,e,n,i){const s=n.data[0];t.strokeRect(e.offset.x+s.start.x*e.scale,e.offset.y+s.start.y*e.scale,s.width*e.scale,s.height*e.scale)}drawInProgress(t,e,n){const i=n.operate.data[0];t.strokeRect(e.offset.x+i.start.x*e.scale,e.offset.y+i.start.y*e.scale,i.width*e.scale,i.height*e.scale)}drawSelection(t,e,n,i,s){const o=n.data[0],a=e.offset.x+o.start.x*e.scale,r=e.offset.y+o.start.y*e.scale,h=o.width*e.scale,l=o.height*e.scale;if(t.fillStyle=i.fillColor,t.fillRect(a,r,h,l),t.strokeStyle=i.strokeColor,t.lineWidth=2,t.setLineDash([5,5]),t.strokeRect(a,r,h,l),s)return;const d=i.handleSize;t.fillStyle=i.handleColor,t.setLineDash([]),t.fillRect(a-d/2,r-d/2,d,d),t.fillRect(a+h-d/2,r-d/2,d,d),t.fillRect(a-d/2,r+l-d/2,d,d),t.fillRect(a+h-d/2,r+l-d/2,d,d)}drawForExport(t,e,n,i=1){const s=e.data[0];t.strokeRect(s.start.x,s.start.y,s.width,s.height)}getTitleAnchor(t,e){return x(t,e)}}class k{constructor(t){this.store=t}draw(t,e,n,i){const s=i.vertexStyle||this.store.getVertexStyle();this.drawPolygon(t,e,n.data,"fullfilled"===n.status,s)}drawInProgress(t,e,n){const i=n.operate.data,s=n.tempPolygonPoint;if(t.beginPath(),i.forEach((n,i)=>{const s=Math.round(e.offset.x+n.point.x*e.scale),o=Math.round(e.offset.y+n.point.y*e.scale);0===i?t.moveTo(s,o):t.lineTo(s,o)}),s){const n=Math.round(e.offset.x+s.x*e.scale),i=Math.round(e.offset.y+s.y*e.scale);t.lineTo(n,i)}if(t.stroke(),this.drawPolygonVertices(t,e,i,n.getVertexStyle()),s){const i=n.getVertexStyle(),o=Math.round(e.offset.x+s.x*e.scale),a=Math.round(e.offset.y+s.y*e.scale),r=i.size/2;switch(t.fillStyle=i.fillColor,t.strokeStyle=i.strokeColor,t.lineWidth=i.strokeWidth,t.beginPath(),i.shape){case"square":t.rect(o-r,a-r,2*r,2*r);break;case"diamond":t.moveTo(o,a-r),t.lineTo(o+r,a),t.lineTo(o,a+r),t.lineTo(o-r,a),t.closePath();break;default:t.arc(o,a,r,0,2*Math.PI)}t.fill(),i.strokeWidth>0&&t.stroke()}}drawSelection(t,e,n,i,s){const o=n.data;if(t.beginPath(),o.forEach((n,i)=>{const s=e.offset.x+n.point.x*e.scale,o=e.offset.y+n.point.y*e.scale;0===i?t.moveTo(s,o):t.lineTo(s,o)}),t.closePath(),t.fillStyle=i.fillColor,t.fill(),t.strokeStyle=i.strokeColor,t.lineWidth=2,t.setLineDash([5,5]),t.stroke(),s)return;const a=i.handleSize;t.fillStyle=i.handleColor,t.setLineDash([]),o.forEach(n=>{const i=Math.round(e.offset.x+n.point.x*e.scale),s=Math.round(e.offset.y+n.point.y*e.scale);t.fillRect(i-a/2,s-a/2,a,a)})}drawForExport(t,e,n,i=1){if("fullfilled"!==e.status)return;const s=e.data;t.beginPath(),s.forEach((e,n)=>{0===n?t.moveTo(e.point.x,e.point.y):t.lineTo(e.point.x,e.point.y)});const o=e.data[0];t.lineTo(o.point.x,o.point.y),t.stroke();const a=f(4,i);s.forEach(e=>{t.beginPath(),t.arc(e.point.x,e.point.y,a,0,2*Math.PI),t.fillStyle=n.strokeColor,t.fill()})}getTitleAnchor(t,e){return x(t,e)}drawPolygon(t,e,n,i,s){if(0!==n.length){if(t.beginPath(),n.forEach((n,i)=>{const s=Math.round(e.offset.x+n.point.x*e.scale),o=Math.round(e.offset.y+n.point.y*e.scale);0===i?t.moveTo(s,o):t.lineTo(s,o)}),i&&n.length>1){const i=n[0];t.lineTo(e.offset.x+i.point.x*e.scale,e.offset.y+i.point.y*e.scale)}t.stroke(),this.drawPolygonVertices(t,e,n,s)}}drawPolygonVertices(t,e,n,i){const s=i||this.store.getVertexStyle(),o=s.size/2;n.forEach(n=>{const i=Math.round(e.offset.x+n.point.x*e.scale),a=Math.round(e.offset.y+n.point.y*e.scale);switch(t.fillStyle=s.fillColor,t.strokeStyle=s.strokeColor,t.lineWidth=s.strokeWidth,t.beginPath(),s.shape){case"square":t.rect(i-o,a-o,2*o,2*o);break;case"diamond":t.moveTo(i,a-o),t.lineTo(i+o,a),t.lineTo(i,a+o),t.lineTo(i-o,a),t.closePath();break;default:t.arc(i,a,o,0,2*Math.PI)}t.fill(),s.strokeWidth>0&&t.stroke()})}}class P{constructor(t,e,n,i){this.ctx=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.shapeRenderers={rect:new C,polygon:new k(n)}}render(t){this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.drawBackgroundImage(t),this.drawAnnotations(),function(t,e,n){const i=n.textStyle;n.textAnnotations.forEach((s,o)=>{if(n.editingTextIndex===o&&n.isEditingVisible())return;if(!s.text)return;const a=s.style||{font:i.font,color:i.color,backgroundColor:i.backgroundColor},r=e.offset.x+s.position.x*e.scale,h=e.offset.y+s.position.y*e.scale,l=n.selectedTextIndex===o;t.font=a.font;const d=t.measureText(s.text),c=d.actualBoundingBoxAscent||.8*s.height,g=c+(d.actualBoundingBoxDescent||.2*s.height),x=i.borderRadius,u=r,f=h,p=s.width+2*i.padding,y=g+2*i.padding;t.fillStyle=a.backgroundColor,t.beginPath(),t.roundRect(u,f,p,y,x),t.fill(),l&&(t.strokeStyle=i.selectedBorderColor,t.lineWidth=2,t.setLineDash([5,5]),t.beginPath(),t.roundRect(u,f,p,y,x),t.stroke(),t.setLineDash([]));const v=r+i.padding,M=h+i.padding+c;t.fillStyle=a.color,t.fillText(s.text,v,M)})}(this.ctx,this.viewport,this.textManager)}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=>{const e=this.annotationManager.getAnnotationStyle(t);this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=e.lineWidth,b(this.ctx,e.lineStyle||"solid"),this.ctx.fillStyle=this.ctx.strokeStyle,"rect"===t.type?this.shapeRenderers.rect.draw(this.ctx,this.viewport,t,e):"polygon"===t.type&&this.shapeRenderers.polygon.draw(this.ctx,this.viewport,t,e),this.annotationManager.enableTitle&&t.title&&this.drawAnnotationTitle(t)}),this.annotationManager.operate.data.length>0&&(this.ctx.strokeStyle=this.annotationManager.strokeStyle,this.ctx.lineWidth=this.annotationManager.lineWidth,this.ctx.fillStyle=this.ctx.strokeStyle,b(this.ctx,this.annotationManager.lineStyle),"rect"===this.annotationManager.operate.type?this.shapeRenderers.rect.drawInProgress(this.ctx,this.viewport,this.annotationManager):"polygon"===this.annotationManager.operate.type&&this.shapeRenderers.polygon.drawInProgress(this.ctx,this.viewport,this.annotationManager)),this.ctx.setLineDash([]),this.drawSelectionHighlight()}drawSelectionHighlight(){const t=this.annotationManager.selectedAnnotation;if(!t)return;const e=this.annotationManager.recordList[t.index];if(!e)return;const n=this.annotationManager.selectionStyle,i=!0===t.locked;this.ctx.save(),"rect"===e.type?this.shapeRenderers.rect.drawSelection(this.ctx,this.viewport,e,n,i):"polygon"===e.type&&this.shapeRenderers.polygon.drawSelection(this.ctx,this.viewport,e,n,i),this.ctx.restore()}drawAnnotationTitle(t){var e,n,i;if(!t.title)return;const s=this.annotationManager.getEffectiveTitleStyle(t),o=this.annotationManager.getEffectiveTitlePosition(t),a=s.font||"12px Arial",r=s.color||"#FFFFFF",h=s.backgroundColor||"rgba(0, 0, 0, 0.7)",l=null!==(e=s.paddingX)&&void 0!==e?e:6,d=null!==(n=s.paddingY)&&void 0!==n?n:3,c=null!==(i=s.borderRadius)&&void 0!==i?i:4;this.ctx.save(),this.ctx.font=a;const x=this.ctx.measureText(t.title).width,u=p(a),f=("rect"===t.type?this.shapeRenderers.rect:this.shapeRenderers.polygon).getTitleAnchor(t,this.viewport);if(!f)return void this.ctx.restore();const y=x+2*l,v=u+2*d,{x:M,y:w}=g({anchor:f,boxWidth:y,boxHeight:v,position:o});this.ctx.fillStyle=h,this.ctx.setLineDash([]),this.ctx.beginPath(),this.ctx.roundRect(M,w,y,v,c),this.ctx.fill(),this.ctx.fillStyle=r,this.ctx.textAlign="left",this.ctx.textBaseline="top",this.ctx.fillText(t.title,M+l,w+d),this.ctx.restore()}getExportPixelRatio(){const t=this.viewport.scale;return t>0?1/t:1}drawForExport(t,e,n,i){const s=this.getExportPixelRatio();t.drawImage(e,0,0,n,i),this.annotationManager.recordList.forEach(e=>{const n=this.annotationManager.getAnnotationStyle(e);t.strokeStyle=n.strokeColor,t.lineWidth=f(n.lineWidth,s),"rect"===e.type?this.shapeRenderers.rect.drawForExport(t,e,n,s):"polygon"===e.type&&this.shapeRenderers.polygon.drawForExport(t,e,n,s)}),this.textManager.textAnnotations.forEach(e=>{const n=this.textManager.textStyle,i=e.style||{font:n.font,color:n.color,backgroundColor:n.backgroundColor};t.font=y(i.font,s);const o=t.measureText(e.text),a=o.actualBoundingBoxAscent||.8*e.height,r=a+(o.actualBoundingBoxDescent||.2*e.height),h=e.position.x,l=e.position.y,d=u(n.padding,s),c=o.width+2*d,g=r+2*d,x=u(n.borderRadius,s);t.fillStyle=i.backgroundColor,t.roundRect?(t.roundRect(h,l,c,g,x),t.fill()):t.fillRect(h,l,c,g),t.fillStyle=i.color,t.fillText(e.text,h+d,l+d+a)}),this.annotationManager.enableTitle&&this.annotationManager.recordList.forEach(e=>{var n,i,o,a,r;if(!e.title)return;const h=this.annotationManager.getEffectiveTitleStyle(e),l=this.annotationManager.getEffectiveTitlePosition(e),d=h.color||"#FFFFFF",c=h.backgroundColor||"rgba(0, 0, 0, 0.7)",x=y(h.font||"12px Arial",s),f=u(null!==(n=h.paddingX)&&void 0!==n?n:6,s),v=u(null!==(i=h.paddingY)&&void 0!==i?i:3,s),M=u(null!==(o=h.borderRadius)&&void 0!==o?o:4,s);t.font=x;const w=t.measureText(e.title).width,m=p(x),A=("rect"===e.type?this.shapeRenderers.rect:this.shapeRenderers.polygon).getTitleAnchor(e);if(!A)return;const T=w+2*f,I=m+2*v,{x:S,y:b}=g({anchor:A,boxWidth:T,boxHeight:I,position:Object.assign(Object.assign({},l),{offsetX:u(null!==(a=l.offsetX)&&void 0!==a?a:0,s),offsetY:u(null!==(r=l.offsetY)&&void 0!==r?r:0,s)}),gap:u(4,s)});t.fillStyle=c,t.roundRect?(t.roundRect(S,b,T,I,M),t.fill()):t.fillRect(S,b,T,I),t.fillStyle=d,t.textAlign="left",t.textBaseline="top",t.fillText(e.title,S+f,b+v)})}}class E{constructor(t,e,n,i,s,o,a,r,h,l){this.canvas=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.renderer=s,this.getDrawType=o,this.getBgImage=a,this.renderCallback=r,this.setDrawTypeCallback=h,this.notifyUndo=l,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(),o=t.clientX-s.left,a=t.clientY-s.top,r=(o-this.viewport.offset.x)/n,h=(a-this.viewport.offset.y)/n;this.viewport.scale=i;const l=r*i+this.viewport.offset.x,d=h*i+this.viewport.offset.y;this.viewport.offset.x+=o-l,this.viewport.offset.y+=a-d,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):A.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index: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 o=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,o),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(o);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):A.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index:n}),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(o);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(o);if("rect"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.startRectDrawing(o)}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,o),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(o);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):A.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index:e}),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(o);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(o);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(o)&&this.annotationManager.addPolygonPoint(o):this.annotationManager.startPolygonDrawing(o),this.annotationManager.updatePolygonTempPoint(o),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,o),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):A.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index:e}),void this.renderCallback();if(this.handleRectModeClick(t,o))return;if(this.handlePolygonModeClick(t,o))return;this.isDragging=!0,this.dragStart={x:t.clientX,y:t.clientY},this.canvas.style.cursor="grabbing"}else""===i&&this.handleNoModeClick(t,o)}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)}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):A.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index: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.movingTextIndex)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.updateMoveStart({x:t.clientX,y:t.clientY}),this.renderCallback()}isHoverLockedAnnotation(t){return!(!t||!this.annotationManager.selectedAnnotation)&&(!0===this.annotationManager.selectedAnnotation.locked&&t.index===this.annotationManager.selectedAnnotation.index)}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")}const n=this.annotationManager.getAnnotationAtPoint(e);if(n)return void(this.canvas.style.cursor=this.isHoverLockedAnnotation(n)?"default":"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),i=this.annotationManager.getAnnotationAtPoint(n);i?this.canvas.style.cursor=this.isHoverLockedAnnotation(i)?"default":"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),i=this.annotationManager.getAnnotationAtPoint(n);i?this.canvas.style.cursor=this.isHoverLockedAnnotation(i)?"default":"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?this.isHoverLockedAnnotation(n)?"default":"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?this.isHoverLockedAnnotation(n)?"default":"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.endTextMoving(),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(this.annotationManager.selectedAnnotation){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);if(n&&n.index===this.annotationManager.selectedAnnotation.index)return void this.annotationManager.startTitleEditing(n.index)}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();!this.getBgImage()||"polygon"!==n||this.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving||(this.justDeselected?this.justDeselected=!1:null===(e=this.annotationManager.selectedAnnotation)||void 0===e||e.type)}handleKeyDown(t){const e=t.target;if(!e||"INPUT"!==e.tagName&&"TEXTAREA"!==e.tagName&&"SELECT"!==e.tagName&&!e.isContentEditable){if("z"===t.key&&(t.ctrlKey||t.metaKey)){return A.withdrawAll(this.annotationManager,this.textManager)&&this.notifyUndo(),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(){this.listeners=new Map}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){var n;null===(n=this.listeners.get(t))||void 0===n||n.delete(e)}emit(t,e){var n;null===(n=this.listeners.get(t))||void 0===n||n.forEach(t=>t(e))}clear(){this.listeners.clear()}}class O{constructor(t){this.canvas=document.createElement("canvas"),this.emitter=new D,this.bgImage=null,this.bgImageSrc="",this.bgImageExt="jpeg",this.drawType="";const{drawType:e,useEvents:n=!0,id:i="container",annotationColor:s,lineStyle:o,vertexStyle:a,textStyle:r,enableTitle:l=!1,clampToImageBounds:d=!0}=t,c=document.getElementById(i);if(!c)throw new Error(`Container with id "${i}" not found`);this.container=c,"absolute"!==c.style.position&&"fixed"!==c.style.position&&"relative"!==c.style.position&&(c.style.position="relative"),this.ctx=this.canvas.getContext("2d"),this.viewport=new h,this.viewport.setSize(c.clientWidth,c.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",c.appendChild(this.canvas),this.annotationManager=new I(this.viewport,this.container,()=>this.render(),(t,e)=>this.emitter.emit(t,e)),this.annotationManager.measureTitleWidth=(t,e)=>(this.ctx.font=e,this.ctx.measureText(t).width),s&&this.annotationManager.setColorConfig(s),o&&this.annotationManager.setLineStyle(o),a&&this.annotationManager.setVertexStyle(a),this.annotationManager.enableTitle=l,l&&this.annotationManager.initTitleSupport(),this.annotationManager.clampEnabled=d,this.textManager=new S(this.viewport,this.container,this.ctx,()=>this.render(),(t,e)=>this.emitter.emit(t,e)),r&&this.textManager.setTextStyle(r),this.textManager.clampEnabled=d,this.renderer=new P(this.ctx,this.viewport,this.annotationManager,this.textManager),this.eventHandler=new E(this.canvas,this.viewport,this.annotationManager,this.textManager,this.renderer,()=>this.drawType,()=>this.bgImage,()=>this.render(),t=>this.setDrawType(t),()=>this.emitter.emit("undo",void 0)),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.annotationManager.adjustTitlePositions(),this.render()}}render(){this.renderer.render(this.bgImage)}clear(t=""){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.setDrawType(t),this.render(),this.emitter.emit("clear",void 0)}withdraw(){const t=this.annotationManager.withdraw(),e=this.textManager.withdraw();(t||e)&&(this.render(),this.emitter.emit("undo",void 0))}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(),this.emitter.emit("clear",void 0),!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()}getAnnotation(t){return this.annotationManager.getAnnotation(t)}getTextAnnotation(t){return this.textManager.getTextAnnotation(t)}on(t,e){this.emitter.on(t,e)}off(t,e){this.emitter.off(t,e)}setAnnotationTitle(t,e){const n=this.annotationManager.setTitle(t,e);return n&&this.render(),n}getAnnotationTitle(t){return this.annotationManager.getTitle(t)}setTitleStyle(t){this.annotationManager.setTitleStyle(t),this.render()}getTitleStyle(){return this.annotationManager.getTitleStyle()}setTitlePosition(t){this.annotationManager.setTitlePosition(t),this.render()}getTitlePosition(){return this.annotationManager.getTitlePosition()}setAnnotationTitleStyle(t,e){const n=this.annotationManager.setAnnotationTitleStyle(t,e);return n&&this.render(),n}setAnnotationTitlePosition(t,e){const n=this.annotationManager.setAnnotationTitlePosition(t,e);return n&&this.render(),n}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,e){this.annotationManager.selectAnnotation(t,e)&&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){if(this.annotationManager.moveSelectedAnnotation(t,e)){const t=this.annotationManager.selectedAnnotation;t&&this.annotationManager.notifyUpdate(t.index),this.render()}}setAnnotationColor(t){this.annotationManager.setColorConfig(t),this.render()}getAnnotationColor(){return this.annotationManager.getColorConfig()}updateSelectedAnnotationStyle(t){if(void 0!==t){const e=this.annotationManager.updateAnnotationStyle(t);return e&&this.render(),e}const e=this.annotationManager.selectedAnnotation;if(!e)return!1;const n=this.annotationManager.recordList[e.index];return!!n&&(n.style=this.annotationManager.getCurrentStyle(),this.annotationManager.notifyUpdate(e.index),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()}updateTextAnnotationStyle(t,e){const n=this.textManager.updateTextAnnotationStyle(t,e);return n&&this.render(),n}setTextInputStyle(t){this.textManager.setInputStyle(t)}setTextSelectionStyle(t){this.textManager.setSelectionStyle(t),this.render()}destroy(){this.emitter.clear(),document.removeEventListener("keydown",this.events.keydown),this.textManager.destroy(),this.annotationManager.destroyTitleInput(),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}export{I as AnnotationManager,O as Drawer,D as Emitter,E as EventHandler,P as Renderer,S as TextAnnotationManager,h as ViewportManager,s as base64ToBlob,i as base64ToFile,O as default,n as getImageTypeFromUrl,o 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),o=Math.abs(e.height);return t.x>=n&&t.x<=n+s&&t.y>=i&&t.y<=i+o}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 o=e[i].point.x,a=e[i].point.y,r=e[s].point.x,l=e[s].point.y;a>t.y!=l>t.y&&t.x<(r-o)*(t.y-a)/(l-a)+o&&(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]),o=s.length,a=new Uint8Array(o);for(let t=0;t<o;++t)a[t]=s.charCodeAt(t);const r=new Blob([a],{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],o=atob(i[1]),a=new ArrayBuffer(o.length),r=new Uint8Array(a);for(let t=0;t<o.length;t++)r[t]=o.charCodeAt(t);e(new Blob([a],{type:s}))})}function o(t,e){return t<2?e?.1:-.1:t<5?e?.05:-.05:e?.02:-.02}function a(t){return"function"==typeof structuredClone?structuredClone(t):JSON.parse(JSON.stringify(t))}function r(){return"undefined"!=typeof crypto&&"function"==typeof crypto.randomUUID?crypto.randomUUID():`id-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}class l{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,o=(n-this.offset.y)/i;this.scale=Math.max(this.minScale,Math.min(t,this.maxScale));const a=s*this.scale+this.offset.x,r=o*this.scale+this.offset.y;this.offset.x+=e-a,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}}const h={minX:Number.NEGATIVE_INFINITY,minY:Number.NEGATIVE_INFINITY,maxX:Number.POSITIVE_INFINITY,maxY:Number.POSITIVE_INFINITY};function d(t,e,n){return Math.min(Math.max(t,e),n)}function c(t){var e,n,i,s;const{anchor:o,boxWidth:a,boxHeight:r,position:l}=t,c=null!==(e=t.bounds)&&void 0!==e?e:h,g=null!==(n=t.gap)&&void 0!==n?n:4,x=null!==(i=l.offsetX)&&void 0!==i?i:0,u=null!==(s=l.offsetY)&&void 0!==s?s:0,f=l.align||"center";let p;switch(f){case"left":p=o.x+x;break;case"right":p=o.x+o.width-a+x;break;default:p=o.x+o.width/2-a/2+x}const y=d(p,c.minX,Math.max(c.minX,c.maxX-a)),v=x+(y-p),M=l.vertical||"top";let w,m=M;return"inside-top"===M?w=o.y+g+u:"bottom"===M?(w=o.y+o.height+g+u,w+r>c.maxY&&(m="top",w=o.y-r-g+u)):(w=o.y-r-g+u,w<c.minY&&(m="bottom",w=o.y+o.height+g+u)),w=d(w,c.minY,Math.max(c.minY,c.maxY-r)),{x:y,y:w,vertical:m,align:f,offsetX:v}}function g(t){const{x:e,y:n}=c(t);return{x:e,y:n}}function x(t,e){if("polygon"===t.type){const n=t.data;if(0===n.length)return null;let i=1/0,s=1/0,o=-1/0,a=-1/0;return n.forEach(t=>{const n=e?e.offset.x+t.point.x*e.scale:t.point.x,r=e?e.offset.y+t.point.y*e.scale:t.point.y;n<i&&(i=n),r<s&&(s=r),n>o&&(o=n),r>a&&(a=r)}),{x:i,y:s,width:o-i,height:a-s}}const n=t.data[0];return e?{x:e.offset.x+n.start.x*e.scale,y:e.offset.y+n.start.y*e.scale,width:n.width*e.scale,height:n.height*e.scale}:{x:n.start.x,y:n.start.y,width:n.width,height:n.height}}function u(t,e){return Math.round(t*e)}function f(t,e){return Math.max(1,u(t,e))}function p(t,e=12){const n=t.match(/(\d+(?:\.\d+)?)px/);return n?parseFloat(n[1]):e}function y(t,e){return t.replace(/(\d+(?:\.\d+)?)px/,(t,n)=>`${f(parseFloat(n),e)}px`)}function v(t,e,n){if(!n)return e;const{originalWidth:i,originalHeight:s}=t;return i&&s?{x:Math.max(0,Math.min(e.x,i)),y:Math.max(0,Math.min(e.y,s))}:e}function M(t,e,n,i,s){t&&s.id&&t(n,{id:s.id,type:e,index:i,data:a(s)})}const w=new class{constructor(){this.type="rect"}startDrawing(t,e){t.isDrawing=!0,t.drawStartPoint=e,t.operate={type:"rect",data:[{start:Object.assign({},e),width:0,height:0}],status:"pending"}}updateDrawing(t,e){if(!t.isDrawing||"rect"!==t.operate.type)return;const n=t.operate.data[0];n.width=e.x-t.drawStartPoint.x,n.height=e.y-t.drawStartPoint.y}addPoint(t,e){return!1}finishDrawing(t){if(!t.isDrawing||"rect"!==t.operate.type)return!1;const e=t.operate.data[0];return Math.abs(e.width)>5&&Math.abs(e.height)>5&&t.pushRecord(Object.assign({},t.operate)),t.operate.data=[],t.isDrawing=!1,!0}cancelDrawing(t){t.operate.data=[],t.isDrawing=!1,t.tempPolygonPoint=null}withdrawInProgress(t){return 0!==t.operate.data.length&&(t.operate.data=[],t.isDrawing=!1,!0)}hitTest(e,n){return t(n,e.data[0])}getHandles(t,e,n){const i=t.data[0],s=e.offset.x+i.start.x*e.scale,o=e.offset.y+i.start.y*e.scale,a=i.width*e.scale,r=i.height*e.scale;return[{x:s,y:o,index:0},{x:s+a,y:o,index:1},{x:s,y:o+r,index:2},{x:s+a,y:o+r,index:3}]}move(t,e,n){const i=t.data[0];i.start.x+=e,i.start.y+=n}snapshotForResize(t){const e=t.data[0];return{start:Object.assign({},e.start),width:e.width,height:e.height}}resize(t,e,n,i){const s=t.data[0],o=i,a=o.start.x,r=o.start.x+o.width,l=o.start.y,h=o.start.y+o.height;let d,c;switch(e){case 0:d=r,c=h;break;case 1:d=a,c=h;break;case 2:d=r,c=l;break;case 3:d=a,c=l;break;default:return}const g=Math.min(n.x,d),x=Math.max(n.x,d),u=Math.min(n.y,c),f=Math.max(n.y,c);s.start.x=g,s.start.y=u,s.width=x-g,s.height=f-u;const p=n.x<d,y=n.y<c;let v;return 0===e?p||y?!p&&y?v=1:p&&!y&&(v=2):v=3:1===e?p&&!y?v=2:p&&y?v=0:p||y||(v=3):2===e?!p&&y?v=1:p&&y?v=0:p||y||(v=3):3===e&&(p&&y?v=0:!p&&y?v=1:p&&!y&&(v=2)),o.start.x=s.start.x,o.start.y=s.start.y,o.width=s.width,o.height=s.height,v}getBounds(t){const e=t.data[0];return{x:e.start.x,y:e.start.y,width:e.width,height:e.height}}};const m=new class{constructor(){this.type="polygon"}startDrawing(t,e){t.isDrawing=!0,t.operate={type:"polygon",data:[{point:e}],status:"pending"},t.tempPolygonPoint=e}updateDrawing(t,e){t.tempPolygonPoint=e}addPoint(t,e){if(!t.isDrawing||"polygon"!==t.operate.type)return!1;const n=t.operate.data.length>0?t.operate.data[t.operate.data.length-1]:null;return!(n&&Math.abs(n.point.x-e.x)<=5&&Math.abs(n.point.y-e.y)<=5)&&(t.operate.data.push({point:e}),!0)}finishDrawing(t){return!(!t.isDrawing||"polygon"!==t.operate.type)&&(t.operate.data.length>=3&&(t.operate.status="fullfilled",t.pushRecord(Object.assign({},t.operate))),t.operate={type:"polygon",data:[],status:"pending"},t.isDrawing=!1,t.tempPolygonPoint=null,!0)}cancelDrawing(t){t.isDrawing&&"polygon"===t.operate.type&&t.operate.data.length>=2&&(t.operate.status="fullfilled",t.pushRecord(Object.assign({},t.operate))),t.operate.data=[],t.isDrawing=!1,t.tempPolygonPoint=null}withdrawInProgress(t){return 0!==t.operate.data.length&&(t.operate.data.pop(),0===t.operate.data.length&&(t.isDrawing=!1),!0)}hitTest(t,n){return e(n,t.data)}getHandles(t,e,n){const i=t.data,s=[];for(let t=0;t<i.length;t++){const n=i[t];s.push({x:e.offset.x+n.point.x*e.scale,y:e.offset.y+n.point.y*e.scale,index:t})}return s}move(t,e,n){t.data.forEach(t=>{t.point.x+=e,t.point.y+=n})}snapshotForResize(t){return t.data.map(t=>({point:Object.assign({},t.point)}))}resize(t,e,n,i){const s=t.data;e>=0&&e<s.length&&(s[e].point.x=n.x,s[e].point.y=n.y)}getBounds(t){const e=t.data;if(0===e.length)return{x:0,y:0,width:0,height:0};let n=1/0,i=1/0,s=-1/0,o=-1/0;return e.forEach(t=>{t.point.x<n&&(n=t.point.x),t.point.y<i&&(i=t.point.y),t.point.x>s&&(s=t.point.x),t.point.y>o&&(o=t.point.y)}),{x:n,y:i,width:s-n,height:o-i}}};const A=new class{constructor(){this.strategies=new Map}register(t){this.strategies.set(t.type,t)}get(t){const e=this.strategies.get(t);if(!e)throw new Error(`No strategy registered for shape type: ${t}`);return e}selectShapeExclusive(t,e,n){return"shape"===n.kind?(e.deselectTextAnnotation(),t.selectAnnotation(n.ref,{lock:n.locked})):(t.deselectAnnotation(),e.selectTextAnnotation(n.index))}deselectAll(t,e){t.deselectAnnotation(),e.deselectTextAnnotation()}withdrawAll(t,e){return t.withdraw()||e.withdraw()}};A.register(w),A.register(m);class T{constructor(t,e,n,i){this.viewport=t,this.container=e,this.renderCallback=n,this.changeCallback=i,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.editingTitleIndex=null,this.titleInput=null,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.titleStyle={font:"12px Arial",color:"#FFFFFF",backgroundColor:"rgba(0, 0, 0, 0.7)",paddingX:6,paddingY:3,borderRadius:4,placeholder:"输入标题..."},this.titlePosition={vertical:"top",align:"center",offsetX:0,offsetY:0},this.enableTitle=!1,this.clampEnabled=!0,this.applyColorConfig()}strategyOf(t){return A.get(t)}clamp(t){return v(this.viewport,t,this.clampEnabled)}clampToImageBounds(t){return v(this.viewport,t,this.clampEnabled)}clampRecordToImageBounds(t){if(!this.clampEnabled)return;const{originalWidth:e,originalHeight:n}=this.viewport;if(!e||!n)return;if("rect"===t.type){const i=t.data[0];if(!i)return;const s=Math.min(i.start.x,i.start.x+i.width),o=Math.max(i.start.x,i.start.x+i.width),a=Math.min(i.start.y,i.start.y+i.height),r=Math.max(i.start.y,i.start.y+i.height);if(s>=0&&a>=0&&o<=e&&r<=n)return;const l=Math.min(o-s,e),h=Math.min(r-a,n);return i.start.x=Math.max(0,Math.min(s,e-l)),i.start.y=Math.max(0,Math.min(a,n-h)),i.width=l,void(i.height=h)}const i=t.data;if(!i||0===i.length)return;let s=1/0,o=1/0,a=-1/0,r=-1/0;for(const t of i)s=Math.min(s,t.point.x),a=Math.max(a,t.point.x),o=Math.min(o,t.point.y),r=Math.max(r,t.point.y);let l=0,h=0;if(a-s>e||s<0?l=-s:a>e&&(l=e-a),r-o>n||o<0?h=-o:r>n&&(h=n-r),0!==l||0!==h)for(const t of i)t.point.x+=l,t.point.y+=h}pushRecord(t){const e=Object.assign(Object.assign({},t),{id:r(),style:this.getCurrentStyle()});this.recordList.push(e),this.deleteHistory=[],this.notifyChange("create",this.recordList.length-1,e)}initTitleSupport(){this.container&&this.enableTitle&&this.createTitleInput()}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)}}notifyChange(t,e,n){M(this.changeCallback,n.type,t,e,n)}notifyUpdate(t){const e=this.recordList[t];e&&this.notifyChange("update",t,e)}resolveIndex(t){return"number"==typeof t?t:this.recordList.findIndex(e=>e.id===t)}getAnnotation(t){const e=this.resolveIndex(t);if(!(e<0||e>=this.recordList.length))return a(this.recordList[e])}updateAnnotationStyle(t){const e=this.resolveIndex(t);return!(e<0||e>=this.recordList.length)&&(this.recordList[e].style=this.getCurrentStyle(),this.notifyUpdate(e),!0)}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()}withdraw(){if(this.operate.data.length>0){const t="polygon"===this.operate.type?"polygon":"rect";return this.strategyOf(t).withdrawInProgress(this),!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,e){var n;const i=this.resolveIndex(t);if(i<0||i>=this.recordList.length)return this.deselectAnnotation(),!1;const s=this.recordList[i],o=void 0!==(null==e?void 0:e.lock)?!!e.lock:(null===(n=this.selectedAnnotation)||void 0===n?void 0:n.index)===i&&!0===this.selectedAnnotation.locked;return this.selectedAnnotation={index:i,type:s.type,locked:o},!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(),this.notifyChange("delete",t,e),!0}startMovingAnnotation(t){return!(!this.selectedAnnotation||!0===this.selectedAnnotation.locked)&&(this.isMovingAnnotation=!0,this.annotationMoveStart={x:t.clientX,y:t.clientY},!0)}updateMoveStart(t){this.annotationMoveStart=t}finishMovingAnnotation(){var t;const e=this.isMovingAnnotation||this.isResizing;if(this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null,e&&this.selectedAnnotation){const e=this.recordList[this.selectedAnnotation.index];(null==e?void 0:e.title)&&this.autoAdjustTitlePosition(e,e.title),this.notifyUpdate(this.selectedAnnotation.index),null===(t=this.renderCallback)||void 0===t||t.call(this)}}clear(){this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,this.deselectAnnotation(),this.deleteHistory=[]}getAnnotations(){return this.recordList.map(t=>a(t))}getSelectedAnnotation(){if(!this.selectedAnnotation)return null;const t=this.recordList[this.selectedAnnotation.index];return t?{index:this.selectedAnnotation.index,type:this.selectedAnnotation.type,data:a(t)}:null}setTitleStyle(t){this.titleStyle=Object.assign(Object.assign({},this.titleStyle),t)}getTitleStyle(){return Object.assign({},this.titleStyle)}setTitlePosition(t){this.titlePosition=Object.assign(Object.assign({},this.titlePosition),t)}getTitlePosition(){return Object.assign({},this.titlePosition)}getEffectiveTitleStyle(t){const e=this.getAnnotationStyle(t);return Object.assign(Object.assign({},this.titleStyle),e.titleStyle||{})}getEffectiveTitlePosition(t){const e=this.getAnnotationStyle(t);return Object.assign(Object.assign({},this.titlePosition),e.titlePosition||{})}captureTitleStyleSnapshot(t){t.style||(t.style=this.getCurrentStyle()),t.style.titleStyle=Object.assign({},this.titleStyle),t.style.titlePositionExplicit||(t.style.titlePosition=Object.assign({},this.titlePosition))}autoAdjustTitlePosition(t,e){var n,i,s;if(!e||(null===(n=t.style)||void 0===n?void 0:n.titlePositionExplicit))return;const{originalWidth:o,originalHeight:a,initialScale:r,scale:l}=this.viewport;if(o<=0||a<=0)return;const h=x(t);if(!h)return;const d=r>0?r:l>0?l:1,g={x:h.x*d,y:h.y*d,width:h.width*d,height:h.height*d},u=this.getEffectiveTitleStyle(t),f=u.font||"12px Arial",y=p(f)+2*(null!==(i=u.paddingY)&&void 0!==i?i:3),v=this.measureTitleWidth,M=v?{minX:0,minY:0,maxX:o*d,maxY:a*d}:{minX:Number.NEGATIVE_INFINITY,minY:0,maxX:Number.POSITIVE_INFINITY,maxY:a*d},w=v?v(e,f)+2*(null!==(s=u.paddingX)&&void 0!==s?s:6):0,m=Object.assign({},this.titlePosition),A=c({anchor:g,boxWidth:w,boxHeight:y,position:m,bounds:M});t.style||(t.style=this.getCurrentStyle()),t.style.titlePosition=Object.assign(Object.assign({},m),{vertical:A.vertical,align:A.align,offsetX:A.offsetX})}adjustTitlePositions(){this.viewport.originalWidth<=0||this.viewport.originalHeight<=0||this.recordList.forEach(t=>{var e;t.title&&!(null===(e=t.style)||void 0===e?void 0:e.titlePositionExplicit)&&this.autoAdjustTitlePosition(t,t.title)})}setAnnotationTitleStyle(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.recordList.length)return!1;const i=this.recordList[n];return i.style||(i.style=this.getCurrentStyle()),i.style.titleStyle=Object.assign(Object.assign({},i.style.titleStyle||this.titleStyle),e),this.notifyUpdate(n),!0}setAnnotationTitlePosition(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.recordList.length)return!1;const i=this.recordList[n];return i.style||(i.style=this.getCurrentStyle()),i.style.titlePosition=Object.assign(Object.assign({},i.style.titlePosition||this.titlePosition),e),i.style.titlePositionExplicit=!0,this.notifyUpdate(n),!0}createTitleInput(){this.container&&(this.titleInput=document.createElement("input"),this.titleInput.type="text",this.titleInput.style.position="absolute",this.titleInput.style.zIndex="99998",this.titleInput.style.display="none",this.titleInput.style.outline="none",this.titleInput.style.border="1px solid #00D9FF",this.titleInput.style.borderRadius="4px",this.titleInput.style.padding="4px 8px",this.titleInput.style.fontSize="13px",this.titleInput.style.fontFamily="Arial, sans-serif",this.titleInput.style.backgroundColor="#ffffff",this.titleInput.style.color="#333",this.titleInput.style.boxShadow="0 2px 8px rgba(0,0,0,0.3)",this.titleInput.style.minWidth="80px",this.titleInput.style.maxWidth="200px",this.titleInput.placeholder=this.titleStyle.placeholder||"输入标题...",this.titleInput.addEventListener("blur",()=>{this.finishTitleEditing()}),this.titleInput.addEventListener("keydown",t=>{t.stopPropagation(),"Enter"===t.key?this.finishTitleEditing():"Escape"===t.key&&(t.preventDefault(),this.cancelTitleEditing())}),this.container.appendChild(this.titleInput))}setTitle(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.recordList.length)return!1;const i=this.recordList[n];return i.title=e||void 0,e&&(this.captureTitleStyleSnapshot(i),this.autoAdjustTitlePosition(i,e)),this.notifyUpdate(n),!0}getTitle(t){const e=this.resolveIndex(t);if(!(e<0||e>=this.recordList.length))return this.recordList[e].title}startTitleEditing(t){if(!this.enableTitle||!this.titleInput||t<0||t>=this.recordList.length)return!1;const e=this.recordList[t];let n,i;if(this.editingTitleIndex=t,this.deselectAnnotation(),"rect"===e.type){const t=e.data[0];n=this.viewport.offset.x+t.start.x*this.viewport.scale,i=this.viewport.offset.y+t.start.y*this.viewport.scale}else{const t=e.data[0];n=this.viewport.offset.x+t.point.x*this.viewport.scale,i=this.viewport.offset.y+t.point.y*this.viewport.scale}return this.titleInput.value=e.title||"",this.titleInput.placeholder=this.getEffectiveTitleStyle(e).placeholder||"输入标题...",this.titleInput.style.left=`${n}px`,this.titleInput.style.top=i-32+"px",this.titleInput.style.display="block",setTimeout(()=>{this.titleInput&&(this.titleInput.focus(),this.titleInput.select())},10),!0}finishTitleEditing(){if(!this.titleInput||null===this.editingTitleIndex)return!1;const t=this.editingTitleIndex,e=this.titleInput.value.trim();if(t>=0&&t<this.recordList.length){const n=this.recordList[t];n.title=e||void 0,e&&(this.captureTitleStyleSnapshot(n),this.autoAdjustTitlePosition(n,e)),this.notifyUpdate(t),this.selectAnnotation(t)}return this.resetTitleEditingState(),this.renderCallback&&this.renderCallback(),!0}cancelTitleEditing(){if(!this.titleInput||null===this.editingTitleIndex)return!1;const t=this.editingTitleIndex;return t>=0&&t<this.recordList.length&&this.selectAnnotation(t),this.resetTitleEditingState(),this.renderCallback&&this.renderCallback(),!0}resetTitleEditingState(){this.titleInput&&(this.titleInput.style.display="none"),this.editingTitleIndex=null}destroyTitleInput(){this.titleInput&&this.titleInput.parentNode&&(this.titleInput.parentNode.removeChild(this.titleInput),this.titleInput=null)}}class I extends T{startRectDrawing(t){t=this.clampToImageBounds(t),this.strategyOf("rect").startDrawing(this,t)}updateRectDrawing(t){this.isDrawing&&"rect"===this.operate.type&&(t=this.clampToImageBounds(t),this.strategyOf("rect").updateDrawing(this,t))}finishRectDrawing(){return this.strategyOf("rect").finishDrawing(this)}startPolygonDrawing(t){t=this.clampToImageBounds(t),this.strategyOf("polygon").startDrawing(this,t)}addPolygonPoint(t){return!(!this.isDrawing||"polygon"!==this.operate.type)&&(t=this.clampToImageBounds(t),this.strategyOf("polygon").addPoint(this,t))}updatePolygonTempPoint(t){this.strategyOf("polygon").updateDrawing(this,this.clampToImageBounds(t))}finishPolygonDrawing(){return this.strategyOf("polygon").finishDrawing(this)}cancelDrawing(){const t="polygon"===this.operate.type?"polygon":"rect";this.strategyOf(t).cancelDrawing(this)}moveSelectedAnnotation(t,e){if(!this.selectedAnnotation)return!1;const n=this.recordList[this.selectedAnnotation.index];return!!n&&(this.strategyOf(n.type).move(n,t,e),this.clampRecordToImageBounds(n),!0)}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=this.strategyOf("rect").snapshotForResize(n):"polygon"===n.type&&(this.originalPolygon=this.strategyOf("polygon").snapshotForResize(n)),!0}resizeRect(t){if(!this.selectedAnnotation||"rect"!==this.selectedAnnotation.type||!this.originalRect||!this.activeHandle)return!1;if(this.activeHandle.index<0||this.activeHandle.index>3)return!1;const e=this.recordList[this.selectedAnnotation.index],n=this.clampToImageBounds(t),i=this.strategyOf("rect").resize(e,this.activeHandle.index,n,this.originalRect);return"number"==typeof i&&(this.activeHandle.index=i),!0}resizePolygon(t){var e;if(!this.selectedAnnotation||"polygon"!==this.selectedAnnotation.type||!this.activeHandle)return!1;const n=this.recordList[this.selectedAnnotation.index],i=this.activeHandle.index,s=n.data;return!(i<0||i>=s.length)&&(this.strategyOf("polygon").resize(n,i,this.clampToImageBounds(t),null!==(e=this.originalPolygon)&&void 0!==e?e:[]),!0)}getAnnotationAtPoint(t){for(let e=this.recordList.length-1;e>=0;e--){const n=this.recordList[e],i=n.type;if(this.strategyOf(i).hitTest(n,t))return{index:e,type:i}}return null}getHandleAtPoint(t,e){if(!this.selectedAnnotation)return null;if(!0===this.selectedAnnotation.locked)return null;const n=this.recordList[this.selectedAnnotation.index],i=this.selectionStyle.handleSize,s=i/2,o=this.selectedAnnotation.type,a=this.strategyOf(o).getHandles(n,this.viewport,i);for(const n of a)if(t>=n.x-s&&t<=n.x+s&&e>=n.y-s&&e<=n.y+s)return"rect"===o?{type:"rect-corner",index:n.index}:{type:"polygon-vertex",index:n.index};return null}}class S{constructor(t,e,n,i,s){this.viewport=t,this.container=e,this.ctx=n,this.renderCallback=i,this.changeCallback=s,this.textAnnotations=[],this.editingTextIndex=null,this.currentEditingIndex=null,this.movingTextIndex=null,this.isTextMoving=!1,this.textMoveStart={x:0,y:0},this.textBeforeEditing="",this.selectedTextIndex=null,this.clampEnabled=!0,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}}notifyChange(t,e,n){M(this.changeCallback,"text",t,e,n)}resolveIndex(t){return"number"==typeof t?t:this.textAnnotations.findIndex(e=>e.id===t)}getTextAnnotation(t){const e=this.resolveIndex(t);if(!(e<0||e>=this.textAnnotations.length))return a(this.textAnnotations[e])}updateTextAnnotationStyle(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.textAnnotations.length)return!1;const i=this.textAnnotations[n];return i.style=Object.assign(Object.assign({},i.style||this.getCurrentStyle()),e),this.notifyChange("update",n,this.textAnnotations[n]),!0}clampToImageBounds(t){return v(this.viewport,t,this.clampEnabled)}addTextAnnotation(t,e,n=""){var i;const s=this.clampToImageBounds({x:t,y:e});t=s.x,e=s.y,this.ctx.font=this.textStyle.font;const o=n||"输入文字...",a=this.ctx.measureText(o);let l;if(a.actualBoundingBoxAscent&&a.actualBoundingBoxDescent)l=a.actualBoundingBoxAscent+a.actualBoundingBoxDescent;else{l=1.2*parseInt((null===(i=this.textStyle.font.match(/\d+/))||void 0===i?void 0:i[0])||"16")}const h={id:r(),position:{x:t,y:e},text:n,style:this.getCurrentStyle(),width:Math.max(a.width,60),height:l};this.textAnnotations.push(h);const d=this.textAnnotations.length-1;return this.notifyChange("create",d,h),this.deleteHistory=[],this.startEditing(d),d}updateTextAnnotation(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.textAnnotations.length)return!1;const i=this.textAnnotations[n];i.text=e,this.ctx.font=this.textStyle.font;const s=this.ctx.measureText(e);return i.width=s.width,i.height=1.2*parseInt(this.textStyle.font),this.notifyChange("update",n,this.textAnnotations[n]),!0}moveTextAnnotation(t,e,n){const i=this.resolveIndex(t);return!(i<0||i>=this.textAnnotations.length)&&(this.textAnnotations[i].position={x:e,y:n},this.notifyChange("update",i,this.textAnnotations[i]),!0)}removeTextAnnotation(t){const e=this.resolveIndex(t);if(e<0||e>=this.textAnnotations.length)return!1;const n=this.textAnnotations[e];return this.deleteHistory.push({annotation:Object.assign({},n),index:e}),this.textAnnotations.splice(e,1),this.notifyChange("delete",e,n),this.editingTextIndex===e?this.resetEditingState():null!==this.editingTextIndex&&this.editingTextIndex>e&&this.editingTextIndex--,this.movingTextIndex===e?this.endTextMoving():null!==this.movingTextIndex&&this.movingTextIndex>e&&this.movingTextIndex--,!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}px`,this.textInput.style.top=`${i}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){const e=this.textAnnotations[t];this.textAnnotations.splice(t,1),this.notifyChange("delete",t,e)}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),this.notifyChange("update",t,n)}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){if(""===this.textAnnotations[t].text&&""===this.textBeforeEditing){const e=this.textAnnotations[t];this.textAnnotations.splice(t,1),this.notifyChange("delete",t,e)}}return this.resetEditingState(),!0}deleteEditingAnnotation(){if(null===this.editingTextIndex)return!1;const t=this.editingTextIndex;if(this.textInput&&(this.textInput.style.display="none"),t>=0&&t<this.textAnnotations.length){const e=this.textAnnotations[t];this.textAnnotations.splice(t,1),this.notifyChange("delete",t,e)}return 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.movingTextIndex=e,this.isTextMoving=!0,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}moveAnnotation(t){if(!this.isTextMoving||null===this.movingTextIndex)return!1;const e=t.clientX-this.textMoveStart.x,n=t.clientY-this.textMoveStart.y,i=this.textAnnotations[this.movingTextIndex];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(){if(this.isTextMoving=!1,null!==this.movingTextIndex){const t=this.textAnnotations[this.movingTextIndex];t&&this.notifyChange("update",this.movingTextIndex,t)}this.movingTextIndex=null}endTextMoving(){this.isTextMoving=!1,this.movingTextIndex=null}isEditingVisible(){var t;return"block"===(null===(t=this.textInput)||void 0===t?void 0:t.style.display)}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,o=this.viewport.offset.y+i.position.y*this.viewport.scale,a=Math.max(i.width,60)+2*this.textStyle.padding,r=i.height+2*this.textStyle.padding;if(t>=s&&t<=s+a&&e>=o&&e<=o+r)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.map(t=>a(t))}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,this.notifyChange("delete",t,e),null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,null!==this.movingTextIndex&&this.movingTextIndex>t&&this.movingTextIndex--,!0}getSelectedTextAnnotation(){if(null===this.selectedTextIndex)return null;const t=this.textAnnotations[this.selectedTextIndex];return t?{index:this.selectedTextIndex,data:a(t)}:null}destroy(){this.textInput&&this.textInput.parentNode&&this.textInput.parentNode.removeChild(this.textInput)}}function b(t,e){switch(e){case"dashed":t.setLineDash([10,5]);break;case"dotted":t.setLineDash([2,4]);break;default:t.setLineDash([])}}class C{draw(t,e,n,i){const s=n.data[0];t.strokeRect(e.offset.x+s.start.x*e.scale,e.offset.y+s.start.y*e.scale,s.width*e.scale,s.height*e.scale)}drawInProgress(t,e,n){const i=n.operate.data[0];t.strokeRect(e.offset.x+i.start.x*e.scale,e.offset.y+i.start.y*e.scale,i.width*e.scale,i.height*e.scale)}drawSelection(t,e,n,i,s){const o=n.data[0],a=e.offset.x+o.start.x*e.scale,r=e.offset.y+o.start.y*e.scale,l=o.width*e.scale,h=o.height*e.scale;if(t.fillStyle=i.fillColor,t.fillRect(a,r,l,h),t.strokeStyle=i.strokeColor,t.lineWidth=2,t.setLineDash([5,5]),t.strokeRect(a,r,l,h),s)return;const d=i.handleSize;t.fillStyle=i.handleColor,t.setLineDash([]),t.fillRect(a-d/2,r-d/2,d,d),t.fillRect(a+l-d/2,r-d/2,d,d),t.fillRect(a-d/2,r+h-d/2,d,d),t.fillRect(a+l-d/2,r+h-d/2,d,d)}drawForExport(t,e,n,i=1){const s=e.data[0];t.strokeRect(s.start.x,s.start.y,s.width,s.height)}getTitleAnchor(t,e){return x(t,e)}}class k{constructor(t){this.store=t}draw(t,e,n,i){const s=i.vertexStyle||this.store.getVertexStyle();this.drawPolygon(t,e,n.data,"fullfilled"===n.status,s)}drawInProgress(t,e,n){const i=n.operate.data,s=n.tempPolygonPoint;if(t.beginPath(),i.forEach((n,i)=>{const s=Math.round(e.offset.x+n.point.x*e.scale),o=Math.round(e.offset.y+n.point.y*e.scale);0===i?t.moveTo(s,o):t.lineTo(s,o)}),s){const n=Math.round(e.offset.x+s.x*e.scale),i=Math.round(e.offset.y+s.y*e.scale);t.lineTo(n,i)}if(t.stroke(),this.drawPolygonVertices(t,e,i,n.getVertexStyle()),s){const i=n.getVertexStyle(),o=Math.round(e.offset.x+s.x*e.scale),a=Math.round(e.offset.y+s.y*e.scale),r=i.size/2;switch(t.fillStyle=i.fillColor,t.strokeStyle=i.strokeColor,t.lineWidth=i.strokeWidth,t.beginPath(),i.shape){case"square":t.rect(o-r,a-r,2*r,2*r);break;case"diamond":t.moveTo(o,a-r),t.lineTo(o+r,a),t.lineTo(o,a+r),t.lineTo(o-r,a),t.closePath();break;default:t.arc(o,a,r,0,2*Math.PI)}t.fill(),i.strokeWidth>0&&t.stroke()}}drawSelection(t,e,n,i,s){const o=n.data;if(t.beginPath(),o.forEach((n,i)=>{const s=e.offset.x+n.point.x*e.scale,o=e.offset.y+n.point.y*e.scale;0===i?t.moveTo(s,o):t.lineTo(s,o)}),t.closePath(),t.fillStyle=i.fillColor,t.fill(),t.strokeStyle=i.strokeColor,t.lineWidth=2,t.setLineDash([5,5]),t.stroke(),s)return;const a=i.handleSize;t.fillStyle=i.handleColor,t.setLineDash([]),o.forEach(n=>{const i=Math.round(e.offset.x+n.point.x*e.scale),s=Math.round(e.offset.y+n.point.y*e.scale);t.fillRect(i-a/2,s-a/2,a,a)})}drawForExport(t,e,n,i=1){if("fullfilled"!==e.status)return;const s=e.data;t.beginPath(),s.forEach((e,n)=>{0===n?t.moveTo(e.point.x,e.point.y):t.lineTo(e.point.x,e.point.y)});const o=e.data[0];t.lineTo(o.point.x,o.point.y),t.stroke();const a=f(4,i);s.forEach(e=>{t.beginPath(),t.arc(e.point.x,e.point.y,a,0,2*Math.PI),t.fillStyle=n.strokeColor,t.fill()})}getTitleAnchor(t,e){return x(t,e)}drawPolygon(t,e,n,i,s){if(0!==n.length){if(t.beginPath(),n.forEach((n,i)=>{const s=Math.round(e.offset.x+n.point.x*e.scale),o=Math.round(e.offset.y+n.point.y*e.scale);0===i?t.moveTo(s,o):t.lineTo(s,o)}),i&&n.length>1){const i=n[0];t.lineTo(e.offset.x+i.point.x*e.scale,e.offset.y+i.point.y*e.scale)}t.stroke(),this.drawPolygonVertices(t,e,n,s)}}drawPolygonVertices(t,e,n,i){const s=i||this.store.getVertexStyle(),o=s.size/2;n.forEach(n=>{const i=Math.round(e.offset.x+n.point.x*e.scale),a=Math.round(e.offset.y+n.point.y*e.scale);switch(t.fillStyle=s.fillColor,t.strokeStyle=s.strokeColor,t.lineWidth=s.strokeWidth,t.beginPath(),s.shape){case"square":t.rect(i-o,a-o,2*o,2*o);break;case"diamond":t.moveTo(i,a-o),t.lineTo(i+o,a),t.lineTo(i,a+o),t.lineTo(i-o,a),t.closePath();break;default:t.arc(i,a,o,0,2*Math.PI)}t.fill(),s.strokeWidth>0&&t.stroke()})}}class P{constructor(t,e,n,i){this.ctx=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.shapeRenderers={rect:new C,polygon:new k(n)}}render(t){this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.drawBackgroundImage(t),this.drawAnnotations(),function(t,e,n){const i=n.textStyle;n.textAnnotations.forEach((s,o)=>{var a,r,l;if(n.editingTextIndex===o&&n.isEditingVisible())return;if(!s.text)return;const h=(null===(a=s.style)||void 0===a?void 0:a.font)||i.font||"16px Arial",d=(null===(r=s.style)||void 0===r?void 0:r.color)||i.color||"#FFD700",c=(null===(l=s.style)||void 0===l?void 0:l.backgroundColor)||i.backgroundColor||"rgba(0,0,0,0.6)",g=e.offset.x+s.position.x*e.scale,x=e.offset.y+s.position.y*e.scale,u=n.selectedTextIndex===o;t.font=h;const f=t.measureText(s.text),p=f.actualBoundingBoxAscent||.8*s.height,y=p+(f.actualBoundingBoxDescent||.2*s.height),v=i.borderRadius,M=g,w=x,m=s.width+2*i.padding,A=y+2*i.padding;t.fillStyle=c,t.beginPath(),t.roundRect(M,w,m,A,v),t.fill(),u&&(t.strokeStyle=i.selectedBorderColor,t.lineWidth=2,t.setLineDash([5,5]),t.beginPath(),t.roundRect(M,w,m,A,v),t.stroke(),t.setLineDash([]));const T=g+i.padding,I=x+i.padding+p;t.fillStyle=d,t.fillText(s.text,T,I)})}(this.ctx,this.viewport,this.textManager)}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=>{const e=this.annotationManager.getAnnotationStyle(t);this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=e.lineWidth,b(this.ctx,e.lineStyle||"solid"),this.ctx.fillStyle=this.ctx.strokeStyle,"rect"===t.type?this.shapeRenderers.rect.draw(this.ctx,this.viewport,t,e):"polygon"===t.type&&this.shapeRenderers.polygon.draw(this.ctx,this.viewport,t,e),this.annotationManager.enableTitle&&t.title&&this.drawAnnotationTitle(t)}),this.annotationManager.operate.data.length>0&&(this.ctx.strokeStyle=this.annotationManager.strokeStyle,this.ctx.lineWidth=this.annotationManager.lineWidth,this.ctx.fillStyle=this.ctx.strokeStyle,b(this.ctx,this.annotationManager.lineStyle),"rect"===this.annotationManager.operate.type?this.shapeRenderers.rect.drawInProgress(this.ctx,this.viewport,this.annotationManager):"polygon"===this.annotationManager.operate.type&&this.shapeRenderers.polygon.drawInProgress(this.ctx,this.viewport,this.annotationManager)),this.ctx.setLineDash([]),this.drawSelectionHighlight()}drawSelectionHighlight(){const t=this.annotationManager.selectedAnnotation;if(!t)return;const e=this.annotationManager.recordList[t.index];if(!e)return;const n=this.annotationManager.selectionStyle,i=!0===t.locked;this.ctx.save(),"rect"===e.type?this.shapeRenderers.rect.drawSelection(this.ctx,this.viewport,e,n,i):"polygon"===e.type&&this.shapeRenderers.polygon.drawSelection(this.ctx,this.viewport,e,n,i),this.ctx.restore()}drawAnnotationTitle(t){var e,n,i;if(!t.title)return;const s=this.annotationManager.getEffectiveTitleStyle(t),o=this.annotationManager.getEffectiveTitlePosition(t),a=s.font||"12px Arial",r=s.color||"#FFFFFF",l=s.backgroundColor||"rgba(0, 0, 0, 0.7)",h=null!==(e=s.paddingX)&&void 0!==e?e:6,d=null!==(n=s.paddingY)&&void 0!==n?n:3,c=null!==(i=s.borderRadius)&&void 0!==i?i:4;this.ctx.save(),this.ctx.font=a;const x=this.ctx.measureText(t.title).width,u=p(a),f=("rect"===t.type?this.shapeRenderers.rect:this.shapeRenderers.polygon).getTitleAnchor(t,this.viewport);if(!f)return void this.ctx.restore();const y=x+2*h,v=u+2*d,{x:M,y:w}=g({anchor:f,boxWidth:y,boxHeight:v,position:o});this.ctx.fillStyle=l,this.ctx.setLineDash([]),this.ctx.beginPath(),this.ctx.roundRect(M,w,y,v,c),this.ctx.fill(),this.ctx.fillStyle=r,this.ctx.textAlign="left",this.ctx.textBaseline="top",this.ctx.fillText(t.title,M+h,w+d),this.ctx.restore()}getExportPixelRatio(){const t=this.viewport.scale;return t>0?1/t:1}drawForExport(t,e,n,i){const s=this.getExportPixelRatio();t.drawImage(e,0,0,n,i),this.annotationManager.recordList.forEach(e=>{const n=this.annotationManager.getAnnotationStyle(e);t.strokeStyle=n.strokeColor,t.lineWidth=f(n.lineWidth,s),"rect"===e.type?this.shapeRenderers.rect.drawForExport(t,e,n,s):"polygon"===e.type&&this.shapeRenderers.polygon.drawForExport(t,e,n,s)}),this.textManager.textAnnotations.forEach(e=>{var n,i,o;const a=this.textManager.textStyle,r=(null===(n=e.style)||void 0===n?void 0:n.font)||a.font||"16px Arial",l=(null===(i=e.style)||void 0===i?void 0:i.color)||a.color||"#FFD700",h=(null===(o=e.style)||void 0===o?void 0:o.backgroundColor)||a.backgroundColor||"rgba(0,0,0,0.6)";t.font=y(r,s);const d=t.measureText(e.text),c=d.actualBoundingBoxAscent||.8*e.height,g=c+(d.actualBoundingBoxDescent||.2*e.height),x=e.position.x,f=e.position.y,p=u(a.padding,s),v=d.width+2*p,M=g+2*p,w=u(a.borderRadius,s);t.fillStyle=h;const m=t;m.roundRect?(t.beginPath(),m.roundRect(x,f,v,M,w),t.fill()):t.fillRect(x,f,v,M),t.fillStyle=l,t.fillText(e.text,x+p,f+p+c)}),this.annotationManager.enableTitle&&this.annotationManager.recordList.forEach(e=>{var n,i,o,a,r;if(!e.title)return;const l=this.annotationManager.getEffectiveTitleStyle(e),h=this.annotationManager.getEffectiveTitlePosition(e),d=l.color||"#FFFFFF",c=l.backgroundColor||"rgba(0, 0, 0, 0.7)",x=y(l.font||"12px Arial",s),f=u(null!==(n=l.paddingX)&&void 0!==n?n:6,s),v=u(null!==(i=l.paddingY)&&void 0!==i?i:3,s),M=u(null!==(o=l.borderRadius)&&void 0!==o?o:4,s);t.font=x;const w=t.measureText(e.title).width,m=p(x),A=("rect"===e.type?this.shapeRenderers.rect:this.shapeRenderers.polygon).getTitleAnchor(e);if(!A)return;const T=w+2*f,I=m+2*v,{x:S,y:b}=g({anchor:A,boxWidth:T,boxHeight:I,position:Object.assign(Object.assign({},h),{offsetX:u(null!==(a=h.offsetX)&&void 0!==a?a:0,s),offsetY:u(null!==(r=h.offsetY)&&void 0!==r?r:0,s)}),gap:u(4,s)});t.fillStyle=c;const C=t;C.roundRect?(t.beginPath(),C.roundRect(S,b,T,I,M),t.fill()):t.fillRect(S,b,T,I),t.fillStyle=d,t.textAlign="left",t.textBaseline="top",t.fillText(e.title,S+f,b+v)})}}class E{constructor(t,e,n,i,s,o,a,r,l,h){this.canvas=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.renderer=s,this.getDrawType=o,this.getBgImage=a,this.renderCallback=r,this.setDrawTypeCallback=l,this.notifyUndo=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(),o=t.clientX-s.left,a=t.clientY-s.top,r=(o-this.viewport.offset.x)/n,l=(a-this.viewport.offset.y)/n;this.viewport.scale=i;const h=r*i+this.viewport.offset.x,d=l*i+this.viewport.offset.y;this.viewport.offset.x+=o-h,this.viewport.offset.y+=a-d,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):A.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index: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 o=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,o),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(o);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):A.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index:n}),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(o);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(o);if("rect"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.startRectDrawing(o)}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,o),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(o);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):A.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index:e}),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(o);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(o);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(o)&&this.annotationManager.addPolygonPoint(o):this.annotationManager.startPolygonDrawing(o),this.annotationManager.updatePolygonTempPoint(o),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,o),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):A.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index:e}),void this.renderCallback();if(this.handleRectModeClick(t,o))return;if(this.handlePolygonModeClick(t,o))return;this.isDragging=!0,this.dragStart={x:t.clientX,y:t.clientY},this.canvas.style.cursor="grabbing"}else""===i&&this.handleNoModeClick(t,o)}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)}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):A.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index: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.movingTextIndex)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.updateMoveStart({x:t.clientX,y:t.clientY}),this.renderCallback()}isHoverLockedAnnotation(t){return!(!t||!this.annotationManager.selectedAnnotation)&&(!0===this.annotationManager.selectedAnnotation.locked&&t.index===this.annotationManager.selectedAnnotation.index)}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")}const n=this.annotationManager.getAnnotationAtPoint(e);if(n)return void(this.canvas.style.cursor=this.isHoverLockedAnnotation(n)?"default":"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),i=this.annotationManager.getAnnotationAtPoint(n);i?this.canvas.style.cursor=this.isHoverLockedAnnotation(i)?"default":"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),i=this.annotationManager.getAnnotationAtPoint(n);i?this.canvas.style.cursor=this.isHoverLockedAnnotation(i)?"default":"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?this.isHoverLockedAnnotation(n)?"default":"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?this.isHoverLockedAnnotation(n)?"default":"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.endTextMoving(),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(this.annotationManager.selectedAnnotation){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);if(n&&n.index===this.annotationManager.selectedAnnotation.index)return void this.annotationManager.startTitleEditing(n.index)}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();!this.getBgImage()||"polygon"!==n||this.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving||(this.justDeselected?this.justDeselected=!1:null===(e=this.annotationManager.selectedAnnotation)||void 0===e||e.type)}handleKeyDown(t){const e=t.target;if(!e||"INPUT"!==e.tagName&&"TEXTAREA"!==e.tagName&&"SELECT"!==e.tagName&&!e.isContentEditable){if("z"===t.key&&(t.ctrlKey||t.metaKey)){return A.withdrawAll(this.annotationManager,this.textManager)&&this.notifyUndo(),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(){this.listeners=new Map}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){var n;null===(n=this.listeners.get(t))||void 0===n||n.delete(e)}emit(t,e){var n;null===(n=this.listeners.get(t))||void 0===n||n.forEach(t=>t(e))}clear(){this.listeners.clear()}}class O{constructor(t){this.canvas=document.createElement("canvas"),this.emitter=new D,this.bgImage=null,this.bgImageSrc="",this.bgImageExt="jpeg",this.drawType="";const{drawType:e,useEvents:n=!0,id:i="container",annotationColor:s,lineStyle:o,vertexStyle:a,textStyle:r,enableTitle:h=!1,clampToImageBounds:d=!0}=t,c=document.getElementById(i);if(!c)throw new Error(`Container with id "${i}" not found`);this.container=c,"absolute"!==c.style.position&&"fixed"!==c.style.position&&"relative"!==c.style.position&&(c.style.position="relative"),this.ctx=this.canvas.getContext("2d"),this.viewport=new l,this.viewport.setSize(c.clientWidth,c.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",c.appendChild(this.canvas),this.annotationManager=new I(this.viewport,this.container,()=>this.render(),(t,e)=>this.emitter.emit(t,e)),this.annotationManager.measureTitleWidth=(t,e)=>(this.ctx.font=e,this.ctx.measureText(t).width),s&&this.annotationManager.setColorConfig(s),o&&this.annotationManager.setLineStyle(o),a&&this.annotationManager.setVertexStyle(a),this.annotationManager.enableTitle=h,h&&this.annotationManager.initTitleSupport(),this.annotationManager.clampEnabled=d,this.textManager=new S(this.viewport,this.container,this.ctx,()=>this.render(),(t,e)=>this.emitter.emit(t,e)),r&&this.textManager.setTextStyle(r),this.textManager.clampEnabled=d,this.renderer=new P(this.ctx,this.viewport,this.annotationManager,this.textManager),this.eventHandler=new E(this.canvas,this.viewport,this.annotationManager,this.textManager,this.renderer,()=>this.drawType,()=>this.bgImage,()=>this.render(),t=>this.setDrawType(t),()=>this.emitter.emit("undo",void 0)),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.annotationManager.adjustTitlePositions(),this.render()}}render(){this.renderer.render(this.bgImage)}clear(t=""){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.setDrawType(t),this.render(),this.emitter.emit("clear",void 0)}withdraw(){const t=this.annotationManager.withdraw(),e=this.textManager.withdraw();(t||e)&&(this.render(),this.emitter.emit("undo",void 0))}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(),this.emitter.emit("clear",void 0),!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()}getAnnotation(t){return this.annotationManager.getAnnotation(t)}getTextAnnotation(t){return this.textManager.getTextAnnotation(t)}on(t,e){this.emitter.on(t,e)}off(t,e){this.emitter.off(t,e)}setAnnotationTitle(t,e){const n=this.annotationManager.setTitle(t,e);return n&&this.render(),n}getAnnotationTitle(t){return this.annotationManager.getTitle(t)}setTitleStyle(t){this.annotationManager.setTitleStyle(t),this.render()}getTitleStyle(){return this.annotationManager.getTitleStyle()}setTitlePosition(t){this.annotationManager.setTitlePosition(t),this.render()}getTitlePosition(){return this.annotationManager.getTitlePosition()}setAnnotationTitleStyle(t,e){const n=this.annotationManager.setAnnotationTitleStyle(t,e);return n&&this.render(),n}setAnnotationTitlePosition(t,e){const n=this.annotationManager.setAnnotationTitlePosition(t,e);return n&&this.render(),n}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.crossOrigin="anonymous",s.src=this.bgImageSrc,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,e){this.annotationManager.selectAnnotation(t,e)&&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){if(this.annotationManager.moveSelectedAnnotation(t,e)){const t=this.annotationManager.selectedAnnotation;t&&this.annotationManager.notifyUpdate(t.index),this.render()}}setAnnotationColor(t){this.annotationManager.setColorConfig(t),this.render()}getAnnotationColor(){return this.annotationManager.getColorConfig()}updateSelectedAnnotationStyle(t){if(void 0!==t){const e=this.annotationManager.updateAnnotationStyle(t);return e&&this.render(),e}const e=this.annotationManager.selectedAnnotation;if(!e)return!1;const n=this.annotationManager.recordList[e.index];return!!n&&(n.style=this.annotationManager.getCurrentStyle(),this.annotationManager.notifyUpdate(e.index),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()}updateTextAnnotationStyle(t,e){const n=this.textManager.updateTextAnnotationStyle(t,e);return n&&this.render(),n}setTextInputStyle(t){this.textManager.setInputStyle(t)}setTextSelectionStyle(t){this.textManager.setSelectionStyle(t),this.render()}destroy(){this.emitter.clear(),document.removeEventListener("keydown",this.events.keydown),this.textManager.destroy(),this.annotationManager.destroyTitleInput(),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}export{I as AnnotationManager,O as Drawer,D as Emitter,E as EventHandler,P as Renderer,S as TextAnnotationManager,l as ViewportManager,s as base64ToBlob,i as base64ToFile,O as default,n as getImageTypeFromUrl,o 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),o=Math.abs(e.height);return t.x>=n&&t.x<=n+s&&t.y>=i&&t.y<=i+o}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 o=e[i].point.x,a=e[i].point.y,r=e[s].point.x,l=e[s].point.y;a>t.y!=l>t.y&&t.x<(r-o)*(t.y-a)/(l-a)+o&&(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]),o=s.length,a=new Uint8Array(o);for(let t=0;t<o;++t)a[t]=s.charCodeAt(t);const r=new Blob([a],{type:i});return new File([r],e,{type:i})}function o(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],o=atob(i[1]),a=new ArrayBuffer(o.length),r=new Uint8Array(a);for(let t=0;t<o.length;t++)r[t]=o.charCodeAt(t);e(new Blob([a],{type:s}))})}function a(t,e){return t<2?e?.1:-.1:t<5?e?.05:-.05:e?.02:-.02}function r(t){return"function"==typeof structuredClone?structuredClone(t):JSON.parse(JSON.stringify(t))}function l(){return"undefined"!=typeof crypto&&"function"==typeof crypto.randomUUID?crypto.randomUUID():`id-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}class h{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,o=(n-this.offset.y)/i;this.scale=Math.max(this.minScale,Math.min(t,this.maxScale));const a=s*this.scale+this.offset.x,r=o*this.scale+this.offset.y;this.offset.x+=e-a,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}}const d={minX:Number.NEGATIVE_INFINITY,minY:Number.NEGATIVE_INFINITY,maxX:Number.POSITIVE_INFINITY,maxY:Number.POSITIVE_INFINITY};function c(t,e,n){return Math.min(Math.max(t,e),n)}function g(t){var e,n,i,s;const{anchor:o,boxWidth:a,boxHeight:r,position:l}=t,h=null!==(e=t.bounds)&&void 0!==e?e:d,g=null!==(n=t.gap)&&void 0!==n?n:4,u=null!==(i=l.offsetX)&&void 0!==i?i:0,x=null!==(s=l.offsetY)&&void 0!==s?s:0,f=l.align||"center";let p;switch(f){case"left":p=o.x+u;break;case"right":p=o.x+o.width-a+u;break;default:p=o.x+o.width/2-a/2+u}const y=c(p,h.minX,Math.max(h.minX,h.maxX-a)),v=u+(y-p),M=l.vertical||"top";let w,m=M;return"inside-top"===M?w=o.y+g+x:"bottom"===M?(w=o.y+o.height+g+x,w+r>h.maxY&&(m="top",w=o.y-r-g+x)):(w=o.y-r-g+x,w<h.minY&&(m="bottom",w=o.y+o.height+g+x)),w=c(w,h.minY,Math.max(h.minY,h.maxY-r)),{x:y,y:w,vertical:m,align:f,offsetX:v}}function u(t){const{x:e,y:n}=g(t);return{x:e,y:n}}function x(t,e){if("polygon"===t.type){const n=t.data;if(0===n.length)return null;let i=1/0,s=1/0,o=-1/0,a=-1/0;return n.forEach(t=>{const n=e?e.offset.x+t.point.x*e.scale:t.point.x,r=e?e.offset.y+t.point.y*e.scale:t.point.y;n<i&&(i=n),r<s&&(s=r),n>o&&(o=n),r>a&&(a=r)}),{x:i,y:s,width:o-i,height:a-s}}const n=t.data[0];return e?{x:e.offset.x+n.start.x*e.scale,y:e.offset.y+n.start.y*e.scale,width:n.width*e.scale,height:n.height*e.scale}:{x:n.start.x,y:n.start.y,width:n.width,height:n.height}}function f(t,e){return Math.round(t*e)}function p(t,e){return Math.max(1,f(t,e))}function y(t,e=12){const n=t.match(/(\d+(?:\.\d+)?)px/);return n?parseFloat(n[1]):e}function v(t,e){return t.replace(/(\d+(?:\.\d+)?)px/,(t,n)=>`${p(parseFloat(n),e)}px`)}function M(t,e,n){if(!n)return e;const{originalWidth:i,originalHeight:s}=t;return i&&s?{x:Math.max(0,Math.min(e.x,i)),y:Math.max(0,Math.min(e.y,s))}:e}function w(t,e,n,i,s){t&&s.id&&t(n,{id:s.id,type:e,index:i,data:r(s)})}const m=new class{constructor(){this.type="rect"}startDrawing(t,e){t.isDrawing=!0,t.drawStartPoint=e,t.operate={type:"rect",data:[{start:Object.assign({},e),width:0,height:0}],status:"pending"}}updateDrawing(t,e){if(!t.isDrawing||"rect"!==t.operate.type)return;const n=t.operate.data[0];n.width=e.x-t.drawStartPoint.x,n.height=e.y-t.drawStartPoint.y}addPoint(t,e){return!1}finishDrawing(t){if(!t.isDrawing||"rect"!==t.operate.type)return!1;const e=t.operate.data[0];return Math.abs(e.width)>5&&Math.abs(e.height)>5&&t.pushRecord(Object.assign({},t.operate)),t.operate.data=[],t.isDrawing=!1,!0}cancelDrawing(t){t.operate.data=[],t.isDrawing=!1,t.tempPolygonPoint=null}withdrawInProgress(t){return 0!==t.operate.data.length&&(t.operate.data=[],t.isDrawing=!1,!0)}hitTest(t,n){return e(n,t.data[0])}getHandles(t,e,n){const i=t.data[0],s=e.offset.x+i.start.x*e.scale,o=e.offset.y+i.start.y*e.scale,a=i.width*e.scale,r=i.height*e.scale;return[{x:s,y:o,index:0},{x:s+a,y:o,index:1},{x:s,y:o+r,index:2},{x:s+a,y:o+r,index:3}]}move(t,e,n){const i=t.data[0];i.start.x+=e,i.start.y+=n}snapshotForResize(t){const e=t.data[0];return{start:Object.assign({},e.start),width:e.width,height:e.height}}resize(t,e,n,i){const s=t.data[0],o=i,a=o.start.x,r=o.start.x+o.width,l=o.start.y,h=o.start.y+o.height;let d,c;switch(e){case 0:d=r,c=h;break;case 1:d=a,c=h;break;case 2:d=r,c=l;break;case 3:d=a,c=l;break;default:return}const g=Math.min(n.x,d),u=Math.max(n.x,d),x=Math.min(n.y,c),f=Math.max(n.y,c);s.start.x=g,s.start.y=x,s.width=u-g,s.height=f-x;const p=n.x<d,y=n.y<c;let v;return 0===e?p||y?!p&&y?v=1:p&&!y&&(v=2):v=3:1===e?p&&!y?v=2:p&&y?v=0:p||y||(v=3):2===e?!p&&y?v=1:p&&y?v=0:p||y||(v=3):3===e&&(p&&y?v=0:!p&&y?v=1:p&&!y&&(v=2)),o.start.x=s.start.x,o.start.y=s.start.y,o.width=s.width,o.height=s.height,v}getBounds(t){const e=t.data[0];return{x:e.start.x,y:e.start.y,width:e.width,height:e.height}}};const A=new class{constructor(){this.type="polygon"}startDrawing(t,e){t.isDrawing=!0,t.operate={type:"polygon",data:[{point:e}],status:"pending"},t.tempPolygonPoint=e}updateDrawing(t,e){t.tempPolygonPoint=e}addPoint(t,e){if(!t.isDrawing||"polygon"!==t.operate.type)return!1;const n=t.operate.data.length>0?t.operate.data[t.operate.data.length-1]:null;return!(n&&Math.abs(n.point.x-e.x)<=5&&Math.abs(n.point.y-e.y)<=5)&&(t.operate.data.push({point:e}),!0)}finishDrawing(t){return!(!t.isDrawing||"polygon"!==t.operate.type)&&(t.operate.data.length>=3&&(t.operate.status="fullfilled",t.pushRecord(Object.assign({},t.operate))),t.operate={type:"polygon",data:[],status:"pending"},t.isDrawing=!1,t.tempPolygonPoint=null,!0)}cancelDrawing(t){t.isDrawing&&"polygon"===t.operate.type&&t.operate.data.length>=2&&(t.operate.status="fullfilled",t.pushRecord(Object.assign({},t.operate))),t.operate.data=[],t.isDrawing=!1,t.tempPolygonPoint=null}withdrawInProgress(t){return 0!==t.operate.data.length&&(t.operate.data.pop(),0===t.operate.data.length&&(t.isDrawing=!1),!0)}hitTest(t,e){return n(e,t.data)}getHandles(t,e,n){const i=t.data,s=[];for(let t=0;t<i.length;t++){const n=i[t];s.push({x:e.offset.x+n.point.x*e.scale,y:e.offset.y+n.point.y*e.scale,index:t})}return s}move(t,e,n){t.data.forEach(t=>{t.point.x+=e,t.point.y+=n})}snapshotForResize(t){return t.data.map(t=>({point:Object.assign({},t.point)}))}resize(t,e,n,i){const s=t.data;e>=0&&e<s.length&&(s[e].point.x=n.x,s[e].point.y=n.y)}getBounds(t){const e=t.data;if(0===e.length)return{x:0,y:0,width:0,height:0};let n=1/0,i=1/0,s=-1/0,o=-1/0;return e.forEach(t=>{t.point.x<n&&(n=t.point.x),t.point.y<i&&(i=t.point.y),t.point.x>s&&(s=t.point.x),t.point.y>o&&(o=t.point.y)}),{x:n,y:i,width:s-n,height:o-i}}};const T=new class{constructor(){this.strategies=new Map}register(t){this.strategies.set(t.type,t)}get(t){const e=this.strategies.get(t);if(!e)throw new Error(`No strategy registered for shape type: ${t}`);return e}selectShapeExclusive(t,e,n){return"shape"===n.kind?(e.deselectTextAnnotation(),t.selectAnnotation(n.ref,{lock:n.locked})):(t.deselectAnnotation(),e.selectTextAnnotation(n.index))}deselectAll(t,e){t.deselectAnnotation(),e.deselectTextAnnotation()}withdrawAll(t,e){return t.withdraw()||e.withdraw()}};T.register(m),T.register(A);class I{constructor(t,e,n,i){this.viewport=t,this.container=e,this.renderCallback=n,this.changeCallback=i,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.editingTitleIndex=null,this.titleInput=null,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.titleStyle={font:"12px Arial",color:"#FFFFFF",backgroundColor:"rgba(0, 0, 0, 0.7)",paddingX:6,paddingY:3,borderRadius:4,placeholder:"输入标题..."},this.titlePosition={vertical:"top",align:"center",offsetX:0,offsetY:0},this.enableTitle=!1,this.clampEnabled=!0,this.applyColorConfig()}strategyOf(t){return T.get(t)}clamp(t){return M(this.viewport,t,this.clampEnabled)}clampToImageBounds(t){return M(this.viewport,t,this.clampEnabled)}clampRecordToImageBounds(t){if(!this.clampEnabled)return;const{originalWidth:e,originalHeight:n}=this.viewport;if(!e||!n)return;if("rect"===t.type){const i=t.data[0];if(!i)return;const s=Math.min(i.start.x,i.start.x+i.width),o=Math.max(i.start.x,i.start.x+i.width),a=Math.min(i.start.y,i.start.y+i.height),r=Math.max(i.start.y,i.start.y+i.height);if(s>=0&&a>=0&&o<=e&&r<=n)return;const l=Math.min(o-s,e),h=Math.min(r-a,n);return i.start.x=Math.max(0,Math.min(s,e-l)),i.start.y=Math.max(0,Math.min(a,n-h)),i.width=l,void(i.height=h)}const i=t.data;if(!i||0===i.length)return;let s=1/0,o=1/0,a=-1/0,r=-1/0;for(const t of i)s=Math.min(s,t.point.x),a=Math.max(a,t.point.x),o=Math.min(o,t.point.y),r=Math.max(r,t.point.y);let l=0,h=0;if(a-s>e||s<0?l=-s:a>e&&(l=e-a),r-o>n||o<0?h=-o:r>n&&(h=n-r),0!==l||0!==h)for(const t of i)t.point.x+=l,t.point.y+=h}pushRecord(t){const e=Object.assign(Object.assign({},t),{id:l(),style:this.getCurrentStyle()});this.recordList.push(e),this.deleteHistory=[],this.notifyChange("create",this.recordList.length-1,e)}initTitleSupport(){this.container&&this.enableTitle&&this.createTitleInput()}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)}}notifyChange(t,e,n){w(this.changeCallback,n.type,t,e,n)}notifyUpdate(t){const e=this.recordList[t];e&&this.notifyChange("update",t,e)}resolveIndex(t){return"number"==typeof t?t:this.recordList.findIndex(e=>e.id===t)}getAnnotation(t){const e=this.resolveIndex(t);if(!(e<0||e>=this.recordList.length))return r(this.recordList[e])}updateAnnotationStyle(t){const e=this.resolveIndex(t);return!(e<0||e>=this.recordList.length)&&(this.recordList[e].style=this.getCurrentStyle(),this.notifyUpdate(e),!0)}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()}withdraw(){if(this.operate.data.length>0){const t="polygon"===this.operate.type?"polygon":"rect";return this.strategyOf(t).withdrawInProgress(this),!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,e){var n;const i=this.resolveIndex(t);if(i<0||i>=this.recordList.length)return this.deselectAnnotation(),!1;const s=this.recordList[i],o=void 0!==(null==e?void 0:e.lock)?!!e.lock:(null===(n=this.selectedAnnotation)||void 0===n?void 0:n.index)===i&&!0===this.selectedAnnotation.locked;return this.selectedAnnotation={index:i,type:s.type,locked:o},!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(),this.notifyChange("delete",t,e),!0}startMovingAnnotation(t){return!(!this.selectedAnnotation||!0===this.selectedAnnotation.locked)&&(this.isMovingAnnotation=!0,this.annotationMoveStart={x:t.clientX,y:t.clientY},!0)}updateMoveStart(t){this.annotationMoveStart=t}finishMovingAnnotation(){var t;const e=this.isMovingAnnotation||this.isResizing;if(this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null,e&&this.selectedAnnotation){const e=this.recordList[this.selectedAnnotation.index];(null==e?void 0:e.title)&&this.autoAdjustTitlePosition(e,e.title),this.notifyUpdate(this.selectedAnnotation.index),null===(t=this.renderCallback)||void 0===t||t.call(this)}}clear(){this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,this.deselectAnnotation(),this.deleteHistory=[]}getAnnotations(){return this.recordList.map(t=>r(t))}getSelectedAnnotation(){if(!this.selectedAnnotation)return null;const t=this.recordList[this.selectedAnnotation.index];return t?{index:this.selectedAnnotation.index,type:this.selectedAnnotation.type,data:r(t)}:null}setTitleStyle(t){this.titleStyle=Object.assign(Object.assign({},this.titleStyle),t)}getTitleStyle(){return Object.assign({},this.titleStyle)}setTitlePosition(t){this.titlePosition=Object.assign(Object.assign({},this.titlePosition),t)}getTitlePosition(){return Object.assign({},this.titlePosition)}getEffectiveTitleStyle(t){const e=this.getAnnotationStyle(t);return Object.assign(Object.assign({},this.titleStyle),e.titleStyle||{})}getEffectiveTitlePosition(t){const e=this.getAnnotationStyle(t);return Object.assign(Object.assign({},this.titlePosition),e.titlePosition||{})}captureTitleStyleSnapshot(t){t.style||(t.style=this.getCurrentStyle()),t.style.titleStyle=Object.assign({},this.titleStyle),t.style.titlePositionExplicit||(t.style.titlePosition=Object.assign({},this.titlePosition))}autoAdjustTitlePosition(t,e){var n,i,s;if(!e||(null===(n=t.style)||void 0===n?void 0:n.titlePositionExplicit))return;const{originalWidth:o,originalHeight:a,initialScale:r,scale:l}=this.viewport;if(o<=0||a<=0)return;const h=x(t);if(!h)return;const d=r>0?r:l>0?l:1,c={x:h.x*d,y:h.y*d,width:h.width*d,height:h.height*d},u=this.getEffectiveTitleStyle(t),f=u.font||"12px Arial",p=y(f)+2*(null!==(i=u.paddingY)&&void 0!==i?i:3),v=this.measureTitleWidth,M=v?{minX:0,minY:0,maxX:o*d,maxY:a*d}:{minX:Number.NEGATIVE_INFINITY,minY:0,maxX:Number.POSITIVE_INFINITY,maxY:a*d},w=v?v(e,f)+2*(null!==(s=u.paddingX)&&void 0!==s?s:6):0,m=Object.assign({},this.titlePosition),A=g({anchor:c,boxWidth:w,boxHeight:p,position:m,bounds:M});t.style||(t.style=this.getCurrentStyle()),t.style.titlePosition=Object.assign(Object.assign({},m),{vertical:A.vertical,align:A.align,offsetX:A.offsetX})}adjustTitlePositions(){this.viewport.originalWidth<=0||this.viewport.originalHeight<=0||this.recordList.forEach(t=>{var e;t.title&&!(null===(e=t.style)||void 0===e?void 0:e.titlePositionExplicit)&&this.autoAdjustTitlePosition(t,t.title)})}setAnnotationTitleStyle(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.recordList.length)return!1;const i=this.recordList[n];return i.style||(i.style=this.getCurrentStyle()),i.style.titleStyle=Object.assign(Object.assign({},i.style.titleStyle||this.titleStyle),e),this.notifyUpdate(n),!0}setAnnotationTitlePosition(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.recordList.length)return!1;const i=this.recordList[n];return i.style||(i.style=this.getCurrentStyle()),i.style.titlePosition=Object.assign(Object.assign({},i.style.titlePosition||this.titlePosition),e),i.style.titlePositionExplicit=!0,this.notifyUpdate(n),!0}createTitleInput(){this.container&&(this.titleInput=document.createElement("input"),this.titleInput.type="text",this.titleInput.style.position="absolute",this.titleInput.style.zIndex="99998",this.titleInput.style.display="none",this.titleInput.style.outline="none",this.titleInput.style.border="1px solid #00D9FF",this.titleInput.style.borderRadius="4px",this.titleInput.style.padding="4px 8px",this.titleInput.style.fontSize="13px",this.titleInput.style.fontFamily="Arial, sans-serif",this.titleInput.style.backgroundColor="#ffffff",this.titleInput.style.color="#333",this.titleInput.style.boxShadow="0 2px 8px rgba(0,0,0,0.3)",this.titleInput.style.minWidth="80px",this.titleInput.style.maxWidth="200px",this.titleInput.placeholder=this.titleStyle.placeholder||"输入标题...",this.titleInput.addEventListener("blur",()=>{this.finishTitleEditing()}),this.titleInput.addEventListener("keydown",t=>{t.stopPropagation(),"Enter"===t.key?this.finishTitleEditing():"Escape"===t.key&&(t.preventDefault(),this.cancelTitleEditing())}),this.container.appendChild(this.titleInput))}setTitle(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.recordList.length)return!1;const i=this.recordList[n];return i.title=e||void 0,e&&(this.captureTitleStyleSnapshot(i),this.autoAdjustTitlePosition(i,e)),this.notifyUpdate(n),!0}getTitle(t){const e=this.resolveIndex(t);if(!(e<0||e>=this.recordList.length))return this.recordList[e].title}startTitleEditing(t){if(!this.enableTitle||!this.titleInput||t<0||t>=this.recordList.length)return!1;const e=this.recordList[t];let n,i;if(this.editingTitleIndex=t,this.deselectAnnotation(),"rect"===e.type){const t=e.data[0];n=this.viewport.offset.x+t.start.x*this.viewport.scale,i=this.viewport.offset.y+t.start.y*this.viewport.scale}else{const t=e.data[0];n=this.viewport.offset.x+t.point.x*this.viewport.scale,i=this.viewport.offset.y+t.point.y*this.viewport.scale}return this.titleInput.value=e.title||"",this.titleInput.placeholder=this.getEffectiveTitleStyle(e).placeholder||"输入标题...",this.titleInput.style.left=`${n}px`,this.titleInput.style.top=i-32+"px",this.titleInput.style.display="block",setTimeout(()=>{this.titleInput&&(this.titleInput.focus(),this.titleInput.select())},10),!0}finishTitleEditing(){if(!this.titleInput||null===this.editingTitleIndex)return!1;const t=this.editingTitleIndex,e=this.titleInput.value.trim();if(t>=0&&t<this.recordList.length){const n=this.recordList[t];n.title=e||void 0,e&&(this.captureTitleStyleSnapshot(n),this.autoAdjustTitlePosition(n,e)),this.notifyUpdate(t),this.selectAnnotation(t)}return this.resetTitleEditingState(),this.renderCallback&&this.renderCallback(),!0}cancelTitleEditing(){if(!this.titleInput||null===this.editingTitleIndex)return!1;const t=this.editingTitleIndex;return t>=0&&t<this.recordList.length&&this.selectAnnotation(t),this.resetTitleEditingState(),this.renderCallback&&this.renderCallback(),!0}resetTitleEditingState(){this.titleInput&&(this.titleInput.style.display="none"),this.editingTitleIndex=null}destroyTitleInput(){this.titleInput&&this.titleInput.parentNode&&(this.titleInput.parentNode.removeChild(this.titleInput),this.titleInput=null)}}class S extends I{startRectDrawing(t){t=this.clampToImageBounds(t),this.strategyOf("rect").startDrawing(this,t)}updateRectDrawing(t){this.isDrawing&&"rect"===this.operate.type&&(t=this.clampToImageBounds(t),this.strategyOf("rect").updateDrawing(this,t))}finishRectDrawing(){return this.strategyOf("rect").finishDrawing(this)}startPolygonDrawing(t){t=this.clampToImageBounds(t),this.strategyOf("polygon").startDrawing(this,t)}addPolygonPoint(t){return!(!this.isDrawing||"polygon"!==this.operate.type)&&(t=this.clampToImageBounds(t),this.strategyOf("polygon").addPoint(this,t))}updatePolygonTempPoint(t){this.strategyOf("polygon").updateDrawing(this,this.clampToImageBounds(t))}finishPolygonDrawing(){return this.strategyOf("polygon").finishDrawing(this)}cancelDrawing(){const t="polygon"===this.operate.type?"polygon":"rect";this.strategyOf(t).cancelDrawing(this)}moveSelectedAnnotation(t,e){if(!this.selectedAnnotation)return!1;const n=this.recordList[this.selectedAnnotation.index];return!!n&&(this.strategyOf(n.type).move(n,t,e),this.clampRecordToImageBounds(n),!0)}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=this.strategyOf("rect").snapshotForResize(n):"polygon"===n.type&&(this.originalPolygon=this.strategyOf("polygon").snapshotForResize(n)),!0}resizeRect(t){if(!this.selectedAnnotation||"rect"!==this.selectedAnnotation.type||!this.originalRect||!this.activeHandle)return!1;if(this.activeHandle.index<0||this.activeHandle.index>3)return!1;const e=this.recordList[this.selectedAnnotation.index],n=this.clampToImageBounds(t),i=this.strategyOf("rect").resize(e,this.activeHandle.index,n,this.originalRect);return"number"==typeof i&&(this.activeHandle.index=i),!0}resizePolygon(t){var e;if(!this.selectedAnnotation||"polygon"!==this.selectedAnnotation.type||!this.activeHandle)return!1;const n=this.recordList[this.selectedAnnotation.index],i=this.activeHandle.index,s=n.data;return!(i<0||i>=s.length)&&(this.strategyOf("polygon").resize(n,i,this.clampToImageBounds(t),null!==(e=this.originalPolygon)&&void 0!==e?e:[]),!0)}getAnnotationAtPoint(t){for(let e=this.recordList.length-1;e>=0;e--){const n=this.recordList[e],i=n.type;if(this.strategyOf(i).hitTest(n,t))return{index:e,type:i}}return null}getHandleAtPoint(t,e){if(!this.selectedAnnotation)return null;if(!0===this.selectedAnnotation.locked)return null;const n=this.recordList[this.selectedAnnotation.index],i=this.selectionStyle.handleSize,s=i/2,o=this.selectedAnnotation.type,a=this.strategyOf(o).getHandles(n,this.viewport,i);for(const n of a)if(t>=n.x-s&&t<=n.x+s&&e>=n.y-s&&e<=n.y+s)return"rect"===o?{type:"rect-corner",index:n.index}:{type:"polygon-vertex",index:n.index};return null}}class b{constructor(t,e,n,i,s){this.viewport=t,this.container=e,this.ctx=n,this.renderCallback=i,this.changeCallback=s,this.textAnnotations=[],this.editingTextIndex=null,this.currentEditingIndex=null,this.movingTextIndex=null,this.isTextMoving=!1,this.textMoveStart={x:0,y:0},this.textBeforeEditing="",this.selectedTextIndex=null,this.clampEnabled=!0,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}}notifyChange(t,e,n){w(this.changeCallback,"text",t,e,n)}resolveIndex(t){return"number"==typeof t?t:this.textAnnotations.findIndex(e=>e.id===t)}getTextAnnotation(t){const e=this.resolveIndex(t);if(!(e<0||e>=this.textAnnotations.length))return r(this.textAnnotations[e])}updateTextAnnotationStyle(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.textAnnotations.length)return!1;const i=this.textAnnotations[n];return i.style=Object.assign(Object.assign({},i.style||this.getCurrentStyle()),e),this.notifyChange("update",n,this.textAnnotations[n]),!0}clampToImageBounds(t){return M(this.viewport,t,this.clampEnabled)}addTextAnnotation(t,e,n=""){var i;const s=this.clampToImageBounds({x:t,y:e});t=s.x,e=s.y,this.ctx.font=this.textStyle.font;const o=n||"输入文字...",a=this.ctx.measureText(o);let r;if(a.actualBoundingBoxAscent&&a.actualBoundingBoxDescent)r=a.actualBoundingBoxAscent+a.actualBoundingBoxDescent;else{r=1.2*parseInt((null===(i=this.textStyle.font.match(/\d+/))||void 0===i?void 0:i[0])||"16")}const h={id:l(),position:{x:t,y:e},text:n,style:this.getCurrentStyle(),width:Math.max(a.width,60),height:r};this.textAnnotations.push(h);const d=this.textAnnotations.length-1;return this.notifyChange("create",d,h),this.deleteHistory=[],this.startEditing(d),d}updateTextAnnotation(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.textAnnotations.length)return!1;const i=this.textAnnotations[n];i.text=e,this.ctx.font=this.textStyle.font;const s=this.ctx.measureText(e);return i.width=s.width,i.height=1.2*parseInt(this.textStyle.font),this.notifyChange("update",n,this.textAnnotations[n]),!0}moveTextAnnotation(t,e,n){const i=this.resolveIndex(t);return!(i<0||i>=this.textAnnotations.length)&&(this.textAnnotations[i].position={x:e,y:n},this.notifyChange("update",i,this.textAnnotations[i]),!0)}removeTextAnnotation(t){const e=this.resolveIndex(t);if(e<0||e>=this.textAnnotations.length)return!1;const n=this.textAnnotations[e];return this.deleteHistory.push({annotation:Object.assign({},n),index:e}),this.textAnnotations.splice(e,1),this.notifyChange("delete",e,n),this.editingTextIndex===e?this.resetEditingState():null!==this.editingTextIndex&&this.editingTextIndex>e&&this.editingTextIndex--,this.movingTextIndex===e?this.endTextMoving():null!==this.movingTextIndex&&this.movingTextIndex>e&&this.movingTextIndex--,!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}px`,this.textInput.style.top=`${i}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){const e=this.textAnnotations[t];this.textAnnotations.splice(t,1),this.notifyChange("delete",t,e)}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),this.notifyChange("update",t,n)}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){if(""===this.textAnnotations[t].text&&""===this.textBeforeEditing){const e=this.textAnnotations[t];this.textAnnotations.splice(t,1),this.notifyChange("delete",t,e)}}return this.resetEditingState(),!0}deleteEditingAnnotation(){if(null===this.editingTextIndex)return!1;const t=this.editingTextIndex;if(this.textInput&&(this.textInput.style.display="none"),t>=0&&t<this.textAnnotations.length){const e=this.textAnnotations[t];this.textAnnotations.splice(t,1),this.notifyChange("delete",t,e)}return 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.movingTextIndex=e,this.isTextMoving=!0,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}moveAnnotation(t){if(!this.isTextMoving||null===this.movingTextIndex)return!1;const e=t.clientX-this.textMoveStart.x,n=t.clientY-this.textMoveStart.y,i=this.textAnnotations[this.movingTextIndex];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(){if(this.isTextMoving=!1,null!==this.movingTextIndex){const t=this.textAnnotations[this.movingTextIndex];t&&this.notifyChange("update",this.movingTextIndex,t)}this.movingTextIndex=null}endTextMoving(){this.isTextMoving=!1,this.movingTextIndex=null}isEditingVisible(){var t;return"block"===(null===(t=this.textInput)||void 0===t?void 0:t.style.display)}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,o=this.viewport.offset.y+i.position.y*this.viewport.scale,a=Math.max(i.width,60)+2*this.textStyle.padding,r=i.height+2*this.textStyle.padding;if(t>=s&&t<=s+a&&e>=o&&e<=o+r)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.map(t=>r(t))}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,this.notifyChange("delete",t,e),null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,null!==this.movingTextIndex&&this.movingTextIndex>t&&this.movingTextIndex--,!0}getSelectedTextAnnotation(){if(null===this.selectedTextIndex)return null;const t=this.textAnnotations[this.selectedTextIndex];return t?{index:this.selectedTextIndex,data:r(t)}:null}destroy(){this.textInput&&this.textInput.parentNode&&this.textInput.parentNode.removeChild(this.textInput)}}function C(t,e){switch(e){case"dashed":t.setLineDash([10,5]);break;case"dotted":t.setLineDash([2,4]);break;default:t.setLineDash([])}}class k{draw(t,e,n,i){const s=n.data[0];t.strokeRect(e.offset.x+s.start.x*e.scale,e.offset.y+s.start.y*e.scale,s.width*e.scale,s.height*e.scale)}drawInProgress(t,e,n){const i=n.operate.data[0];t.strokeRect(e.offset.x+i.start.x*e.scale,e.offset.y+i.start.y*e.scale,i.width*e.scale,i.height*e.scale)}drawSelection(t,e,n,i,s){const o=n.data[0],a=e.offset.x+o.start.x*e.scale,r=e.offset.y+o.start.y*e.scale,l=o.width*e.scale,h=o.height*e.scale;if(t.fillStyle=i.fillColor,t.fillRect(a,r,l,h),t.strokeStyle=i.strokeColor,t.lineWidth=2,t.setLineDash([5,5]),t.strokeRect(a,r,l,h),s)return;const d=i.handleSize;t.fillStyle=i.handleColor,t.setLineDash([]),t.fillRect(a-d/2,r-d/2,d,d),t.fillRect(a+l-d/2,r-d/2,d,d),t.fillRect(a-d/2,r+h-d/2,d,d),t.fillRect(a+l-d/2,r+h-d/2,d,d)}drawForExport(t,e,n,i=1){const s=e.data[0];t.strokeRect(s.start.x,s.start.y,s.width,s.height)}getTitleAnchor(t,e){return x(t,e)}}class P{constructor(t){this.store=t}draw(t,e,n,i){const s=i.vertexStyle||this.store.getVertexStyle();this.drawPolygon(t,e,n.data,"fullfilled"===n.status,s)}drawInProgress(t,e,n){const i=n.operate.data,s=n.tempPolygonPoint;if(t.beginPath(),i.forEach((n,i)=>{const s=Math.round(e.offset.x+n.point.x*e.scale),o=Math.round(e.offset.y+n.point.y*e.scale);0===i?t.moveTo(s,o):t.lineTo(s,o)}),s){const n=Math.round(e.offset.x+s.x*e.scale),i=Math.round(e.offset.y+s.y*e.scale);t.lineTo(n,i)}if(t.stroke(),this.drawPolygonVertices(t,e,i,n.getVertexStyle()),s){const i=n.getVertexStyle(),o=Math.round(e.offset.x+s.x*e.scale),a=Math.round(e.offset.y+s.y*e.scale),r=i.size/2;switch(t.fillStyle=i.fillColor,t.strokeStyle=i.strokeColor,t.lineWidth=i.strokeWidth,t.beginPath(),i.shape){case"square":t.rect(o-r,a-r,2*r,2*r);break;case"diamond":t.moveTo(o,a-r),t.lineTo(o+r,a),t.lineTo(o,a+r),t.lineTo(o-r,a),t.closePath();break;default:t.arc(o,a,r,0,2*Math.PI)}t.fill(),i.strokeWidth>0&&t.stroke()}}drawSelection(t,e,n,i,s){const o=n.data;if(t.beginPath(),o.forEach((n,i)=>{const s=e.offset.x+n.point.x*e.scale,o=e.offset.y+n.point.y*e.scale;0===i?t.moveTo(s,o):t.lineTo(s,o)}),t.closePath(),t.fillStyle=i.fillColor,t.fill(),t.strokeStyle=i.strokeColor,t.lineWidth=2,t.setLineDash([5,5]),t.stroke(),s)return;const a=i.handleSize;t.fillStyle=i.handleColor,t.setLineDash([]),o.forEach(n=>{const i=Math.round(e.offset.x+n.point.x*e.scale),s=Math.round(e.offset.y+n.point.y*e.scale);t.fillRect(i-a/2,s-a/2,a,a)})}drawForExport(t,e,n,i=1){if("fullfilled"!==e.status)return;const s=e.data;t.beginPath(),s.forEach((e,n)=>{0===n?t.moveTo(e.point.x,e.point.y):t.lineTo(e.point.x,e.point.y)});const o=e.data[0];t.lineTo(o.point.x,o.point.y),t.stroke();const a=p(4,i);s.forEach(e=>{t.beginPath(),t.arc(e.point.x,e.point.y,a,0,2*Math.PI),t.fillStyle=n.strokeColor,t.fill()})}getTitleAnchor(t,e){return x(t,e)}drawPolygon(t,e,n,i,s){if(0!==n.length){if(t.beginPath(),n.forEach((n,i)=>{const s=Math.round(e.offset.x+n.point.x*e.scale),o=Math.round(e.offset.y+n.point.y*e.scale);0===i?t.moveTo(s,o):t.lineTo(s,o)}),i&&n.length>1){const i=n[0];t.lineTo(e.offset.x+i.point.x*e.scale,e.offset.y+i.point.y*e.scale)}t.stroke(),this.drawPolygonVertices(t,e,n,s)}}drawPolygonVertices(t,e,n,i){const s=i||this.store.getVertexStyle(),o=s.size/2;n.forEach(n=>{const i=Math.round(e.offset.x+n.point.x*e.scale),a=Math.round(e.offset.y+n.point.y*e.scale);switch(t.fillStyle=s.fillColor,t.strokeStyle=s.strokeColor,t.lineWidth=s.strokeWidth,t.beginPath(),s.shape){case"square":t.rect(i-o,a-o,2*o,2*o);break;case"diamond":t.moveTo(i,a-o),t.lineTo(i+o,a),t.lineTo(i,a+o),t.lineTo(i-o,a),t.closePath();break;default:t.arc(i,a,o,0,2*Math.PI)}t.fill(),s.strokeWidth>0&&t.stroke()})}}class E{constructor(t,e,n,i){this.ctx=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.shapeRenderers={rect:new k,polygon:new P(n)}}render(t){this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.drawBackgroundImage(t),this.drawAnnotations(),function(t,e,n){const i=n.textStyle;n.textAnnotations.forEach((s,o)=>{if(n.editingTextIndex===o&&n.isEditingVisible())return;if(!s.text)return;const a=s.style||{font:i.font,color:i.color,backgroundColor:i.backgroundColor},r=e.offset.x+s.position.x*e.scale,l=e.offset.y+s.position.y*e.scale,h=n.selectedTextIndex===o;t.font=a.font;const d=t.measureText(s.text),c=d.actualBoundingBoxAscent||.8*s.height,g=c+(d.actualBoundingBoxDescent||.2*s.height),u=i.borderRadius,x=r,f=l,p=s.width+2*i.padding,y=g+2*i.padding;t.fillStyle=a.backgroundColor,t.beginPath(),t.roundRect(x,f,p,y,u),t.fill(),h&&(t.strokeStyle=i.selectedBorderColor,t.lineWidth=2,t.setLineDash([5,5]),t.beginPath(),t.roundRect(x,f,p,y,u),t.stroke(),t.setLineDash([]));const v=r+i.padding,M=l+i.padding+c;t.fillStyle=a.color,t.fillText(s.text,v,M)})}(this.ctx,this.viewport,this.textManager)}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=>{const e=this.annotationManager.getAnnotationStyle(t);this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=e.lineWidth,C(this.ctx,e.lineStyle||"solid"),this.ctx.fillStyle=this.ctx.strokeStyle,"rect"===t.type?this.shapeRenderers.rect.draw(this.ctx,this.viewport,t,e):"polygon"===t.type&&this.shapeRenderers.polygon.draw(this.ctx,this.viewport,t,e),this.annotationManager.enableTitle&&t.title&&this.drawAnnotationTitle(t)}),this.annotationManager.operate.data.length>0&&(this.ctx.strokeStyle=this.annotationManager.strokeStyle,this.ctx.lineWidth=this.annotationManager.lineWidth,this.ctx.fillStyle=this.ctx.strokeStyle,C(this.ctx,this.annotationManager.lineStyle),"rect"===this.annotationManager.operate.type?this.shapeRenderers.rect.drawInProgress(this.ctx,this.viewport,this.annotationManager):"polygon"===this.annotationManager.operate.type&&this.shapeRenderers.polygon.drawInProgress(this.ctx,this.viewport,this.annotationManager)),this.ctx.setLineDash([]),this.drawSelectionHighlight()}drawSelectionHighlight(){const t=this.annotationManager.selectedAnnotation;if(!t)return;const e=this.annotationManager.recordList[t.index];if(!e)return;const n=this.annotationManager.selectionStyle,i=!0===t.locked;this.ctx.save(),"rect"===e.type?this.shapeRenderers.rect.drawSelection(this.ctx,this.viewport,e,n,i):"polygon"===e.type&&this.shapeRenderers.polygon.drawSelection(this.ctx,this.viewport,e,n,i),this.ctx.restore()}drawAnnotationTitle(t){var e,n,i;if(!t.title)return;const s=this.annotationManager.getEffectiveTitleStyle(t),o=this.annotationManager.getEffectiveTitlePosition(t),a=s.font||"12px Arial",r=s.color||"#FFFFFF",l=s.backgroundColor||"rgba(0, 0, 0, 0.7)",h=null!==(e=s.paddingX)&&void 0!==e?e:6,d=null!==(n=s.paddingY)&&void 0!==n?n:3,c=null!==(i=s.borderRadius)&&void 0!==i?i:4;this.ctx.save(),this.ctx.font=a;const g=this.ctx.measureText(t.title).width,x=y(a),f=("rect"===t.type?this.shapeRenderers.rect:this.shapeRenderers.polygon).getTitleAnchor(t,this.viewport);if(!f)return void this.ctx.restore();const p=g+2*h,v=x+2*d,{x:M,y:w}=u({anchor:f,boxWidth:p,boxHeight:v,position:o});this.ctx.fillStyle=l,this.ctx.setLineDash([]),this.ctx.beginPath(),this.ctx.roundRect(M,w,p,v,c),this.ctx.fill(),this.ctx.fillStyle=r,this.ctx.textAlign="left",this.ctx.textBaseline="top",this.ctx.fillText(t.title,M+h,w+d),this.ctx.restore()}getExportPixelRatio(){const t=this.viewport.scale;return t>0?1/t:1}drawForExport(t,e,n,i){const s=this.getExportPixelRatio();t.drawImage(e,0,0,n,i),this.annotationManager.recordList.forEach(e=>{const n=this.annotationManager.getAnnotationStyle(e);t.strokeStyle=n.strokeColor,t.lineWidth=p(n.lineWidth,s),"rect"===e.type?this.shapeRenderers.rect.drawForExport(t,e,n,s):"polygon"===e.type&&this.shapeRenderers.polygon.drawForExport(t,e,n,s)}),this.textManager.textAnnotations.forEach(e=>{const n=this.textManager.textStyle,i=e.style||{font:n.font,color:n.color,backgroundColor:n.backgroundColor};t.font=v(i.font,s);const o=t.measureText(e.text),a=o.actualBoundingBoxAscent||.8*e.height,r=a+(o.actualBoundingBoxDescent||.2*e.height),l=e.position.x,h=e.position.y,d=f(n.padding,s),c=o.width+2*d,g=r+2*d,u=f(n.borderRadius,s);t.fillStyle=i.backgroundColor,t.roundRect?(t.roundRect(l,h,c,g,u),t.fill()):t.fillRect(l,h,c,g),t.fillStyle=i.color,t.fillText(e.text,l+d,h+d+a)}),this.annotationManager.enableTitle&&this.annotationManager.recordList.forEach(e=>{var n,i,o,a,r;if(!e.title)return;const l=this.annotationManager.getEffectiveTitleStyle(e),h=this.annotationManager.getEffectiveTitlePosition(e),d=l.color||"#FFFFFF",c=l.backgroundColor||"rgba(0, 0, 0, 0.7)",g=v(l.font||"12px Arial",s),x=f(null!==(n=l.paddingX)&&void 0!==n?n:6,s),p=f(null!==(i=l.paddingY)&&void 0!==i?i:3,s),M=f(null!==(o=l.borderRadius)&&void 0!==o?o:4,s);t.font=g;const w=t.measureText(e.title).width,m=y(g),A=("rect"===e.type?this.shapeRenderers.rect:this.shapeRenderers.polygon).getTitleAnchor(e);if(!A)return;const T=w+2*x,I=m+2*p,{x:S,y:b}=u({anchor:A,boxWidth:T,boxHeight:I,position:Object.assign(Object.assign({},h),{offsetX:f(null!==(a=h.offsetX)&&void 0!==a?a:0,s),offsetY:f(null!==(r=h.offsetY)&&void 0!==r?r:0,s)}),gap:f(4,s)});t.fillStyle=c,t.roundRect?(t.roundRect(S,b,T,I,M),t.fill()):t.fillRect(S,b,T,I),t.fillStyle=d,t.textAlign="left",t.textBaseline="top",t.fillText(e.title,S+x,b+p)})}}class D{constructor(t,e,n,i,s,o,a,r,l,h){this.canvas=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.renderer=s,this.getDrawType=o,this.getBgImage=a,this.renderCallback=r,this.setDrawTypeCallback=l,this.notifyUndo=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(),o=t.clientX-s.left,a=t.clientY-s.top,r=(o-this.viewport.offset.x)/n,l=(a-this.viewport.offset.y)/n;this.viewport.scale=i;const h=r*i+this.viewport.offset.x,d=l*i+this.viewport.offset.y;this.viewport.offset.x+=o-h,this.viewport.offset.y+=a-d,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):T.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index: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 o=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,o),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(o);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):T.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index:n}),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(o);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(o);if("rect"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.startRectDrawing(o)}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,o),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(o);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):T.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index:e}),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(o);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(o);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(o)&&this.annotationManager.addPolygonPoint(o):this.annotationManager.startPolygonDrawing(o),this.annotationManager.updatePolygonTempPoint(o),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,o),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):T.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index:e}),void this.renderCallback();if(this.handleRectModeClick(t,o))return;if(this.handlePolygonModeClick(t,o))return;this.isDragging=!0,this.dragStart={x:t.clientX,y:t.clientY},this.canvas.style.cursor="grabbing"}else""===i&&this.handleNoModeClick(t,o)}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)}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):T.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index: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.movingTextIndex)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.updateMoveStart({x:t.clientX,y:t.clientY}),this.renderCallback()}isHoverLockedAnnotation(t){return!(!t||!this.annotationManager.selectedAnnotation)&&(!0===this.annotationManager.selectedAnnotation.locked&&t.index===this.annotationManager.selectedAnnotation.index)}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")}const n=this.annotationManager.getAnnotationAtPoint(e);if(n)return void(this.canvas.style.cursor=this.isHoverLockedAnnotation(n)?"default":"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),i=this.annotationManager.getAnnotationAtPoint(n);i?this.canvas.style.cursor=this.isHoverLockedAnnotation(i)?"default":"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),i=this.annotationManager.getAnnotationAtPoint(n);i?this.canvas.style.cursor=this.isHoverLockedAnnotation(i)?"default":"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?this.isHoverLockedAnnotation(n)?"default":"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?this.isHoverLockedAnnotation(n)?"default":"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.endTextMoving(),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(this.annotationManager.selectedAnnotation){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);if(n&&n.index===this.annotationManager.selectedAnnotation.index)return void this.annotationManager.startTitleEditing(n.index)}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();!this.getBgImage()||"polygon"!==n||this.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving||(this.justDeselected?this.justDeselected=!1:null===(e=this.annotationManager.selectedAnnotation)||void 0===e||e.type)}handleKeyDown(t){const e=t.target;if(!e||"INPUT"!==e.tagName&&"TEXTAREA"!==e.tagName&&"SELECT"!==e.tagName&&!e.isContentEditable){if("z"===t.key&&(t.ctrlKey||t.metaKey)){return T.withdrawAll(this.annotationManager,this.textManager)&&this.notifyUndo(),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 O{constructor(){this.listeners=new Map}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){var n;null===(n=this.listeners.get(t))||void 0===n||n.delete(e)}emit(t,e){var n;null===(n=this.listeners.get(t))||void 0===n||n.forEach(t=>t(e))}clear(){this.listeners.clear()}}class R{constructor(t){this.canvas=document.createElement("canvas"),this.emitter=new O,this.bgImage=null,this.bgImageSrc="",this.bgImageExt="jpeg",this.drawType="";const{drawType:e,useEvents:n=!0,id:i="container",annotationColor:s,lineStyle:o,vertexStyle:a,textStyle:r,enableTitle:l=!1,clampToImageBounds:d=!0}=t,c=document.getElementById(i);if(!c)throw new Error(`Container with id "${i}" not found`);this.container=c,"absolute"!==c.style.position&&"fixed"!==c.style.position&&"relative"!==c.style.position&&(c.style.position="relative"),this.ctx=this.canvas.getContext("2d"),this.viewport=new h,this.viewport.setSize(c.clientWidth,c.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",c.appendChild(this.canvas),this.annotationManager=new S(this.viewport,this.container,()=>this.render(),(t,e)=>this.emitter.emit(t,e)),this.annotationManager.measureTitleWidth=(t,e)=>(this.ctx.font=e,this.ctx.measureText(t).width),s&&this.annotationManager.setColorConfig(s),o&&this.annotationManager.setLineStyle(o),a&&this.annotationManager.setVertexStyle(a),this.annotationManager.enableTitle=l,l&&this.annotationManager.initTitleSupport(),this.annotationManager.clampEnabled=d,this.textManager=new b(this.viewport,this.container,this.ctx,()=>this.render(),(t,e)=>this.emitter.emit(t,e)),r&&this.textManager.setTextStyle(r),this.textManager.clampEnabled=d,this.renderer=new E(this.ctx,this.viewport,this.annotationManager,this.textManager),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.emitter.emit("undo",void 0)),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.annotationManager.adjustTitlePositions(),this.render()}}render(){this.renderer.render(this.bgImage)}clear(t=""){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.setDrawType(t),this.render(),this.emitter.emit("clear",void 0)}withdraw(){const t=this.annotationManager.withdraw(),e=this.textManager.withdraw();(t||e)&&(this.render(),this.emitter.emit("undo",void 0))}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(),this.emitter.emit("clear",void 0),!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()}getAnnotation(t){return this.annotationManager.getAnnotation(t)}getTextAnnotation(t){return this.textManager.getTextAnnotation(t)}on(t,e){this.emitter.on(t,e)}off(t,e){this.emitter.off(t,e)}setAnnotationTitle(t,e){const n=this.annotationManager.setTitle(t,e);return n&&this.render(),n}getAnnotationTitle(t){return this.annotationManager.getTitle(t)}setTitleStyle(t){this.annotationManager.setTitleStyle(t),this.render()}getTitleStyle(){return this.annotationManager.getTitleStyle()}setTitlePosition(t){this.annotationManager.setTitlePosition(t),this.render()}getTitlePosition(){return this.annotationManager.getTitlePosition()}setAnnotationTitleStyle(t,e){const n=this.annotationManager.setAnnotationTitleStyle(t,e);return n&&this.render(),n}setAnnotationTitlePosition(t,e){const n=this.annotationManager.setAnnotationTitlePosition(t,e);return n&&this.render(),n}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 o(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,e){this.annotationManager.selectAnnotation(t,e)&&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){if(this.annotationManager.moveSelectedAnnotation(t,e)){const t=this.annotationManager.selectedAnnotation;t&&this.annotationManager.notifyUpdate(t.index),this.render()}}setAnnotationColor(t){this.annotationManager.setColorConfig(t),this.render()}getAnnotationColor(){return this.annotationManager.getColorConfig()}updateSelectedAnnotationStyle(t){if(void 0!==t){const e=this.annotationManager.updateAnnotationStyle(t);return e&&this.render(),e}const e=this.annotationManager.selectedAnnotation;if(!e)return!1;const n=this.annotationManager.recordList[e.index];return!!n&&(n.style=this.annotationManager.getCurrentStyle(),this.annotationManager.notifyUpdate(e.index),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()}updateTextAnnotationStyle(t,e){const n=this.textManager.updateTextAnnotationStyle(t,e);return n&&this.render(),n}setTextInputStyle(t){this.textManager.setInputStyle(t)}setTextSelectionStyle(t){this.textManager.setSelectionStyle(t),this.render()}destroy(){this.emitter.clear(),document.removeEventListener("keydown",this.events.keydown),this.textManager.destroy(),this.annotationManager.destroyTitleInput(),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}t.AnnotationManager=S,t.Drawer=R,t.Emitter=O,t.EventHandler=D,t.Renderer=E,t.TextAnnotationManager=b,t.ViewportManager=h,t.base64ToBlob=o,t.base64ToFile=s,t.default=R,t.getImageTypeFromUrl=i,t.getZoomDelta=a,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),o=Math.abs(e.height);return t.x>=n&&t.x<=n+s&&t.y>=i&&t.y<=i+o}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 o=e[i].point.x,a=e[i].point.y,r=e[s].point.x,l=e[s].point.y;a>t.y!=l>t.y&&t.x<(r-o)*(t.y-a)/(l-a)+o&&(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]),o=s.length,a=new Uint8Array(o);for(let t=0;t<o;++t)a[t]=s.charCodeAt(t);const r=new Blob([a],{type:i});return new File([r],e,{type:i})}function o(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],o=atob(i[1]),a=new ArrayBuffer(o.length),r=new Uint8Array(a);for(let t=0;t<o.length;t++)r[t]=o.charCodeAt(t);e(new Blob([a],{type:s}))})}function a(t,e){return t<2?e?.1:-.1:t<5?e?.05:-.05:e?.02:-.02}function r(t){return"function"==typeof structuredClone?structuredClone(t):JSON.parse(JSON.stringify(t))}function l(){return"undefined"!=typeof crypto&&"function"==typeof crypto.randomUUID?crypto.randomUUID():`id-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}class h{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,o=(n-this.offset.y)/i;this.scale=Math.max(this.minScale,Math.min(t,this.maxScale));const a=s*this.scale+this.offset.x,r=o*this.scale+this.offset.y;this.offset.x+=e-a,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}}const d={minX:Number.NEGATIVE_INFINITY,minY:Number.NEGATIVE_INFINITY,maxX:Number.POSITIVE_INFINITY,maxY:Number.POSITIVE_INFINITY};function c(t,e,n){return Math.min(Math.max(t,e),n)}function g(t){var e,n,i,s;const{anchor:o,boxWidth:a,boxHeight:r,position:l}=t,h=null!==(e=t.bounds)&&void 0!==e?e:d,g=null!==(n=t.gap)&&void 0!==n?n:4,u=null!==(i=l.offsetX)&&void 0!==i?i:0,x=null!==(s=l.offsetY)&&void 0!==s?s:0,f=l.align||"center";let p;switch(f){case"left":p=o.x+u;break;case"right":p=o.x+o.width-a+u;break;default:p=o.x+o.width/2-a/2+u}const y=c(p,h.minX,Math.max(h.minX,h.maxX-a)),v=u+(y-p),M=l.vertical||"top";let w,m=M;return"inside-top"===M?w=o.y+g+x:"bottom"===M?(w=o.y+o.height+g+x,w+r>h.maxY&&(m="top",w=o.y-r-g+x)):(w=o.y-r-g+x,w<h.minY&&(m="bottom",w=o.y+o.height+g+x)),w=c(w,h.minY,Math.max(h.minY,h.maxY-r)),{x:y,y:w,vertical:m,align:f,offsetX:v}}function u(t){const{x:e,y:n}=g(t);return{x:e,y:n}}function x(t,e){if("polygon"===t.type){const n=t.data;if(0===n.length)return null;let i=1/0,s=1/0,o=-1/0,a=-1/0;return n.forEach(t=>{const n=e?e.offset.x+t.point.x*e.scale:t.point.x,r=e?e.offset.y+t.point.y*e.scale:t.point.y;n<i&&(i=n),r<s&&(s=r),n>o&&(o=n),r>a&&(a=r)}),{x:i,y:s,width:o-i,height:a-s}}const n=t.data[0];return e?{x:e.offset.x+n.start.x*e.scale,y:e.offset.y+n.start.y*e.scale,width:n.width*e.scale,height:n.height*e.scale}:{x:n.start.x,y:n.start.y,width:n.width,height:n.height}}function f(t,e){return Math.round(t*e)}function p(t,e){return Math.max(1,f(t,e))}function y(t,e=12){const n=t.match(/(\d+(?:\.\d+)?)px/);return n?parseFloat(n[1]):e}function v(t,e){return t.replace(/(\d+(?:\.\d+)?)px/,(t,n)=>`${p(parseFloat(n),e)}px`)}function M(t,e,n){if(!n)return e;const{originalWidth:i,originalHeight:s}=t;return i&&s?{x:Math.max(0,Math.min(e.x,i)),y:Math.max(0,Math.min(e.y,s))}:e}function w(t,e,n,i,s){t&&s.id&&t(n,{id:s.id,type:e,index:i,data:r(s)})}const m=new class{constructor(){this.type="rect"}startDrawing(t,e){t.isDrawing=!0,t.drawStartPoint=e,t.operate={type:"rect",data:[{start:Object.assign({},e),width:0,height:0}],status:"pending"}}updateDrawing(t,e){if(!t.isDrawing||"rect"!==t.operate.type)return;const n=t.operate.data[0];n.width=e.x-t.drawStartPoint.x,n.height=e.y-t.drawStartPoint.y}addPoint(t,e){return!1}finishDrawing(t){if(!t.isDrawing||"rect"!==t.operate.type)return!1;const e=t.operate.data[0];return Math.abs(e.width)>5&&Math.abs(e.height)>5&&t.pushRecord(Object.assign({},t.operate)),t.operate.data=[],t.isDrawing=!1,!0}cancelDrawing(t){t.operate.data=[],t.isDrawing=!1,t.tempPolygonPoint=null}withdrawInProgress(t){return 0!==t.operate.data.length&&(t.operate.data=[],t.isDrawing=!1,!0)}hitTest(t,n){return e(n,t.data[0])}getHandles(t,e,n){const i=t.data[0],s=e.offset.x+i.start.x*e.scale,o=e.offset.y+i.start.y*e.scale,a=i.width*e.scale,r=i.height*e.scale;return[{x:s,y:o,index:0},{x:s+a,y:o,index:1},{x:s,y:o+r,index:2},{x:s+a,y:o+r,index:3}]}move(t,e,n){const i=t.data[0];i.start.x+=e,i.start.y+=n}snapshotForResize(t){const e=t.data[0];return{start:Object.assign({},e.start),width:e.width,height:e.height}}resize(t,e,n,i){const s=t.data[0],o=i,a=o.start.x,r=o.start.x+o.width,l=o.start.y,h=o.start.y+o.height;let d,c;switch(e){case 0:d=r,c=h;break;case 1:d=a,c=h;break;case 2:d=r,c=l;break;case 3:d=a,c=l;break;default:return}const g=Math.min(n.x,d),u=Math.max(n.x,d),x=Math.min(n.y,c),f=Math.max(n.y,c);s.start.x=g,s.start.y=x,s.width=u-g,s.height=f-x;const p=n.x<d,y=n.y<c;let v;return 0===e?p||y?!p&&y?v=1:p&&!y&&(v=2):v=3:1===e?p&&!y?v=2:p&&y?v=0:p||y||(v=3):2===e?!p&&y?v=1:p&&y?v=0:p||y||(v=3):3===e&&(p&&y?v=0:!p&&y?v=1:p&&!y&&(v=2)),o.start.x=s.start.x,o.start.y=s.start.y,o.width=s.width,o.height=s.height,v}getBounds(t){const e=t.data[0];return{x:e.start.x,y:e.start.y,width:e.width,height:e.height}}};const A=new class{constructor(){this.type="polygon"}startDrawing(t,e){t.isDrawing=!0,t.operate={type:"polygon",data:[{point:e}],status:"pending"},t.tempPolygonPoint=e}updateDrawing(t,e){t.tempPolygonPoint=e}addPoint(t,e){if(!t.isDrawing||"polygon"!==t.operate.type)return!1;const n=t.operate.data.length>0?t.operate.data[t.operate.data.length-1]:null;return!(n&&Math.abs(n.point.x-e.x)<=5&&Math.abs(n.point.y-e.y)<=5)&&(t.operate.data.push({point:e}),!0)}finishDrawing(t){return!(!t.isDrawing||"polygon"!==t.operate.type)&&(t.operate.data.length>=3&&(t.operate.status="fullfilled",t.pushRecord(Object.assign({},t.operate))),t.operate={type:"polygon",data:[],status:"pending"},t.isDrawing=!1,t.tempPolygonPoint=null,!0)}cancelDrawing(t){t.isDrawing&&"polygon"===t.operate.type&&t.operate.data.length>=2&&(t.operate.status="fullfilled",t.pushRecord(Object.assign({},t.operate))),t.operate.data=[],t.isDrawing=!1,t.tempPolygonPoint=null}withdrawInProgress(t){return 0!==t.operate.data.length&&(t.operate.data.pop(),0===t.operate.data.length&&(t.isDrawing=!1),!0)}hitTest(t,e){return n(e,t.data)}getHandles(t,e,n){const i=t.data,s=[];for(let t=0;t<i.length;t++){const n=i[t];s.push({x:e.offset.x+n.point.x*e.scale,y:e.offset.y+n.point.y*e.scale,index:t})}return s}move(t,e,n){t.data.forEach(t=>{t.point.x+=e,t.point.y+=n})}snapshotForResize(t){return t.data.map(t=>({point:Object.assign({},t.point)}))}resize(t,e,n,i){const s=t.data;e>=0&&e<s.length&&(s[e].point.x=n.x,s[e].point.y=n.y)}getBounds(t){const e=t.data;if(0===e.length)return{x:0,y:0,width:0,height:0};let n=1/0,i=1/0,s=-1/0,o=-1/0;return e.forEach(t=>{t.point.x<n&&(n=t.point.x),t.point.y<i&&(i=t.point.y),t.point.x>s&&(s=t.point.x),t.point.y>o&&(o=t.point.y)}),{x:n,y:i,width:s-n,height:o-i}}};const T=new class{constructor(){this.strategies=new Map}register(t){this.strategies.set(t.type,t)}get(t){const e=this.strategies.get(t);if(!e)throw new Error(`No strategy registered for shape type: ${t}`);return e}selectShapeExclusive(t,e,n){return"shape"===n.kind?(e.deselectTextAnnotation(),t.selectAnnotation(n.ref,{lock:n.locked})):(t.deselectAnnotation(),e.selectTextAnnotation(n.index))}deselectAll(t,e){t.deselectAnnotation(),e.deselectTextAnnotation()}withdrawAll(t,e){return t.withdraw()||e.withdraw()}};T.register(m),T.register(A);class I{constructor(t,e,n,i){this.viewport=t,this.container=e,this.renderCallback=n,this.changeCallback=i,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.editingTitleIndex=null,this.titleInput=null,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.titleStyle={font:"12px Arial",color:"#FFFFFF",backgroundColor:"rgba(0, 0, 0, 0.7)",paddingX:6,paddingY:3,borderRadius:4,placeholder:"输入标题..."},this.titlePosition={vertical:"top",align:"center",offsetX:0,offsetY:0},this.enableTitle=!1,this.clampEnabled=!0,this.applyColorConfig()}strategyOf(t){return T.get(t)}clamp(t){return M(this.viewport,t,this.clampEnabled)}clampToImageBounds(t){return M(this.viewport,t,this.clampEnabled)}clampRecordToImageBounds(t){if(!this.clampEnabled)return;const{originalWidth:e,originalHeight:n}=this.viewport;if(!e||!n)return;if("rect"===t.type){const i=t.data[0];if(!i)return;const s=Math.min(i.start.x,i.start.x+i.width),o=Math.max(i.start.x,i.start.x+i.width),a=Math.min(i.start.y,i.start.y+i.height),r=Math.max(i.start.y,i.start.y+i.height);if(s>=0&&a>=0&&o<=e&&r<=n)return;const l=Math.min(o-s,e),h=Math.min(r-a,n);return i.start.x=Math.max(0,Math.min(s,e-l)),i.start.y=Math.max(0,Math.min(a,n-h)),i.width=l,void(i.height=h)}const i=t.data;if(!i||0===i.length)return;let s=1/0,o=1/0,a=-1/0,r=-1/0;for(const t of i)s=Math.min(s,t.point.x),a=Math.max(a,t.point.x),o=Math.min(o,t.point.y),r=Math.max(r,t.point.y);let l=0,h=0;if(a-s>e||s<0?l=-s:a>e&&(l=e-a),r-o>n||o<0?h=-o:r>n&&(h=n-r),0!==l||0!==h)for(const t of i)t.point.x+=l,t.point.y+=h}pushRecord(t){const e=Object.assign(Object.assign({},t),{id:l(),style:this.getCurrentStyle()});this.recordList.push(e),this.deleteHistory=[],this.notifyChange("create",this.recordList.length-1,e)}initTitleSupport(){this.container&&this.enableTitle&&this.createTitleInput()}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)}}notifyChange(t,e,n){w(this.changeCallback,n.type,t,e,n)}notifyUpdate(t){const e=this.recordList[t];e&&this.notifyChange("update",t,e)}resolveIndex(t){return"number"==typeof t?t:this.recordList.findIndex(e=>e.id===t)}getAnnotation(t){const e=this.resolveIndex(t);if(!(e<0||e>=this.recordList.length))return r(this.recordList[e])}updateAnnotationStyle(t){const e=this.resolveIndex(t);return!(e<0||e>=this.recordList.length)&&(this.recordList[e].style=this.getCurrentStyle(),this.notifyUpdate(e),!0)}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()}withdraw(){if(this.operate.data.length>0){const t="polygon"===this.operate.type?"polygon":"rect";return this.strategyOf(t).withdrawInProgress(this),!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,e){var n;const i=this.resolveIndex(t);if(i<0||i>=this.recordList.length)return this.deselectAnnotation(),!1;const s=this.recordList[i],o=void 0!==(null==e?void 0:e.lock)?!!e.lock:(null===(n=this.selectedAnnotation)||void 0===n?void 0:n.index)===i&&!0===this.selectedAnnotation.locked;return this.selectedAnnotation={index:i,type:s.type,locked:o},!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(),this.notifyChange("delete",t,e),!0}startMovingAnnotation(t){return!(!this.selectedAnnotation||!0===this.selectedAnnotation.locked)&&(this.isMovingAnnotation=!0,this.annotationMoveStart={x:t.clientX,y:t.clientY},!0)}updateMoveStart(t){this.annotationMoveStart=t}finishMovingAnnotation(){var t;const e=this.isMovingAnnotation||this.isResizing;if(this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null,e&&this.selectedAnnotation){const e=this.recordList[this.selectedAnnotation.index];(null==e?void 0:e.title)&&this.autoAdjustTitlePosition(e,e.title),this.notifyUpdate(this.selectedAnnotation.index),null===(t=this.renderCallback)||void 0===t||t.call(this)}}clear(){this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,this.deselectAnnotation(),this.deleteHistory=[]}getAnnotations(){return this.recordList.map(t=>r(t))}getSelectedAnnotation(){if(!this.selectedAnnotation)return null;const t=this.recordList[this.selectedAnnotation.index];return t?{index:this.selectedAnnotation.index,type:this.selectedAnnotation.type,data:r(t)}:null}setTitleStyle(t){this.titleStyle=Object.assign(Object.assign({},this.titleStyle),t)}getTitleStyle(){return Object.assign({},this.titleStyle)}setTitlePosition(t){this.titlePosition=Object.assign(Object.assign({},this.titlePosition),t)}getTitlePosition(){return Object.assign({},this.titlePosition)}getEffectiveTitleStyle(t){const e=this.getAnnotationStyle(t);return Object.assign(Object.assign({},this.titleStyle),e.titleStyle||{})}getEffectiveTitlePosition(t){const e=this.getAnnotationStyle(t);return Object.assign(Object.assign({},this.titlePosition),e.titlePosition||{})}captureTitleStyleSnapshot(t){t.style||(t.style=this.getCurrentStyle()),t.style.titleStyle=Object.assign({},this.titleStyle),t.style.titlePositionExplicit||(t.style.titlePosition=Object.assign({},this.titlePosition))}autoAdjustTitlePosition(t,e){var n,i,s;if(!e||(null===(n=t.style)||void 0===n?void 0:n.titlePositionExplicit))return;const{originalWidth:o,originalHeight:a,initialScale:r,scale:l}=this.viewport;if(o<=0||a<=0)return;const h=x(t);if(!h)return;const d=r>0?r:l>0?l:1,c={x:h.x*d,y:h.y*d,width:h.width*d,height:h.height*d},u=this.getEffectiveTitleStyle(t),f=u.font||"12px Arial",p=y(f)+2*(null!==(i=u.paddingY)&&void 0!==i?i:3),v=this.measureTitleWidth,M=v?{minX:0,minY:0,maxX:o*d,maxY:a*d}:{minX:Number.NEGATIVE_INFINITY,minY:0,maxX:Number.POSITIVE_INFINITY,maxY:a*d},w=v?v(e,f)+2*(null!==(s=u.paddingX)&&void 0!==s?s:6):0,m=Object.assign({},this.titlePosition),A=g({anchor:c,boxWidth:w,boxHeight:p,position:m,bounds:M});t.style||(t.style=this.getCurrentStyle()),t.style.titlePosition=Object.assign(Object.assign({},m),{vertical:A.vertical,align:A.align,offsetX:A.offsetX})}adjustTitlePositions(){this.viewport.originalWidth<=0||this.viewport.originalHeight<=0||this.recordList.forEach(t=>{var e;t.title&&!(null===(e=t.style)||void 0===e?void 0:e.titlePositionExplicit)&&this.autoAdjustTitlePosition(t,t.title)})}setAnnotationTitleStyle(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.recordList.length)return!1;const i=this.recordList[n];return i.style||(i.style=this.getCurrentStyle()),i.style.titleStyle=Object.assign(Object.assign({},i.style.titleStyle||this.titleStyle),e),this.notifyUpdate(n),!0}setAnnotationTitlePosition(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.recordList.length)return!1;const i=this.recordList[n];return i.style||(i.style=this.getCurrentStyle()),i.style.titlePosition=Object.assign(Object.assign({},i.style.titlePosition||this.titlePosition),e),i.style.titlePositionExplicit=!0,this.notifyUpdate(n),!0}createTitleInput(){this.container&&(this.titleInput=document.createElement("input"),this.titleInput.type="text",this.titleInput.style.position="absolute",this.titleInput.style.zIndex="99998",this.titleInput.style.display="none",this.titleInput.style.outline="none",this.titleInput.style.border="1px solid #00D9FF",this.titleInput.style.borderRadius="4px",this.titleInput.style.padding="4px 8px",this.titleInput.style.fontSize="13px",this.titleInput.style.fontFamily="Arial, sans-serif",this.titleInput.style.backgroundColor="#ffffff",this.titleInput.style.color="#333",this.titleInput.style.boxShadow="0 2px 8px rgba(0,0,0,0.3)",this.titleInput.style.minWidth="80px",this.titleInput.style.maxWidth="200px",this.titleInput.placeholder=this.titleStyle.placeholder||"输入标题...",this.titleInput.addEventListener("blur",()=>{this.finishTitleEditing()}),this.titleInput.addEventListener("keydown",t=>{t.stopPropagation(),"Enter"===t.key?this.finishTitleEditing():"Escape"===t.key&&(t.preventDefault(),this.cancelTitleEditing())}),this.container.appendChild(this.titleInput))}setTitle(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.recordList.length)return!1;const i=this.recordList[n];return i.title=e||void 0,e&&(this.captureTitleStyleSnapshot(i),this.autoAdjustTitlePosition(i,e)),this.notifyUpdate(n),!0}getTitle(t){const e=this.resolveIndex(t);if(!(e<0||e>=this.recordList.length))return this.recordList[e].title}startTitleEditing(t){if(!this.enableTitle||!this.titleInput||t<0||t>=this.recordList.length)return!1;const e=this.recordList[t];let n,i;if(this.editingTitleIndex=t,this.deselectAnnotation(),"rect"===e.type){const t=e.data[0];n=this.viewport.offset.x+t.start.x*this.viewport.scale,i=this.viewport.offset.y+t.start.y*this.viewport.scale}else{const t=e.data[0];n=this.viewport.offset.x+t.point.x*this.viewport.scale,i=this.viewport.offset.y+t.point.y*this.viewport.scale}return this.titleInput.value=e.title||"",this.titleInput.placeholder=this.getEffectiveTitleStyle(e).placeholder||"输入标题...",this.titleInput.style.left=`${n}px`,this.titleInput.style.top=i-32+"px",this.titleInput.style.display="block",setTimeout(()=>{this.titleInput&&(this.titleInput.focus(),this.titleInput.select())},10),!0}finishTitleEditing(){if(!this.titleInput||null===this.editingTitleIndex)return!1;const t=this.editingTitleIndex,e=this.titleInput.value.trim();if(t>=0&&t<this.recordList.length){const n=this.recordList[t];n.title=e||void 0,e&&(this.captureTitleStyleSnapshot(n),this.autoAdjustTitlePosition(n,e)),this.notifyUpdate(t),this.selectAnnotation(t)}return this.resetTitleEditingState(),this.renderCallback&&this.renderCallback(),!0}cancelTitleEditing(){if(!this.titleInput||null===this.editingTitleIndex)return!1;const t=this.editingTitleIndex;return t>=0&&t<this.recordList.length&&this.selectAnnotation(t),this.resetTitleEditingState(),this.renderCallback&&this.renderCallback(),!0}resetTitleEditingState(){this.titleInput&&(this.titleInput.style.display="none"),this.editingTitleIndex=null}destroyTitleInput(){this.titleInput&&this.titleInput.parentNode&&(this.titleInput.parentNode.removeChild(this.titleInput),this.titleInput=null)}}class S extends I{startRectDrawing(t){t=this.clampToImageBounds(t),this.strategyOf("rect").startDrawing(this,t)}updateRectDrawing(t){this.isDrawing&&"rect"===this.operate.type&&(t=this.clampToImageBounds(t),this.strategyOf("rect").updateDrawing(this,t))}finishRectDrawing(){return this.strategyOf("rect").finishDrawing(this)}startPolygonDrawing(t){t=this.clampToImageBounds(t),this.strategyOf("polygon").startDrawing(this,t)}addPolygonPoint(t){return!(!this.isDrawing||"polygon"!==this.operate.type)&&(t=this.clampToImageBounds(t),this.strategyOf("polygon").addPoint(this,t))}updatePolygonTempPoint(t){this.strategyOf("polygon").updateDrawing(this,this.clampToImageBounds(t))}finishPolygonDrawing(){return this.strategyOf("polygon").finishDrawing(this)}cancelDrawing(){const t="polygon"===this.operate.type?"polygon":"rect";this.strategyOf(t).cancelDrawing(this)}moveSelectedAnnotation(t,e){if(!this.selectedAnnotation)return!1;const n=this.recordList[this.selectedAnnotation.index];return!!n&&(this.strategyOf(n.type).move(n,t,e),this.clampRecordToImageBounds(n),!0)}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=this.strategyOf("rect").snapshotForResize(n):"polygon"===n.type&&(this.originalPolygon=this.strategyOf("polygon").snapshotForResize(n)),!0}resizeRect(t){if(!this.selectedAnnotation||"rect"!==this.selectedAnnotation.type||!this.originalRect||!this.activeHandle)return!1;if(this.activeHandle.index<0||this.activeHandle.index>3)return!1;const e=this.recordList[this.selectedAnnotation.index],n=this.clampToImageBounds(t),i=this.strategyOf("rect").resize(e,this.activeHandle.index,n,this.originalRect);return"number"==typeof i&&(this.activeHandle.index=i),!0}resizePolygon(t){var e;if(!this.selectedAnnotation||"polygon"!==this.selectedAnnotation.type||!this.activeHandle)return!1;const n=this.recordList[this.selectedAnnotation.index],i=this.activeHandle.index,s=n.data;return!(i<0||i>=s.length)&&(this.strategyOf("polygon").resize(n,i,this.clampToImageBounds(t),null!==(e=this.originalPolygon)&&void 0!==e?e:[]),!0)}getAnnotationAtPoint(t){for(let e=this.recordList.length-1;e>=0;e--){const n=this.recordList[e],i=n.type;if(this.strategyOf(i).hitTest(n,t))return{index:e,type:i}}return null}getHandleAtPoint(t,e){if(!this.selectedAnnotation)return null;if(!0===this.selectedAnnotation.locked)return null;const n=this.recordList[this.selectedAnnotation.index],i=this.selectionStyle.handleSize,s=i/2,o=this.selectedAnnotation.type,a=this.strategyOf(o).getHandles(n,this.viewport,i);for(const n of a)if(t>=n.x-s&&t<=n.x+s&&e>=n.y-s&&e<=n.y+s)return"rect"===o?{type:"rect-corner",index:n.index}:{type:"polygon-vertex",index:n.index};return null}}class b{constructor(t,e,n,i,s){this.viewport=t,this.container=e,this.ctx=n,this.renderCallback=i,this.changeCallback=s,this.textAnnotations=[],this.editingTextIndex=null,this.currentEditingIndex=null,this.movingTextIndex=null,this.isTextMoving=!1,this.textMoveStart={x:0,y:0},this.textBeforeEditing="",this.selectedTextIndex=null,this.clampEnabled=!0,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}}notifyChange(t,e,n){w(this.changeCallback,"text",t,e,n)}resolveIndex(t){return"number"==typeof t?t:this.textAnnotations.findIndex(e=>e.id===t)}getTextAnnotation(t){const e=this.resolveIndex(t);if(!(e<0||e>=this.textAnnotations.length))return r(this.textAnnotations[e])}updateTextAnnotationStyle(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.textAnnotations.length)return!1;const i=this.textAnnotations[n];return i.style=Object.assign(Object.assign({},i.style||this.getCurrentStyle()),e),this.notifyChange("update",n,this.textAnnotations[n]),!0}clampToImageBounds(t){return M(this.viewport,t,this.clampEnabled)}addTextAnnotation(t,e,n=""){var i;const s=this.clampToImageBounds({x:t,y:e});t=s.x,e=s.y,this.ctx.font=this.textStyle.font;const o=n||"输入文字...",a=this.ctx.measureText(o);let r;if(a.actualBoundingBoxAscent&&a.actualBoundingBoxDescent)r=a.actualBoundingBoxAscent+a.actualBoundingBoxDescent;else{r=1.2*parseInt((null===(i=this.textStyle.font.match(/\d+/))||void 0===i?void 0:i[0])||"16")}const h={id:l(),position:{x:t,y:e},text:n,style:this.getCurrentStyle(),width:Math.max(a.width,60),height:r};this.textAnnotations.push(h);const d=this.textAnnotations.length-1;return this.notifyChange("create",d,h),this.deleteHistory=[],this.startEditing(d),d}updateTextAnnotation(t,e){const n=this.resolveIndex(t);if(n<0||n>=this.textAnnotations.length)return!1;const i=this.textAnnotations[n];i.text=e,this.ctx.font=this.textStyle.font;const s=this.ctx.measureText(e);return i.width=s.width,i.height=1.2*parseInt(this.textStyle.font),this.notifyChange("update",n,this.textAnnotations[n]),!0}moveTextAnnotation(t,e,n){const i=this.resolveIndex(t);return!(i<0||i>=this.textAnnotations.length)&&(this.textAnnotations[i].position={x:e,y:n},this.notifyChange("update",i,this.textAnnotations[i]),!0)}removeTextAnnotation(t){const e=this.resolveIndex(t);if(e<0||e>=this.textAnnotations.length)return!1;const n=this.textAnnotations[e];return this.deleteHistory.push({annotation:Object.assign({},n),index:e}),this.textAnnotations.splice(e,1),this.notifyChange("delete",e,n),this.editingTextIndex===e?this.resetEditingState():null!==this.editingTextIndex&&this.editingTextIndex>e&&this.editingTextIndex--,this.movingTextIndex===e?this.endTextMoving():null!==this.movingTextIndex&&this.movingTextIndex>e&&this.movingTextIndex--,!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}px`,this.textInput.style.top=`${i}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){const e=this.textAnnotations[t];this.textAnnotations.splice(t,1),this.notifyChange("delete",t,e)}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),this.notifyChange("update",t,n)}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){if(""===this.textAnnotations[t].text&&""===this.textBeforeEditing){const e=this.textAnnotations[t];this.textAnnotations.splice(t,1),this.notifyChange("delete",t,e)}}return this.resetEditingState(),!0}deleteEditingAnnotation(){if(null===this.editingTextIndex)return!1;const t=this.editingTextIndex;if(this.textInput&&(this.textInput.style.display="none"),t>=0&&t<this.textAnnotations.length){const e=this.textAnnotations[t];this.textAnnotations.splice(t,1),this.notifyChange("delete",t,e)}return 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.movingTextIndex=e,this.isTextMoving=!0,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}moveAnnotation(t){if(!this.isTextMoving||null===this.movingTextIndex)return!1;const e=t.clientX-this.textMoveStart.x,n=t.clientY-this.textMoveStart.y,i=this.textAnnotations[this.movingTextIndex];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(){if(this.isTextMoving=!1,null!==this.movingTextIndex){const t=this.textAnnotations[this.movingTextIndex];t&&this.notifyChange("update",this.movingTextIndex,t)}this.movingTextIndex=null}endTextMoving(){this.isTextMoving=!1,this.movingTextIndex=null}isEditingVisible(){var t;return"block"===(null===(t=this.textInput)||void 0===t?void 0:t.style.display)}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,o=this.viewport.offset.y+i.position.y*this.viewport.scale,a=Math.max(i.width,60)+2*this.textStyle.padding,r=i.height+2*this.textStyle.padding;if(t>=s&&t<=s+a&&e>=o&&e<=o+r)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.map(t=>r(t))}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,this.notifyChange("delete",t,e),null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,null!==this.movingTextIndex&&this.movingTextIndex>t&&this.movingTextIndex--,!0}getSelectedTextAnnotation(){if(null===this.selectedTextIndex)return null;const t=this.textAnnotations[this.selectedTextIndex];return t?{index:this.selectedTextIndex,data:r(t)}:null}destroy(){this.textInput&&this.textInput.parentNode&&this.textInput.parentNode.removeChild(this.textInput)}}function C(t,e){switch(e){case"dashed":t.setLineDash([10,5]);break;case"dotted":t.setLineDash([2,4]);break;default:t.setLineDash([])}}class k{draw(t,e,n,i){const s=n.data[0];t.strokeRect(e.offset.x+s.start.x*e.scale,e.offset.y+s.start.y*e.scale,s.width*e.scale,s.height*e.scale)}drawInProgress(t,e,n){const i=n.operate.data[0];t.strokeRect(e.offset.x+i.start.x*e.scale,e.offset.y+i.start.y*e.scale,i.width*e.scale,i.height*e.scale)}drawSelection(t,e,n,i,s){const o=n.data[0],a=e.offset.x+o.start.x*e.scale,r=e.offset.y+o.start.y*e.scale,l=o.width*e.scale,h=o.height*e.scale;if(t.fillStyle=i.fillColor,t.fillRect(a,r,l,h),t.strokeStyle=i.strokeColor,t.lineWidth=2,t.setLineDash([5,5]),t.strokeRect(a,r,l,h),s)return;const d=i.handleSize;t.fillStyle=i.handleColor,t.setLineDash([]),t.fillRect(a-d/2,r-d/2,d,d),t.fillRect(a+l-d/2,r-d/2,d,d),t.fillRect(a-d/2,r+h-d/2,d,d),t.fillRect(a+l-d/2,r+h-d/2,d,d)}drawForExport(t,e,n,i=1){const s=e.data[0];t.strokeRect(s.start.x,s.start.y,s.width,s.height)}getTitleAnchor(t,e){return x(t,e)}}class P{constructor(t){this.store=t}draw(t,e,n,i){const s=i.vertexStyle||this.store.getVertexStyle();this.drawPolygon(t,e,n.data,"fullfilled"===n.status,s)}drawInProgress(t,e,n){const i=n.operate.data,s=n.tempPolygonPoint;if(t.beginPath(),i.forEach((n,i)=>{const s=Math.round(e.offset.x+n.point.x*e.scale),o=Math.round(e.offset.y+n.point.y*e.scale);0===i?t.moveTo(s,o):t.lineTo(s,o)}),s){const n=Math.round(e.offset.x+s.x*e.scale),i=Math.round(e.offset.y+s.y*e.scale);t.lineTo(n,i)}if(t.stroke(),this.drawPolygonVertices(t,e,i,n.getVertexStyle()),s){const i=n.getVertexStyle(),o=Math.round(e.offset.x+s.x*e.scale),a=Math.round(e.offset.y+s.y*e.scale),r=i.size/2;switch(t.fillStyle=i.fillColor,t.strokeStyle=i.strokeColor,t.lineWidth=i.strokeWidth,t.beginPath(),i.shape){case"square":t.rect(o-r,a-r,2*r,2*r);break;case"diamond":t.moveTo(o,a-r),t.lineTo(o+r,a),t.lineTo(o,a+r),t.lineTo(o-r,a),t.closePath();break;default:t.arc(o,a,r,0,2*Math.PI)}t.fill(),i.strokeWidth>0&&t.stroke()}}drawSelection(t,e,n,i,s){const o=n.data;if(t.beginPath(),o.forEach((n,i)=>{const s=e.offset.x+n.point.x*e.scale,o=e.offset.y+n.point.y*e.scale;0===i?t.moveTo(s,o):t.lineTo(s,o)}),t.closePath(),t.fillStyle=i.fillColor,t.fill(),t.strokeStyle=i.strokeColor,t.lineWidth=2,t.setLineDash([5,5]),t.stroke(),s)return;const a=i.handleSize;t.fillStyle=i.handleColor,t.setLineDash([]),o.forEach(n=>{const i=Math.round(e.offset.x+n.point.x*e.scale),s=Math.round(e.offset.y+n.point.y*e.scale);t.fillRect(i-a/2,s-a/2,a,a)})}drawForExport(t,e,n,i=1){if("fullfilled"!==e.status)return;const s=e.data;t.beginPath(),s.forEach((e,n)=>{0===n?t.moveTo(e.point.x,e.point.y):t.lineTo(e.point.x,e.point.y)});const o=e.data[0];t.lineTo(o.point.x,o.point.y),t.stroke();const a=p(4,i);s.forEach(e=>{t.beginPath(),t.arc(e.point.x,e.point.y,a,0,2*Math.PI),t.fillStyle=n.strokeColor,t.fill()})}getTitleAnchor(t,e){return x(t,e)}drawPolygon(t,e,n,i,s){if(0!==n.length){if(t.beginPath(),n.forEach((n,i)=>{const s=Math.round(e.offset.x+n.point.x*e.scale),o=Math.round(e.offset.y+n.point.y*e.scale);0===i?t.moveTo(s,o):t.lineTo(s,o)}),i&&n.length>1){const i=n[0];t.lineTo(e.offset.x+i.point.x*e.scale,e.offset.y+i.point.y*e.scale)}t.stroke(),this.drawPolygonVertices(t,e,n,s)}}drawPolygonVertices(t,e,n,i){const s=i||this.store.getVertexStyle(),o=s.size/2;n.forEach(n=>{const i=Math.round(e.offset.x+n.point.x*e.scale),a=Math.round(e.offset.y+n.point.y*e.scale);switch(t.fillStyle=s.fillColor,t.strokeStyle=s.strokeColor,t.lineWidth=s.strokeWidth,t.beginPath(),s.shape){case"square":t.rect(i-o,a-o,2*o,2*o);break;case"diamond":t.moveTo(i,a-o),t.lineTo(i+o,a),t.lineTo(i,a+o),t.lineTo(i-o,a),t.closePath();break;default:t.arc(i,a,o,0,2*Math.PI)}t.fill(),s.strokeWidth>0&&t.stroke()})}}class E{constructor(t,e,n,i){this.ctx=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.shapeRenderers={rect:new k,polygon:new P(n)}}render(t){this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.drawBackgroundImage(t),this.drawAnnotations(),function(t,e,n){const i=n.textStyle;n.textAnnotations.forEach((s,o)=>{var a,r,l;if(n.editingTextIndex===o&&n.isEditingVisible())return;if(!s.text)return;const h=(null===(a=s.style)||void 0===a?void 0:a.font)||i.font||"16px Arial",d=(null===(r=s.style)||void 0===r?void 0:r.color)||i.color||"#FFD700",c=(null===(l=s.style)||void 0===l?void 0:l.backgroundColor)||i.backgroundColor||"rgba(0,0,0,0.6)",g=e.offset.x+s.position.x*e.scale,u=e.offset.y+s.position.y*e.scale,x=n.selectedTextIndex===o;t.font=h;const f=t.measureText(s.text),p=f.actualBoundingBoxAscent||.8*s.height,y=p+(f.actualBoundingBoxDescent||.2*s.height),v=i.borderRadius,M=g,w=u,m=s.width+2*i.padding,A=y+2*i.padding;t.fillStyle=c,t.beginPath(),t.roundRect(M,w,m,A,v),t.fill(),x&&(t.strokeStyle=i.selectedBorderColor,t.lineWidth=2,t.setLineDash([5,5]),t.beginPath(),t.roundRect(M,w,m,A,v),t.stroke(),t.setLineDash([]));const T=g+i.padding,I=u+i.padding+p;t.fillStyle=d,t.fillText(s.text,T,I)})}(this.ctx,this.viewport,this.textManager)}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=>{const e=this.annotationManager.getAnnotationStyle(t);this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=e.lineWidth,C(this.ctx,e.lineStyle||"solid"),this.ctx.fillStyle=this.ctx.strokeStyle,"rect"===t.type?this.shapeRenderers.rect.draw(this.ctx,this.viewport,t,e):"polygon"===t.type&&this.shapeRenderers.polygon.draw(this.ctx,this.viewport,t,e),this.annotationManager.enableTitle&&t.title&&this.drawAnnotationTitle(t)}),this.annotationManager.operate.data.length>0&&(this.ctx.strokeStyle=this.annotationManager.strokeStyle,this.ctx.lineWidth=this.annotationManager.lineWidth,this.ctx.fillStyle=this.ctx.strokeStyle,C(this.ctx,this.annotationManager.lineStyle),"rect"===this.annotationManager.operate.type?this.shapeRenderers.rect.drawInProgress(this.ctx,this.viewport,this.annotationManager):"polygon"===this.annotationManager.operate.type&&this.shapeRenderers.polygon.drawInProgress(this.ctx,this.viewport,this.annotationManager)),this.ctx.setLineDash([]),this.drawSelectionHighlight()}drawSelectionHighlight(){const t=this.annotationManager.selectedAnnotation;if(!t)return;const e=this.annotationManager.recordList[t.index];if(!e)return;const n=this.annotationManager.selectionStyle,i=!0===t.locked;this.ctx.save(),"rect"===e.type?this.shapeRenderers.rect.drawSelection(this.ctx,this.viewport,e,n,i):"polygon"===e.type&&this.shapeRenderers.polygon.drawSelection(this.ctx,this.viewport,e,n,i),this.ctx.restore()}drawAnnotationTitle(t){var e,n,i;if(!t.title)return;const s=this.annotationManager.getEffectiveTitleStyle(t),o=this.annotationManager.getEffectiveTitlePosition(t),a=s.font||"12px Arial",r=s.color||"#FFFFFF",l=s.backgroundColor||"rgba(0, 0, 0, 0.7)",h=null!==(e=s.paddingX)&&void 0!==e?e:6,d=null!==(n=s.paddingY)&&void 0!==n?n:3,c=null!==(i=s.borderRadius)&&void 0!==i?i:4;this.ctx.save(),this.ctx.font=a;const g=this.ctx.measureText(t.title).width,x=y(a),f=("rect"===t.type?this.shapeRenderers.rect:this.shapeRenderers.polygon).getTitleAnchor(t,this.viewport);if(!f)return void this.ctx.restore();const p=g+2*h,v=x+2*d,{x:M,y:w}=u({anchor:f,boxWidth:p,boxHeight:v,position:o});this.ctx.fillStyle=l,this.ctx.setLineDash([]),this.ctx.beginPath(),this.ctx.roundRect(M,w,p,v,c),this.ctx.fill(),this.ctx.fillStyle=r,this.ctx.textAlign="left",this.ctx.textBaseline="top",this.ctx.fillText(t.title,M+h,w+d),this.ctx.restore()}getExportPixelRatio(){const t=this.viewport.scale;return t>0?1/t:1}drawForExport(t,e,n,i){const s=this.getExportPixelRatio();t.drawImage(e,0,0,n,i),this.annotationManager.recordList.forEach(e=>{const n=this.annotationManager.getAnnotationStyle(e);t.strokeStyle=n.strokeColor,t.lineWidth=p(n.lineWidth,s),"rect"===e.type?this.shapeRenderers.rect.drawForExport(t,e,n,s):"polygon"===e.type&&this.shapeRenderers.polygon.drawForExport(t,e,n,s)}),this.textManager.textAnnotations.forEach(e=>{var n,i,o;const a=this.textManager.textStyle,r=(null===(n=e.style)||void 0===n?void 0:n.font)||a.font||"16px Arial",l=(null===(i=e.style)||void 0===i?void 0:i.color)||a.color||"#FFD700",h=(null===(o=e.style)||void 0===o?void 0:o.backgroundColor)||a.backgroundColor||"rgba(0,0,0,0.6)";t.font=v(r,s);const d=t.measureText(e.text),c=d.actualBoundingBoxAscent||.8*e.height,g=c+(d.actualBoundingBoxDescent||.2*e.height),u=e.position.x,x=e.position.y,p=f(a.padding,s),y=d.width+2*p,M=g+2*p,w=f(a.borderRadius,s);t.fillStyle=h;const m=t;m.roundRect?(t.beginPath(),m.roundRect(u,x,y,M,w),t.fill()):t.fillRect(u,x,y,M),t.fillStyle=l,t.fillText(e.text,u+p,x+p+c)}),this.annotationManager.enableTitle&&this.annotationManager.recordList.forEach(e=>{var n,i,o,a,r;if(!e.title)return;const l=this.annotationManager.getEffectiveTitleStyle(e),h=this.annotationManager.getEffectiveTitlePosition(e),d=l.color||"#FFFFFF",c=l.backgroundColor||"rgba(0, 0, 0, 0.7)",g=v(l.font||"12px Arial",s),x=f(null!==(n=l.paddingX)&&void 0!==n?n:6,s),p=f(null!==(i=l.paddingY)&&void 0!==i?i:3,s),M=f(null!==(o=l.borderRadius)&&void 0!==o?o:4,s);t.font=g;const w=t.measureText(e.title).width,m=y(g),A=("rect"===e.type?this.shapeRenderers.rect:this.shapeRenderers.polygon).getTitleAnchor(e);if(!A)return;const T=w+2*x,I=m+2*p,{x:S,y:b}=u({anchor:A,boxWidth:T,boxHeight:I,position:Object.assign(Object.assign({},h),{offsetX:f(null!==(a=h.offsetX)&&void 0!==a?a:0,s),offsetY:f(null!==(r=h.offsetY)&&void 0!==r?r:0,s)}),gap:f(4,s)});t.fillStyle=c;const C=t;C.roundRect?(t.beginPath(),C.roundRect(S,b,T,I,M),t.fill()):t.fillRect(S,b,T,I),t.fillStyle=d,t.textAlign="left",t.textBaseline="top",t.fillText(e.title,S+x,b+p)})}}class D{constructor(t,e,n,i,s,o,a,r,l,h){this.canvas=t,this.viewport=e,this.annotationManager=n,this.textManager=i,this.renderer=s,this.getDrawType=o,this.getBgImage=a,this.renderCallback=r,this.setDrawTypeCallback=l,this.notifyUndo=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(),o=t.clientX-s.left,a=t.clientY-s.top,r=(o-this.viewport.offset.x)/n,l=(a-this.viewport.offset.y)/n;this.viewport.scale=i;const h=r*i+this.viewport.offset.x,d=l*i+this.viewport.offset.y;this.viewport.offset.x+=o-h,this.viewport.offset.y+=a-d,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):T.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index: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 o=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,o),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(o);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):T.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index:n}),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(o);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(o);if("rect"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.startRectDrawing(o)}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,o),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(o);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):T.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index:e}),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(o);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(o);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(o)&&this.annotationManager.addPolygonPoint(o):this.annotationManager.startPolygonDrawing(o),this.annotationManager.updatePolygonTempPoint(o),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,o),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):T.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index:e}),void this.renderCallback();if(this.handleRectModeClick(t,o))return;if(this.handlePolygonModeClick(t,o))return;this.isDragging=!0,this.dragStart={x:t.clientX,y:t.clientY},this.canvas.style.cursor="grabbing"}else""===i&&this.handleNoModeClick(t,o)}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)}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):T.selectShapeExclusive(this.annotationManager,this.textManager,{kind:"text",index: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.movingTextIndex)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.updateMoveStart({x:t.clientX,y:t.clientY}),this.renderCallback()}isHoverLockedAnnotation(t){return!(!t||!this.annotationManager.selectedAnnotation)&&(!0===this.annotationManager.selectedAnnotation.locked&&t.index===this.annotationManager.selectedAnnotation.index)}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")}const n=this.annotationManager.getAnnotationAtPoint(e);if(n)return void(this.canvas.style.cursor=this.isHoverLockedAnnotation(n)?"default":"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),i=this.annotationManager.getAnnotationAtPoint(n);i?this.canvas.style.cursor=this.isHoverLockedAnnotation(i)?"default":"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),i=this.annotationManager.getAnnotationAtPoint(n);i?this.canvas.style.cursor=this.isHoverLockedAnnotation(i)?"default":"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?this.isHoverLockedAnnotation(n)?"default":"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?this.isHoverLockedAnnotation(n)?"default":"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.endTextMoving(),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(this.annotationManager.selectedAnnotation){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),n=this.annotationManager.getAnnotationAtPoint(e);if(n&&n.index===this.annotationManager.selectedAnnotation.index)return void this.annotationManager.startTitleEditing(n.index)}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();!this.getBgImage()||"polygon"!==n||this.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving||(this.justDeselected?this.justDeselected=!1:null===(e=this.annotationManager.selectedAnnotation)||void 0===e||e.type)}handleKeyDown(t){const e=t.target;if(!e||"INPUT"!==e.tagName&&"TEXTAREA"!==e.tagName&&"SELECT"!==e.tagName&&!e.isContentEditable){if("z"===t.key&&(t.ctrlKey||t.metaKey)){return T.withdrawAll(this.annotationManager,this.textManager)&&this.notifyUndo(),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 O{constructor(){this.listeners=new Map}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){var n;null===(n=this.listeners.get(t))||void 0===n||n.delete(e)}emit(t,e){var n;null===(n=this.listeners.get(t))||void 0===n||n.forEach(t=>t(e))}clear(){this.listeners.clear()}}class R{constructor(t){this.canvas=document.createElement("canvas"),this.emitter=new O,this.bgImage=null,this.bgImageSrc="",this.bgImageExt="jpeg",this.drawType="";const{drawType:e,useEvents:n=!0,id:i="container",annotationColor:s,lineStyle:o,vertexStyle:a,textStyle:r,enableTitle:l=!1,clampToImageBounds:d=!0}=t,c=document.getElementById(i);if(!c)throw new Error(`Container with id "${i}" not found`);this.container=c,"absolute"!==c.style.position&&"fixed"!==c.style.position&&"relative"!==c.style.position&&(c.style.position="relative"),this.ctx=this.canvas.getContext("2d"),this.viewport=new h,this.viewport.setSize(c.clientWidth,c.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",c.appendChild(this.canvas),this.annotationManager=new S(this.viewport,this.container,()=>this.render(),(t,e)=>this.emitter.emit(t,e)),this.annotationManager.measureTitleWidth=(t,e)=>(this.ctx.font=e,this.ctx.measureText(t).width),s&&this.annotationManager.setColorConfig(s),o&&this.annotationManager.setLineStyle(o),a&&this.annotationManager.setVertexStyle(a),this.annotationManager.enableTitle=l,l&&this.annotationManager.initTitleSupport(),this.annotationManager.clampEnabled=d,this.textManager=new b(this.viewport,this.container,this.ctx,()=>this.render(),(t,e)=>this.emitter.emit(t,e)),r&&this.textManager.setTextStyle(r),this.textManager.clampEnabled=d,this.renderer=new E(this.ctx,this.viewport,this.annotationManager,this.textManager),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.emitter.emit("undo",void 0)),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.annotationManager.adjustTitlePositions(),this.render()}}render(){this.renderer.render(this.bgImage)}clear(t=""){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.setDrawType(t),this.render(),this.emitter.emit("clear",void 0)}withdraw(){const t=this.annotationManager.withdraw(),e=this.textManager.withdraw();(t||e)&&(this.render(),this.emitter.emit("undo",void 0))}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(),this.emitter.emit("clear",void 0),!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()}getAnnotation(t){return this.annotationManager.getAnnotation(t)}getTextAnnotation(t){return this.textManager.getTextAnnotation(t)}on(t,e){this.emitter.on(t,e)}off(t,e){this.emitter.off(t,e)}setAnnotationTitle(t,e){const n=this.annotationManager.setTitle(t,e);return n&&this.render(),n}getAnnotationTitle(t){return this.annotationManager.getTitle(t)}setTitleStyle(t){this.annotationManager.setTitleStyle(t),this.render()}getTitleStyle(){return this.annotationManager.getTitleStyle()}setTitlePosition(t){this.annotationManager.setTitlePosition(t),this.render()}getTitlePosition(){return this.annotationManager.getTitlePosition()}setAnnotationTitleStyle(t,e){const n=this.annotationManager.setAnnotationTitleStyle(t,e);return n&&this.render(),n}setAnnotationTitlePosition(t,e){const n=this.annotationManager.setAnnotationTitlePosition(t,e);return n&&this.render(),n}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.crossOrigin="anonymous",s.src=this.bgImageSrc,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 o(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,e){this.annotationManager.selectAnnotation(t,e)&&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){if(this.annotationManager.moveSelectedAnnotation(t,e)){const t=this.annotationManager.selectedAnnotation;t&&this.annotationManager.notifyUpdate(t.index),this.render()}}setAnnotationColor(t){this.annotationManager.setColorConfig(t),this.render()}getAnnotationColor(){return this.annotationManager.getColorConfig()}updateSelectedAnnotationStyle(t){if(void 0!==t){const e=this.annotationManager.updateAnnotationStyle(t);return e&&this.render(),e}const e=this.annotationManager.selectedAnnotation;if(!e)return!1;const n=this.annotationManager.recordList[e.index];return!!n&&(n.style=this.annotationManager.getCurrentStyle(),this.annotationManager.notifyUpdate(e.index),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()}updateTextAnnotationStyle(t,e){const n=this.textManager.updateTextAnnotationStyle(t,e);return n&&this.render(),n}setTextInputStyle(t){this.textManager.setInputStyle(t)}setTextSelectionStyle(t){this.textManager.setSelectionStyle(t),this.render()}destroy(){this.emitter.clear(),document.removeEventListener("keydown",this.events.keydown),this.textManager.destroy(),this.annotationManager.destroyTitleInput(),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}t.AnnotationManager=S,t.Drawer=R,t.Emitter=O,t.EventHandler=D,t.Renderer=E,t.TextAnnotationManager=b,t.ViewportManager=h,t.base64ToBlob=o,t.base64ToFile=s,t.default=R,t.getImageTypeFromUrl=i,t.getZoomDelta=a,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.3.4",
4
+ "version": "1.3.5",
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",