image-annotation-drawer 1.1.0 → 1.2.0
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 +37 -0
- package/dist/index.d.ts +49 -22
- package/dist/index.esm.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.0] - 2026-08-12
|
|
11
|
+
|
|
12
|
+
### Added - 标注变更事件系统
|
|
13
|
+
|
|
14
|
+
- **事件订阅 API**:
|
|
15
|
+
- `on(event, listener)` / `off(event, listener)` - 订阅/取消订阅标注变更事件
|
|
16
|
+
- 内置零依赖 `Emitter`,`destroy()` 时自动清空所有监听器
|
|
17
|
+
- **事件类型**(`DrawerEventMap`):
|
|
18
|
+
- `create` - 新标注画完入库(矩形/多边形/文本)
|
|
19
|
+
- `delete` - 标注被删除
|
|
20
|
+
- `update` - 标注数据变化(拖拽/缩放结束、标题/文本/样式修改、程序化移动)
|
|
21
|
+
- `clear` - 清空所有标注
|
|
22
|
+
- `undo` - 撤销成功(含 Ctrl+Z 快捷键路径)
|
|
23
|
+
- **事件载荷**(`ShapeChangePayload`):携带 `id`、`type`、`index` 及标注数据的**深拷贝快照**,外部修改不影响内部状态
|
|
24
|
+
- **导出类型**:`DrawerEventMap`、`DrawerEventName`、`DrawerListener`、`ShapeChangePayload`、`ChangeNotify`
|
|
25
|
+
|
|
26
|
+
### Added - 标注稳定 ID 与按 id 定位
|
|
27
|
+
|
|
28
|
+
- **稳定唯一 ID**:标注入库时自动生成 `id`(`Operate.id` / `TextAnnotation.id`),撤销、删除、重排后仍可稳定定位
|
|
29
|
+
- **新增 API**:
|
|
30
|
+
- `getAnnotation(ref)` - 按索引或 id 获取单个矩形/多边形标注(深拷贝快照)
|
|
31
|
+
- `getTextAnnotation(ref)` - 按索引或 id 获取单个文本标注(深拷贝快照)
|
|
32
|
+
- **既有 API 支持 id 定位**:以下方法的参数由 `index: number` 扩展为 `ref: number | string`,向后兼容:
|
|
33
|
+
- `setAnnotationTitle` / `getAnnotationTitle`
|
|
34
|
+
- `setAnnotationTitleStyle` / `setAnnotationTitlePosition`
|
|
35
|
+
- `selectAnnotation`
|
|
36
|
+
- `updateTextAnnotation` / `moveTextAnnotation` / `removeTextAnnotation` / `updateTextAnnotationStyle`
|
|
37
|
+
- **`updateSelectedAnnotationStyle(ref?)` 重载**:不传参时操作当前选中标注(原有行为);传入索引或 id 时直接更新指定标注
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- `getAnnotations()` / `getSelectedAnnotation()` 返回值改为深拷贝快照,外部修改不再影响内部状态
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- 第三种绘制完成路径(双击结束等)入库时未清空删除历史,现与 `finishRectDrawing` / `finishPolygonDrawing` 行为一致
|
|
46
|
+
|
|
10
47
|
## [1.1.0] - 2026-08-11
|
|
11
48
|
|
|
12
49
|
### Added - 标注标题功能
|
package/dist/index.d.ts
CHANGED
|
@@ -10,14 +10,16 @@
|
|
|
10
10
|
* - 图片导出:支持导出标注后的图片
|
|
11
11
|
* - TypeScript 支持:完整的类型定义
|
|
12
12
|
*/
|
|
13
|
-
export type { Shape, Point, Rect, Polygon, TextAnnotation, Operate, DrawerOptions, DrawType, SelectedAnnotation, ActiveHandle, TextStyle, TextInputStyle, SelectionStyle, AnnotationStyle, LineStyle, VertexStyle, ColorConfig, ViewportSize, ViewportOffset, DrawerEventHandlers, TitleStyle, TitlePosition, } from './modules/types';
|
|
13
|
+
export type { Shape, Point, Rect, Polygon, TextAnnotation, Operate, DrawerOptions, DrawType, SelectedAnnotation, ActiveHandle, TextStyle, TextInputStyle, SelectionStyle, AnnotationStyle, LineStyle, VertexStyle, ColorConfig, ViewportSize, ViewportOffset, DrawerEventHandlers, TitleStyle, TitlePosition, DrawerEventMap, DrawerEventName, DrawerListener, ShapeChangePayload, ChangeNotify, } from './modules/types';
|
|
14
14
|
export { isPointInRect, isPointInPolygon, getImageTypeFromUrl, base64ToFile, base64ToBlob, getZoomDelta, } from './modules/utils';
|
|
15
15
|
export { ViewportManager } from './modules/viewport';
|
|
16
16
|
export { AnnotationManager } from './modules/annotations';
|
|
17
17
|
export { TextAnnotationManager } from './modules/text-annotation';
|
|
18
18
|
export { Renderer } from './modules/renderer';
|
|
19
19
|
export { EventHandler } from './modules/events';
|
|
20
|
+
export { Emitter } from './modules/emitter';
|
|
20
21
|
import type { Rect, Polygon, TextAnnotation, Operate, DrawerOptions, DrawType, ColorConfig, LineStyle, VertexStyle, TextStyle, TextInputStyle, TitleStyle, TitlePosition } from './modules/types';
|
|
22
|
+
import type { DrawerEventName, DrawerListener } from './modules/types';
|
|
21
23
|
/**
|
|
22
24
|
* Drawer 类 - 图片标注库的主入口
|
|
23
25
|
*
|
|
@@ -40,6 +42,7 @@ export declare class Drawer {
|
|
|
40
42
|
private renderer;
|
|
41
43
|
private eventHandler;
|
|
42
44
|
private events;
|
|
45
|
+
private emitter;
|
|
43
46
|
private bgImage;
|
|
44
47
|
private bgImageSrc;
|
|
45
48
|
private bgImageExt;
|
|
@@ -99,22 +102,44 @@ export declare class Drawer {
|
|
|
99
102
|
* 获取当前所有标注数据
|
|
100
103
|
*/
|
|
101
104
|
getAnnotations(): Operate<Rect | Polygon | TextAnnotation>[];
|
|
105
|
+
/**
|
|
106
|
+
* 按索引或 id 获取单个矩形/多边形标注(深拷贝快照)
|
|
107
|
+
* @param ref - 标注索引或标注 id
|
|
108
|
+
* @returns 标注快照,不存在则返回 undefined
|
|
109
|
+
*/
|
|
110
|
+
getAnnotation(ref: number | string): Operate<Rect | Polygon> | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* 按索引或 id 获取单个文本标注(深拷贝快照)
|
|
113
|
+
* @param ref - 文本标注索引或标注 id
|
|
114
|
+
* @returns 文本标注快照,不存在则返回 undefined
|
|
115
|
+
*/
|
|
116
|
+
getTextAnnotation(ref: number | string): TextAnnotation | undefined;
|
|
117
|
+
/**
|
|
118
|
+
* 订阅标注变更事件
|
|
119
|
+
* @example
|
|
120
|
+
* drawer.on('create', ({ id, type, index, data }) => console.log('新标注', id, data))
|
|
121
|
+
*/
|
|
122
|
+
on<K extends DrawerEventName>(event: K, listener: DrawerListener<K>): void;
|
|
123
|
+
/**
|
|
124
|
+
* 取消订阅
|
|
125
|
+
*/
|
|
126
|
+
off<K extends DrawerEventName>(event: K, listener: DrawerListener<K>): void;
|
|
102
127
|
/**
|
|
103
128
|
* 设置标注标题
|
|
104
|
-
* @param index -
|
|
129
|
+
* @param index - 标注索引或标注 id
|
|
105
130
|
* @param title - 标题文本
|
|
106
131
|
* @returns 是否设置成功
|
|
107
132
|
* @example
|
|
108
133
|
* // 设置第一个标注的标题
|
|
109
134
|
* drawer.setAnnotationTitle(0, '这是一个人脸')
|
|
110
135
|
*/
|
|
111
|
-
setAnnotationTitle(index: number, title: string): boolean;
|
|
136
|
+
setAnnotationTitle(index: number | string, title: string): boolean;
|
|
112
137
|
/**
|
|
113
138
|
* 获取标注标题
|
|
114
|
-
* @param index -
|
|
139
|
+
* @param index - 标注索引或标注 id
|
|
115
140
|
* @returns 标题文本,如果没有则返回 undefined
|
|
116
141
|
*/
|
|
117
|
-
getAnnotationTitle(index: number): string | undefined;
|
|
142
|
+
getAnnotationTitle(index: number | string): string | undefined;
|
|
118
143
|
/**
|
|
119
144
|
* 设置标题样式(全局默认)
|
|
120
145
|
* @param style - 标题样式配置
|
|
@@ -152,22 +177,22 @@ export declare class Drawer {
|
|
|
152
177
|
getTitlePosition(): TitlePosition;
|
|
153
178
|
/**
|
|
154
179
|
* 单独设置某个标注的标题样式(不影响全局默认,也不影响其他标注)
|
|
155
|
-
* @param index -
|
|
180
|
+
* @param index - 标注索引或标注 id
|
|
156
181
|
* @param style - 标题样式(部分覆盖)
|
|
157
182
|
* @example
|
|
158
183
|
* drawer.setAnnotationTitleStyle(0, { color: '#FF0000', font: 'bold 16px Arial' })
|
|
159
184
|
* // 单独自定义某个标注的标题输入框占位提示
|
|
160
185
|
* drawer.setAnnotationTitleStyle(0, { placeholder: '请输入人脸名称' })
|
|
161
186
|
*/
|
|
162
|
-
setAnnotationTitleStyle(index: number, style: Partial<TitleStyle>): boolean;
|
|
187
|
+
setAnnotationTitleStyle(index: number | string, style: Partial<TitleStyle>): boolean;
|
|
163
188
|
/**
|
|
164
189
|
* 单独设置某个标注的标题位置(不影响全局默认,也不影响其他标注)
|
|
165
|
-
* @param index -
|
|
190
|
+
* @param index - 标注索引或标注 id
|
|
166
191
|
* @param position - 标题位置(部分覆盖)
|
|
167
192
|
* @example
|
|
168
193
|
* drawer.setAnnotationTitlePosition(0, { vertical: 'bottom', align: 'left' })
|
|
169
194
|
*/
|
|
170
|
-
setAnnotationTitlePosition(index: number, position: Partial<TitlePosition>): boolean;
|
|
195
|
+
setAnnotationTitlePosition(index: number | string, position: Partial<TitlePosition>): boolean;
|
|
171
196
|
/**
|
|
172
197
|
* 获取所有文本标注
|
|
173
198
|
*/
|
|
@@ -197,31 +222,31 @@ export declare class Drawer {
|
|
|
197
222
|
addTextAnnotation(x: number, y: number, text?: string): void;
|
|
198
223
|
/**
|
|
199
224
|
* 更新文本标注内容
|
|
200
|
-
* @param index -
|
|
225
|
+
* @param index - 标注索引或标注 id
|
|
201
226
|
* @param text - 新文本内容
|
|
202
227
|
*/
|
|
203
|
-
updateTextAnnotation(index: number, text: string): void;
|
|
228
|
+
updateTextAnnotation(index: number | string, text: string): void;
|
|
204
229
|
/**
|
|
205
230
|
* 移动文本标注位置
|
|
206
|
-
* @param index -
|
|
231
|
+
* @param index - 标注索引或标注 id
|
|
207
232
|
* @param x - 新位置 X(图像坐标)
|
|
208
233
|
* @param y - 新位置 Y(图像坐标)
|
|
209
234
|
*/
|
|
210
|
-
moveTextAnnotation(index: number, x: number, y: number): void;
|
|
235
|
+
moveTextAnnotation(index: number | string, x: number, y: number): void;
|
|
211
236
|
/**
|
|
212
237
|
* 删除文本标注
|
|
213
|
-
* @param index -
|
|
238
|
+
* @param index - 标注索引或标注 id
|
|
214
239
|
*/
|
|
215
|
-
removeTextAnnotation(index: number): void;
|
|
240
|
+
removeTextAnnotation(index: number | string): void;
|
|
216
241
|
/**
|
|
217
242
|
* 清除所有文本标注
|
|
218
243
|
*/
|
|
219
244
|
clearTextAnnotations(): void;
|
|
220
245
|
/**
|
|
221
246
|
* 选中指定索引的标注
|
|
222
|
-
* @param index -
|
|
247
|
+
* @param index - 标注索引或标注 id
|
|
223
248
|
*/
|
|
224
|
-
selectAnnotation(index: number): void;
|
|
249
|
+
selectAnnotation(index: number | string): void;
|
|
225
250
|
/**
|
|
226
251
|
* 取消选中
|
|
227
252
|
*/
|
|
@@ -266,10 +291,12 @@ export declare class Drawer {
|
|
|
266
291
|
*/
|
|
267
292
|
getAnnotationColor(): ColorConfig;
|
|
268
293
|
/**
|
|
269
|
-
*
|
|
270
|
-
*
|
|
294
|
+
* 更新标注的样式为当前设置的样式
|
|
295
|
+
* 不传参时操作当前选中的标注(原有行为);传参时按索引或 id 直接指定标注
|
|
296
|
+
* 调用此方法后,目标标注会保存当前的新样式
|
|
297
|
+
* @param ref - 可选,标注索引或标注 id
|
|
271
298
|
*/
|
|
272
|
-
updateSelectedAnnotationStyle(): boolean;
|
|
299
|
+
updateSelectedAnnotationStyle(ref?: number | string): boolean;
|
|
273
300
|
/**
|
|
274
301
|
* 设置边线样式
|
|
275
302
|
* @param style - 边线样式:'solid' | 'dashed' | 'dotted'
|
|
@@ -310,14 +337,14 @@ export declare class Drawer {
|
|
|
310
337
|
/**
|
|
311
338
|
* 更新指定文本标注的样式(只影响该标注,不影响全局默认和其他标注)
|
|
312
339
|
* 可用于把当前全局样式(如加粗)应用到已存在的文本标注上
|
|
313
|
-
* @param index -
|
|
340
|
+
* @param index - 标注索引或标注 id
|
|
314
341
|
* @param style - 样式(部分覆盖)
|
|
315
342
|
* @returns 是否更新成功
|
|
316
343
|
* @example
|
|
317
344
|
* // 让第一个文本标注变为粗体
|
|
318
345
|
* drawer.updateTextAnnotationStyle(0, { font: 'bold 16px Arial' })
|
|
319
346
|
*/
|
|
320
|
-
updateTextAnnotationStyle(index: number, style: Partial<Pick<TextStyle, 'font' | 'color' | 'backgroundColor'>>): boolean;
|
|
347
|
+
updateTextAnnotationStyle(index: number | string, style: Partial<Pick<TextStyle, 'font' | 'color' | 'backgroundColor'>>): boolean;
|
|
321
348
|
/**
|
|
322
349
|
* 设置文本输入框样式
|
|
323
350
|
* @param style - 输入框样式配置
|
package/dist/index.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function t(t,e){const i=e.width>=0?e.start.x:e.start.x+e.width,n=e.height>=0?e.start.y:e.start.y+e.height,s=Math.abs(e.width),a=Math.abs(e.height);return t.x>=i&&t.x<=i+s&&t.y>=n&&t.y<=n+a}function e(t,e){if(e.length<3)return!1;let i=!1;for(let n=0,s=e.length-1;n<e.length;s=n++){const a=e[n].point.x,o=e[n].point.y,r=e[s].point.x,h=e[s].point.y;o>t.y!=h>t.y&&t.x<(r-a)*(t.y-o)/(h-o)+a&&(i=!i)}return i}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 n(t,e){const i=t.split(";base64,"),n=i[0].split(":")[1],s=window.atob(i[1]),a=s.length,o=new Uint8Array(a);for(let t=0;t<a;++t)o[t]=s.charCodeAt(t);const r=new Blob([o],{type:n});return new File([r],e,{type:n})}function s(t){return new Promise((e,i)=>{const n=t.split(";base64,");if(n.length<2)return void i(new Error("Invalid base64 string"));const s=n[0].split(":")[1],a=atob(n[1]),o=new ArrayBuffer(a.length),r=new Uint8Array(o);for(let t=0;t<a.length;t++)r[t]=a.charCodeAt(t);e(new Blob([o],{type:s}))})}function a(t,e){return t<2?e?.1:-.1:t<5?e?.05:-.05:e?.02:-.02}class o{constructor(){this.width=0,this.height=0,this.originalWidth=0,this.originalHeight=0,this.scale=1,this.minScale=1,this.maxScale=10,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}setSize(t,e){this.width=t,this.height=e}setOriginalSize(t,e){this.originalWidth=t,this.originalHeight=e}calculateInitialView(){if(0===this.originalWidth||0===this.originalHeight)return;const t=this.width/this.originalWidth,e=this.height/this.originalHeight;this.scale=Math.min(t,e),this.initialScale=this.scale,this.minScale=this.initialScale,this.offset={x:(this.width-this.originalWidth*this.scale)/2,y:(this.height-this.originalHeight*this.scale)/2},this.initialOffset=Object.assign({},this.offset),this.calculateBoundaries(),this.isInitialScale=!0}calculateBoundaries(){const t=this.originalWidth*this.scale,e=this.originalHeight*this.scale;this.maxOffsetX=0,this.maxOffsetY=0,this.minOffsetX=this.width-t,this.minOffsetY=this.height-e,this.minOffsetX>this.maxOffsetX&&([this.minOffsetX,this.maxOffsetX]=[this.maxOffsetX,this.minOffsetX]),this.minOffsetY>this.maxOffsetY&&([this.minOffsetY,this.maxOffsetY]=[this.maxOffsetY,this.minOffsetY])}constrainViewport(){this.offset.x>this.maxOffsetX?this.offset.x=this.maxOffsetX:this.offset.x<this.minOffsetX&&(this.offset.x=this.minOffsetX),this.offset.y>this.maxOffsetY?this.offset.y=this.maxOffsetY:this.offset.y<this.minOffsetY&&(this.offset.y=this.minOffsetY)}toImageCoordinates(t,e){return{x:(t-this.offset.x)/this.scale,y:(e-this.offset.y)/this.scale}}toCanvasCoordinates(t,e){return{x:this.offset.x+t*this.scale,y:this.offset.y+e*this.scale}}updateScale(t,e,i){const n=this.scale,s=(e-this.offset.x)/n,a=(i-this.offset.y)/n;this.scale=Math.max(this.minScale,Math.min(t,this.maxScale));const o=s*this.scale+this.offset.x,r=a*this.scale+this.offset.y;this.offset.x+=e-o,this.offset.y+=i-r,this.calculateBoundaries(),this.constrainViewport(),this.isInitialScale=this.scale===this.initialScale}resetToInitial(){this.scale=this.initialScale,this.offset=Object.assign({},this.initialOffset),this.calculateBoundaries(),this.isInitialScale=!0}updateOffset(t,e){this.offset.x+=t,this.offset.y+=e,this.constrainViewport()}reset(){this.scale=1,this.minScale=1,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}}class r{constructor(t,e,i){this.viewport=t,this.container=e,this.renderCallback=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.applyColorConfig()}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)}}setLineStyle(t){this.lineStyle=t}setVertexStyle(t){this.vertexStyle=Object.assign(Object.assign({},this.vertexStyle),t),t.fillColor&&(this.strokeStyle=t.fillColor)}getLineStyle(){return this.lineStyle}getVertexStyle(){return Object.assign({},this.vertexStyle)}getAnnotationStyle(t){return t.style||this.getCurrentStyle()}startRectDrawing(t){this.isDrawing=!0,this.drawStartPoint=t,this.operate={type:"rect",data:[{start:Object.assign({},t),width:0,height:0}],status:"pending"}}updateRectDrawing(t){if(!this.isDrawing||"rect"!==this.operate.type)return;const e=this.operate.data[0];e.width=t.x-this.drawStartPoint.x,e.height=t.y-this.drawStartPoint.y}finishRectDrawing(){if(!this.isDrawing||"rect"!==this.operate.type)return!1;const t=this.operate.data[0];if(Math.abs(t.width)>5&&Math.abs(t.height)>5){const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[]}return this.operate.data=[],this.isDrawing=!1,!0}startPolygonDrawing(t){this.isDrawing=!0,this.operate={type:"polygon",data:[{point:t}],status:"pending"},this.tempPolygonPoint=t}addPolygonPoint(t){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;const e=this.operate.data.length>0?this.operate.data[this.operate.data.length-1]:null;return!(e&&Math.abs(e.point.x-t.x)<=5&&Math.abs(e.point.y-t.y)<=5)&&(this.operate.data.push({point:t}),!0)}updatePolygonTempPoint(t){this.tempPolygonPoint=t}finishPolygonDrawing(){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;if(this.operate.data.length>=3){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[]}return this.operate={type:"polygon",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,!0}cancelDrawing(){if(this.isDrawing&&"polygon"===this.operate.type&&this.operate.data.length>=2){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t)}this.operate.data=[],this.isDrawing=!1,this.tempPolygonPoint=null}withdraw(){if(this.operate.data.length>0)return"polygon"===this.operate.type?(this.operate.data.pop(),0===this.operate.data.length&&(this.isDrawing=!1)):(this.operate.data=[],this.isDrawing=!1),!0;if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.recordList.splice(e,0,t),!0}return this.recordList.length>0&&(this.recordList.pop(),!0)}selectAnnotation(t){if(t<0||t>=this.recordList.length)return this.deselectAnnotation(),!1;const e=this.recordList[t];return this.selectedAnnotation={index:t,type:e.type},!0}deselectAnnotation(){this.selectedAnnotation=null,this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}deleteSelectedAnnotation(){if(!this.selectedAnnotation)return!1;const t=this.selectedAnnotation.index,e=this.recordList[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.recordList.splice(t,1),this.deselectAnnotation(),!0}startMovingAnnotation(t){return!!this.selectedAnnotation&&(this.isMovingAnnotation=!0,this.annotationMoveStart={x:t.clientX,y:t.clientY},!0)}moveSelectedAnnotation(t,e){if(!this.selectedAnnotation)return!1;const i=this.recordList[this.selectedAnnotation.index];if(!i)return!1;if("rect"===i.type){const n=i.data[0];n.start.x+=t,n.start.y+=e}else if("polygon"===i.type){i.data.forEach(i=>{i.point.x+=t,i.point.y+=e})}return!0}finishMovingAnnotation(){this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}startResizing(t,e){if(!this.selectedAnnotation)return!1;this.activeHandle=t,this.isResizing=!0;const i=this.recordList[this.selectedAnnotation.index];return"rect"===i.type?this.originalRect=Object.assign({},i.data[0]):"polygon"===i.type&&(this.originalPolygon=i.data.map(t=>({point:Object.assign({},t.point)}))),!0}resizeRect(t){if(!this.selectedAnnotation||"rect"!==this.selectedAnnotation.type||!this.originalRect||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data[0],i=this.originalRect,n=i.start.x,s=i.start.x+i.width,a=i.start.y,o=i.start.y+i.height;let r,h;switch(this.activeHandle.index){case 0:r=s,h=o;break;case 1:r=n,h=o;break;case 2:r=s,h=a;break;case 3:r=n,h=a;break;default:return!1}const l=Math.min(t.x,r),c=Math.max(t.x,r),d=Math.min(t.y,h),g=Math.max(t.y,h);e.start.x=l,e.start.y=d,e.width=c-l,e.height=g-d;const x=t.x<r,p=t.y<h;return 0===this.activeHandle.index?x||p?!x&&p?this.activeHandle.index=1:x&&!p&&(this.activeHandle.index=2):this.activeHandle.index=3:1===this.activeHandle.index?x&&!p?this.activeHandle.index=2:x&&p?this.activeHandle.index=0:x||p||(this.activeHandle.index=3):2===this.activeHandle.index?!x&&p?this.activeHandle.index=1:x&&p?this.activeHandle.index=0:x||p||(this.activeHandle.index=3):3===this.activeHandle.index&&(x&&p?this.activeHandle.index=0:!x&&p?this.activeHandle.index=1:x&&!p&&(this.activeHandle.index=2)),this.originalRect=Object.assign({},e),!0}resizePolygon(t){if(!this.selectedAnnotation||"polygon"!==this.selectedAnnotation.type||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data,i=this.activeHandle.index;return i>=0&&i<e.length&&(e[i].point.x=t.x,e[i].point.y=t.y,!0)}getAnnotationAtPoint(i){for(let n=this.recordList.length-1;n>=0;n--){const s=this.recordList[n];if("rect"===s.type){if(t(i,s.data[0]))return{index:n,type:"rect"}}else if("polygon"===s.type){if(e(i,s.data))return{index:n,type:"polygon"}}}return null}getHandleAtPoint(t,e){if(!this.selectedAnnotation)return null;const i=this.recordList[this.selectedAnnotation.index],n=this.selectionStyle.handleSize/2;if("rect"===i.type){const s=i.data[0],a=this.viewport.offset.x+s.start.x*this.viewport.scale,o=this.viewport.offset.y+s.start.y*this.viewport.scale,r=s.width*this.viewport.scale,h=s.height*this.viewport.scale,l=[{x:a,y:o,index:0},{x:a+r,y:o,index:1},{x:a,y:o+h,index:2},{x:a+r,y:o+h,index:3}];for(const i of l)if(t>=i.x-n&&t<=i.x+n&&e>=i.y-n&&e<=i.y+n)return{type:"rect-corner",index:i.index}}else if("polygon"===i.type){const s=i.data;for(let i=0;i<s.length;i++){const a=s[i],o=this.viewport.offset.x+a.point.x*this.viewport.scale,r=this.viewport.offset.y+a.point.y*this.viewport.scale;if(t>=o-n&&t<=o+n&&e>=r-n&&e<=r+n)return{type:"polygon-vertex",index:i}}}return null}clear(){this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,this.deselectAnnotation(),this.deleteHistory=[]}getAnnotations(){return[...this.recordList]}getSelectedAnnotation(){if(!this.selectedAnnotation)return null;const t=this.recordList[this.selectedAnnotation.index];return t?{index:this.selectedAnnotation.index,type:this.selectedAnnotation.type,data:t}:null}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.titlePosition=Object.assign({},this.titlePosition)}setAnnotationTitleStyle(t,e){if(t<0||t>=this.recordList.length)return!1;const i=this.recordList[t];return i.style||(i.style=this.getCurrentStyle()),i.style.titleStyle=Object.assign(Object.assign({},i.style.titleStyle||this.titleStyle),e),!0}setAnnotationTitlePosition(t,e){if(t<0||t>=this.recordList.length)return!1;const i=this.recordList[t];return i.style||(i.style=this.getCurrentStyle()),i.style.titlePosition=Object.assign(Object.assign({},i.style.titlePosition||this.titlePosition),e),!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){if(t<0||t>=this.recordList.length)return!1;const i=this.recordList[t];return i.title=e||void 0,e&&this.captureTitleStyleSnapshot(i),!0}getTitle(t){if(!(t<0||t>=this.recordList.length))return this.recordList[t].title}startTitleEditing(t){if(!this.enableTitle||!this.titleInput||t<0||t>=this.recordList.length)return!1;const e=this.recordList[t];let i,n;if(this.editingTitleIndex=t,this.deselectAnnotation(),"rect"===e.type){const t=e.data[0];i=this.viewport.offset.x+t.start.x*this.viewport.scale,n=this.viewport.offset.y+t.start.y*this.viewport.scale}else{const t=e.data[0];i=this.viewport.offset.x+t.point.x*this.viewport.scale,n=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=`${i}px`,this.titleInput.style.top=n-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 i=this.recordList[t];i.title=e||void 0,e&&this.captureTitleStyleSnapshot(i),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 h{constructor(t,e,i,n){this.viewport=t,this.container=e,this.ctx=i,this.renderCallback=n,this.textAnnotations=[],this.editingTextIndex=null,this.currentEditingIndex=null,this.isTextMoving=!1,this.textMoveStart={x:0,y:0},this.textBeforeEditing="",this.selectedTextIndex=null,this.textInput=null,this.deleteHistory=[],this.defaultInputStyle={border:"2px solid #00D9FF",borderRadius:"6px",padding:"6px 10px",fontSize:"16px",fontFamily:"Arial, sans-serif",backgroundColor:"#ffffff",color:"#333",boxShadow:"0 4px 12px rgba(0,0,0,0.3)",minWidth:"60px",maxWidth:"200px"},this.textStyle={font:"16px Arial",color:"#FFD700",padding:6,backgroundColor:"rgba(0,0,0,0.6)",borderRadius:4,selectedBorderColor:"#00D9FF",selectedBackgroundColor:"rgba(0,217,255,0.15)",inputStyle:Object.assign({},this.defaultInputStyle)},this.createTextInput()}createTextInput(){this.textInput=document.createElement("input"),this.textInput.type="text",this.textInput.style.position="absolute",this.textInput.style.zIndex="99999",this.textInput.style.display="none",this.textInput.style.outline="none",this.textInput.style.width="fit-content",this.textInput.placeholder="输入文字...",this.applyInputStyle(),this.textInput.addEventListener("blur",()=>{this.finishEditing(),this.renderCallback&&this.renderCallback()}),this.textInput.addEventListener("keydown",t=>{t.stopPropagation(),"Enter"===t.key?(this.finishEditing(),this.renderCallback&&this.renderCallback()):"Escape"===t.key?(t.preventDefault(),this.cancelEditing()):"Delete"===t.key&&""===this.textInput.value&&(t.preventDefault(),this.deleteEditingAnnotation())}),this.textInput.addEventListener("input",()=>{this.adjustInputWidth()}),this.container.appendChild(this.textInput)}applyInputStyle(){if(!this.textInput)return;const t=Object.assign(Object.assign({},this.defaultInputStyle),this.textStyle.inputStyle);this.textInput.style.border=t.border,this.textInput.style.borderRadius=t.borderRadius,this.textInput.style.padding=t.padding,this.textInput.style.fontSize=t.fontSize,this.textInput.style.fontFamily=t.fontFamily,this.textInput.style.backgroundColor=t.backgroundColor,this.textInput.style.color=t.color,this.textInput.style.boxShadow=t.boxShadow,this.textInput.style.minWidth=t.minWidth,this.textInput.style.maxWidth=t.maxWidth}setTextStyle(t){this.textStyle=Object.assign(Object.assign({},this.textStyle),t),this.applyInputStyle()}setInputStyle(t){this.textStyle.inputStyle=Object.assign(Object.assign({},this.textStyle.inputStyle),t),this.applyInputStyle()}setSelectionStyle(t){void 0!==t.selectedBorderColor&&(this.textStyle.selectedBorderColor=t.selectedBorderColor),void 0!==t.selectedBackgroundColor&&(this.textStyle.selectedBackgroundColor=t.selectedBackgroundColor)}getCurrentStyle(){return{font:this.textStyle.font,color:this.textStyle.color,backgroundColor:this.textStyle.backgroundColor}}updateTextAnnotationStyle(t,e){if(t<0||t>=this.textAnnotations.length)return!1;const i=this.textAnnotations[t];return i.style=Object.assign(Object.assign({},i.style||this.getCurrentStyle()),e),!0}addTextAnnotation(t,e,i=""){var n;this.ctx.font=this.textStyle.font;const s=i||"输入文字...",a=this.ctx.measureText(s);let o;if(a.actualBoundingBoxAscent&&a.actualBoundingBoxDescent)o=a.actualBoundingBoxAscent+a.actualBoundingBoxDescent;else{o=1.2*parseInt((null===(n=this.textStyle.font.match(/\d+/))||void 0===n?void 0:n[0])||"16")}const r={position:{x:t,y:e},text:i,style:this.getCurrentStyle(),width:Math.max(a.width,60),height:o};this.textAnnotations.push(r);const h=this.textAnnotations.length-1;return this.deleteHistory=[],this.startEditing(h),h}updateTextAnnotation(t,e){if(t<0||t>=this.textAnnotations.length)return!1;const i=this.textAnnotations[t];i.text=e,this.ctx.font=this.textStyle.font;const n=this.ctx.measureText(e);return i.width=n.width,i.height=1.2*parseInt(this.textStyle.font),!0}moveTextAnnotation(t,e,i){return!(t<0||t>=this.textAnnotations.length)&&(this.textAnnotations[t].position={x:e,y:i},!0)}removeTextAnnotation(t){if(t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.textAnnotations.splice(t,1),this.editingTextIndex===t?this.cancelEditing():null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,!0}clearTextAnnotations(){this.textAnnotations=[],this.selectedTextIndex=null,this.cancelEditing(),this.deleteHistory=[]}startEditing(t){if(!this.textInput||t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];this.editingTextIndex=t,this.currentEditingIndex=t,this.textBeforeEditing=e.text;const i=this.viewport.offset.x+e.position.x*this.viewport.scale,n=this.viewport.offset.y+e.position.y*this.viewport.scale;return this.textInput.value=e.text,this.textInput.style.left=`${i}px`,this.textInput.style.top=`${n}px`,this.textInput.style.display="block",this.adjustInputWidth(),setTimeout(()=>{this.textInput&&(this.textInput.focus(),this.textInput.select())},10),!0}finishEditing(){if(!this.textInput)return!1;const t=this.currentEditingIndex,e=this.textInput.value.trim();if(null===t||t<0||t>=this.textAnnotations.length)return this.resetEditingState(),!1;if(""===e)this.textAnnotations.splice(t,1);else{const i=this.textAnnotations[t];i.text=e,this.ctx.font=this.textStyle.font;const n=this.ctx.measureText(i.text);i.width=n.width,i.height=1.2*parseInt(this.textStyle.font)}return this.resetEditingState(),!0}cancelEditing(){if(!this.textInput||null===this.editingTextIndex)return!1;this.textInput.value=this.textBeforeEditing;const t=this.editingTextIndex;if(t>=0&&t<this.textAnnotations.length){""===this.textAnnotations[t].text&&""===this.textBeforeEditing&&this.textAnnotations.splice(t,1)}return this.resetEditingState(),!0}deleteEditingAnnotation(){if(null===this.editingTextIndex)return!1;const t=this.editingTextIndex;return this.textInput&&(this.textInput.style.display="none"),t>=0&&t<this.textAnnotations.length&&this.textAnnotations.splice(t,1),this.resetEditingState(),!0}resetEditingState(){this.textInput&&(this.textInput.style.display="none"),this.editingTextIndex=null,this.currentEditingIndex=null,this.textBeforeEditing=""}adjustInputWidth(){if(!this.textInput||null===this.editingTextIndex)return;this.ctx.font=this.textStyle.font;const t=this.textInput.value||this.textInput.placeholder||"",e=this.ctx.measureText(t).width,i=Math.min(Math.max(e+24,60),200);this.textInput.style.width=`${i}px`}startMoving(t,e){return!(e<0||e>=this.textAnnotations.length)&&(this.editingTextIndex=e,this.isTextMoving=!0,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}moveAnnotation(t){if(!this.isTextMoving||null===this.editingTextIndex)return!1;const e=t.clientX-this.textMoveStart.x,i=t.clientY-this.textMoveStart.y,n=this.textAnnotations[this.editingTextIndex];return!!n&&(n.position.x+=e/this.viewport.scale,n.position.y+=i/this.viewport.scale,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}finishMoving(){this.isTextMoving=!1}checkTextClick(t,e){for(let i=this.textAnnotations.length-1;i>=0;i--){const n=this.textAnnotations[i],s=this.viewport.offset.x+n.position.x*this.viewport.scale,a=this.viewport.offset.y+n.position.y*this.viewport.scale,o=Math.max(n.width,60)+2*this.textStyle.padding,r=n.height+2*this.textStyle.padding;if(t>=s&&t<=s+o&&e>=a&&e<=a+r)return i}return null}checkTextClickForMove(t){const e=this.checkTextClick(t.offsetX,t.offsetY);return null!==e?(this.startMoving(t,e),{index:e,handled:!0}):{index:-1,handled:!1}}getTextAnnotations(){return[...this.textAnnotations]}withdraw(){if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.textAnnotations.splice(e,0,t),!0}return this.textAnnotations.length>0&&(this.textAnnotations.pop(),!0)}selectTextAnnotation(t){return t<0||t>=this.textAnnotations.length?(this.deselectTextAnnotation(),!1):(this.selectedTextIndex=t,null!==this.editingTextIndex&&this.finishEditing(),!0)}deselectTextAnnotation(){this.selectedTextIndex=null}deleteSelectedTextAnnotation(){if(null===this.selectedTextIndex)return!1;const t=this.selectedTextIndex,e=this.textAnnotations[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.textAnnotations.splice(t,1),this.selectedTextIndex=null,null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,!0}getSelectedTextAnnotation(){if(null===this.selectedTextIndex)return null;const t=this.textAnnotations[this.selectedTextIndex];return t?{index:this.selectedTextIndex,data:t}:null}destroy(){this.textInput&&this.textInput.parentNode&&this.textInput.parentNode.removeChild(this.textInput)}}class l{constructor(t,e,i,n,s){this.ctx=t,this.viewport=e,this.annotationManager=i,this.textManager=n,this.canvas=s}render(t){this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.drawBackgroundImage(t),this.drawAnnotations(),this.drawTextAnnotations()}drawBackgroundImage(t){this.ctx.drawImage(t,this.viewport.offset.x,this.viewport.offset.y,this.viewport.originalWidth*this.viewport.scale,this.viewport.originalHeight*this.viewport.scale)}drawAnnotations(){this.annotationManager.recordList.forEach((t,e)=>{var i;const n=this.annotationManager.getAnnotationStyle(t);this.ctx.strokeStyle=n.strokeColor,this.ctx.lineWidth=n.lineWidth,this.setLineDash(n.lineStyle||"solid"),this.ctx.fillStyle=this.ctx.strokeStyle;const s=(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.index)===e;if("rect"===t.type)this.drawRect(t.data[0],s);else if("polygon"===t.type){const e=n.vertexStyle||this.annotationManager.getVertexStyle();this.drawPolygon(t.data,"fullfilled"===t.status,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,this.setLineDash(this.annotationManager.lineStyle),"rect"===this.annotationManager.operate.type?this.drawRect(this.annotationManager.operate.data[0],!1):"polygon"===this.annotationManager.operate.type&&this.drawCurrentPolygon()),this.ctx.setLineDash([]),this.drawSelectionHighlight()}setLineDash(t){switch(t){case"dashed":this.ctx.setLineDash([10,5]);break;case"dotted":this.ctx.setLineDash([2,4]);break;default:this.ctx.setLineDash([])}}drawRect(t,e=!1){this.ctx.strokeRect(this.viewport.offset.x+t.start.x*this.viewport.scale,this.viewport.offset.y+t.start.y*this.viewport.scale,t.width*this.viewport.scale,t.height*this.viewport.scale)}drawPolygon(t,e,i){if(0!==t.length){if(this.ctx.beginPath(),t.forEach((t,e)=>{const i=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(i,n):this.ctx.lineTo(i,n)}),e&&t.length>1){const e=t[0];this.ctx.lineTo(this.viewport.offset.x+e.point.x*this.viewport.scale,this.viewport.offset.y+e.point.y*this.viewport.scale)}this.ctx.stroke(),this.drawPolygonVertices(t,i)}}drawPolygonVertices(t,e){const i=e||this.annotationManager.getVertexStyle(),n=i.size/2;t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),s=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);switch(this.ctx.fillStyle=i.fillColor,this.ctx.strokeStyle=i.strokeColor,this.ctx.lineWidth=i.strokeWidth,this.ctx.beginPath(),i.shape){case"square":this.ctx.rect(e-n,s-n,2*n,2*n);break;case"diamond":this.ctx.moveTo(e,s-n),this.ctx.lineTo(e+n,s),this.ctx.lineTo(e,s+n),this.ctx.lineTo(e-n,s),this.ctx.closePath();break;default:this.ctx.arc(e,s,n,0,2*Math.PI)}this.ctx.fill(),i.strokeWidth>0&&this.ctx.stroke()})}drawCurrentPolygon(){const t=this.annotationManager.operate.data,e=this.annotationManager.tempPolygonPoint;if(this.ctx.beginPath(),t.forEach((t,e)=>{const i=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(i,n):this.ctx.lineTo(i,n)}),e){const t=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+e.y*this.viewport.scale);this.ctx.lineTo(t,i)}if(this.ctx.stroke(),this.drawPolygonVertices(t,this.annotationManager.getVertexStyle()),e){const t=this.annotationManager.getVertexStyle(),i=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+e.y*this.viewport.scale),s=t.size/2;switch(this.ctx.fillStyle=t.fillColor,this.ctx.strokeStyle=t.strokeColor,this.ctx.lineWidth=t.strokeWidth,this.ctx.beginPath(),t.shape){case"square":this.ctx.rect(i-s,n-s,2*s,2*s);break;case"diamond":this.ctx.moveTo(i,n-s),this.ctx.lineTo(i+s,n),this.ctx.lineTo(i,n+s),this.ctx.lineTo(i-s,n),this.ctx.closePath();break;default:this.ctx.arc(i,n,s,0,2*Math.PI)}this.ctx.fill(),t.strokeWidth>0&&this.ctx.stroke()}}drawSelectionHighlight(){const t=this.annotationManager.selectedAnnotation;if(!t)return;const e=this.annotationManager.recordList[t.index];if(!e)return;const i=this.annotationManager.selectionStyle;this.ctx.save(),"rect"===e.type?this.drawRectSelectionHighlight(e.data[0],i):"polygon"===e.type&&this.drawPolygonSelectionHighlight(e.data,i),this.ctx.restore()}drawRectSelectionHighlight(t,e){const i=this.viewport.offset.x+t.start.x*this.viewport.scale,n=this.viewport.offset.y+t.start.y*this.viewport.scale,s=t.width*this.viewport.scale,a=t.height*this.viewport.scale;this.ctx.fillStyle=e.fillColor,this.ctx.fillRect(i,n,s,a),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.strokeRect(i,n,s,a);const o=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),this.ctx.fillRect(i-o/2,n-o/2,o,o),this.ctx.fillRect(i+s-o/2,n-o/2,o,o),this.ctx.fillRect(i-o/2,n+a-o/2,o,o),this.ctx.fillRect(i+s-o/2,n+a-o/2,o,o)}drawPolygonSelectionHighlight(t,e){this.ctx.beginPath(),t.forEach((t,e)=>{const i=this.viewport.offset.x+t.point.x*this.viewport.scale,n=this.viewport.offset.y+t.point.y*this.viewport.scale;0===e?this.ctx.moveTo(i,n):this.ctx.lineTo(i,n)}),this.ctx.closePath(),this.ctx.fillStyle=e.fillColor,this.ctx.fill(),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.stroke();const i=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);this.ctx.fillRect(e-i/2,n-i/2,i,i)})}drawAnnotationTitle(t){var e,i,n;if(!t.title)return;const s=this.annotationManager.getEffectiveTitleStyle(t),a=this.annotationManager.getEffectiveTitlePosition(t),o=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,c=null!==(i=s.paddingY)&&void 0!==i?i:3,d=null!==(n=s.borderRadius)&&void 0!==n?n:4;this.ctx.save(),this.ctx.font=o;const g=this.ctx.measureText(t.title).width,x=o.match(/(\d+)px/),p=x?parseInt(x[1]):12;let f,u,y,v;if("rect"===t.type){const e=t.data[0];f=this.viewport.offset.x+e.start.x*this.viewport.scale,u=this.viewport.offset.y+e.start.y*this.viewport.scale,y=e.width*this.viewport.scale,v=e.height*this.viewport.scale}else{const e=t.data;if(0===e.length)return void this.ctx.restore();let i=1/0,n=1/0,s=-1/0,a=-1/0;e.forEach(t=>{const e=this.viewport.offset.x+t.point.x*this.viewport.scale,o=this.viewport.offset.y+t.point.y*this.viewport.scale;e<i&&(i=e),o<n&&(n=o),e>s&&(s=e),o>a&&(a=o)}),f=i,u=n,y=s-i,v=a-n}const M=g+2*l,w=p+2*c,A=a.vertical||"top",S=a.offsetX||0,T=a.offsetY||0;let b;switch(A){case"bottom":b=u+v+4+T;break;case"inside-top":b=u+4+T;break;default:b=u-w-4+T}let I;switch(a.align||"center"){case"left":I=f+S;break;case"right":I=f+y-M+S;break;default:I=f+y/2-M/2+S}this.ctx.fillStyle=h,this.ctx.setLineDash([]),this.ctx.beginPath(),this.ctx.roundRect(I,b,M,w,d),this.ctx.fill(),this.ctx.fillStyle=r,this.ctx.textAlign="left",this.ctx.textBaseline="top",this.ctx.fillText(t.title,I+l,b+c),this.ctx.restore()}drawTextAnnotations(){const t=this.textManager.textStyle;this.textManager.textAnnotations.forEach((e,i)=>{if(this.textManager.editingTextIndex===i&&this.textManager.textInput&&"none"!==this.textManager.textInput.style.display)return;if(!e.text)return;const n=e.style||{font:t.font,color:t.color,backgroundColor:t.backgroundColor},s=this.viewport.offset.x+e.position.x*this.viewport.scale,a=this.viewport.offset.y+e.position.y*this.viewport.scale,o=this.textManager.selectedTextIndex===i;this.ctx.font=n.font;const r=this.ctx.measureText(e.text),h=r.actualBoundingBoxAscent||.8*e.height,l=h+(r.actualBoundingBoxDescent||.2*e.height),c=t.borderRadius,d=s,g=a,x=e.width+2*t.padding,p=l+2*t.padding;this.ctx.fillStyle=n.backgroundColor,this.ctx.beginPath(),this.ctx.roundRect(d,g,x,p,c),this.ctx.fill(),o&&(this.ctx.strokeStyle=t.selectedBorderColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.beginPath(),this.ctx.roundRect(d,g,x,p,c),this.ctx.stroke(),this.ctx.setLineDash([]));const f=s+t.padding,u=a+t.padding+h;this.ctx.fillStyle=n.color,this.ctx.fillText(e.text,f,u)})}drawForExport(t,e,i,n){t.drawImage(e,0,0,i,n),this.annotationManager.recordList.forEach(e=>{const i=this.annotationManager.getAnnotationStyle(e);if(t.strokeStyle=i.strokeColor,t.lineWidth=i.lineWidth,"rect"===e.type){const i=e.data[0];t.strokeRect(i.start.x,i.start.y,i.width,i.height)}else if("polygon"===e.type&&"fullfilled"===e.status){t.beginPath(),e.data.forEach((e,i)=>{0===i?t.moveTo(e.point.x,e.point.y):t.lineTo(e.point.x,e.point.y)});const n=e.data[0];t.lineTo(n.point.x,n.point.y),t.stroke(),e.data.forEach(e=>{t.beginPath(),t.arc(e.point.x,e.point.y,4,0,2*Math.PI),t.fillStyle=i.strokeColor,t.fill()})}}),this.textManager.textAnnotations.forEach(e=>{const i=this.textManager.textStyle,n=e.style||{font:i.font,color:i.color,backgroundColor:i.backgroundColor};t.font=n.font;const s=t.measureText(e.text),a=s.actualBoundingBoxAscent||.8*e.height,o=a+(s.actualBoundingBoxDescent||.2*e.height),r=e.position.x,h=e.position.y,l=e.width+2*i.padding,c=o+2*i.padding,d=i.borderRadius;t.fillStyle=n.backgroundColor,t.roundRect?(t.roundRect(r,h,l,c,d),t.fill()):t.fillRect(r,h,l,c),t.fillStyle=n.color,t.fillText(e.text,e.position.x+i.padding,e.position.y+i.padding+a)}),this.annotationManager.enableTitle&&this.annotationManager.recordList.forEach(e=>{var i,n,s;if(!e.title)return;const a=this.annotationManager.getEffectiveTitleStyle(e),o=this.annotationManager.getEffectiveTitlePosition(e),r=a.font||"12px Arial",h=a.color||"#FFFFFF",l=a.backgroundColor||"rgba(0, 0, 0, 0.7)",c=null!==(i=a.paddingX)&&void 0!==i?i:6,d=null!==(n=a.paddingY)&&void 0!==n?n:3,g=null!==(s=a.borderRadius)&&void 0!==s?s:4;t.font=r;const x=t.measureText(e.title).width,p=r.match(/(\d+)px/),f=p?parseInt(p[1]):12;let u,y,v,M;if("rect"===e.type){const t=e.data[0];u=t.start.x,y=t.start.y,v=t.width,M=t.height}else{const t=e.data;if(0===t.length)return;let i=1/0,n=1/0,s=-1/0,a=-1/0;t.forEach(t=>{t.point.x<i&&(i=t.point.x),t.point.y<n&&(n=t.point.y),t.point.x>s&&(s=t.point.x),t.point.y>a&&(a=t.point.y)}),u=i,y=n,v=s-i,M=a-n}const w=x+2*c,A=f+2*d,S=o.vertical||"top",T=o.offsetX||0,b=o.offsetY||0;let I;switch(S){case"bottom":I=y+M+4+b;break;case"inside-top":I=y+4+b;break;default:I=y-A-4+b}let m;switch(o.align||"center"){case"left":m=u+T;break;case"right":m=u+v-w+T;break;default:m=u+v/2-w/2+T}t.fillStyle=l,t.roundRect?(t.roundRect(m,I,w,A,g),t.fill()):t.fillRect(m,I,w,A),t.fillStyle=h,t.textAlign="left",t.textBaseline="top",t.fillText(e.title,m+c,I+d)})}}class c{constructor(t,e,i,n,s,a,o,r,h){this.canvas=t,this.viewport=e,this.annotationManager=i,this.textManager=n,this.renderer=s,this.getDrawType=a,this.getBgImage=o,this.renderCallback=r,this.setDrawTypeCallback=h,this.isDragging=!1,this.dragStart={x:0,y:0},this.justFinishedMove=!1,this.justDeselected=!1}handleWheel(t){if(t.preventDefault(),!this.getBgImage())return;const e=t.deltaY>0?-.02:.02,i=this.viewport.scale,n=Math.max(this.viewport.minScale,Math.min(i+e,this.viewport.maxScale)),s=this.canvas.getBoundingClientRect(),a=t.clientX-s.left,o=t.clientY-s.top,r=(a-this.viewport.offset.x)/i,h=(o-this.viewport.offset.y)/i;this.viewport.scale=n;const l=r*n+this.viewport.offset.x,c=h*n+this.viewport.offset.y;this.viewport.offset.x+=a-l,this.viewport.offset.y+=o-c,this.viewport.calculateBoundaries(),this.viewport.constrainViewport(),this.viewport.isInitialScale=this.viewport.scale===this.viewport.initialScale,this.renderCallback()}handleMouseDown(t){var e,i;if(0!==t.button)return;const n=this.getDrawType(),s=this.getBgImage();if(this.annotationManager.selectedAnnotation&&s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(i)return this.annotationManager.startResizing(i,e),void this.renderCallback()}if("text"===n){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getAnnotationAtPoint(e);if("rect"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(e);if("polygon"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();if(this.annotationManager.selectedAnnotation)return this.annotationManager.deselectAnnotation(),void this.renderCallback()}return null!==this.textManager.selectedTextIndex?(this.textManager.deselectTextAnnotation(),void this.renderCallback()):void this.handleTextModeClick(t)}if(!s)return;const a=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if("rect"===n){if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return this.annotationManager.startResizing(e,a),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(a);return i&&"rect"===i.type?(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const i=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==i)return this.textManager.selectedTextIndex===i?this.textManager.startMoving(t,i):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(i)),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(a);if("polygon"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const s=this.annotationManager.getAnnotationAtPoint(a);if("rect"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.startRectDrawing(a)}else if("polygon"===n){if("polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e&&"polygon-vertex"===e.type)return this.annotationManager.startResizing(e,a),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(a);return i&&"polygon"===i.type?(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(a);if("rect"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const s=this.annotationManager.getAnnotationAtPoint(a);if("polygon"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.isDrawing?this.checkPolygonPointValid(a)&&this.annotationManager.addPolygonPoint(a):this.annotationManager.startPolygonDrawing(a),this.annotationManager.updatePolygonTempPoint(a),this.renderCallback()}else if("drag"===n){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return this.annotationManager.startResizing(e,a),void this.renderCallback()}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(this.handleRectModeClick(t,a))return;if(this.handlePolygonModeClick(t,a))return;this.isDragging=!0,this.dragStart={x:t.clientX,y:t.clientY},this.canvas.style.cursor="grabbing"}else""===n&&this.handleNoModeClick(t,a)}checkTextClickInDragMode(t){return!!this.textManager.checkTextClickForMove(t).handled&&(this.canvas.style.cursor="grabbing",!0)}handleTextModeClick(t){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.startMoving(t,e),this.canvas.style.cursor="grabbing",this.renderCallback(),!0;const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return this.textManager.addTextAnnotation(i.x,i.y),!0}handleRectModeClick(t,e){var i,n;if("rect"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)){const i=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(i)return this.annotationManager.startResizing(i,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===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handlePolygonModeClick(t,e){var i,n;if("polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)){const i=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(i&&"polygon-vertex"===i.type)return this.annotationManager.startResizing(i,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===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handleRectModeClickForMove(t,e){const i=this.annotationManager.getAnnotationAtPoint(e);return!(!i||"rect"!==i.type)&&(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handlePolygonModeClickForMove(t,e){const i=this.annotationManager.getAnnotationAtPoint(e);return!(!i||"polygon"!==i.type)&&(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handleNoModeClick(t,e){const i=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==i)return this.textManager.selectedTextIndex===i?this.textManager.startMoving(t,i):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(i)),void this.renderCallback();this.textManager.deselectTextAnnotation();const n=this.annotationManager.getAnnotationAtPoint(e);n?(this.annotationManager.selectAnnotation(n.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,i=t.clientY-this.dragStart.y;return this.viewport.updateOffset(e,i),this.dragStart={x:t.clientX,y:t.clientY},void this.renderCallback()}if(this.textManager.isTextMoving&&null!==this.textManager.editingTextIndex)this.textManager.moveAnnotation(t)&&this.renderCallback();else if((this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&this.annotationManager.selectedAnnotation)this.handleAnnotationMove(t);else{if(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving||this.updateCursor(t),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updateRectDrawing(e),this.renderCallback()}if("polygon"===e&&this.annotationManager.isDrawing){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updatePolygonTempPoint(e),this.renderCallback()}}}handleAnnotationMove(t){var e,i;if(this.annotationManager.isResizing&&this.annotationManager.activeHandle){const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return"rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)?this.annotationManager.resizeRect(n):"polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)&&this.annotationManager.resizePolygon(n),void this.renderCallback()}if(!this.annotationManager.isMovingAnnotation||!this.annotationManager.selectedAnnotation)return;const n=(t.clientX-this.annotationManager.annotationMoveStart.x)/this.viewport.scale,s=(t.clientY-this.annotationManager.annotationMoveStart.y)/this.viewport.scale;this.annotationManager.moveSelectedAnnotation(n,s),this.annotationManager.annotationMoveStart={x:t.clientX,y:t.clientY},this.renderCallback()}updateCursor(t){const e=this.getDrawType();if("text"===e){if(this.getBgImage()){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(this.annotationManager.getAnnotationAtPoint(e))return void(this.canvas.style.cursor="move")}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);return void(this.canvas.style.cursor=null!==e?"move":"crosshair")}"rect"!==e?"polygon"!==e?"drag"!==e?""!==e?this.canvas.style.cursor="default":this.updateNoModeCursor(t):this.updateDragModeCursor(t):this.updatePolygonModeCursor(t):this.updateRectModeCursor(t)}updateRectModeCursor(t){var e;if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void(this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize")}const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(i)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updatePolygonModeCursor(t){var e;if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){if(this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="crosshair")}const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(i)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updateDragModeCursor(t){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(null!==this.textManager.checkTextClick(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="move");const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=i?"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),i=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=i?"move":"default"}handleMouseUp(t){if(this.isDragging){this.isDragging=!1;const t=this.getDrawType();return void(this.canvas.style.cursor="drag"===t?"grab":"default")}if(this.textManager.isTextMoving){this.justFinishedMove=!0,this.textManager.finishMoving();const t=this.getDrawType();"drag"===t?this.canvas.style.cursor="grab":""===t?this.canvas.style.cursor="move":(this.textManager.editingTextIndex=null,this.canvas.style.cursor="default")}(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&(this.justFinishedMove=!0,this.annotationManager.finishMovingAnnotation(),this.canvas.style.cursor=this.annotationManager.selectedAnnotation?"move":"default"),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type&&(this.annotationManager.finishRectDrawing(),this.renderCallback())}handleMouseLeave(t){(this.isDragging||this.textManager.isTextMoving||this.annotationManager.isResizing||this.annotationManager.isMovingAnnotation)&&this.handleMouseUp(t)}handleDoubleClick(t){if(!this.getBgImage())return;this.justFinishedMove=!1;const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return void this.textManager.startEditing(e);if(this.annotationManager.selectedAnnotation){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getAnnotationAtPoint(e);if(i&&i.index===this.annotationManager.selectedAnnotation.index)return void this.annotationManager.startTitleEditing(i.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 i=this.getDrawType();if(!this.getBgImage()||"polygon"!==i||this.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;if(this.justDeselected)return void(this.justDeselected=!1);if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type))return;const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.checkPolygonPointValid(n)&&(this.annotationManager.isDrawing?this.annotationManager.addPolygonPoint(n):this.annotationManager.startPolygonDrawing(n)),this.annotationManager.updatePolygonTempPoint(n),this.renderCallback()}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 this.annotationManager.withdraw()||this.textManager.withdraw(),void this.renderCallback();if(" "===t.key)return this.viewport.resetToInitial(),void this.renderCallback();if("Escape"!==t.key){if("Delete"===t.key||"Backspace"===t.key){if(null!==this.textManager.editingTextIndex)return this.textManager.removeTextAnnotation(this.textManager.editingTextIndex),void this.renderCallback();if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.renderCallback();this.annotationManager.selectedAnnotation&&(this.annotationManager.deleteSelectedAnnotation(),this.renderCallback())}}else this.annotationManager.isDrawing?(this.annotationManager.cancelDrawing(),this.renderCallback()):this.annotationManager.selectedAnnotation&&(this.annotationManager.deselectAnnotation(),this.renderCallback())}}}class d{constructor(t){this.canvas=document.createElement("canvas"),this.bgImage=null,this.bgImageSrc="",this.bgImageExt="jpeg",this.drawType="";const{drawType:e,useEvents:i=!0,id:n="container",annotationColor:s,lineStyle:a,vertexStyle:d,textStyle:g,enableTitle:x=!1}=t,p=document.getElementById(n);if(!p)throw new Error(`Container with id "${n}" not found`);this.container=p,"absolute"!==p.style.position&&"fixed"!==p.style.position&&"relative"!==p.style.position&&(p.style.position="relative"),this.ctx=this.canvas.getContext("2d"),this.viewport=new o,this.viewport.setSize(p.clientWidth,p.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",p.appendChild(this.canvas),this.annotationManager=new r(this.viewport,this.container,()=>this.render()),s&&this.annotationManager.setColorConfig(s),a&&this.annotationManager.setLineStyle(a),d&&this.annotationManager.setVertexStyle(d),this.annotationManager.enableTitle=x,x&&this.annotationManager.initTitleSupport(),this.textManager=new h(this.viewport,this.container,this.ctx,()=>this.render()),g&&this.textManager.setTextStyle(g),this.renderer=new l(this.ctx,this.viewport,this.annotationManager,this.textManager,this.canvas),this.eventHandler=new c(this.canvas,this.viewport,this.annotationManager,this.textManager,this.renderer,()=>this.drawType,()=>this.bgImage,()=>this.render(),t=>this.setDrawType(t)),this.events={wheel:t=>this.eventHandler.handleWheel(t),mousedown:t=>this.eventHandler.handleMouseDown(t),mousemove:t=>this.eventHandler.handleMouseMove(t),mouseup:t=>this.eventHandler.handleMouseUp(t),mouseleave:t=>this.eventHandler.handleMouseLeave(t),dblclick:t=>this.eventHandler.handleDoubleClick(t),click:t=>this.eventHandler.handleClick(t),keydown:t=>this.eventHandler.handleKeyDown(t)},this.setDrawType(e||""),i&&this.addEventListeners()}setDrawType(t){"polygon"===this.drawType&&this.annotationManager.isDrawing&&this.annotationManager.operate.data.length>0?console.warn("Cannot switch mode while polygon is being drawn. Please complete or cancel the polygon first."):this.drawType!==t&&(this.annotationManager.operate.data=[],this.annotationManager.isDrawing=!1,this.annotationManager.tempPolygonPoint=null,""!==t&&this.deselectAnnotation(),this.annotationManager.operate.type=t,this.drawType=t,this.canvas.style.cursor="drag"===t?"grab":"text"===t?"text":"default")}drawImage(t){this.bgImageSrc=t,this.bgImageExt=i(t);const e=new Image;e.crossOrigin="anonymous",e.src=t,e.onload=()=>{this.bgImage=e,this.viewport.setOriginalSize(e.width,e.height),this.viewport.calculateInitialView(),this.render()}}render(){this.renderer.render(this.bgImage)}clear(t=""){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.setDrawType(t),this.render()}withdraw(){const t=this.annotationManager.withdraw(),e=this.textManager.withdraw();(t||e)&&this.render()}resize(){const t=this.canvas.parentElement;t&&(this.viewport.setSize(t.clientWidth,t.clientHeight),this.canvas.width=this.viewport.width,this.canvas.height=this.viewport.height,this.canvas.style.width=`${this.viewport.width}px`,this.canvas.style.height=`${this.viewport.height}px`,this.render())}addEventListeners(){this.canvas.addEventListener("mousedown",this.events.mousedown),this.canvas.addEventListener("mousemove",this.events.mousemove),this.canvas.addEventListener("mouseup",this.events.mouseup),this.canvas.addEventListener("mouseleave",this.events.mouseleave),this.canvas.addEventListener("wheel",this.events.wheel),this.canvas.addEventListener("contextmenu",t=>t.preventDefault()),document.addEventListener("keydown",this.events.keydown),this.handleClickEventListener()}handleClickEventListener(){let t=null,e=0;this.canvas.addEventListener("click",i=>{if(this.eventHandler.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;const n=this.eventHandler.justFinishedMove;n&&(this.eventHandler.justFinishedMove=!1),e++,1===e?t=window.setTimeout(()=>{1!==e||n||this.events.click(i),e=0,t=null},300):2===e&&(this.eventHandler.justFinishedMove=!1,this.events.dblclick(i),e=0,null!==t&&(clearTimeout(t),t=null))})}changeScale(t){if(!this.bgImage)return;const e=a(this.viewport.scale,t),i=this.viewport.width/2,n=this.viewport.height/2,s=this.viewport.scale+e;this.viewport.updateScale(s,i,n),this.render()}clearCanvas(t=!1,e=!0){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.textManager.deselectTextAnnotation(),!t&&e&&(this.bgImage=null,this.bgImageSrc="",this.viewport.setOriginalSize(0,0),this.viewport.reset()),this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.bgImage&&this.render(),"drag"===this.drawType&&(this.canvas.style.cursor="default")}clearAnnotations(){this.clearCanvas(!0,!1)}getAnnotations(){return this.annotationManager.getAnnotations()}setAnnotationTitle(t,e){const i=this.annotationManager.setTitle(t,e);return i&&this.render(),i}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 i=this.annotationManager.setAnnotationTitleStyle(t,e);return i&&this.render(),i}setAnnotationTitlePosition(t,e){const i=this.annotationManager.setAnnotationTitlePosition(t,e);return i&&this.render(),i}getTextAnnotations(){return this.textManager.getTextAnnotations()}exportAnnotationImage(){return new Promise((t,e)=>{if(!this.bgImage)return void e(new Error("No background image loaded"));const i=document.createElement("canvas");i.width=this.viewport.originalWidth,i.height=this.viewport.originalHeight;const n=i.getContext("2d");if(!n)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(n,s,this.viewport.originalWidth,this.viewport.originalHeight);const e=i.toDataURL(`image/${this.bgImageExt}`,.7);t(e)}catch(i){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 n(t,e)}static base64ToBlob(t){return s(t)}addTextAnnotation(t,e,i=""){this.textManager.addTextAnnotation(t,e,i),this.render()}updateTextAnnotation(t,e){this.textManager.updateTextAnnotation(t,e)&&this.render()}moveTextAnnotation(t,e,i){this.textManager.moveTextAnnotation(t,e,i)&&this.render()}removeTextAnnotation(t){this.textManager.removeTextAnnotation(t)&&this.render()}clearTextAnnotations(){this.textManager.clearTextAnnotations(),this.render()}selectAnnotation(t){this.annotationManager.selectAnnotation(t)&&this.render()}deselectAnnotation(){this.annotationManager.deselectAnnotation(),this.textManager.deselectTextAnnotation(),this.textManager.editingTextIndex=null,this.render()}getSelectedAnnotation(){const t=this.annotationManager.getSelectedAnnotation();if(t)return t;const e=this.textManager.getSelectedTextAnnotation();return e?{index:e.index,type:"text",data:e.data}:null}deleteSelectedAnnotation(){if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.render();this.annotationManager.deleteSelectedAnnotation()&&this.render()}moveSelectedAnnotation(t,e){this.annotationManager.moveSelectedAnnotation(t,e)&&this.render()}setAnnotationColor(t){this.annotationManager.setColorConfig(t),this.render()}getAnnotationColor(){return this.annotationManager.getColorConfig()}updateSelectedAnnotationStyle(){const t=this.annotationManager.selectedAnnotation;if(!t)return!1;const e=this.annotationManager.recordList[t.index];return!!e&&(e.style=this.annotationManager.getCurrentStyle(),this.render(),!0)}setLineStyle(t){this.annotationManager.setLineStyle(t),this.render()}getLineStyle(){return this.annotationManager.getLineStyle()}setVertexStyle(t){this.annotationManager.setVertexStyle(t),this.render()}getVertexStyle(){return this.annotationManager.getVertexStyle()}setTextStyle(t){this.textManager.setTextStyle(t),this.render()}updateTextAnnotationStyle(t,e){const i=this.textManager.updateTextAnnotationStyle(t,e);return i&&this.render(),i}setTextInputStyle(t){this.textManager.setInputStyle(t)}setTextSelectionStyle(t){this.textManager.setSelectionStyle(t),this.render()}destroy(){this.textManager.destroy(),this.annotationManager.destroyTitleInput(),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}export{r as AnnotationManager,d as Drawer,c as EventHandler,l as Renderer,h as TextAnnotationManager,o as ViewportManager,s as base64ToBlob,n as base64ToFile,d as default,i as getImageTypeFromUrl,a as getZoomDelta,e as isPointInPolygon,t as isPointInRect};
|
|
1
|
+
function t(t,e){const i=e.width>=0?e.start.x:e.start.x+e.width,n=e.height>=0?e.start.y:e.start.y+e.height,s=Math.abs(e.width),o=Math.abs(e.height);return t.x>=i&&t.x<=i+s&&t.y>=n&&t.y<=n+o}function e(t,e){if(e.length<3)return!1;let i=!1;for(let n=0,s=e.length-1;n<e.length;s=n++){const o=e[n].point.x,a=e[n].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&&(i=!i)}return i}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 n(t,e){const i=t.split(";base64,"),n=i[0].split(":")[1],s=window.atob(i[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:n});return new File([r],e,{type:n})}function s(t){return new Promise((e,i)=>{const n=t.split(";base64,");if(n.length<2)return void i(new Error("Invalid base64 string"));const s=n[0].split(":")[1],o=atob(n[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,i){const n=this.scale,s=(e-this.offset.x)/n,o=(i-this.offset.y)/n;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+=i-r,this.calculateBoundaries(),this.constrainViewport(),this.isInitialScale=this.scale===this.initialScale}resetToInitial(){this.scale=this.initialScale,this.offset=Object.assign({},this.initialOffset),this.calculateBoundaries(),this.isInitialScale=!0}updateOffset(t,e){this.offset.x+=t,this.offset.y+=e,this.constrainViewport()}reset(){this.scale=1,this.minScale=1,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}}class l{constructor(t,e,i,n){this.viewport=t,this.container=e,this.renderCallback=i,this.changeCallback=n,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.applyColorConfig()}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,i){this.changeCallback&&i.id&&this.changeCallback(t,{id:i.id,type:i.type,index:e,data:a(i)})}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()}startRectDrawing(t){this.isDrawing=!0,this.drawStartPoint=t,this.operate={type:"rect",data:[{start:Object.assign({},t),width:0,height:0}],status:"pending"}}updateRectDrawing(t){if(!this.isDrawing||"rect"!==this.operate.type)return;const e=this.operate.data[0];e.width=t.x-this.drawStartPoint.x,e.height=t.y-this.drawStartPoint.y}finishRectDrawing(){if(!this.isDrawing||"rect"!==this.operate.type)return!1;const t=this.operate.data[0];if(Math.abs(t.width)>5&&Math.abs(t.height)>5){const t=Object.assign(Object.assign({},this.operate),{id:r(),style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[],this.notifyChange("create",this.recordList.length-1,t)}return this.operate.data=[],this.isDrawing=!1,!0}startPolygonDrawing(t){this.isDrawing=!0,this.operate={type:"polygon",data:[{point:t}],status:"pending"},this.tempPolygonPoint=t}addPolygonPoint(t){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;const e=this.operate.data.length>0?this.operate.data[this.operate.data.length-1]:null;return!(e&&Math.abs(e.point.x-t.x)<=5&&Math.abs(e.point.y-t.y)<=5)&&(this.operate.data.push({point:t}),!0)}updatePolygonTempPoint(t){this.tempPolygonPoint=t}finishPolygonDrawing(){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;if(this.operate.data.length>=3){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{id:r(),style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[],this.notifyChange("create",this.recordList.length-1,t)}return this.operate={type:"polygon",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,!0}cancelDrawing(){if(this.isDrawing&&"polygon"===this.operate.type&&this.operate.data.length>=2){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{id:r(),style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[],this.notifyChange("create",this.recordList.length-1,t)}this.operate.data=[],this.isDrawing=!1,this.tempPolygonPoint=null}withdraw(){if(this.operate.data.length>0)return"polygon"===this.operate.type?(this.operate.data.pop(),0===this.operate.data.length&&(this.isDrawing=!1)):(this.operate.data=[],this.isDrawing=!1),!0;if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.recordList.splice(e,0,t),!0}return this.recordList.length>0&&(this.recordList.pop(),!0)}selectAnnotation(t){const e=this.resolveIndex(t);if(e<0||e>=this.recordList.length)return this.deselectAnnotation(),!1;const i=this.recordList[e];return this.selectedAnnotation={index:e,type:i.type},!0}deselectAnnotation(){this.selectedAnnotation=null,this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}deleteSelectedAnnotation(){if(!this.selectedAnnotation)return!1;const t=this.selectedAnnotation.index,e=this.recordList[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.recordList.splice(t,1),this.deselectAnnotation(),this.notifyChange("delete",t,e),!0}startMovingAnnotation(t){return!!this.selectedAnnotation&&(this.isMovingAnnotation=!0,this.annotationMoveStart={x:t.clientX,y:t.clientY},!0)}moveSelectedAnnotation(t,e){if(!this.selectedAnnotation)return!1;const i=this.recordList[this.selectedAnnotation.index];if(!i)return!1;if("rect"===i.type){const n=i.data[0];n.start.x+=t,n.start.y+=e}else if("polygon"===i.type){i.data.forEach(i=>{i.point.x+=t,i.point.y+=e})}return!0}finishMovingAnnotation(){const t=this.isMovingAnnotation||this.isResizing;this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null,t&&this.selectedAnnotation&&this.notifyUpdate(this.selectedAnnotation.index)}startResizing(t,e){if(!this.selectedAnnotation)return!1;this.activeHandle=t,this.isResizing=!0;const i=this.recordList[this.selectedAnnotation.index];return"rect"===i.type?this.originalRect=Object.assign({},i.data[0]):"polygon"===i.type&&(this.originalPolygon=i.data.map(t=>({point:Object.assign({},t.point)}))),!0}resizeRect(t){if(!this.selectedAnnotation||"rect"!==this.selectedAnnotation.type||!this.originalRect||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data[0],i=this.originalRect,n=i.start.x,s=i.start.x+i.width,o=i.start.y,a=i.start.y+i.height;let r,h;switch(this.activeHandle.index){case 0:r=s,h=a;break;case 1:r=n,h=a;break;case 2:r=s,h=o;break;case 3:r=n,h=o;break;default:return!1}const l=Math.min(t.x,r),c=Math.max(t.x,r),d=Math.min(t.y,h),g=Math.max(t.y,h);e.start.x=l,e.start.y=d,e.width=c-l,e.height=g-d;const x=t.x<r,f=t.y<h;return 0===this.activeHandle.index?x||f?!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2):this.activeHandle.index=3:1===this.activeHandle.index?x&&!f?this.activeHandle.index=2:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):2===this.activeHandle.index?!x&&f?this.activeHandle.index=1:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):3===this.activeHandle.index&&(x&&f?this.activeHandle.index=0:!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2)),this.originalRect=Object.assign({},e),!0}resizePolygon(t){if(!this.selectedAnnotation||"polygon"!==this.selectedAnnotation.type||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data,i=this.activeHandle.index;return i>=0&&i<e.length&&(e[i].point.x=t.x,e[i].point.y=t.y,!0)}getAnnotationAtPoint(i){for(let n=this.recordList.length-1;n>=0;n--){const s=this.recordList[n];if("rect"===s.type){if(t(i,s.data[0]))return{index:n,type:"rect"}}else if("polygon"===s.type){if(e(i,s.data))return{index:n,type:"polygon"}}}return null}getHandleAtPoint(t,e){if(!this.selectedAnnotation)return null;const i=this.recordList[this.selectedAnnotation.index],n=this.selectionStyle.handleSize/2;if("rect"===i.type){const s=i.data[0],o=this.viewport.offset.x+s.start.x*this.viewport.scale,a=this.viewport.offset.y+s.start.y*this.viewport.scale,r=s.width*this.viewport.scale,h=s.height*this.viewport.scale,l=[{x:o,y:a,index:0},{x:o+r,y:a,index:1},{x:o,y:a+h,index:2},{x:o+r,y:a+h,index:3}];for(const i of l)if(t>=i.x-n&&t<=i.x+n&&e>=i.y-n&&e<=i.y+n)return{type:"rect-corner",index:i.index}}else if("polygon"===i.type){const s=i.data;for(let i=0;i<s.length;i++){const o=s[i],a=this.viewport.offset.x+o.point.x*this.viewport.scale,r=this.viewport.offset.y+o.point.y*this.viewport.scale;if(t>=a-n&&t<=a+n&&e>=r-n&&e<=r+n)return{type:"polygon-vertex",index:i}}}return null}clear(){this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,this.deselectAnnotation(),this.deleteHistory=[]}getAnnotations(){return this.recordList.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.titlePosition=Object.assign({},this.titlePosition)}setAnnotationTitleStyle(t,e){const i=this.resolveIndex(t);if(i<0||i>=this.recordList.length)return!1;const n=this.recordList[i];return n.style||(n.style=this.getCurrentStyle()),n.style.titleStyle=Object.assign(Object.assign({},n.style.titleStyle||this.titleStyle),e),this.notifyUpdate(i),!0}setAnnotationTitlePosition(t,e){const i=this.resolveIndex(t);if(i<0||i>=this.recordList.length)return!1;const n=this.recordList[i];return n.style||(n.style=this.getCurrentStyle()),n.style.titlePosition=Object.assign(Object.assign({},n.style.titlePosition||this.titlePosition),e),this.notifyUpdate(i),!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 i=this.resolveIndex(t);if(i<0||i>=this.recordList.length)return!1;const n=this.recordList[i];return n.title=e||void 0,e&&this.captureTitleStyleSnapshot(n),this.notifyUpdate(i),!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 i,n;if(this.editingTitleIndex=t,this.deselectAnnotation(),"rect"===e.type){const t=e.data[0];i=this.viewport.offset.x+t.start.x*this.viewport.scale,n=this.viewport.offset.y+t.start.y*this.viewport.scale}else{const t=e.data[0];i=this.viewport.offset.x+t.point.x*this.viewport.scale,n=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=`${i}px`,this.titleInput.style.top=n-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 i=this.recordList[t];i.title=e||void 0,e&&this.captureTitleStyleSnapshot(i),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 c{constructor(t,e,i,n,s){this.viewport=t,this.container=e,this.ctx=i,this.renderCallback=n,this.changeCallback=s,this.textAnnotations=[],this.editingTextIndex=null,this.currentEditingIndex=null,this.isTextMoving=!1,this.textMoveStart={x:0,y:0},this.textBeforeEditing="",this.selectedTextIndex=null,this.textInput=null,this.deleteHistory=[],this.defaultInputStyle={border:"2px solid #00D9FF",borderRadius:"6px",padding:"6px 10px",fontSize:"16px",fontFamily:"Arial, sans-serif",backgroundColor:"#ffffff",color:"#333",boxShadow:"0 4px 12px rgba(0,0,0,0.3)",minWidth:"60px",maxWidth:"200px"},this.textStyle={font:"16px Arial",color:"#FFD700",padding:6,backgroundColor:"rgba(0,0,0,0.6)",borderRadius:4,selectedBorderColor:"#00D9FF",selectedBackgroundColor:"rgba(0,217,255,0.15)",inputStyle:Object.assign({},this.defaultInputStyle)},this.createTextInput()}createTextInput(){this.textInput=document.createElement("input"),this.textInput.type="text",this.textInput.style.position="absolute",this.textInput.style.zIndex="99999",this.textInput.style.display="none",this.textInput.style.outline="none",this.textInput.style.width="fit-content",this.textInput.placeholder="输入文字...",this.applyInputStyle(),this.textInput.addEventListener("blur",()=>{this.finishEditing(),this.renderCallback&&this.renderCallback()}),this.textInput.addEventListener("keydown",t=>{t.stopPropagation(),"Enter"===t.key?(this.finishEditing(),this.renderCallback&&this.renderCallback()):"Escape"===t.key?(t.preventDefault(),this.cancelEditing()):"Delete"===t.key&&""===this.textInput.value&&(t.preventDefault(),this.deleteEditingAnnotation())}),this.textInput.addEventListener("input",()=>{this.adjustInputWidth()}),this.container.appendChild(this.textInput)}applyInputStyle(){if(!this.textInput)return;const t=Object.assign(Object.assign({},this.defaultInputStyle),this.textStyle.inputStyle);this.textInput.style.border=t.border,this.textInput.style.borderRadius=t.borderRadius,this.textInput.style.padding=t.padding,this.textInput.style.fontSize=t.fontSize,this.textInput.style.fontFamily=t.fontFamily,this.textInput.style.backgroundColor=t.backgroundColor,this.textInput.style.color=t.color,this.textInput.style.boxShadow=t.boxShadow,this.textInput.style.minWidth=t.minWidth,this.textInput.style.maxWidth=t.maxWidth}setTextStyle(t){this.textStyle=Object.assign(Object.assign({},this.textStyle),t),this.applyInputStyle()}setInputStyle(t){this.textStyle.inputStyle=Object.assign(Object.assign({},this.textStyle.inputStyle),t),this.applyInputStyle()}setSelectionStyle(t){void 0!==t.selectedBorderColor&&(this.textStyle.selectedBorderColor=t.selectedBorderColor),void 0!==t.selectedBackgroundColor&&(this.textStyle.selectedBackgroundColor=t.selectedBackgroundColor)}getCurrentStyle(){return{font:this.textStyle.font,color:this.textStyle.color,backgroundColor:this.textStyle.backgroundColor}}notifyChange(t,e,i){this.changeCallback&&i.id&&this.changeCallback(t,{id:i.id,type:"text",index:e,data:a(i)})}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 i=this.resolveIndex(t);if(i<0||i>=this.textAnnotations.length)return!1;const n=this.textAnnotations[i];return n.style=Object.assign(Object.assign({},n.style||this.getCurrentStyle()),e),this.notifyChange("update",i,this.textAnnotations[i]),!0}addTextAnnotation(t,e,i=""){var n;this.ctx.font=this.textStyle.font;const s=i||"输入文字...",o=this.ctx.measureText(s);let a;if(o.actualBoundingBoxAscent&&o.actualBoundingBoxDescent)a=o.actualBoundingBoxAscent+o.actualBoundingBoxDescent;else{a=1.2*parseInt((null===(n=this.textStyle.font.match(/\d+/))||void 0===n?void 0:n[0])||"16")}const h={id:r(),position:{x:t,y:e},text:i,style:this.getCurrentStyle(),width:Math.max(o.width,60),height:a};this.textAnnotations.push(h);const l=this.textAnnotations.length-1;return this.notifyChange("create",l,h),this.deleteHistory=[],this.startEditing(l),l}updateTextAnnotation(t,e){const i=this.resolveIndex(t);if(i<0||i>=this.textAnnotations.length)return!1;const n=this.textAnnotations[i];n.text=e,this.ctx.font=this.textStyle.font;const s=this.ctx.measureText(e);return n.width=s.width,n.height=1.2*parseInt(this.textStyle.font),this.notifyChange("update",i,this.textAnnotations[i]),!0}moveTextAnnotation(t,e,i){const n=this.resolveIndex(t);return!(n<0||n>=this.textAnnotations.length)&&(this.textAnnotations[n].position={x:e,y:i},this.notifyChange("update",n,this.textAnnotations[n]),!0)}removeTextAnnotation(t){const e=this.resolveIndex(t);if(e<0||e>=this.textAnnotations.length)return!1;const i=this.textAnnotations[e];return this.deleteHistory.push({annotation:Object.assign({},i),index:e}),this.textAnnotations.splice(e,1),this.notifyChange("delete",e,i),this.editingTextIndex===e?this.resetEditingState():null!==this.editingTextIndex&&this.editingTextIndex>e&&this.editingTextIndex--,!0}clearTextAnnotations(){this.textAnnotations=[],this.selectedTextIndex=null,this.cancelEditing(),this.deleteHistory=[]}startEditing(t){if(!this.textInput||t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];this.editingTextIndex=t,this.currentEditingIndex=t,this.textBeforeEditing=e.text;const i=this.viewport.offset.x+e.position.x*this.viewport.scale,n=this.viewport.offset.y+e.position.y*this.viewport.scale;return this.textInput.value=e.text,this.textInput.style.left=`${i}px`,this.textInput.style.top=`${n}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 i=this.textAnnotations[t];i.text=e,this.ctx.font=this.textStyle.font;const n=this.ctx.measureText(i.text);i.width=n.width,i.height=1.2*parseInt(this.textStyle.font),this.notifyChange("update",t,i)}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,i=Math.min(Math.max(e+24,60),200);this.textInput.style.width=`${i}px`}startMoving(t,e){return!(e<0||e>=this.textAnnotations.length)&&(this.editingTextIndex=e,this.isTextMoving=!0,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}moveAnnotation(t){if(!this.isTextMoving||null===this.editingTextIndex)return!1;const e=t.clientX-this.textMoveStart.x,i=t.clientY-this.textMoveStart.y,n=this.textAnnotations[this.editingTextIndex];return!!n&&(n.position.x+=e/this.viewport.scale,n.position.y+=i/this.viewport.scale,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}finishMoving(){if(this.isTextMoving=!1,null!==this.editingTextIndex){const t=this.textAnnotations[this.editingTextIndex];t&&this.notifyChange("update",this.editingTextIndex,t)}}checkTextClick(t,e){for(let i=this.textAnnotations.length-1;i>=0;i--){const n=this.textAnnotations[i],s=this.viewport.offset.x+n.position.x*this.viewport.scale,o=this.viewport.offset.y+n.position.y*this.viewport.scale,a=Math.max(n.width,60)+2*this.textStyle.padding,r=n.height+2*this.textStyle.padding;if(t>=s&&t<=s+a&&e>=o&&e<=o+r)return i}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--,!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)}}class d{constructor(t,e,i,n,s){this.ctx=t,this.viewport=e,this.annotationManager=i,this.textManager=n,this.canvas=s}render(t){this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.drawBackgroundImage(t),this.drawAnnotations(),this.drawTextAnnotations()}drawBackgroundImage(t){this.ctx.drawImage(t,this.viewport.offset.x,this.viewport.offset.y,this.viewport.originalWidth*this.viewport.scale,this.viewport.originalHeight*this.viewport.scale)}drawAnnotations(){this.annotationManager.recordList.forEach((t,e)=>{var i;const n=this.annotationManager.getAnnotationStyle(t);this.ctx.strokeStyle=n.strokeColor,this.ctx.lineWidth=n.lineWidth,this.setLineDash(n.lineStyle||"solid"),this.ctx.fillStyle=this.ctx.strokeStyle;const s=(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.index)===e;if("rect"===t.type)this.drawRect(t.data[0],s);else if("polygon"===t.type){const e=n.vertexStyle||this.annotationManager.getVertexStyle();this.drawPolygon(t.data,"fullfilled"===t.status,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,this.setLineDash(this.annotationManager.lineStyle),"rect"===this.annotationManager.operate.type?this.drawRect(this.annotationManager.operate.data[0],!1):"polygon"===this.annotationManager.operate.type&&this.drawCurrentPolygon()),this.ctx.setLineDash([]),this.drawSelectionHighlight()}setLineDash(t){switch(t){case"dashed":this.ctx.setLineDash([10,5]);break;case"dotted":this.ctx.setLineDash([2,4]);break;default:this.ctx.setLineDash([])}}drawRect(t,e=!1){this.ctx.strokeRect(this.viewport.offset.x+t.start.x*this.viewport.scale,this.viewport.offset.y+t.start.y*this.viewport.scale,t.width*this.viewport.scale,t.height*this.viewport.scale)}drawPolygon(t,e,i){if(0!==t.length){if(this.ctx.beginPath(),t.forEach((t,e)=>{const i=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(i,n):this.ctx.lineTo(i,n)}),e&&t.length>1){const e=t[0];this.ctx.lineTo(this.viewport.offset.x+e.point.x*this.viewport.scale,this.viewport.offset.y+e.point.y*this.viewport.scale)}this.ctx.stroke(),this.drawPolygonVertices(t,i)}}drawPolygonVertices(t,e){const i=e||this.annotationManager.getVertexStyle(),n=i.size/2;t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),s=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);switch(this.ctx.fillStyle=i.fillColor,this.ctx.strokeStyle=i.strokeColor,this.ctx.lineWidth=i.strokeWidth,this.ctx.beginPath(),i.shape){case"square":this.ctx.rect(e-n,s-n,2*n,2*n);break;case"diamond":this.ctx.moveTo(e,s-n),this.ctx.lineTo(e+n,s),this.ctx.lineTo(e,s+n),this.ctx.lineTo(e-n,s),this.ctx.closePath();break;default:this.ctx.arc(e,s,n,0,2*Math.PI)}this.ctx.fill(),i.strokeWidth>0&&this.ctx.stroke()})}drawCurrentPolygon(){const t=this.annotationManager.operate.data,e=this.annotationManager.tempPolygonPoint;if(this.ctx.beginPath(),t.forEach((t,e)=>{const i=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(i,n):this.ctx.lineTo(i,n)}),e){const t=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+e.y*this.viewport.scale);this.ctx.lineTo(t,i)}if(this.ctx.stroke(),this.drawPolygonVertices(t,this.annotationManager.getVertexStyle()),e){const t=this.annotationManager.getVertexStyle(),i=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+e.y*this.viewport.scale),s=t.size/2;switch(this.ctx.fillStyle=t.fillColor,this.ctx.strokeStyle=t.strokeColor,this.ctx.lineWidth=t.strokeWidth,this.ctx.beginPath(),t.shape){case"square":this.ctx.rect(i-s,n-s,2*s,2*s);break;case"diamond":this.ctx.moveTo(i,n-s),this.ctx.lineTo(i+s,n),this.ctx.lineTo(i,n+s),this.ctx.lineTo(i-s,n),this.ctx.closePath();break;default:this.ctx.arc(i,n,s,0,2*Math.PI)}this.ctx.fill(),t.strokeWidth>0&&this.ctx.stroke()}}drawSelectionHighlight(){const t=this.annotationManager.selectedAnnotation;if(!t)return;const e=this.annotationManager.recordList[t.index];if(!e)return;const i=this.annotationManager.selectionStyle;this.ctx.save(),"rect"===e.type?this.drawRectSelectionHighlight(e.data[0],i):"polygon"===e.type&&this.drawPolygonSelectionHighlight(e.data,i),this.ctx.restore()}drawRectSelectionHighlight(t,e){const i=this.viewport.offset.x+t.start.x*this.viewport.scale,n=this.viewport.offset.y+t.start.y*this.viewport.scale,s=t.width*this.viewport.scale,o=t.height*this.viewport.scale;this.ctx.fillStyle=e.fillColor,this.ctx.fillRect(i,n,s,o),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.strokeRect(i,n,s,o);const a=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),this.ctx.fillRect(i-a/2,n-a/2,a,a),this.ctx.fillRect(i+s-a/2,n-a/2,a,a),this.ctx.fillRect(i-a/2,n+o-a/2,a,a),this.ctx.fillRect(i+s-a/2,n+o-a/2,a,a)}drawPolygonSelectionHighlight(t,e){this.ctx.beginPath(),t.forEach((t,e)=>{const i=this.viewport.offset.x+t.point.x*this.viewport.scale,n=this.viewport.offset.y+t.point.y*this.viewport.scale;0===e?this.ctx.moveTo(i,n):this.ctx.lineTo(i,n)}),this.ctx.closePath(),this.ctx.fillStyle=e.fillColor,this.ctx.fill(),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.stroke();const i=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);this.ctx.fillRect(e-i/2,n-i/2,i,i)})}drawAnnotationTitle(t){var e,i,n;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,c=null!==(i=s.paddingY)&&void 0!==i?i:3,d=null!==(n=s.borderRadius)&&void 0!==n?n:4;this.ctx.save(),this.ctx.font=a;const g=this.ctx.measureText(t.title).width,x=a.match(/(\d+)px/),f=x?parseInt(x[1]):12;let p,u,y,v;if("rect"===t.type){const e=t.data[0];p=this.viewport.offset.x+e.start.x*this.viewport.scale,u=this.viewport.offset.y+e.start.y*this.viewport.scale,y=e.width*this.viewport.scale,v=e.height*this.viewport.scale}else{const e=t.data;if(0===e.length)return void this.ctx.restore();let i=1/0,n=1/0,s=-1/0,o=-1/0;e.forEach(t=>{const e=this.viewport.offset.x+t.point.x*this.viewport.scale,a=this.viewport.offset.y+t.point.y*this.viewport.scale;e<i&&(i=e),a<n&&(n=a),e>s&&(s=e),a>o&&(o=a)}),p=i,u=n,y=s-i,v=o-n}const M=g+2*l,w=f+2*c,A=o.vertical||"top",S=o.offsetX||0,T=o.offsetY||0;let b;switch(A){case"bottom":b=u+v+4+T;break;case"inside-top":b=u+4+T;break;default:b=u-w-4+T}let I;switch(o.align||"center"){case"left":I=p+S;break;case"right":I=p+y-M+S;break;default:I=p+y/2-M/2+S}this.ctx.fillStyle=h,this.ctx.setLineDash([]),this.ctx.beginPath(),this.ctx.roundRect(I,b,M,w,d),this.ctx.fill(),this.ctx.fillStyle=r,this.ctx.textAlign="left",this.ctx.textBaseline="top",this.ctx.fillText(t.title,I+l,b+c),this.ctx.restore()}drawTextAnnotations(){const t=this.textManager.textStyle;this.textManager.textAnnotations.forEach((e,i)=>{if(this.textManager.editingTextIndex===i&&this.textManager.textInput&&"none"!==this.textManager.textInput.style.display)return;if(!e.text)return;const n=e.style||{font:t.font,color:t.color,backgroundColor:t.backgroundColor},s=this.viewport.offset.x+e.position.x*this.viewport.scale,o=this.viewport.offset.y+e.position.y*this.viewport.scale,a=this.textManager.selectedTextIndex===i;this.ctx.font=n.font;const r=this.ctx.measureText(e.text),h=r.actualBoundingBoxAscent||.8*e.height,l=h+(r.actualBoundingBoxDescent||.2*e.height),c=t.borderRadius,d=s,g=o,x=e.width+2*t.padding,f=l+2*t.padding;this.ctx.fillStyle=n.backgroundColor,this.ctx.beginPath(),this.ctx.roundRect(d,g,x,f,c),this.ctx.fill(),a&&(this.ctx.strokeStyle=t.selectedBorderColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.beginPath(),this.ctx.roundRect(d,g,x,f,c),this.ctx.stroke(),this.ctx.setLineDash([]));const p=s+t.padding,u=o+t.padding+h;this.ctx.fillStyle=n.color,this.ctx.fillText(e.text,p,u)})}drawForExport(t,e,i,n){t.drawImage(e,0,0,i,n),this.annotationManager.recordList.forEach(e=>{const i=this.annotationManager.getAnnotationStyle(e);if(t.strokeStyle=i.strokeColor,t.lineWidth=i.lineWidth,"rect"===e.type){const i=e.data[0];t.strokeRect(i.start.x,i.start.y,i.width,i.height)}else if("polygon"===e.type&&"fullfilled"===e.status){t.beginPath(),e.data.forEach((e,i)=>{0===i?t.moveTo(e.point.x,e.point.y):t.lineTo(e.point.x,e.point.y)});const n=e.data[0];t.lineTo(n.point.x,n.point.y),t.stroke(),e.data.forEach(e=>{t.beginPath(),t.arc(e.point.x,e.point.y,4,0,2*Math.PI),t.fillStyle=i.strokeColor,t.fill()})}}),this.textManager.textAnnotations.forEach(e=>{const i=this.textManager.textStyle,n=e.style||{font:i.font,color:i.color,backgroundColor:i.backgroundColor};t.font=n.font;const s=t.measureText(e.text),o=s.actualBoundingBoxAscent||.8*e.height,a=o+(s.actualBoundingBoxDescent||.2*e.height),r=e.position.x,h=e.position.y,l=e.width+2*i.padding,c=a+2*i.padding,d=i.borderRadius;t.fillStyle=n.backgroundColor,t.roundRect?(t.roundRect(r,h,l,c,d),t.fill()):t.fillRect(r,h,l,c),t.fillStyle=n.color,t.fillText(e.text,e.position.x+i.padding,e.position.y+i.padding+o)}),this.annotationManager.enableTitle&&this.annotationManager.recordList.forEach(e=>{var i,n,s;if(!e.title)return;const o=this.annotationManager.getEffectiveTitleStyle(e),a=this.annotationManager.getEffectiveTitlePosition(e),r=o.font||"12px Arial",h=o.color||"#FFFFFF",l=o.backgroundColor||"rgba(0, 0, 0, 0.7)",c=null!==(i=o.paddingX)&&void 0!==i?i:6,d=null!==(n=o.paddingY)&&void 0!==n?n:3,g=null!==(s=o.borderRadius)&&void 0!==s?s:4;t.font=r;const x=t.measureText(e.title).width,f=r.match(/(\d+)px/),p=f?parseInt(f[1]):12;let u,y,v,M;if("rect"===e.type){const t=e.data[0];u=t.start.x,y=t.start.y,v=t.width,M=t.height}else{const t=e.data;if(0===t.length)return;let i=1/0,n=1/0,s=-1/0,o=-1/0;t.forEach(t=>{t.point.x<i&&(i=t.point.x),t.point.y<n&&(n=t.point.y),t.point.x>s&&(s=t.point.x),t.point.y>o&&(o=t.point.y)}),u=i,y=n,v=s-i,M=o-n}const w=x+2*c,A=p+2*d,S=a.vertical||"top",T=a.offsetX||0,b=a.offsetY||0;let I;switch(S){case"bottom":I=y+M+4+b;break;case"inside-top":I=y+4+b;break;default:I=y-A-4+b}let C;switch(a.align||"center"){case"left":C=u+T;break;case"right":C=u+v-w+T;break;default:C=u+v/2-w/2+T}t.fillStyle=l,t.roundRect?(t.roundRect(C,I,w,A,g),t.fill()):t.fillRect(C,I,w,A),t.fillStyle=h,t.textAlign="left",t.textBaseline="top",t.fillText(e.title,C+c,I+d)})}}class g{constructor(t,e,i,n,s,o,a,r,h,l){this.canvas=t,this.viewport=e,this.annotationManager=i,this.textManager=n,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,i=this.viewport.scale,n=Math.max(this.viewport.minScale,Math.min(i+e,this.viewport.maxScale)),s=this.canvas.getBoundingClientRect(),o=t.clientX-s.left,a=t.clientY-s.top,r=(o-this.viewport.offset.x)/i,h=(a-this.viewport.offset.y)/i;this.viewport.scale=n;const l=r*n+this.viewport.offset.x,c=h*n+this.viewport.offset.y;this.viewport.offset.x+=o-l,this.viewport.offset.y+=a-c,this.viewport.calculateBoundaries(),this.viewport.constrainViewport(),this.viewport.isInitialScale=this.viewport.scale===this.viewport.initialScale,this.renderCallback()}handleMouseDown(t){var e,i;if(0!==t.button)return;const n=this.getDrawType(),s=this.getBgImage();if(this.annotationManager.selectedAnnotation&&s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(i)return this.annotationManager.startResizing(i,e),void this.renderCallback()}if("text"===n){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getAnnotationAtPoint(e);if("rect"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(e);if("polygon"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.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"===n){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 i=this.annotationManager.getAnnotationAtPoint(o);return i&&"rect"===i.type?(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const i=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==i)return this.textManager.selectedTextIndex===i?this.textManager.startMoving(t,i):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(i)),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(o);if("polygon"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.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"===n){if("polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.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 i=this.annotationManager.getAnnotationAtPoint(o);return i&&"polygon"===i.type?(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(o);if("rect"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.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"===n){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):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(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""===n&&this.handleNoModeClick(t,o)}checkTextClickInDragMode(t){return!!this.textManager.checkTextClickForMove(t).handled&&(this.canvas.style.cursor="grabbing",!0)}handleTextModeClick(t){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.startMoving(t,e),this.canvas.style.cursor="grabbing",this.renderCallback(),!0;const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return this.textManager.addTextAnnotation(i.x,i.y),!0}handleRectModeClick(t,e){var i,n;if("rect"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)){const i=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(i)return this.annotationManager.startResizing(i,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===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handlePolygonModeClick(t,e){var i,n;if("polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)){const i=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(i&&"polygon-vertex"===i.type)return this.annotationManager.startResizing(i,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===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handleRectModeClickForMove(t,e){const i=this.annotationManager.getAnnotationAtPoint(e);return!(!i||"rect"!==i.type)&&(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handlePolygonModeClickForMove(t,e){const i=this.annotationManager.getAnnotationAtPoint(e);return!(!i||"polygon"!==i.type)&&(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handleNoModeClick(t,e){const i=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==i)return this.textManager.selectedTextIndex===i?this.textManager.startMoving(t,i):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(i)),void this.renderCallback();this.textManager.deselectTextAnnotation();const n=this.annotationManager.getAnnotationAtPoint(e);n?(this.annotationManager.selectAnnotation(n.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,i=t.clientY-this.dragStart.y;return this.viewport.updateOffset(e,i),this.dragStart={x:t.clientX,y:t.clientY},void this.renderCallback()}if(this.textManager.isTextMoving&&null!==this.textManager.editingTextIndex)this.textManager.moveAnnotation(t)&&this.renderCallback();else if((this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&this.annotationManager.selectedAnnotation)this.handleAnnotationMove(t);else{if(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving||this.updateCursor(t),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updateRectDrawing(e),this.renderCallback()}if("polygon"===e&&this.annotationManager.isDrawing){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updatePolygonTempPoint(e),this.renderCallback()}}}handleAnnotationMove(t){var e,i;if(this.annotationManager.isResizing&&this.annotationManager.activeHandle){const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return"rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)?this.annotationManager.resizeRect(n):"polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)&&this.annotationManager.resizePolygon(n),void this.renderCallback()}if(!this.annotationManager.isMovingAnnotation||!this.annotationManager.selectedAnnotation)return;const n=(t.clientX-this.annotationManager.annotationMoveStart.x)/this.viewport.scale,s=(t.clientY-this.annotationManager.annotationMoveStart.y)/this.viewport.scale;this.annotationManager.moveSelectedAnnotation(n,s),this.annotationManager.annotationMoveStart={x:t.clientX,y:t.clientY},this.renderCallback()}updateCursor(t){const e=this.getDrawType();if("text"===e){if(this.getBgImage()){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(this.annotationManager.getAnnotationAtPoint(e))return void(this.canvas.style.cursor="move")}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);return void(this.canvas.style.cursor=null!==e?"move":"crosshair")}"rect"!==e?"polygon"!==e?"drag"!==e?""!==e?this.canvas.style.cursor="default":this.updateNoModeCursor(t):this.updateDragModeCursor(t):this.updatePolygonModeCursor(t):this.updateRectModeCursor(t)}updateRectModeCursor(t){var e;if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void(this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize")}const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(i)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updatePolygonModeCursor(t){var e;if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){if(this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="crosshair")}const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(i)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updateDragModeCursor(t){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(null!==this.textManager.checkTextClick(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="move");const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=i?"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),i=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=i?"move":"default"}handleMouseUp(t){if(this.isDragging){this.isDragging=!1;const t=this.getDrawType();return void(this.canvas.style.cursor="drag"===t?"grab":"default")}if(this.textManager.isTextMoving){this.justFinishedMove=!0,this.textManager.finishMoving();const t=this.getDrawType();"drag"===t?this.canvas.style.cursor="grab":""===t?this.canvas.style.cursor="move":(this.textManager.editingTextIndex=null,this.canvas.style.cursor="default")}(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&(this.justFinishedMove=!0,this.annotationManager.finishMovingAnnotation(),this.canvas.style.cursor=this.annotationManager.selectedAnnotation?"move":"default"),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type&&(this.annotationManager.finishRectDrawing(),this.renderCallback())}handleMouseLeave(t){(this.isDragging||this.textManager.isTextMoving||this.annotationManager.isResizing||this.annotationManager.isMovingAnnotation)&&this.handleMouseUp(t)}handleDoubleClick(t){if(!this.getBgImage())return;this.justFinishedMove=!1;const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return void this.textManager.startEditing(e);if(this.annotationManager.selectedAnnotation){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getAnnotationAtPoint(e);if(i&&i.index===this.annotationManager.selectedAnnotation.index)return void this.annotationManager.startTitleEditing(i.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 i=this.getDrawType();if(!this.getBgImage()||"polygon"!==i||this.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;if(this.justDeselected)return void(this.justDeselected=!1);if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type))return;const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.checkPolygonPointValid(n)&&(this.annotationManager.isDrawing?this.annotationManager.addPolygonPoint(n):this.annotationManager.startPolygonDrawing(n)),this.annotationManager.updatePolygonTempPoint(n),this.renderCallback()}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(this.annotationManager.withdraw()||this.textManager.withdraw())&&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 x{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 i;null===(i=this.listeners.get(t))||void 0===i||i.delete(e)}emit(t,e){var i;null===(i=this.listeners.get(t))||void 0===i||i.forEach(t=>t(e))}clear(){this.listeners.clear()}}class f{constructor(t){this.canvas=document.createElement("canvas"),this.emitter=new x,this.bgImage=null,this.bgImageSrc="",this.bgImageExt="jpeg",this.drawType="";const{drawType:e,useEvents:i=!0,id:n="container",annotationColor:s,lineStyle:o,vertexStyle:a,textStyle:r,enableTitle:f=!1}=t,p=document.getElementById(n);if(!p)throw new Error(`Container with id "${n}" not found`);this.container=p,"absolute"!==p.style.position&&"fixed"!==p.style.position&&"relative"!==p.style.position&&(p.style.position="relative"),this.ctx=this.canvas.getContext("2d"),this.viewport=new h,this.viewport.setSize(p.clientWidth,p.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",p.appendChild(this.canvas),this.annotationManager=new l(this.viewport,this.container,()=>this.render(),(t,e)=>this.emitter.emit(t,e)),s&&this.annotationManager.setColorConfig(s),o&&this.annotationManager.setLineStyle(o),a&&this.annotationManager.setVertexStyle(a),this.annotationManager.enableTitle=f,f&&this.annotationManager.initTitleSupport(),this.textManager=new c(this.viewport,this.container,this.ctx,()=>this.render(),(t,e)=>this.emitter.emit(t,e)),r&&this.textManager.setTextStyle(r),this.renderer=new d(this.ctx,this.viewport,this.annotationManager,this.textManager,this.canvas),this.eventHandler=new g(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||""),i&&this.addEventListeners()}setDrawType(t){"polygon"===this.drawType&&this.annotationManager.isDrawing&&this.annotationManager.operate.data.length>0?console.warn("Cannot switch mode while polygon is being drawn. Please complete or cancel the polygon first."):this.drawType!==t&&(this.annotationManager.operate.data=[],this.annotationManager.isDrawing=!1,this.annotationManager.tempPolygonPoint=null,""!==t&&this.deselectAnnotation(),this.annotationManager.operate.type=t,this.drawType=t,this.canvas.style.cursor="drag"===t?"grab":"text"===t?"text":"default")}drawImage(t){this.bgImageSrc=t,this.bgImageExt=i(t);const e=new Image;e.crossOrigin="anonymous",e.src=t,e.onload=()=>{this.bgImage=e,this.viewport.setOriginalSize(e.width,e.height),this.viewport.calculateInitialView(),this.render()}}render(){this.renderer.render(this.bgImage)}clear(t=""){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.setDrawType(t),this.render(),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",i=>{if(this.eventHandler.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;const n=this.eventHandler.justFinishedMove;n&&(this.eventHandler.justFinishedMove=!1),e++,1===e?t=window.setTimeout(()=>{1!==e||n||this.events.click(i),e=0,t=null},300):2===e&&(this.eventHandler.justFinishedMove=!1,this.events.dblclick(i),e=0,null!==t&&(clearTimeout(t),t=null))})}changeScale(t){if(!this.bgImage)return;const e=o(this.viewport.scale,t),i=this.viewport.width/2,n=this.viewport.height/2,s=this.viewport.scale+e;this.viewport.updateScale(s,i,n),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 i=this.annotationManager.setTitle(t,e);return i&&this.render(),i}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 i=this.annotationManager.setAnnotationTitleStyle(t,e);return i&&this.render(),i}setAnnotationTitlePosition(t,e){const i=this.annotationManager.setAnnotationTitlePosition(t,e);return i&&this.render(),i}getTextAnnotations(){return this.textManager.getTextAnnotations()}exportAnnotationImage(){return new Promise((t,e)=>{if(!this.bgImage)return void e(new Error("No background image loaded"));const i=document.createElement("canvas");i.width=this.viewport.originalWidth,i.height=this.viewport.originalHeight;const n=i.getContext("2d");if(!n)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(n,s,this.viewport.originalWidth,this.viewport.originalHeight);const e=i.toDataURL(`image/${this.bgImageExt}`,.7);t(e)}catch(i){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 n(t,e)}static base64ToBlob(t){return s(t)}addTextAnnotation(t,e,i=""){this.textManager.addTextAnnotation(t,e,i),this.render()}updateTextAnnotation(t,e){this.textManager.updateTextAnnotation(t,e)&&this.render()}moveTextAnnotation(t,e,i){this.textManager.moveTextAnnotation(t,e,i)&&this.render()}removeTextAnnotation(t){this.textManager.removeTextAnnotation(t)&&this.render()}clearTextAnnotations(){this.textManager.clearTextAnnotations(),this.render()}selectAnnotation(t){this.annotationManager.selectAnnotation(t)&&this.render()}deselectAnnotation(){this.annotationManager.deselectAnnotation(),this.textManager.deselectTextAnnotation(),this.textManager.editingTextIndex=null,this.render()}getSelectedAnnotation(){const t=this.annotationManager.getSelectedAnnotation();if(t)return t;const e=this.textManager.getSelectedTextAnnotation();return e?{index:e.index,type:"text",data:e.data}:null}deleteSelectedAnnotation(){if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.render();this.annotationManager.deleteSelectedAnnotation()&&this.render()}moveSelectedAnnotation(t,e){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 i=this.annotationManager.recordList[e.index];return!!i&&(i.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 i=this.textManager.updateTextAnnotationStyle(t,e);return i&&this.render(),i}setTextInputStyle(t){this.textManager.setInputStyle(t)}setTextSelectionStyle(t){this.textManager.setSelectionStyle(t),this.render()}destroy(){this.emitter.clear(),this.textManager.destroy(),this.annotationManager.destroyTitleInput(),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}export{l as AnnotationManager,f as Drawer,x as Emitter,g as EventHandler,d as Renderer,c as TextAnnotationManager,h as ViewportManager,s as base64ToBlob,n as base64ToFile,f as default,i 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 i=e.width>=0?e.start.x:e.start.x+e.width,n=e.height>=0?e.start.y:e.start.y+e.height,s=Math.abs(e.width),a=Math.abs(e.height);return t.x>=i&&t.x<=i+s&&t.y>=n&&t.y<=n+a}function i(t,e){if(e.length<3)return!1;let i=!1;for(let n=0,s=e.length-1;n<e.length;s=n++){const a=e[n].point.x,o=e[n].point.y,r=e[s].point.x,h=e[s].point.y;o>t.y!=h>t.y&&t.x<(r-a)*(t.y-o)/(h-o)+a&&(i=!i)}return i}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 s(t,e){const i=t.split(";base64,"),n=i[0].split(":")[1],s=window.atob(i[1]),a=s.length,o=new Uint8Array(a);for(let t=0;t<a;++t)o[t]=s.charCodeAt(t);const r=new Blob([o],{type:n});return new File([r],e,{type:n})}function a(t){return new Promise((e,i)=>{const n=t.split(";base64,");if(n.length<2)return void i(new Error("Invalid base64 string"));const s=n[0].split(":")[1],a=atob(n[1]),o=new ArrayBuffer(a.length),r=new Uint8Array(o);for(let t=0;t<a.length;t++)r[t]=a.charCodeAt(t);e(new Blob([o],{type:s}))})}function o(t,e){return t<2?e?.1:-.1:t<5?e?.05:-.05:e?.02:-.02}class r{constructor(){this.width=0,this.height=0,this.originalWidth=0,this.originalHeight=0,this.scale=1,this.minScale=1,this.maxScale=10,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}setSize(t,e){this.width=t,this.height=e}setOriginalSize(t,e){this.originalWidth=t,this.originalHeight=e}calculateInitialView(){if(0===this.originalWidth||0===this.originalHeight)return;const t=this.width/this.originalWidth,e=this.height/this.originalHeight;this.scale=Math.min(t,e),this.initialScale=this.scale,this.minScale=this.initialScale,this.offset={x:(this.width-this.originalWidth*this.scale)/2,y:(this.height-this.originalHeight*this.scale)/2},this.initialOffset=Object.assign({},this.offset),this.calculateBoundaries(),this.isInitialScale=!0}calculateBoundaries(){const t=this.originalWidth*this.scale,e=this.originalHeight*this.scale;this.maxOffsetX=0,this.maxOffsetY=0,this.minOffsetX=this.width-t,this.minOffsetY=this.height-e,this.minOffsetX>this.maxOffsetX&&([this.minOffsetX,this.maxOffsetX]=[this.maxOffsetX,this.minOffsetX]),this.minOffsetY>this.maxOffsetY&&([this.minOffsetY,this.maxOffsetY]=[this.maxOffsetY,this.minOffsetY])}constrainViewport(){this.offset.x>this.maxOffsetX?this.offset.x=this.maxOffsetX:this.offset.x<this.minOffsetX&&(this.offset.x=this.minOffsetX),this.offset.y>this.maxOffsetY?this.offset.y=this.maxOffsetY:this.offset.y<this.minOffsetY&&(this.offset.y=this.minOffsetY)}toImageCoordinates(t,e){return{x:(t-this.offset.x)/this.scale,y:(e-this.offset.y)/this.scale}}toCanvasCoordinates(t,e){return{x:this.offset.x+t*this.scale,y:this.offset.y+e*this.scale}}updateScale(t,e,i){const n=this.scale,s=(e-this.offset.x)/n,a=(i-this.offset.y)/n;this.scale=Math.max(this.minScale,Math.min(t,this.maxScale));const o=s*this.scale+this.offset.x,r=a*this.scale+this.offset.y;this.offset.x+=e-o,this.offset.y+=i-r,this.calculateBoundaries(),this.constrainViewport(),this.isInitialScale=this.scale===this.initialScale}resetToInitial(){this.scale=this.initialScale,this.offset=Object.assign({},this.initialOffset),this.calculateBoundaries(),this.isInitialScale=!0}updateOffset(t,e){this.offset.x+=t,this.offset.y+=e,this.constrainViewport()}reset(){this.scale=1,this.minScale=1,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}}class h{constructor(t,e,i){this.viewport=t,this.container=e,this.renderCallback=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.applyColorConfig()}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)}}setLineStyle(t){this.lineStyle=t}setVertexStyle(t){this.vertexStyle=Object.assign(Object.assign({},this.vertexStyle),t),t.fillColor&&(this.strokeStyle=t.fillColor)}getLineStyle(){return this.lineStyle}getVertexStyle(){return Object.assign({},this.vertexStyle)}getAnnotationStyle(t){return t.style||this.getCurrentStyle()}startRectDrawing(t){this.isDrawing=!0,this.drawStartPoint=t,this.operate={type:"rect",data:[{start:Object.assign({},t),width:0,height:0}],status:"pending"}}updateRectDrawing(t){if(!this.isDrawing||"rect"!==this.operate.type)return;const e=this.operate.data[0];e.width=t.x-this.drawStartPoint.x,e.height=t.y-this.drawStartPoint.y}finishRectDrawing(){if(!this.isDrawing||"rect"!==this.operate.type)return!1;const t=this.operate.data[0];if(Math.abs(t.width)>5&&Math.abs(t.height)>5){const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[]}return this.operate.data=[],this.isDrawing=!1,!0}startPolygonDrawing(t){this.isDrawing=!0,this.operate={type:"polygon",data:[{point:t}],status:"pending"},this.tempPolygonPoint=t}addPolygonPoint(t){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;const e=this.operate.data.length>0?this.operate.data[this.operate.data.length-1]:null;return!(e&&Math.abs(e.point.x-t.x)<=5&&Math.abs(e.point.y-t.y)<=5)&&(this.operate.data.push({point:t}),!0)}updatePolygonTempPoint(t){this.tempPolygonPoint=t}finishPolygonDrawing(){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;if(this.operate.data.length>=3){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[]}return this.operate={type:"polygon",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,!0}cancelDrawing(){if(this.isDrawing&&"polygon"===this.operate.type&&this.operate.data.length>=2){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{style:this.getCurrentStyle()});this.recordList.push(t)}this.operate.data=[],this.isDrawing=!1,this.tempPolygonPoint=null}withdraw(){if(this.operate.data.length>0)return"polygon"===this.operate.type?(this.operate.data.pop(),0===this.operate.data.length&&(this.isDrawing=!1)):(this.operate.data=[],this.isDrawing=!1),!0;if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.recordList.splice(e,0,t),!0}return this.recordList.length>0&&(this.recordList.pop(),!0)}selectAnnotation(t){if(t<0||t>=this.recordList.length)return this.deselectAnnotation(),!1;const e=this.recordList[t];return this.selectedAnnotation={index:t,type:e.type},!0}deselectAnnotation(){this.selectedAnnotation=null,this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}deleteSelectedAnnotation(){if(!this.selectedAnnotation)return!1;const t=this.selectedAnnotation.index,e=this.recordList[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.recordList.splice(t,1),this.deselectAnnotation(),!0}startMovingAnnotation(t){return!!this.selectedAnnotation&&(this.isMovingAnnotation=!0,this.annotationMoveStart={x:t.clientX,y:t.clientY},!0)}moveSelectedAnnotation(t,e){if(!this.selectedAnnotation)return!1;const i=this.recordList[this.selectedAnnotation.index];if(!i)return!1;if("rect"===i.type){const n=i.data[0];n.start.x+=t,n.start.y+=e}else if("polygon"===i.type){i.data.forEach(i=>{i.point.x+=t,i.point.y+=e})}return!0}finishMovingAnnotation(){this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}startResizing(t,e){if(!this.selectedAnnotation)return!1;this.activeHandle=t,this.isResizing=!0;const i=this.recordList[this.selectedAnnotation.index];return"rect"===i.type?this.originalRect=Object.assign({},i.data[0]):"polygon"===i.type&&(this.originalPolygon=i.data.map(t=>({point:Object.assign({},t.point)}))),!0}resizeRect(t){if(!this.selectedAnnotation||"rect"!==this.selectedAnnotation.type||!this.originalRect||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data[0],i=this.originalRect,n=i.start.x,s=i.start.x+i.width,a=i.start.y,o=i.start.y+i.height;let r,h;switch(this.activeHandle.index){case 0:r=s,h=o;break;case 1:r=n,h=o;break;case 2:r=s,h=a;break;case 3:r=n,h=a;break;default:return!1}const l=Math.min(t.x,r),c=Math.max(t.x,r),d=Math.min(t.y,h),g=Math.max(t.y,h);e.start.x=l,e.start.y=d,e.width=c-l,e.height=g-d;const x=t.x<r,f=t.y<h;return 0===this.activeHandle.index?x||f?!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2):this.activeHandle.index=3:1===this.activeHandle.index?x&&!f?this.activeHandle.index=2:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):2===this.activeHandle.index?!x&&f?this.activeHandle.index=1:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):3===this.activeHandle.index&&(x&&f?this.activeHandle.index=0:!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2)),this.originalRect=Object.assign({},e),!0}resizePolygon(t){if(!this.selectedAnnotation||"polygon"!==this.selectedAnnotation.type||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data,i=this.activeHandle.index;return i>=0&&i<e.length&&(e[i].point.x=t.x,e[i].point.y=t.y,!0)}getAnnotationAtPoint(t){for(let n=this.recordList.length-1;n>=0;n--){const s=this.recordList[n];if("rect"===s.type){if(e(t,s.data[0]))return{index:n,type:"rect"}}else if("polygon"===s.type){if(i(t,s.data))return{index:n,type:"polygon"}}}return null}getHandleAtPoint(t,e){if(!this.selectedAnnotation)return null;const i=this.recordList[this.selectedAnnotation.index],n=this.selectionStyle.handleSize/2;if("rect"===i.type){const s=i.data[0],a=this.viewport.offset.x+s.start.x*this.viewport.scale,o=this.viewport.offset.y+s.start.y*this.viewport.scale,r=s.width*this.viewport.scale,h=s.height*this.viewport.scale,l=[{x:a,y:o,index:0},{x:a+r,y:o,index:1},{x:a,y:o+h,index:2},{x:a+r,y:o+h,index:3}];for(const i of l)if(t>=i.x-n&&t<=i.x+n&&e>=i.y-n&&e<=i.y+n)return{type:"rect-corner",index:i.index}}else if("polygon"===i.type){const s=i.data;for(let i=0;i<s.length;i++){const a=s[i],o=this.viewport.offset.x+a.point.x*this.viewport.scale,r=this.viewport.offset.y+a.point.y*this.viewport.scale;if(t>=o-n&&t<=o+n&&e>=r-n&&e<=r+n)return{type:"polygon-vertex",index:i}}}return null}clear(){this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,this.deselectAnnotation(),this.deleteHistory=[]}getAnnotations(){return[...this.recordList]}getSelectedAnnotation(){if(!this.selectedAnnotation)return null;const t=this.recordList[this.selectedAnnotation.index];return t?{index:this.selectedAnnotation.index,type:this.selectedAnnotation.type,data:t}:null}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.titlePosition=Object.assign({},this.titlePosition)}setAnnotationTitleStyle(t,e){if(t<0||t>=this.recordList.length)return!1;const i=this.recordList[t];return i.style||(i.style=this.getCurrentStyle()),i.style.titleStyle=Object.assign(Object.assign({},i.style.titleStyle||this.titleStyle),e),!0}setAnnotationTitlePosition(t,e){if(t<0||t>=this.recordList.length)return!1;const i=this.recordList[t];return i.style||(i.style=this.getCurrentStyle()),i.style.titlePosition=Object.assign(Object.assign({},i.style.titlePosition||this.titlePosition),e),!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){if(t<0||t>=this.recordList.length)return!1;const i=this.recordList[t];return i.title=e||void 0,e&&this.captureTitleStyleSnapshot(i),!0}getTitle(t){if(!(t<0||t>=this.recordList.length))return this.recordList[t].title}startTitleEditing(t){if(!this.enableTitle||!this.titleInput||t<0||t>=this.recordList.length)return!1;const e=this.recordList[t];let i,n;if(this.editingTitleIndex=t,this.deselectAnnotation(),"rect"===e.type){const t=e.data[0];i=this.viewport.offset.x+t.start.x*this.viewport.scale,n=this.viewport.offset.y+t.start.y*this.viewport.scale}else{const t=e.data[0];i=this.viewport.offset.x+t.point.x*this.viewport.scale,n=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=`${i}px`,this.titleInput.style.top=n-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 i=this.recordList[t];i.title=e||void 0,e&&this.captureTitleStyleSnapshot(i),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 l{constructor(t,e,i,n){this.viewport=t,this.container=e,this.ctx=i,this.renderCallback=n,this.textAnnotations=[],this.editingTextIndex=null,this.currentEditingIndex=null,this.isTextMoving=!1,this.textMoveStart={x:0,y:0},this.textBeforeEditing="",this.selectedTextIndex=null,this.textInput=null,this.deleteHistory=[],this.defaultInputStyle={border:"2px solid #00D9FF",borderRadius:"6px",padding:"6px 10px",fontSize:"16px",fontFamily:"Arial, sans-serif",backgroundColor:"#ffffff",color:"#333",boxShadow:"0 4px 12px rgba(0,0,0,0.3)",minWidth:"60px",maxWidth:"200px"},this.textStyle={font:"16px Arial",color:"#FFD700",padding:6,backgroundColor:"rgba(0,0,0,0.6)",borderRadius:4,selectedBorderColor:"#00D9FF",selectedBackgroundColor:"rgba(0,217,255,0.15)",inputStyle:Object.assign({},this.defaultInputStyle)},this.createTextInput()}createTextInput(){this.textInput=document.createElement("input"),this.textInput.type="text",this.textInput.style.position="absolute",this.textInput.style.zIndex="99999",this.textInput.style.display="none",this.textInput.style.outline="none",this.textInput.style.width="fit-content",this.textInput.placeholder="输入文字...",this.applyInputStyle(),this.textInput.addEventListener("blur",()=>{this.finishEditing(),this.renderCallback&&this.renderCallback()}),this.textInput.addEventListener("keydown",t=>{t.stopPropagation(),"Enter"===t.key?(this.finishEditing(),this.renderCallback&&this.renderCallback()):"Escape"===t.key?(t.preventDefault(),this.cancelEditing()):"Delete"===t.key&&""===this.textInput.value&&(t.preventDefault(),this.deleteEditingAnnotation())}),this.textInput.addEventListener("input",()=>{this.adjustInputWidth()}),this.container.appendChild(this.textInput)}applyInputStyle(){if(!this.textInput)return;const t=Object.assign(Object.assign({},this.defaultInputStyle),this.textStyle.inputStyle);this.textInput.style.border=t.border,this.textInput.style.borderRadius=t.borderRadius,this.textInput.style.padding=t.padding,this.textInput.style.fontSize=t.fontSize,this.textInput.style.fontFamily=t.fontFamily,this.textInput.style.backgroundColor=t.backgroundColor,this.textInput.style.color=t.color,this.textInput.style.boxShadow=t.boxShadow,this.textInput.style.minWidth=t.minWidth,this.textInput.style.maxWidth=t.maxWidth}setTextStyle(t){this.textStyle=Object.assign(Object.assign({},this.textStyle),t),this.applyInputStyle()}setInputStyle(t){this.textStyle.inputStyle=Object.assign(Object.assign({},this.textStyle.inputStyle),t),this.applyInputStyle()}setSelectionStyle(t){void 0!==t.selectedBorderColor&&(this.textStyle.selectedBorderColor=t.selectedBorderColor),void 0!==t.selectedBackgroundColor&&(this.textStyle.selectedBackgroundColor=t.selectedBackgroundColor)}getCurrentStyle(){return{font:this.textStyle.font,color:this.textStyle.color,backgroundColor:this.textStyle.backgroundColor}}updateTextAnnotationStyle(t,e){if(t<0||t>=this.textAnnotations.length)return!1;const i=this.textAnnotations[t];return i.style=Object.assign(Object.assign({},i.style||this.getCurrentStyle()),e),!0}addTextAnnotation(t,e,i=""){var n;this.ctx.font=this.textStyle.font;const s=i||"输入文字...",a=this.ctx.measureText(s);let o;if(a.actualBoundingBoxAscent&&a.actualBoundingBoxDescent)o=a.actualBoundingBoxAscent+a.actualBoundingBoxDescent;else{o=1.2*parseInt((null===(n=this.textStyle.font.match(/\d+/))||void 0===n?void 0:n[0])||"16")}const r={position:{x:t,y:e},text:i,style:this.getCurrentStyle(),width:Math.max(a.width,60),height:o};this.textAnnotations.push(r);const h=this.textAnnotations.length-1;return this.deleteHistory=[],this.startEditing(h),h}updateTextAnnotation(t,e){if(t<0||t>=this.textAnnotations.length)return!1;const i=this.textAnnotations[t];i.text=e,this.ctx.font=this.textStyle.font;const n=this.ctx.measureText(e);return i.width=n.width,i.height=1.2*parseInt(this.textStyle.font),!0}moveTextAnnotation(t,e,i){return!(t<0||t>=this.textAnnotations.length)&&(this.textAnnotations[t].position={x:e,y:i},!0)}removeTextAnnotation(t){if(t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.textAnnotations.splice(t,1),this.editingTextIndex===t?this.cancelEditing():null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,!0}clearTextAnnotations(){this.textAnnotations=[],this.selectedTextIndex=null,this.cancelEditing(),this.deleteHistory=[]}startEditing(t){if(!this.textInput||t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];this.editingTextIndex=t,this.currentEditingIndex=t,this.textBeforeEditing=e.text;const i=this.viewport.offset.x+e.position.x*this.viewport.scale,n=this.viewport.offset.y+e.position.y*this.viewport.scale;return this.textInput.value=e.text,this.textInput.style.left=`${i}px`,this.textInput.style.top=`${n}px`,this.textInput.style.display="block",this.adjustInputWidth(),setTimeout(()=>{this.textInput&&(this.textInput.focus(),this.textInput.select())},10),!0}finishEditing(){if(!this.textInput)return!1;const t=this.currentEditingIndex,e=this.textInput.value.trim();if(null===t||t<0||t>=this.textAnnotations.length)return this.resetEditingState(),!1;if(""===e)this.textAnnotations.splice(t,1);else{const i=this.textAnnotations[t];i.text=e,this.ctx.font=this.textStyle.font;const n=this.ctx.measureText(i.text);i.width=n.width,i.height=1.2*parseInt(this.textStyle.font)}return this.resetEditingState(),!0}cancelEditing(){if(!this.textInput||null===this.editingTextIndex)return!1;this.textInput.value=this.textBeforeEditing;const t=this.editingTextIndex;if(t>=0&&t<this.textAnnotations.length){""===this.textAnnotations[t].text&&""===this.textBeforeEditing&&this.textAnnotations.splice(t,1)}return this.resetEditingState(),!0}deleteEditingAnnotation(){if(null===this.editingTextIndex)return!1;const t=this.editingTextIndex;return this.textInput&&(this.textInput.style.display="none"),t>=0&&t<this.textAnnotations.length&&this.textAnnotations.splice(t,1),this.resetEditingState(),!0}resetEditingState(){this.textInput&&(this.textInput.style.display="none"),this.editingTextIndex=null,this.currentEditingIndex=null,this.textBeforeEditing=""}adjustInputWidth(){if(!this.textInput||null===this.editingTextIndex)return;this.ctx.font=this.textStyle.font;const t=this.textInput.value||this.textInput.placeholder||"",e=this.ctx.measureText(t).width,i=Math.min(Math.max(e+24,60),200);this.textInput.style.width=`${i}px`}startMoving(t,e){return!(e<0||e>=this.textAnnotations.length)&&(this.editingTextIndex=e,this.isTextMoving=!0,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}moveAnnotation(t){if(!this.isTextMoving||null===this.editingTextIndex)return!1;const e=t.clientX-this.textMoveStart.x,i=t.clientY-this.textMoveStart.y,n=this.textAnnotations[this.editingTextIndex];return!!n&&(n.position.x+=e/this.viewport.scale,n.position.y+=i/this.viewport.scale,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}finishMoving(){this.isTextMoving=!1}checkTextClick(t,e){for(let i=this.textAnnotations.length-1;i>=0;i--){const n=this.textAnnotations[i],s=this.viewport.offset.x+n.position.x*this.viewport.scale,a=this.viewport.offset.y+n.position.y*this.viewport.scale,o=Math.max(n.width,60)+2*this.textStyle.padding,r=n.height+2*this.textStyle.padding;if(t>=s&&t<=s+o&&e>=a&&e<=a+r)return i}return null}checkTextClickForMove(t){const e=this.checkTextClick(t.offsetX,t.offsetY);return null!==e?(this.startMoving(t,e),{index:e,handled:!0}):{index:-1,handled:!1}}getTextAnnotations(){return[...this.textAnnotations]}withdraw(){if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.textAnnotations.splice(e,0,t),!0}return this.textAnnotations.length>0&&(this.textAnnotations.pop(),!0)}selectTextAnnotation(t){return t<0||t>=this.textAnnotations.length?(this.deselectTextAnnotation(),!1):(this.selectedTextIndex=t,null!==this.editingTextIndex&&this.finishEditing(),!0)}deselectTextAnnotation(){this.selectedTextIndex=null}deleteSelectedTextAnnotation(){if(null===this.selectedTextIndex)return!1;const t=this.selectedTextIndex,e=this.textAnnotations[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.textAnnotations.splice(t,1),this.selectedTextIndex=null,null!==this.editingTextIndex&&this.editingTextIndex>t&&this.editingTextIndex--,!0}getSelectedTextAnnotation(){if(null===this.selectedTextIndex)return null;const t=this.textAnnotations[this.selectedTextIndex];return t?{index:this.selectedTextIndex,data:t}:null}destroy(){this.textInput&&this.textInput.parentNode&&this.textInput.parentNode.removeChild(this.textInput)}}class c{constructor(t,e,i,n,s){this.ctx=t,this.viewport=e,this.annotationManager=i,this.textManager=n,this.canvas=s}render(t){this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.drawBackgroundImage(t),this.drawAnnotations(),this.drawTextAnnotations()}drawBackgroundImage(t){this.ctx.drawImage(t,this.viewport.offset.x,this.viewport.offset.y,this.viewport.originalWidth*this.viewport.scale,this.viewport.originalHeight*this.viewport.scale)}drawAnnotations(){this.annotationManager.recordList.forEach((t,e)=>{var i;const n=this.annotationManager.getAnnotationStyle(t);this.ctx.strokeStyle=n.strokeColor,this.ctx.lineWidth=n.lineWidth,this.setLineDash(n.lineStyle||"solid"),this.ctx.fillStyle=this.ctx.strokeStyle;const s=(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.index)===e;if("rect"===t.type)this.drawRect(t.data[0],s);else if("polygon"===t.type){const e=n.vertexStyle||this.annotationManager.getVertexStyle();this.drawPolygon(t.data,"fullfilled"===t.status,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,this.setLineDash(this.annotationManager.lineStyle),"rect"===this.annotationManager.operate.type?this.drawRect(this.annotationManager.operate.data[0],!1):"polygon"===this.annotationManager.operate.type&&this.drawCurrentPolygon()),this.ctx.setLineDash([]),this.drawSelectionHighlight()}setLineDash(t){switch(t){case"dashed":this.ctx.setLineDash([10,5]);break;case"dotted":this.ctx.setLineDash([2,4]);break;default:this.ctx.setLineDash([])}}drawRect(t,e=!1){this.ctx.strokeRect(this.viewport.offset.x+t.start.x*this.viewport.scale,this.viewport.offset.y+t.start.y*this.viewport.scale,t.width*this.viewport.scale,t.height*this.viewport.scale)}drawPolygon(t,e,i){if(0!==t.length){if(this.ctx.beginPath(),t.forEach((t,e)=>{const i=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(i,n):this.ctx.lineTo(i,n)}),e&&t.length>1){const e=t[0];this.ctx.lineTo(this.viewport.offset.x+e.point.x*this.viewport.scale,this.viewport.offset.y+e.point.y*this.viewport.scale)}this.ctx.stroke(),this.drawPolygonVertices(t,i)}}drawPolygonVertices(t,e){const i=e||this.annotationManager.getVertexStyle(),n=i.size/2;t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),s=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);switch(this.ctx.fillStyle=i.fillColor,this.ctx.strokeStyle=i.strokeColor,this.ctx.lineWidth=i.strokeWidth,this.ctx.beginPath(),i.shape){case"square":this.ctx.rect(e-n,s-n,2*n,2*n);break;case"diamond":this.ctx.moveTo(e,s-n),this.ctx.lineTo(e+n,s),this.ctx.lineTo(e,s+n),this.ctx.lineTo(e-n,s),this.ctx.closePath();break;default:this.ctx.arc(e,s,n,0,2*Math.PI)}this.ctx.fill(),i.strokeWidth>0&&this.ctx.stroke()})}drawCurrentPolygon(){const t=this.annotationManager.operate.data,e=this.annotationManager.tempPolygonPoint;if(this.ctx.beginPath(),t.forEach((t,e)=>{const i=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(i,n):this.ctx.lineTo(i,n)}),e){const t=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+e.y*this.viewport.scale);this.ctx.lineTo(t,i)}if(this.ctx.stroke(),this.drawPolygonVertices(t,this.annotationManager.getVertexStyle()),e){const t=this.annotationManager.getVertexStyle(),i=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+e.y*this.viewport.scale),s=t.size/2;switch(this.ctx.fillStyle=t.fillColor,this.ctx.strokeStyle=t.strokeColor,this.ctx.lineWidth=t.strokeWidth,this.ctx.beginPath(),t.shape){case"square":this.ctx.rect(i-s,n-s,2*s,2*s);break;case"diamond":this.ctx.moveTo(i,n-s),this.ctx.lineTo(i+s,n),this.ctx.lineTo(i,n+s),this.ctx.lineTo(i-s,n),this.ctx.closePath();break;default:this.ctx.arc(i,n,s,0,2*Math.PI)}this.ctx.fill(),t.strokeWidth>0&&this.ctx.stroke()}}drawSelectionHighlight(){const t=this.annotationManager.selectedAnnotation;if(!t)return;const e=this.annotationManager.recordList[t.index];if(!e)return;const i=this.annotationManager.selectionStyle;this.ctx.save(),"rect"===e.type?this.drawRectSelectionHighlight(e.data[0],i):"polygon"===e.type&&this.drawPolygonSelectionHighlight(e.data,i),this.ctx.restore()}drawRectSelectionHighlight(t,e){const i=this.viewport.offset.x+t.start.x*this.viewport.scale,n=this.viewport.offset.y+t.start.y*this.viewport.scale,s=t.width*this.viewport.scale,a=t.height*this.viewport.scale;this.ctx.fillStyle=e.fillColor,this.ctx.fillRect(i,n,s,a),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.strokeRect(i,n,s,a);const o=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),this.ctx.fillRect(i-o/2,n-o/2,o,o),this.ctx.fillRect(i+s-o/2,n-o/2,o,o),this.ctx.fillRect(i-o/2,n+a-o/2,o,o),this.ctx.fillRect(i+s-o/2,n+a-o/2,o,o)}drawPolygonSelectionHighlight(t,e){this.ctx.beginPath(),t.forEach((t,e)=>{const i=this.viewport.offset.x+t.point.x*this.viewport.scale,n=this.viewport.offset.y+t.point.y*this.viewport.scale;0===e?this.ctx.moveTo(i,n):this.ctx.lineTo(i,n)}),this.ctx.closePath(),this.ctx.fillStyle=e.fillColor,this.ctx.fill(),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.stroke();const i=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);this.ctx.fillRect(e-i/2,n-i/2,i,i)})}drawAnnotationTitle(t){var e,i,n;if(!t.title)return;const s=this.annotationManager.getEffectiveTitleStyle(t),a=this.annotationManager.getEffectiveTitlePosition(t),o=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,c=null!==(i=s.paddingY)&&void 0!==i?i:3,d=null!==(n=s.borderRadius)&&void 0!==n?n:4;this.ctx.save(),this.ctx.font=o;const g=this.ctx.measureText(t.title).width,x=o.match(/(\d+)px/),f=x?parseInt(x[1]):12;let p,u,y,v;if("rect"===t.type){const e=t.data[0];p=this.viewport.offset.x+e.start.x*this.viewport.scale,u=this.viewport.offset.y+e.start.y*this.viewport.scale,y=e.width*this.viewport.scale,v=e.height*this.viewport.scale}else{const e=t.data;if(0===e.length)return void this.ctx.restore();let i=1/0,n=1/0,s=-1/0,a=-1/0;e.forEach(t=>{const e=this.viewport.offset.x+t.point.x*this.viewport.scale,o=this.viewport.offset.y+t.point.y*this.viewport.scale;e<i&&(i=e),o<n&&(n=o),e>s&&(s=e),o>a&&(a=o)}),p=i,u=n,y=s-i,v=a-n}const M=g+2*l,w=f+2*c,A=a.vertical||"top",S=a.offsetX||0,T=a.offsetY||0;let b;switch(A){case"bottom":b=u+v+4+T;break;case"inside-top":b=u+4+T;break;default:b=u-w-4+T}let I;switch(a.align||"center"){case"left":I=p+S;break;case"right":I=p+y-M+S;break;default:I=p+y/2-M/2+S}this.ctx.fillStyle=h,this.ctx.setLineDash([]),this.ctx.beginPath(),this.ctx.roundRect(I,b,M,w,d),this.ctx.fill(),this.ctx.fillStyle=r,this.ctx.textAlign="left",this.ctx.textBaseline="top",this.ctx.fillText(t.title,I+l,b+c),this.ctx.restore()}drawTextAnnotations(){const t=this.textManager.textStyle;this.textManager.textAnnotations.forEach((e,i)=>{if(this.textManager.editingTextIndex===i&&this.textManager.textInput&&"none"!==this.textManager.textInput.style.display)return;if(!e.text)return;const n=e.style||{font:t.font,color:t.color,backgroundColor:t.backgroundColor},s=this.viewport.offset.x+e.position.x*this.viewport.scale,a=this.viewport.offset.y+e.position.y*this.viewport.scale,o=this.textManager.selectedTextIndex===i;this.ctx.font=n.font;const r=this.ctx.measureText(e.text),h=r.actualBoundingBoxAscent||.8*e.height,l=h+(r.actualBoundingBoxDescent||.2*e.height),c=t.borderRadius,d=s,g=a,x=e.width+2*t.padding,f=l+2*t.padding;this.ctx.fillStyle=n.backgroundColor,this.ctx.beginPath(),this.ctx.roundRect(d,g,x,f,c),this.ctx.fill(),o&&(this.ctx.strokeStyle=t.selectedBorderColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.beginPath(),this.ctx.roundRect(d,g,x,f,c),this.ctx.stroke(),this.ctx.setLineDash([]));const p=s+t.padding,u=a+t.padding+h;this.ctx.fillStyle=n.color,this.ctx.fillText(e.text,p,u)})}drawForExport(t,e,i,n){t.drawImage(e,0,0,i,n),this.annotationManager.recordList.forEach(e=>{const i=this.annotationManager.getAnnotationStyle(e);if(t.strokeStyle=i.strokeColor,t.lineWidth=i.lineWidth,"rect"===e.type){const i=e.data[0];t.strokeRect(i.start.x,i.start.y,i.width,i.height)}else if("polygon"===e.type&&"fullfilled"===e.status){t.beginPath(),e.data.forEach((e,i)=>{0===i?t.moveTo(e.point.x,e.point.y):t.lineTo(e.point.x,e.point.y)});const n=e.data[0];t.lineTo(n.point.x,n.point.y),t.stroke(),e.data.forEach(e=>{t.beginPath(),t.arc(e.point.x,e.point.y,4,0,2*Math.PI),t.fillStyle=i.strokeColor,t.fill()})}}),this.textManager.textAnnotations.forEach(e=>{const i=this.textManager.textStyle,n=e.style||{font:i.font,color:i.color,backgroundColor:i.backgroundColor};t.font=n.font;const s=t.measureText(e.text),a=s.actualBoundingBoxAscent||.8*e.height,o=a+(s.actualBoundingBoxDescent||.2*e.height),r=e.position.x,h=e.position.y,l=e.width+2*i.padding,c=o+2*i.padding,d=i.borderRadius;t.fillStyle=n.backgroundColor,t.roundRect?(t.roundRect(r,h,l,c,d),t.fill()):t.fillRect(r,h,l,c),t.fillStyle=n.color,t.fillText(e.text,e.position.x+i.padding,e.position.y+i.padding+a)}),this.annotationManager.enableTitle&&this.annotationManager.recordList.forEach(e=>{var i,n,s;if(!e.title)return;const a=this.annotationManager.getEffectiveTitleStyle(e),o=this.annotationManager.getEffectiveTitlePosition(e),r=a.font||"12px Arial",h=a.color||"#FFFFFF",l=a.backgroundColor||"rgba(0, 0, 0, 0.7)",c=null!==(i=a.paddingX)&&void 0!==i?i:6,d=null!==(n=a.paddingY)&&void 0!==n?n:3,g=null!==(s=a.borderRadius)&&void 0!==s?s:4;t.font=r;const x=t.measureText(e.title).width,f=r.match(/(\d+)px/),p=f?parseInt(f[1]):12;let u,y,v,M;if("rect"===e.type){const t=e.data[0];u=t.start.x,y=t.start.y,v=t.width,M=t.height}else{const t=e.data;if(0===t.length)return;let i=1/0,n=1/0,s=-1/0,a=-1/0;t.forEach(t=>{t.point.x<i&&(i=t.point.x),t.point.y<n&&(n=t.point.y),t.point.x>s&&(s=t.point.x),t.point.y>a&&(a=t.point.y)}),u=i,y=n,v=s-i,M=a-n}const w=x+2*c,A=p+2*d,S=o.vertical||"top",T=o.offsetX||0,b=o.offsetY||0;let I;switch(S){case"bottom":I=y+M+4+b;break;case"inside-top":I=y+4+b;break;default:I=y-A-4+b}let m;switch(o.align||"center"){case"left":m=u+T;break;case"right":m=u+v-w+T;break;default:m=u+v/2-w/2+T}t.fillStyle=l,t.roundRect?(t.roundRect(m,I,w,A,g),t.fill()):t.fillRect(m,I,w,A),t.fillStyle=h,t.textAlign="left",t.textBaseline="top",t.fillText(e.title,m+c,I+d)})}}class d{constructor(t,e,i,n,s,a,o,r,h){this.canvas=t,this.viewport=e,this.annotationManager=i,this.textManager=n,this.renderer=s,this.getDrawType=a,this.getBgImage=o,this.renderCallback=r,this.setDrawTypeCallback=h,this.isDragging=!1,this.dragStart={x:0,y:0},this.justFinishedMove=!1,this.justDeselected=!1}handleWheel(t){if(t.preventDefault(),!this.getBgImage())return;const e=t.deltaY>0?-.02:.02,i=this.viewport.scale,n=Math.max(this.viewport.minScale,Math.min(i+e,this.viewport.maxScale)),s=this.canvas.getBoundingClientRect(),a=t.clientX-s.left,o=t.clientY-s.top,r=(a-this.viewport.offset.x)/i,h=(o-this.viewport.offset.y)/i;this.viewport.scale=n;const l=r*n+this.viewport.offset.x,c=h*n+this.viewport.offset.y;this.viewport.offset.x+=a-l,this.viewport.offset.y+=o-c,this.viewport.calculateBoundaries(),this.viewport.constrainViewport(),this.viewport.isInitialScale=this.viewport.scale===this.viewport.initialScale,this.renderCallback()}handleMouseDown(t){var e,i;if(0!==t.button)return;const n=this.getDrawType(),s=this.getBgImage();if(this.annotationManager.selectedAnnotation&&s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(i)return this.annotationManager.startResizing(i,e),void this.renderCallback()}if("text"===n){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getAnnotationAtPoint(e);if("rect"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(e);if("polygon"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();if(this.annotationManager.selectedAnnotation)return this.annotationManager.deselectAnnotation(),void this.renderCallback()}return null!==this.textManager.selectedTextIndex?(this.textManager.deselectTextAnnotation(),void this.renderCallback()):void this.handleTextModeClick(t)}if(!s)return;const a=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if("rect"===n){if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return this.annotationManager.startResizing(e,a),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(a);return i&&"rect"===i.type?(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const i=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==i)return this.textManager.selectedTextIndex===i?this.textManager.startMoving(t,i):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(i)),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(a);if("polygon"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const s=this.annotationManager.getAnnotationAtPoint(a);if("rect"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.startRectDrawing(a)}else if("polygon"===n){if("polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e&&"polygon-vertex"===e.type)return this.annotationManager.startResizing(e,a),void this.renderCallback();const i=this.annotationManager.getAnnotationAtPoint(a);return i&&"polygon"===i.type?(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(a);if("rect"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const s=this.annotationManager.getAnnotationAtPoint(a);if("polygon"===(null==s?void 0:s.type))return this.annotationManager.selectAnnotation(s.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();this.annotationManager.isDrawing?this.checkPolygonPointValid(a)&&this.annotationManager.addPolygonPoint(a):this.annotationManager.startPolygonDrawing(a),this.annotationManager.updatePolygonTempPoint(a),this.renderCallback()}else if("drag"===n){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return this.annotationManager.startResizing(e,a),void this.renderCallback()}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(this.handleRectModeClick(t,a))return;if(this.handlePolygonModeClick(t,a))return;this.isDragging=!0,this.dragStart={x:t.clientX,y:t.clientY},this.canvas.style.cursor="grabbing"}else""===n&&this.handleNoModeClick(t,a)}checkTextClickInDragMode(t){return!!this.textManager.checkTextClickForMove(t).handled&&(this.canvas.style.cursor="grabbing",!0)}handleTextModeClick(t){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.startMoving(t,e),this.canvas.style.cursor="grabbing",this.renderCallback(),!0;const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return this.textManager.addTextAnnotation(i.x,i.y),!0}handleRectModeClick(t,e){var i,n;if("rect"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)){const i=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(i)return this.annotationManager.startResizing(i,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===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handlePolygonModeClick(t,e){var i,n;if("polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)){const i=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(i&&"polygon-vertex"===i.type)return this.annotationManager.startResizing(i,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===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handleRectModeClickForMove(t,e){const i=this.annotationManager.getAnnotationAtPoint(e);return!(!i||"rect"!==i.type)&&(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handlePolygonModeClickForMove(t,e){const i=this.annotationManager.getAnnotationAtPoint(e);return!(!i||"polygon"!==i.type)&&(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handleNoModeClick(t,e){const i=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==i)return this.textManager.selectedTextIndex===i?this.textManager.startMoving(t,i):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(i)),void this.renderCallback();this.textManager.deselectTextAnnotation();const n=this.annotationManager.getAnnotationAtPoint(e);n?(this.annotationManager.selectAnnotation(n.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,i=t.clientY-this.dragStart.y;return this.viewport.updateOffset(e,i),this.dragStart={x:t.clientX,y:t.clientY},void this.renderCallback()}if(this.textManager.isTextMoving&&null!==this.textManager.editingTextIndex)this.textManager.moveAnnotation(t)&&this.renderCallback();else if((this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&this.annotationManager.selectedAnnotation)this.handleAnnotationMove(t);else{if(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving||this.updateCursor(t),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updateRectDrawing(e),this.renderCallback()}if("polygon"===e&&this.annotationManager.isDrawing){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updatePolygonTempPoint(e),this.renderCallback()}}}handleAnnotationMove(t){var e,i;if(this.annotationManager.isResizing&&this.annotationManager.activeHandle){const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return"rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)?this.annotationManager.resizeRect(n):"polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)&&this.annotationManager.resizePolygon(n),void this.renderCallback()}if(!this.annotationManager.isMovingAnnotation||!this.annotationManager.selectedAnnotation)return;const n=(t.clientX-this.annotationManager.annotationMoveStart.x)/this.viewport.scale,s=(t.clientY-this.annotationManager.annotationMoveStart.y)/this.viewport.scale;this.annotationManager.moveSelectedAnnotation(n,s),this.annotationManager.annotationMoveStart={x:t.clientX,y:t.clientY},this.renderCallback()}updateCursor(t){const e=this.getDrawType();if("text"===e){if(this.getBgImage()){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(this.annotationManager.getAnnotationAtPoint(e))return void(this.canvas.style.cursor="move")}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);return void(this.canvas.style.cursor=null!==e?"move":"crosshair")}"rect"!==e?"polygon"!==e?"drag"!==e?""!==e?this.canvas.style.cursor="default":this.updateNoModeCursor(t):this.updateDragModeCursor(t):this.updatePolygonModeCursor(t):this.updateRectModeCursor(t)}updateRectModeCursor(t){var e;if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void(this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize")}const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(i)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updatePolygonModeCursor(t){var e;if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){if(this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="crosshair")}const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(i)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updateDragModeCursor(t){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(null!==this.textManager.checkTextClick(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="move");const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=i?"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),i=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=i?"move":"default"}handleMouseUp(t){if(this.isDragging){this.isDragging=!1;const t=this.getDrawType();return void(this.canvas.style.cursor="drag"===t?"grab":"default")}if(this.textManager.isTextMoving){this.justFinishedMove=!0,this.textManager.finishMoving();const t=this.getDrawType();"drag"===t?this.canvas.style.cursor="grab":""===t?this.canvas.style.cursor="move":(this.textManager.editingTextIndex=null,this.canvas.style.cursor="default")}(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&(this.justFinishedMove=!0,this.annotationManager.finishMovingAnnotation(),this.canvas.style.cursor=this.annotationManager.selectedAnnotation?"move":"default"),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type&&(this.annotationManager.finishRectDrawing(),this.renderCallback())}handleMouseLeave(t){(this.isDragging||this.textManager.isTextMoving||this.annotationManager.isResizing||this.annotationManager.isMovingAnnotation)&&this.handleMouseUp(t)}handleDoubleClick(t){if(!this.getBgImage())return;this.justFinishedMove=!1;const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return void this.textManager.startEditing(e);if(this.annotationManager.selectedAnnotation){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getAnnotationAtPoint(e);if(i&&i.index===this.annotationManager.selectedAnnotation.index)return void this.annotationManager.startTitleEditing(i.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 i=this.getDrawType();if(!this.getBgImage()||"polygon"!==i||this.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;if(this.justDeselected)return void(this.justDeselected=!1);if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type))return;const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.checkPolygonPointValid(n)&&(this.annotationManager.isDrawing?this.annotationManager.addPolygonPoint(n):this.annotationManager.startPolygonDrawing(n)),this.annotationManager.updatePolygonTempPoint(n),this.renderCallback()}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 this.annotationManager.withdraw()||this.textManager.withdraw(),void this.renderCallback();if(" "===t.key)return this.viewport.resetToInitial(),void this.renderCallback();if("Escape"!==t.key){if("Delete"===t.key||"Backspace"===t.key){if(null!==this.textManager.editingTextIndex)return this.textManager.removeTextAnnotation(this.textManager.editingTextIndex),void this.renderCallback();if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.renderCallback();this.annotationManager.selectedAnnotation&&(this.annotationManager.deleteSelectedAnnotation(),this.renderCallback())}}else this.annotationManager.isDrawing?(this.annotationManager.cancelDrawing(),this.renderCallback()):this.annotationManager.selectedAnnotation&&(this.annotationManager.deselectAnnotation(),this.renderCallback())}}}class g{constructor(t){this.canvas=document.createElement("canvas"),this.bgImage=null,this.bgImageSrc="",this.bgImageExt="jpeg",this.drawType="";const{drawType:e,useEvents:i=!0,id:n="container",annotationColor:s,lineStyle:a,vertexStyle:o,textStyle:g,enableTitle:x=!1}=t,f=document.getElementById(n);if(!f)throw new Error(`Container with id "${n}" not found`);this.container=f,"absolute"!==f.style.position&&"fixed"!==f.style.position&&"relative"!==f.style.position&&(f.style.position="relative"),this.ctx=this.canvas.getContext("2d"),this.viewport=new r,this.viewport.setSize(f.clientWidth,f.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",f.appendChild(this.canvas),this.annotationManager=new h(this.viewport,this.container,()=>this.render()),s&&this.annotationManager.setColorConfig(s),a&&this.annotationManager.setLineStyle(a),o&&this.annotationManager.setVertexStyle(o),this.annotationManager.enableTitle=x,x&&this.annotationManager.initTitleSupport(),this.textManager=new l(this.viewport,this.container,this.ctx,()=>this.render()),g&&this.textManager.setTextStyle(g),this.renderer=new c(this.ctx,this.viewport,this.annotationManager,this.textManager,this.canvas),this.eventHandler=new d(this.canvas,this.viewport,this.annotationManager,this.textManager,this.renderer,()=>this.drawType,()=>this.bgImage,()=>this.render(),t=>this.setDrawType(t)),this.events={wheel:t=>this.eventHandler.handleWheel(t),mousedown:t=>this.eventHandler.handleMouseDown(t),mousemove:t=>this.eventHandler.handleMouseMove(t),mouseup:t=>this.eventHandler.handleMouseUp(t),mouseleave:t=>this.eventHandler.handleMouseLeave(t),dblclick:t=>this.eventHandler.handleDoubleClick(t),click:t=>this.eventHandler.handleClick(t),keydown:t=>this.eventHandler.handleKeyDown(t)},this.setDrawType(e||""),i&&this.addEventListeners()}setDrawType(t){"polygon"===this.drawType&&this.annotationManager.isDrawing&&this.annotationManager.operate.data.length>0?console.warn("Cannot switch mode while polygon is being drawn. Please complete or cancel the polygon first."):this.drawType!==t&&(this.annotationManager.operate.data=[],this.annotationManager.isDrawing=!1,this.annotationManager.tempPolygonPoint=null,""!==t&&this.deselectAnnotation(),this.annotationManager.operate.type=t,this.drawType=t,this.canvas.style.cursor="drag"===t?"grab":"text"===t?"text":"default")}drawImage(t){this.bgImageSrc=t,this.bgImageExt=n(t);const e=new Image;e.crossOrigin="anonymous",e.src=t,e.onload=()=>{this.bgImage=e,this.viewport.setOriginalSize(e.width,e.height),this.viewport.calculateInitialView(),this.render()}}render(){this.renderer.render(this.bgImage)}clear(t=""){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.setDrawType(t),this.render()}withdraw(){const t=this.annotationManager.withdraw(),e=this.textManager.withdraw();(t||e)&&this.render()}resize(){const t=this.canvas.parentElement;t&&(this.viewport.setSize(t.clientWidth,t.clientHeight),this.canvas.width=this.viewport.width,this.canvas.height=this.viewport.height,this.canvas.style.width=`${this.viewport.width}px`,this.canvas.style.height=`${this.viewport.height}px`,this.render())}addEventListeners(){this.canvas.addEventListener("mousedown",this.events.mousedown),this.canvas.addEventListener("mousemove",this.events.mousemove),this.canvas.addEventListener("mouseup",this.events.mouseup),this.canvas.addEventListener("mouseleave",this.events.mouseleave),this.canvas.addEventListener("wheel",this.events.wheel),this.canvas.addEventListener("contextmenu",t=>t.preventDefault()),document.addEventListener("keydown",this.events.keydown),this.handleClickEventListener()}handleClickEventListener(){let t=null,e=0;this.canvas.addEventListener("click",i=>{if(this.eventHandler.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;const n=this.eventHandler.justFinishedMove;n&&(this.eventHandler.justFinishedMove=!1),e++,1===e?t=window.setTimeout(()=>{1!==e||n||this.events.click(i),e=0,t=null},300):2===e&&(this.eventHandler.justFinishedMove=!1,this.events.dblclick(i),e=0,null!==t&&(clearTimeout(t),t=null))})}changeScale(t){if(!this.bgImage)return;const e=o(this.viewport.scale,t),i=this.viewport.width/2,n=this.viewport.height/2,s=this.viewport.scale+e;this.viewport.updateScale(s,i,n),this.render()}clearCanvas(t=!1,e=!0){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.textManager.deselectTextAnnotation(),!t&&e&&(this.bgImage=null,this.bgImageSrc="",this.viewport.setOriginalSize(0,0),this.viewport.reset()),this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.bgImage&&this.render(),"drag"===this.drawType&&(this.canvas.style.cursor="default")}clearAnnotations(){this.clearCanvas(!0,!1)}getAnnotations(){return this.annotationManager.getAnnotations()}setAnnotationTitle(t,e){const i=this.annotationManager.setTitle(t,e);return i&&this.render(),i}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 i=this.annotationManager.setAnnotationTitleStyle(t,e);return i&&this.render(),i}setAnnotationTitlePosition(t,e){const i=this.annotationManager.setAnnotationTitlePosition(t,e);return i&&this.render(),i}getTextAnnotations(){return this.textManager.getTextAnnotations()}exportAnnotationImage(){return new Promise((t,e)=>{if(!this.bgImage)return void e(new Error("No background image loaded"));const i=document.createElement("canvas");i.width=this.viewport.originalWidth,i.height=this.viewport.originalHeight;const n=i.getContext("2d");if(!n)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(n,s,this.viewport.originalWidth,this.viewport.originalHeight);const e=i.toDataURL(`image/${this.bgImageExt}`,.7);t(e)}catch(i){this.exportCurrentViewImage().then(t).catch(t=>e(new Error(`Both methods failed: ${t.message}`)))}},s.onerror=()=>{e(new Error("Failed to load image for export"))}})}exportCurrentViewImage(){return new Promise((t,e)=>{try{t(this.canvas.toDataURL(`image/${this.bgImageExt}`))}catch(t){e(new Error(`Failed to export current view: ${t.message}`))}})}base64ToFile(t,e){return s(t,e)}static base64ToBlob(t){return a(t)}addTextAnnotation(t,e,i=""){this.textManager.addTextAnnotation(t,e,i),this.render()}updateTextAnnotation(t,e){this.textManager.updateTextAnnotation(t,e)&&this.render()}moveTextAnnotation(t,e,i){this.textManager.moveTextAnnotation(t,e,i)&&this.render()}removeTextAnnotation(t){this.textManager.removeTextAnnotation(t)&&this.render()}clearTextAnnotations(){this.textManager.clearTextAnnotations(),this.render()}selectAnnotation(t){this.annotationManager.selectAnnotation(t)&&this.render()}deselectAnnotation(){this.annotationManager.deselectAnnotation(),this.textManager.deselectTextAnnotation(),this.textManager.editingTextIndex=null,this.render()}getSelectedAnnotation(){const t=this.annotationManager.getSelectedAnnotation();if(t)return t;const e=this.textManager.getSelectedTextAnnotation();return e?{index:e.index,type:"text",data:e.data}:null}deleteSelectedAnnotation(){if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.render();this.annotationManager.deleteSelectedAnnotation()&&this.render()}moveSelectedAnnotation(t,e){this.annotationManager.moveSelectedAnnotation(t,e)&&this.render()}setAnnotationColor(t){this.annotationManager.setColorConfig(t),this.render()}getAnnotationColor(){return this.annotationManager.getColorConfig()}updateSelectedAnnotationStyle(){const t=this.annotationManager.selectedAnnotation;if(!t)return!1;const e=this.annotationManager.recordList[t.index];return!!e&&(e.style=this.annotationManager.getCurrentStyle(),this.render(),!0)}setLineStyle(t){this.annotationManager.setLineStyle(t),this.render()}getLineStyle(){return this.annotationManager.getLineStyle()}setVertexStyle(t){this.annotationManager.setVertexStyle(t),this.render()}getVertexStyle(){return this.annotationManager.getVertexStyle()}setTextStyle(t){this.textManager.setTextStyle(t),this.render()}updateTextAnnotationStyle(t,e){const i=this.textManager.updateTextAnnotationStyle(t,e);return i&&this.render(),i}setTextInputStyle(t){this.textManager.setInputStyle(t)}setTextSelectionStyle(t){this.textManager.setSelectionStyle(t),this.render()}destroy(){this.textManager.destroy(),this.annotationManager.destroyTitleInput(),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}t.AnnotationManager=h,t.Drawer=g,t.EventHandler=d,t.Renderer=c,t.TextAnnotationManager=l,t.ViewportManager=r,t.base64ToBlob=a,t.base64ToFile=s,t.default=g,t.getImageTypeFromUrl=n,t.getZoomDelta=o,t.isPointInPolygon=i,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 i=e.width>=0?e.start.x:e.start.x+e.width,n=e.height>=0?e.start.y:e.start.y+e.height,s=Math.abs(e.width),o=Math.abs(e.height);return t.x>=i&&t.x<=i+s&&t.y>=n&&t.y<=n+o}function i(t,e){if(e.length<3)return!1;let i=!1;for(let n=0,s=e.length-1;n<e.length;s=n++){const o=e[n].point.x,a=e[n].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&&(i=!i)}return i}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 s(t,e){const i=t.split(";base64,"),n=i[0].split(":")[1],s=window.atob(i[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:n});return new File([r],e,{type:n})}function o(t){return new Promise((e,i)=>{const n=t.split(";base64,");if(n.length<2)return void i(new Error("Invalid base64 string"));const s=n[0].split(":")[1],o=atob(n[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 h(){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,i){const n=this.scale,s=(e-this.offset.x)/n,o=(i-this.offset.y)/n;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+=i-r,this.calculateBoundaries(),this.constrainViewport(),this.isInitialScale=this.scale===this.initialScale}resetToInitial(){this.scale=this.initialScale,this.offset=Object.assign({},this.initialOffset),this.calculateBoundaries(),this.isInitialScale=!0}updateOffset(t,e){this.offset.x+=t,this.offset.y+=e,this.constrainViewport()}reset(){this.scale=1,this.minScale=1,this.offset={x:0,y:0},this.initialScale=1,this.initialOffset={x:0,y:0},this.isInitialScale=!0,this.minOffsetX=0,this.minOffsetY=0,this.maxOffsetX=0,this.maxOffsetY=0}}class c{constructor(t,e,i,n){this.viewport=t,this.container=e,this.renderCallback=i,this.changeCallback=n,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.applyColorConfig()}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,i){this.changeCallback&&i.id&&this.changeCallback(t,{id:i.id,type:i.type,index:e,data:r(i)})}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()}startRectDrawing(t){this.isDrawing=!0,this.drawStartPoint=t,this.operate={type:"rect",data:[{start:Object.assign({},t),width:0,height:0}],status:"pending"}}updateRectDrawing(t){if(!this.isDrawing||"rect"!==this.operate.type)return;const e=this.operate.data[0];e.width=t.x-this.drawStartPoint.x,e.height=t.y-this.drawStartPoint.y}finishRectDrawing(){if(!this.isDrawing||"rect"!==this.operate.type)return!1;const t=this.operate.data[0];if(Math.abs(t.width)>5&&Math.abs(t.height)>5){const t=Object.assign(Object.assign({},this.operate),{id:h(),style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[],this.notifyChange("create",this.recordList.length-1,t)}return this.operate.data=[],this.isDrawing=!1,!0}startPolygonDrawing(t){this.isDrawing=!0,this.operate={type:"polygon",data:[{point:t}],status:"pending"},this.tempPolygonPoint=t}addPolygonPoint(t){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;const e=this.operate.data.length>0?this.operate.data[this.operate.data.length-1]:null;return!(e&&Math.abs(e.point.x-t.x)<=5&&Math.abs(e.point.y-t.y)<=5)&&(this.operate.data.push({point:t}),!0)}updatePolygonTempPoint(t){this.tempPolygonPoint=t}finishPolygonDrawing(){if(!this.isDrawing||"polygon"!==this.operate.type)return!1;if(this.operate.data.length>=3){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{id:h(),style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[],this.notifyChange("create",this.recordList.length-1,t)}return this.operate={type:"polygon",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,!0}cancelDrawing(){if(this.isDrawing&&"polygon"===this.operate.type&&this.operate.data.length>=2){this.operate.status="fullfilled";const t=Object.assign(Object.assign({},this.operate),{id:h(),style:this.getCurrentStyle()});this.recordList.push(t),this.deleteHistory=[],this.notifyChange("create",this.recordList.length-1,t)}this.operate.data=[],this.isDrawing=!1,this.tempPolygonPoint=null}withdraw(){if(this.operate.data.length>0)return"polygon"===this.operate.type?(this.operate.data.pop(),0===this.operate.data.length&&(this.isDrawing=!1)):(this.operate.data=[],this.isDrawing=!1),!0;if(this.deleteHistory.length>0){const{annotation:t,index:e}=this.deleteHistory.pop();return this.recordList.splice(e,0,t),!0}return this.recordList.length>0&&(this.recordList.pop(),!0)}selectAnnotation(t){const e=this.resolveIndex(t);if(e<0||e>=this.recordList.length)return this.deselectAnnotation(),!1;const i=this.recordList[e];return this.selectedAnnotation={index:e,type:i.type},!0}deselectAnnotation(){this.selectedAnnotation=null,this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null}deleteSelectedAnnotation(){if(!this.selectedAnnotation)return!1;const t=this.selectedAnnotation.index,e=this.recordList[t];return this.deleteHistory.push({annotation:Object.assign({},e),index:t}),this.recordList.splice(t,1),this.deselectAnnotation(),this.notifyChange("delete",t,e),!0}startMovingAnnotation(t){return!!this.selectedAnnotation&&(this.isMovingAnnotation=!0,this.annotationMoveStart={x:t.clientX,y:t.clientY},!0)}moveSelectedAnnotation(t,e){if(!this.selectedAnnotation)return!1;const i=this.recordList[this.selectedAnnotation.index];if(!i)return!1;if("rect"===i.type){const n=i.data[0];n.start.x+=t,n.start.y+=e}else if("polygon"===i.type){i.data.forEach(i=>{i.point.x+=t,i.point.y+=e})}return!0}finishMovingAnnotation(){const t=this.isMovingAnnotation||this.isResizing;this.isMovingAnnotation=!1,this.isResizing=!1,this.activeHandle=null,this.originalRect=null,this.originalPolygon=null,t&&this.selectedAnnotation&&this.notifyUpdate(this.selectedAnnotation.index)}startResizing(t,e){if(!this.selectedAnnotation)return!1;this.activeHandle=t,this.isResizing=!0;const i=this.recordList[this.selectedAnnotation.index];return"rect"===i.type?this.originalRect=Object.assign({},i.data[0]):"polygon"===i.type&&(this.originalPolygon=i.data.map(t=>({point:Object.assign({},t.point)}))),!0}resizeRect(t){if(!this.selectedAnnotation||"rect"!==this.selectedAnnotation.type||!this.originalRect||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data[0],i=this.originalRect,n=i.start.x,s=i.start.x+i.width,o=i.start.y,a=i.start.y+i.height;let r,h;switch(this.activeHandle.index){case 0:r=s,h=a;break;case 1:r=n,h=a;break;case 2:r=s,h=o;break;case 3:r=n,h=o;break;default:return!1}const l=Math.min(t.x,r),c=Math.max(t.x,r),d=Math.min(t.y,h),g=Math.max(t.y,h);e.start.x=l,e.start.y=d,e.width=c-l,e.height=g-d;const x=t.x<r,f=t.y<h;return 0===this.activeHandle.index?x||f?!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2):this.activeHandle.index=3:1===this.activeHandle.index?x&&!f?this.activeHandle.index=2:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):2===this.activeHandle.index?!x&&f?this.activeHandle.index=1:x&&f?this.activeHandle.index=0:x||f||(this.activeHandle.index=3):3===this.activeHandle.index&&(x&&f?this.activeHandle.index=0:!x&&f?this.activeHandle.index=1:x&&!f&&(this.activeHandle.index=2)),this.originalRect=Object.assign({},e),!0}resizePolygon(t){if(!this.selectedAnnotation||"polygon"!==this.selectedAnnotation.type||!this.activeHandle)return!1;const e=this.recordList[this.selectedAnnotation.index].data,i=this.activeHandle.index;return i>=0&&i<e.length&&(e[i].point.x=t.x,e[i].point.y=t.y,!0)}getAnnotationAtPoint(t){for(let n=this.recordList.length-1;n>=0;n--){const s=this.recordList[n];if("rect"===s.type){if(e(t,s.data[0]))return{index:n,type:"rect"}}else if("polygon"===s.type){if(i(t,s.data))return{index:n,type:"polygon"}}}return null}getHandleAtPoint(t,e){if(!this.selectedAnnotation)return null;const i=this.recordList[this.selectedAnnotation.index],n=this.selectionStyle.handleSize/2;if("rect"===i.type){const s=i.data[0],o=this.viewport.offset.x+s.start.x*this.viewport.scale,a=this.viewport.offset.y+s.start.y*this.viewport.scale,r=s.width*this.viewport.scale,h=s.height*this.viewport.scale,l=[{x:o,y:a,index:0},{x:o+r,y:a,index:1},{x:o,y:a+h,index:2},{x:o+r,y:a+h,index:3}];for(const i of l)if(t>=i.x-n&&t<=i.x+n&&e>=i.y-n&&e<=i.y+n)return{type:"rect-corner",index:i.index}}else if("polygon"===i.type){const s=i.data;for(let i=0;i<s.length;i++){const o=s[i],a=this.viewport.offset.x+o.point.x*this.viewport.scale,r=this.viewport.offset.y+o.point.y*this.viewport.scale;if(t>=a-n&&t<=a+n&&e>=r-n&&e<=r+n)return{type:"polygon-vertex",index:i}}}return null}clear(){this.recordList=[],this.operate={type:"rect",data:[],status:"pending"},this.isDrawing=!1,this.tempPolygonPoint=null,this.deselectAnnotation(),this.deleteHistory=[]}getAnnotations(){return this.recordList.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.titlePosition=Object.assign({},this.titlePosition)}setAnnotationTitleStyle(t,e){const i=this.resolveIndex(t);if(i<0||i>=this.recordList.length)return!1;const n=this.recordList[i];return n.style||(n.style=this.getCurrentStyle()),n.style.titleStyle=Object.assign(Object.assign({},n.style.titleStyle||this.titleStyle),e),this.notifyUpdate(i),!0}setAnnotationTitlePosition(t,e){const i=this.resolveIndex(t);if(i<0||i>=this.recordList.length)return!1;const n=this.recordList[i];return n.style||(n.style=this.getCurrentStyle()),n.style.titlePosition=Object.assign(Object.assign({},n.style.titlePosition||this.titlePosition),e),this.notifyUpdate(i),!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 i=this.resolveIndex(t);if(i<0||i>=this.recordList.length)return!1;const n=this.recordList[i];return n.title=e||void 0,e&&this.captureTitleStyleSnapshot(n),this.notifyUpdate(i),!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 i,n;if(this.editingTitleIndex=t,this.deselectAnnotation(),"rect"===e.type){const t=e.data[0];i=this.viewport.offset.x+t.start.x*this.viewport.scale,n=this.viewport.offset.y+t.start.y*this.viewport.scale}else{const t=e.data[0];i=this.viewport.offset.x+t.point.x*this.viewport.scale,n=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=`${i}px`,this.titleInput.style.top=n-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 i=this.recordList[t];i.title=e||void 0,e&&this.captureTitleStyleSnapshot(i),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 d{constructor(t,e,i,n,s){this.viewport=t,this.container=e,this.ctx=i,this.renderCallback=n,this.changeCallback=s,this.textAnnotations=[],this.editingTextIndex=null,this.currentEditingIndex=null,this.isTextMoving=!1,this.textMoveStart={x:0,y:0},this.textBeforeEditing="",this.selectedTextIndex=null,this.textInput=null,this.deleteHistory=[],this.defaultInputStyle={border:"2px solid #00D9FF",borderRadius:"6px",padding:"6px 10px",fontSize:"16px",fontFamily:"Arial, sans-serif",backgroundColor:"#ffffff",color:"#333",boxShadow:"0 4px 12px rgba(0,0,0,0.3)",minWidth:"60px",maxWidth:"200px"},this.textStyle={font:"16px Arial",color:"#FFD700",padding:6,backgroundColor:"rgba(0,0,0,0.6)",borderRadius:4,selectedBorderColor:"#00D9FF",selectedBackgroundColor:"rgba(0,217,255,0.15)",inputStyle:Object.assign({},this.defaultInputStyle)},this.createTextInput()}createTextInput(){this.textInput=document.createElement("input"),this.textInput.type="text",this.textInput.style.position="absolute",this.textInput.style.zIndex="99999",this.textInput.style.display="none",this.textInput.style.outline="none",this.textInput.style.width="fit-content",this.textInput.placeholder="输入文字...",this.applyInputStyle(),this.textInput.addEventListener("blur",()=>{this.finishEditing(),this.renderCallback&&this.renderCallback()}),this.textInput.addEventListener("keydown",t=>{t.stopPropagation(),"Enter"===t.key?(this.finishEditing(),this.renderCallback&&this.renderCallback()):"Escape"===t.key?(t.preventDefault(),this.cancelEditing()):"Delete"===t.key&&""===this.textInput.value&&(t.preventDefault(),this.deleteEditingAnnotation())}),this.textInput.addEventListener("input",()=>{this.adjustInputWidth()}),this.container.appendChild(this.textInput)}applyInputStyle(){if(!this.textInput)return;const t=Object.assign(Object.assign({},this.defaultInputStyle),this.textStyle.inputStyle);this.textInput.style.border=t.border,this.textInput.style.borderRadius=t.borderRadius,this.textInput.style.padding=t.padding,this.textInput.style.fontSize=t.fontSize,this.textInput.style.fontFamily=t.fontFamily,this.textInput.style.backgroundColor=t.backgroundColor,this.textInput.style.color=t.color,this.textInput.style.boxShadow=t.boxShadow,this.textInput.style.minWidth=t.minWidth,this.textInput.style.maxWidth=t.maxWidth}setTextStyle(t){this.textStyle=Object.assign(Object.assign({},this.textStyle),t),this.applyInputStyle()}setInputStyle(t){this.textStyle.inputStyle=Object.assign(Object.assign({},this.textStyle.inputStyle),t),this.applyInputStyle()}setSelectionStyle(t){void 0!==t.selectedBorderColor&&(this.textStyle.selectedBorderColor=t.selectedBorderColor),void 0!==t.selectedBackgroundColor&&(this.textStyle.selectedBackgroundColor=t.selectedBackgroundColor)}getCurrentStyle(){return{font:this.textStyle.font,color:this.textStyle.color,backgroundColor:this.textStyle.backgroundColor}}notifyChange(t,e,i){this.changeCallback&&i.id&&this.changeCallback(t,{id:i.id,type:"text",index:e,data:r(i)})}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 i=this.resolveIndex(t);if(i<0||i>=this.textAnnotations.length)return!1;const n=this.textAnnotations[i];return n.style=Object.assign(Object.assign({},n.style||this.getCurrentStyle()),e),this.notifyChange("update",i,this.textAnnotations[i]),!0}addTextAnnotation(t,e,i=""){var n;this.ctx.font=this.textStyle.font;const s=i||"输入文字...",o=this.ctx.measureText(s);let a;if(o.actualBoundingBoxAscent&&o.actualBoundingBoxDescent)a=o.actualBoundingBoxAscent+o.actualBoundingBoxDescent;else{a=1.2*parseInt((null===(n=this.textStyle.font.match(/\d+/))||void 0===n?void 0:n[0])||"16")}const r={id:h(),position:{x:t,y:e},text:i,style:this.getCurrentStyle(),width:Math.max(o.width,60),height:a};this.textAnnotations.push(r);const l=this.textAnnotations.length-1;return this.notifyChange("create",l,r),this.deleteHistory=[],this.startEditing(l),l}updateTextAnnotation(t,e){const i=this.resolveIndex(t);if(i<0||i>=this.textAnnotations.length)return!1;const n=this.textAnnotations[i];n.text=e,this.ctx.font=this.textStyle.font;const s=this.ctx.measureText(e);return n.width=s.width,n.height=1.2*parseInt(this.textStyle.font),this.notifyChange("update",i,this.textAnnotations[i]),!0}moveTextAnnotation(t,e,i){const n=this.resolveIndex(t);return!(n<0||n>=this.textAnnotations.length)&&(this.textAnnotations[n].position={x:e,y:i},this.notifyChange("update",n,this.textAnnotations[n]),!0)}removeTextAnnotation(t){const e=this.resolveIndex(t);if(e<0||e>=this.textAnnotations.length)return!1;const i=this.textAnnotations[e];return this.deleteHistory.push({annotation:Object.assign({},i),index:e}),this.textAnnotations.splice(e,1),this.notifyChange("delete",e,i),this.editingTextIndex===e?this.resetEditingState():null!==this.editingTextIndex&&this.editingTextIndex>e&&this.editingTextIndex--,!0}clearTextAnnotations(){this.textAnnotations=[],this.selectedTextIndex=null,this.cancelEditing(),this.deleteHistory=[]}startEditing(t){if(!this.textInput||t<0||t>=this.textAnnotations.length)return!1;const e=this.textAnnotations[t];this.editingTextIndex=t,this.currentEditingIndex=t,this.textBeforeEditing=e.text;const i=this.viewport.offset.x+e.position.x*this.viewport.scale,n=this.viewport.offset.y+e.position.y*this.viewport.scale;return this.textInput.value=e.text,this.textInput.style.left=`${i}px`,this.textInput.style.top=`${n}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 i=this.textAnnotations[t];i.text=e,this.ctx.font=this.textStyle.font;const n=this.ctx.measureText(i.text);i.width=n.width,i.height=1.2*parseInt(this.textStyle.font),this.notifyChange("update",t,i)}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,i=Math.min(Math.max(e+24,60),200);this.textInput.style.width=`${i}px`}startMoving(t,e){return!(e<0||e>=this.textAnnotations.length)&&(this.editingTextIndex=e,this.isTextMoving=!0,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}moveAnnotation(t){if(!this.isTextMoving||null===this.editingTextIndex)return!1;const e=t.clientX-this.textMoveStart.x,i=t.clientY-this.textMoveStart.y,n=this.textAnnotations[this.editingTextIndex];return!!n&&(n.position.x+=e/this.viewport.scale,n.position.y+=i/this.viewport.scale,this.textMoveStart={x:t.clientX,y:t.clientY},!0)}finishMoving(){if(this.isTextMoving=!1,null!==this.editingTextIndex){const t=this.textAnnotations[this.editingTextIndex];t&&this.notifyChange("update",this.editingTextIndex,t)}}checkTextClick(t,e){for(let i=this.textAnnotations.length-1;i>=0;i--){const n=this.textAnnotations[i],s=this.viewport.offset.x+n.position.x*this.viewport.scale,o=this.viewport.offset.y+n.position.y*this.viewport.scale,a=Math.max(n.width,60)+2*this.textStyle.padding,r=n.height+2*this.textStyle.padding;if(t>=s&&t<=s+a&&e>=o&&e<=o+r)return i}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--,!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)}}class g{constructor(t,e,i,n,s){this.ctx=t,this.viewport=e,this.annotationManager=i,this.textManager=n,this.canvas=s}render(t){this.ctx.clearRect(0,0,this.viewport.width,this.viewport.height),t&&this.drawBackgroundImage(t),this.drawAnnotations(),this.drawTextAnnotations()}drawBackgroundImage(t){this.ctx.drawImage(t,this.viewport.offset.x,this.viewport.offset.y,this.viewport.originalWidth*this.viewport.scale,this.viewport.originalHeight*this.viewport.scale)}drawAnnotations(){this.annotationManager.recordList.forEach((t,e)=>{var i;const n=this.annotationManager.getAnnotationStyle(t);this.ctx.strokeStyle=n.strokeColor,this.ctx.lineWidth=n.lineWidth,this.setLineDash(n.lineStyle||"solid"),this.ctx.fillStyle=this.ctx.strokeStyle;const s=(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.index)===e;if("rect"===t.type)this.drawRect(t.data[0],s);else if("polygon"===t.type){const e=n.vertexStyle||this.annotationManager.getVertexStyle();this.drawPolygon(t.data,"fullfilled"===t.status,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,this.setLineDash(this.annotationManager.lineStyle),"rect"===this.annotationManager.operate.type?this.drawRect(this.annotationManager.operate.data[0],!1):"polygon"===this.annotationManager.operate.type&&this.drawCurrentPolygon()),this.ctx.setLineDash([]),this.drawSelectionHighlight()}setLineDash(t){switch(t){case"dashed":this.ctx.setLineDash([10,5]);break;case"dotted":this.ctx.setLineDash([2,4]);break;default:this.ctx.setLineDash([])}}drawRect(t,e=!1){this.ctx.strokeRect(this.viewport.offset.x+t.start.x*this.viewport.scale,this.viewport.offset.y+t.start.y*this.viewport.scale,t.width*this.viewport.scale,t.height*this.viewport.scale)}drawPolygon(t,e,i){if(0!==t.length){if(this.ctx.beginPath(),t.forEach((t,e)=>{const i=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(i,n):this.ctx.lineTo(i,n)}),e&&t.length>1){const e=t[0];this.ctx.lineTo(this.viewport.offset.x+e.point.x*this.viewport.scale,this.viewport.offset.y+e.point.y*this.viewport.scale)}this.ctx.stroke(),this.drawPolygonVertices(t,i)}}drawPolygonVertices(t,e){const i=e||this.annotationManager.getVertexStyle(),n=i.size/2;t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),s=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);switch(this.ctx.fillStyle=i.fillColor,this.ctx.strokeStyle=i.strokeColor,this.ctx.lineWidth=i.strokeWidth,this.ctx.beginPath(),i.shape){case"square":this.ctx.rect(e-n,s-n,2*n,2*n);break;case"diamond":this.ctx.moveTo(e,s-n),this.ctx.lineTo(e+n,s),this.ctx.lineTo(e,s+n),this.ctx.lineTo(e-n,s),this.ctx.closePath();break;default:this.ctx.arc(e,s,n,0,2*Math.PI)}this.ctx.fill(),i.strokeWidth>0&&this.ctx.stroke()})}drawCurrentPolygon(){const t=this.annotationManager.operate.data,e=this.annotationManager.tempPolygonPoint;if(this.ctx.beginPath(),t.forEach((t,e)=>{const i=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);0===e?this.ctx.moveTo(i,n):this.ctx.lineTo(i,n)}),e){const t=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),i=Math.round(this.viewport.offset.y+e.y*this.viewport.scale);this.ctx.lineTo(t,i)}if(this.ctx.stroke(),this.drawPolygonVertices(t,this.annotationManager.getVertexStyle()),e){const t=this.annotationManager.getVertexStyle(),i=Math.round(this.viewport.offset.x+e.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+e.y*this.viewport.scale),s=t.size/2;switch(this.ctx.fillStyle=t.fillColor,this.ctx.strokeStyle=t.strokeColor,this.ctx.lineWidth=t.strokeWidth,this.ctx.beginPath(),t.shape){case"square":this.ctx.rect(i-s,n-s,2*s,2*s);break;case"diamond":this.ctx.moveTo(i,n-s),this.ctx.lineTo(i+s,n),this.ctx.lineTo(i,n+s),this.ctx.lineTo(i-s,n),this.ctx.closePath();break;default:this.ctx.arc(i,n,s,0,2*Math.PI)}this.ctx.fill(),t.strokeWidth>0&&this.ctx.stroke()}}drawSelectionHighlight(){const t=this.annotationManager.selectedAnnotation;if(!t)return;const e=this.annotationManager.recordList[t.index];if(!e)return;const i=this.annotationManager.selectionStyle;this.ctx.save(),"rect"===e.type?this.drawRectSelectionHighlight(e.data[0],i):"polygon"===e.type&&this.drawPolygonSelectionHighlight(e.data,i),this.ctx.restore()}drawRectSelectionHighlight(t,e){const i=this.viewport.offset.x+t.start.x*this.viewport.scale,n=this.viewport.offset.y+t.start.y*this.viewport.scale,s=t.width*this.viewport.scale,o=t.height*this.viewport.scale;this.ctx.fillStyle=e.fillColor,this.ctx.fillRect(i,n,s,o),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.strokeRect(i,n,s,o);const a=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),this.ctx.fillRect(i-a/2,n-a/2,a,a),this.ctx.fillRect(i+s-a/2,n-a/2,a,a),this.ctx.fillRect(i-a/2,n+o-a/2,a,a),this.ctx.fillRect(i+s-a/2,n+o-a/2,a,a)}drawPolygonSelectionHighlight(t,e){this.ctx.beginPath(),t.forEach((t,e)=>{const i=this.viewport.offset.x+t.point.x*this.viewport.scale,n=this.viewport.offset.y+t.point.y*this.viewport.scale;0===e?this.ctx.moveTo(i,n):this.ctx.lineTo(i,n)}),this.ctx.closePath(),this.ctx.fillStyle=e.fillColor,this.ctx.fill(),this.ctx.strokeStyle=e.strokeColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.stroke();const i=e.handleSize;this.ctx.fillStyle=e.handleColor,this.ctx.setLineDash([]),t.forEach(t=>{const e=Math.round(this.viewport.offset.x+t.point.x*this.viewport.scale),n=Math.round(this.viewport.offset.y+t.point.y*this.viewport.scale);this.ctx.fillRect(e-i/2,n-i/2,i,i)})}drawAnnotationTitle(t){var e,i,n;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,c=null!==(i=s.paddingY)&&void 0!==i?i:3,d=null!==(n=s.borderRadius)&&void 0!==n?n:4;this.ctx.save(),this.ctx.font=a;const g=this.ctx.measureText(t.title).width,x=a.match(/(\d+)px/),f=x?parseInt(x[1]):12;let p,u,y,v;if("rect"===t.type){const e=t.data[0];p=this.viewport.offset.x+e.start.x*this.viewport.scale,u=this.viewport.offset.y+e.start.y*this.viewport.scale,y=e.width*this.viewport.scale,v=e.height*this.viewport.scale}else{const e=t.data;if(0===e.length)return void this.ctx.restore();let i=1/0,n=1/0,s=-1/0,o=-1/0;e.forEach(t=>{const e=this.viewport.offset.x+t.point.x*this.viewport.scale,a=this.viewport.offset.y+t.point.y*this.viewport.scale;e<i&&(i=e),a<n&&(n=a),e>s&&(s=e),a>o&&(o=a)}),p=i,u=n,y=s-i,v=o-n}const M=g+2*l,w=f+2*c,A=o.vertical||"top",S=o.offsetX||0,T=o.offsetY||0;let I;switch(A){case"bottom":I=u+v+4+T;break;case"inside-top":I=u+4+T;break;default:I=u-w-4+T}let b;switch(o.align||"center"){case"left":b=p+S;break;case"right":b=p+y-M+S;break;default:b=p+y/2-M/2+S}this.ctx.fillStyle=h,this.ctx.setLineDash([]),this.ctx.beginPath(),this.ctx.roundRect(b,I,M,w,d),this.ctx.fill(),this.ctx.fillStyle=r,this.ctx.textAlign="left",this.ctx.textBaseline="top",this.ctx.fillText(t.title,b+l,I+c),this.ctx.restore()}drawTextAnnotations(){const t=this.textManager.textStyle;this.textManager.textAnnotations.forEach((e,i)=>{if(this.textManager.editingTextIndex===i&&this.textManager.textInput&&"none"!==this.textManager.textInput.style.display)return;if(!e.text)return;const n=e.style||{font:t.font,color:t.color,backgroundColor:t.backgroundColor},s=this.viewport.offset.x+e.position.x*this.viewport.scale,o=this.viewport.offset.y+e.position.y*this.viewport.scale,a=this.textManager.selectedTextIndex===i;this.ctx.font=n.font;const r=this.ctx.measureText(e.text),h=r.actualBoundingBoxAscent||.8*e.height,l=h+(r.actualBoundingBoxDescent||.2*e.height),c=t.borderRadius,d=s,g=o,x=e.width+2*t.padding,f=l+2*t.padding;this.ctx.fillStyle=n.backgroundColor,this.ctx.beginPath(),this.ctx.roundRect(d,g,x,f,c),this.ctx.fill(),a&&(this.ctx.strokeStyle=t.selectedBorderColor,this.ctx.lineWidth=2,this.ctx.setLineDash([5,5]),this.ctx.beginPath(),this.ctx.roundRect(d,g,x,f,c),this.ctx.stroke(),this.ctx.setLineDash([]));const p=s+t.padding,u=o+t.padding+h;this.ctx.fillStyle=n.color,this.ctx.fillText(e.text,p,u)})}drawForExport(t,e,i,n){t.drawImage(e,0,0,i,n),this.annotationManager.recordList.forEach(e=>{const i=this.annotationManager.getAnnotationStyle(e);if(t.strokeStyle=i.strokeColor,t.lineWidth=i.lineWidth,"rect"===e.type){const i=e.data[0];t.strokeRect(i.start.x,i.start.y,i.width,i.height)}else if("polygon"===e.type&&"fullfilled"===e.status){t.beginPath(),e.data.forEach((e,i)=>{0===i?t.moveTo(e.point.x,e.point.y):t.lineTo(e.point.x,e.point.y)});const n=e.data[0];t.lineTo(n.point.x,n.point.y),t.stroke(),e.data.forEach(e=>{t.beginPath(),t.arc(e.point.x,e.point.y,4,0,2*Math.PI),t.fillStyle=i.strokeColor,t.fill()})}}),this.textManager.textAnnotations.forEach(e=>{const i=this.textManager.textStyle,n=e.style||{font:i.font,color:i.color,backgroundColor:i.backgroundColor};t.font=n.font;const s=t.measureText(e.text),o=s.actualBoundingBoxAscent||.8*e.height,a=o+(s.actualBoundingBoxDescent||.2*e.height),r=e.position.x,h=e.position.y,l=e.width+2*i.padding,c=a+2*i.padding,d=i.borderRadius;t.fillStyle=n.backgroundColor,t.roundRect?(t.roundRect(r,h,l,c,d),t.fill()):t.fillRect(r,h,l,c),t.fillStyle=n.color,t.fillText(e.text,e.position.x+i.padding,e.position.y+i.padding+o)}),this.annotationManager.enableTitle&&this.annotationManager.recordList.forEach(e=>{var i,n,s;if(!e.title)return;const o=this.annotationManager.getEffectiveTitleStyle(e),a=this.annotationManager.getEffectiveTitlePosition(e),r=o.font||"12px Arial",h=o.color||"#FFFFFF",l=o.backgroundColor||"rgba(0, 0, 0, 0.7)",c=null!==(i=o.paddingX)&&void 0!==i?i:6,d=null!==(n=o.paddingY)&&void 0!==n?n:3,g=null!==(s=o.borderRadius)&&void 0!==s?s:4;t.font=r;const x=t.measureText(e.title).width,f=r.match(/(\d+)px/),p=f?parseInt(f[1]):12;let u,y,v,M;if("rect"===e.type){const t=e.data[0];u=t.start.x,y=t.start.y,v=t.width,M=t.height}else{const t=e.data;if(0===t.length)return;let i=1/0,n=1/0,s=-1/0,o=-1/0;t.forEach(t=>{t.point.x<i&&(i=t.point.x),t.point.y<n&&(n=t.point.y),t.point.x>s&&(s=t.point.x),t.point.y>o&&(o=t.point.y)}),u=i,y=n,v=s-i,M=o-n}const w=x+2*c,A=p+2*d,S=a.vertical||"top",T=a.offsetX||0,I=a.offsetY||0;let b;switch(S){case"bottom":b=y+M+4+I;break;case"inside-top":b=y+4+I;break;default:b=y-A-4+I}let m;switch(a.align||"center"){case"left":m=u+T;break;case"right":m=u+v-w+T;break;default:m=u+v/2-w/2+T}t.fillStyle=l,t.roundRect?(t.roundRect(m,b,w,A,g),t.fill()):t.fillRect(m,b,w,A),t.fillStyle=h,t.textAlign="left",t.textBaseline="top",t.fillText(e.title,m+c,b+d)})}}class x{constructor(t,e,i,n,s,o,a,r,h,l){this.canvas=t,this.viewport=e,this.annotationManager=i,this.textManager=n,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,i=this.viewport.scale,n=Math.max(this.viewport.minScale,Math.min(i+e,this.viewport.maxScale)),s=this.canvas.getBoundingClientRect(),o=t.clientX-s.left,a=t.clientY-s.top,r=(o-this.viewport.offset.x)/i,h=(a-this.viewport.offset.y)/i;this.viewport.scale=n;const l=r*n+this.viewport.offset.x,c=h*n+this.viewport.offset.y;this.viewport.offset.x+=o-l,this.viewport.offset.y+=a-c,this.viewport.calculateBoundaries(),this.viewport.constrainViewport(),this.viewport.isInitialScale=this.viewport.scale===this.viewport.initialScale,this.renderCallback()}handleMouseDown(t){var e,i;if(0!==t.button)return;const n=this.getDrawType(),s=this.getBgImage();if(this.annotationManager.selectedAnnotation&&s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(i)return this.annotationManager.startResizing(i,e),void this.renderCallback()}if("text"===n){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();if(s){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getAnnotationAtPoint(e);if("rect"===(null==i?void 0:i.type))return this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(e);if("polygon"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.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"===n){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 i=this.annotationManager.getAnnotationAtPoint(o);return i&&"rect"===i.type?(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const i=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==i)return this.textManager.selectedTextIndex===i?this.textManager.startMoving(t,i):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(i)),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(o);if("polygon"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.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"===n){if("polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.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 i=this.annotationManager.getAnnotationAtPoint(o);return i&&"polygon"===i.type?(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),void this.renderCallback()):(this.annotationManager.deselectAnnotation(),this.justDeselected=!0,void this.renderCallback())}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.selectedTextIndex===e?this.textManager.startMoving(t,e):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(e)),void this.renderCallback();const n=this.annotationManager.getAnnotationAtPoint(o);if("rect"===(null==n?void 0:n.type))return this.annotationManager.selectAnnotation(n.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"===n){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):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(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""===n&&this.handleNoModeClick(t,o)}checkTextClickInDragMode(t){return!!this.textManager.checkTextClickForMove(t).handled&&(this.canvas.style.cursor="grabbing",!0)}handleTextModeClick(t){const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return this.textManager.startMoving(t,e),this.canvas.style.cursor="grabbing",this.renderCallback(),!0;const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return this.textManager.addTextAnnotation(i.x,i.y),!0}handleRectModeClick(t,e){var i,n;if("rect"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)){const i=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(i)return this.annotationManager.startResizing(i,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===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handlePolygonModeClick(t,e){var i,n;if("polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)){const i=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(i&&"polygon-vertex"===i.type)return this.annotationManager.startResizing(i,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===(n=this.annotationManager.selectedAnnotation)||void 0===n?void 0:n.type)&&(this.annotationManager.deselectAnnotation(),this.renderCallback(),!0)}handleRectModeClickForMove(t,e){const i=this.annotationManager.getAnnotationAtPoint(e);return!(!i||"rect"!==i.type)&&(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handlePolygonModeClickForMove(t,e){const i=this.annotationManager.getAnnotationAtPoint(e);return!(!i||"polygon"!==i.type)&&(this.annotationManager.selectAnnotation(i.index),this.annotationManager.startMovingAnnotation(t),this.renderCallback(),!0)}handleNoModeClick(t,e){const i=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==i)return this.textManager.selectedTextIndex===i?this.textManager.startMoving(t,i):(this.annotationManager.deselectAnnotation(),this.textManager.selectTextAnnotation(i)),void this.renderCallback();this.textManager.deselectTextAnnotation();const n=this.annotationManager.getAnnotationAtPoint(e);n?(this.annotationManager.selectAnnotation(n.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,i=t.clientY-this.dragStart.y;return this.viewport.updateOffset(e,i),this.dragStart={x:t.clientX,y:t.clientY},void this.renderCallback()}if(this.textManager.isTextMoving&&null!==this.textManager.editingTextIndex)this.textManager.moveAnnotation(t)&&this.renderCallback();else if((this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&this.annotationManager.selectedAnnotation)this.handleAnnotationMove(t);else{if(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving||this.updateCursor(t),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updateRectDrawing(e),this.renderCallback()}if("polygon"===e&&this.annotationManager.isDrawing){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.updatePolygonTempPoint(e),this.renderCallback()}}}handleAnnotationMove(t){var e,i;if(this.annotationManager.isResizing&&this.annotationManager.activeHandle){const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);return"rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)?this.annotationManager.resizeRect(n):"polygon"===(null===(i=this.annotationManager.selectedAnnotation)||void 0===i?void 0:i.type)&&this.annotationManager.resizePolygon(n),void this.renderCallback()}if(!this.annotationManager.isMovingAnnotation||!this.annotationManager.selectedAnnotation)return;const n=(t.clientX-this.annotationManager.annotationMoveStart.x)/this.viewport.scale,s=(t.clientY-this.annotationManager.annotationMoveStart.y)/this.viewport.scale;this.annotationManager.moveSelectedAnnotation(n,s),this.annotationManager.annotationMoveStart={x:t.clientX,y:t.clientY},this.renderCallback()}updateCursor(t){const e=this.getDrawType();if("text"===e){if(this.getBgImage()){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(this.annotationManager.getAnnotationAtPoint(e))return void(this.canvas.style.cursor="move")}const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);return void(this.canvas.style.cursor=null!==e?"move":"crosshair")}"rect"!==e?"polygon"!==e?"drag"!==e?""!==e?this.canvas.style.cursor="default":this.updateNoModeCursor(t):this.updateDragModeCursor(t):this.updatePolygonModeCursor(t):this.updateRectModeCursor(t)}updateRectModeCursor(t){var e;if("rect"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void(this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize")}const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(i)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updatePolygonModeCursor(t){var e;if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type)){if(this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="crosshair")}const i=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.annotationManager.getAnnotationAtPoint(i)?this.canvas.style.cursor="move":null===this.textManager.checkTextClick(t.offsetX,t.offsetY)?this.canvas.style.cursor="crosshair":this.canvas.style.cursor="move"}updateDragModeCursor(t){if(this.annotationManager.selectedAnnotation){const e=this.annotationManager.getHandleAtPoint(t.offsetX,t.offsetY);if(e)return void("rect-corner"===e.type?this.canvas.style.cursor=0===e.index||3===e.index?"nwse-resize":"nesw-resize":this.canvas.style.cursor="crosshair")}if(null!==this.textManager.checkTextClick(t.offsetX,t.offsetY))return void(this.canvas.style.cursor="move");const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=i?"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),i=this.annotationManager.getAnnotationAtPoint(e);this.canvas.style.cursor=i?"move":"default"}handleMouseUp(t){if(this.isDragging){this.isDragging=!1;const t=this.getDrawType();return void(this.canvas.style.cursor="drag"===t?"grab":"default")}if(this.textManager.isTextMoving){this.justFinishedMove=!0,this.textManager.finishMoving();const t=this.getDrawType();"drag"===t?this.canvas.style.cursor="grab":""===t?this.canvas.style.cursor="move":(this.textManager.editingTextIndex=null,this.canvas.style.cursor="default")}(this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing)&&(this.justFinishedMove=!0,this.annotationManager.finishMovingAnnotation(),this.canvas.style.cursor=this.annotationManager.selectedAnnotation?"move":"default"),this.annotationManager.isDrawing&&"rect"===this.annotationManager.operate.type&&(this.annotationManager.finishRectDrawing(),this.renderCallback())}handleMouseLeave(t){(this.isDragging||this.textManager.isTextMoving||this.annotationManager.isResizing||this.annotationManager.isMovingAnnotation)&&this.handleMouseUp(t)}handleDoubleClick(t){if(!this.getBgImage())return;this.justFinishedMove=!1;const e=this.textManager.checkTextClick(t.offsetX,t.offsetY);if(null!==e)return void this.textManager.startEditing(e);if(this.annotationManager.selectedAnnotation){const e=this.viewport.toImageCoordinates(t.offsetX,t.offsetY),i=this.annotationManager.getAnnotationAtPoint(e);if(i&&i.index===this.annotationManager.selectedAnnotation.index)return void this.annotationManager.startTitleEditing(i.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 i=this.getDrawType();if(!this.getBgImage()||"polygon"!==i||this.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;if(this.justDeselected)return void(this.justDeselected=!1);if("polygon"===(null===(e=this.annotationManager.selectedAnnotation)||void 0===e?void 0:e.type))return;const n=this.viewport.toImageCoordinates(t.offsetX,t.offsetY);this.checkPolygonPointValid(n)&&(this.annotationManager.isDrawing?this.annotationManager.addPolygonPoint(n):this.annotationManager.startPolygonDrawing(n)),this.annotationManager.updatePolygonTempPoint(n),this.renderCallback()}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(this.annotationManager.withdraw()||this.textManager.withdraw())&&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 f{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 i;null===(i=this.listeners.get(t))||void 0===i||i.delete(e)}emit(t,e){var i;null===(i=this.listeners.get(t))||void 0===i||i.forEach(t=>t(e))}clear(){this.listeners.clear()}}class p{constructor(t){this.canvas=document.createElement("canvas"),this.emitter=new f,this.bgImage=null,this.bgImageSrc="",this.bgImageExt="jpeg",this.drawType="";const{drawType:e,useEvents:i=!0,id:n="container",annotationColor:s,lineStyle:o,vertexStyle:a,textStyle:r,enableTitle:h=!1}=t,p=document.getElementById(n);if(!p)throw new Error(`Container with id "${n}" not found`);this.container=p,"absolute"!==p.style.position&&"fixed"!==p.style.position&&"relative"!==p.style.position&&(p.style.position="relative"),this.ctx=this.canvas.getContext("2d"),this.viewport=new l,this.viewport.setSize(p.clientWidth,p.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",p.appendChild(this.canvas),this.annotationManager=new c(this.viewport,this.container,()=>this.render(),(t,e)=>this.emitter.emit(t,e)),s&&this.annotationManager.setColorConfig(s),o&&this.annotationManager.setLineStyle(o),a&&this.annotationManager.setVertexStyle(a),this.annotationManager.enableTitle=h,h&&this.annotationManager.initTitleSupport(),this.textManager=new d(this.viewport,this.container,this.ctx,()=>this.render(),(t,e)=>this.emitter.emit(t,e)),r&&this.textManager.setTextStyle(r),this.renderer=new g(this.ctx,this.viewport,this.annotationManager,this.textManager,this.canvas),this.eventHandler=new x(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||""),i&&this.addEventListeners()}setDrawType(t){"polygon"===this.drawType&&this.annotationManager.isDrawing&&this.annotationManager.operate.data.length>0?console.warn("Cannot switch mode while polygon is being drawn. Please complete or cancel the polygon first."):this.drawType!==t&&(this.annotationManager.operate.data=[],this.annotationManager.isDrawing=!1,this.annotationManager.tempPolygonPoint=null,""!==t&&this.deselectAnnotation(),this.annotationManager.operate.type=t,this.drawType=t,this.canvas.style.cursor="drag"===t?"grab":"text"===t?"text":"default")}drawImage(t){this.bgImageSrc=t,this.bgImageExt=n(t);const e=new Image;e.crossOrigin="anonymous",e.src=t,e.onload=()=>{this.bgImage=e,this.viewport.setOriginalSize(e.width,e.height),this.viewport.calculateInitialView(),this.render()}}render(){this.renderer.render(this.bgImage)}clear(t=""){this.annotationManager.clear(),this.textManager.clearTextAnnotations(),this.setDrawType(t),this.render(),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",i=>{if(this.eventHandler.isDragging||this.annotationManager.isMovingAnnotation||this.annotationManager.isResizing||this.textManager.isTextMoving)return;const n=this.eventHandler.justFinishedMove;n&&(this.eventHandler.justFinishedMove=!1),e++,1===e?t=window.setTimeout(()=>{1!==e||n||this.events.click(i),e=0,t=null},300):2===e&&(this.eventHandler.justFinishedMove=!1,this.events.dblclick(i),e=0,null!==t&&(clearTimeout(t),t=null))})}changeScale(t){if(!this.bgImage)return;const e=a(this.viewport.scale,t),i=this.viewport.width/2,n=this.viewport.height/2,s=this.viewport.scale+e;this.viewport.updateScale(s,i,n),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 i=this.annotationManager.setTitle(t,e);return i&&this.render(),i}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 i=this.annotationManager.setAnnotationTitleStyle(t,e);return i&&this.render(),i}setAnnotationTitlePosition(t,e){const i=this.annotationManager.setAnnotationTitlePosition(t,e);return i&&this.render(),i}getTextAnnotations(){return this.textManager.getTextAnnotations()}exportAnnotationImage(){return new Promise((t,e)=>{if(!this.bgImage)return void e(new Error("No background image loaded"));const i=document.createElement("canvas");i.width=this.viewport.originalWidth,i.height=this.viewport.originalHeight;const n=i.getContext("2d");if(!n)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(n,s,this.viewport.originalWidth,this.viewport.originalHeight);const e=i.toDataURL(`image/${this.bgImageExt}`,.7);t(e)}catch(i){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,i=""){this.textManager.addTextAnnotation(t,e,i),this.render()}updateTextAnnotation(t,e){this.textManager.updateTextAnnotation(t,e)&&this.render()}moveTextAnnotation(t,e,i){this.textManager.moveTextAnnotation(t,e,i)&&this.render()}removeTextAnnotation(t){this.textManager.removeTextAnnotation(t)&&this.render()}clearTextAnnotations(){this.textManager.clearTextAnnotations(),this.render()}selectAnnotation(t){this.annotationManager.selectAnnotation(t)&&this.render()}deselectAnnotation(){this.annotationManager.deselectAnnotation(),this.textManager.deselectTextAnnotation(),this.textManager.editingTextIndex=null,this.render()}getSelectedAnnotation(){const t=this.annotationManager.getSelectedAnnotation();if(t)return t;const e=this.textManager.getSelectedTextAnnotation();return e?{index:e.index,type:"text",data:e.data}:null}deleteSelectedAnnotation(){if(null!==this.textManager.selectedTextIndex)return this.textManager.deleteSelectedTextAnnotation(),void this.render();this.annotationManager.deleteSelectedAnnotation()&&this.render()}moveSelectedAnnotation(t,e){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 i=this.annotationManager.recordList[e.index];return!!i&&(i.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 i=this.textManager.updateTextAnnotationStyle(t,e);return i&&this.render(),i}setTextInputStyle(t){this.textManager.setInputStyle(t)}setTextSelectionStyle(t){this.textManager.setSelectionStyle(t),this.render()}destroy(){this.emitter.clear(),this.textManager.destroy(),this.annotationManager.destroyTitleInput(),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}t.AnnotationManager=c,t.Drawer=p,t.Emitter=f,t.EventHandler=x,t.Renderer=g,t.TextAnnotationManager=d,t.ViewportManager=l,t.base64ToBlob=o,t.base64ToFile=s,t.default=p,t.getImageTypeFromUrl=n,t.getZoomDelta=a,t.isPointInPolygon=i,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.
|
|
4
|
+
"version": "1.2.0",
|
|
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",
|