luo-image-annotator 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,71 +1,72 @@
1
- var rt = Object.defineProperty;
2
- var ct = (v, t, e) => t in v ? rt(v, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : v[t] = e;
3
- var b = (v, t, e) => ct(v, typeof t != "symbol" ? t + "" : t, e);
4
- import { defineComponent as R, ref as C, watchEffect as ht, openBlock as p, createElementBlock as x, normalizeClass as T, computed as gt, onMounted as dt, watch as q, createElementVNode as h, createVNode as S, Fragment as P, renderList as D, createCommentVNode as H, normalizeStyle as j, toDisplayString as z, createTextVNode as F, withDirectives as N, vModelText as J, createBlock as Y, nextTick as vt } from "vue";
5
- const W = (v, t) => Math.sqrt(Math.pow(v.x - t.x, 2) + Math.pow(v.y - t.y, 2)), ut = (v, t) => {
6
- let e = !1;
7
- for (let s = 0, a = t.length - 1; s < t.length; a = s++) {
8
- const n = t[s].x, o = t[s].y, i = t[a].x, r = t[a].y;
9
- o > v.y != r > v.y && v.x < (i - n) * (v.y - o) / (r - o) + n && (e = !e);
1
+ var Jt = Object.defineProperty;
2
+ var jt = (m, t, i) => t in m ? Jt(m, t, { enumerable: !0, configurable: !0, writable: !0, value: i }) : m[t] = i;
3
+ var _ = (m, t, i) => jt(m, typeof t != "symbol" ? t + "" : t, i);
4
+ import { defineComponent as X, ref as I, watchEffect as Xt, openBlock as p, createElementBlock as b, normalizeClass as U, computed as ct, onMounted as Yt, watch as V, createElementVNode as g, toDisplayString as P, Fragment as T, renderList as D, normalizeStyle as F, createCommentVNode as H, createVNode as $, createTextVNode as N, withDirectives as Z, vModelText as G, createBlock as ht, nextTick as qt } from "vue";
5
+ const Q = (m, t) => Math.sqrt(Math.pow(m.x - t.x, 2) + Math.pow(m.y - t.y, 2)), Kt = (m, t) => {
6
+ let i = !1;
7
+ for (let n = 0, r = t.length - 1; n < t.length; r = n++) {
8
+ const o = t[n].x, c = t[n].y, a = t[r].x, d = t[r].y;
9
+ c > m.y != d > m.y && m.x < (a - o) * (m.y - c) / (d - c) + o && (i = !i);
10
10
  }
11
- return e;
12
- }, K = (v, t, e) => {
13
- const s = e * (Math.PI / 180), a = Math.cos(s), n = Math.sin(s), o = v.x - t.x, i = v.y - t.y;
11
+ return i;
12
+ }, dt = (m, t, i) => {
13
+ const n = i * (Math.PI / 180), r = Math.cos(n), o = Math.sin(n), c = m.x - t.x, a = m.y - t.y;
14
14
  return {
15
- x: t.x + (o * a - i * n),
16
- y: t.y + (o * n + i * a)
15
+ x: t.x + (c * r - a * o),
16
+ y: t.y + (c * o + a * r)
17
17
  };
18
18
  };
19
- class mt {
19
+ class Zt {
20
20
  constructor(t) {
21
- b(this, "canvas");
22
- b(this, "ctx");
23
- b(this, "img");
24
- b(this, "annotations", []);
21
+ _(this, "canvas");
22
+ _(this, "ctx");
23
+ _(this, "img");
24
+ _(this, "annotations", []);
25
25
  // 状态
26
- b(this, "currentTool", null);
27
- b(this, "activeAnnotation", null);
28
- b(this, "hoverAnnotation", null);
29
- b(this, "isDrawing", !1);
30
- b(this, "isDragging", !1);
31
- b(this, "isPanning", !1);
26
+ _(this, "currentTool", null);
27
+ _(this, "interactionMode", "none");
28
+ _(this, "activeAnnotation", null);
29
+ _(this, "hoverAnnotation", null);
30
+ _(this, "isDrawing", !1);
31
+ _(this, "isDragging", !1);
32
+ _(this, "isPanning", !1);
32
33
  // 平移模式
33
- b(this, "panStartPoint", null);
34
+ _(this, "panStartPoint", null);
34
35
  // 平移起点
35
- b(this, "dragStartPoint", null);
36
- b(this, "dragStartAnnotation", null);
36
+ _(this, "dragStartPoint", null);
37
+ _(this, "dragStartAnnotation", null);
37
38
  // 快照用于撤销/diff
38
- b(this, "lastMouseMovePoint", null);
39
+ _(this, "lastMouseMovePoint", null);
39
40
  // 用于绘制辅助线
40
- b(this, "isHoveringStartPoint", !1);
41
+ _(this, "isHoveringStartPoint", !1);
41
42
  // 多边形闭合吸附状态
42
43
  // 设置
43
- b(this, "currentLabelColor", "#FF4081");
44
+ _(this, "currentLabelColor", "#FF4081");
44
45
  // 当前选中标签颜色
45
- b(this, "visibleLabels", /* @__PURE__ */ new Set());
46
+ _(this, "visibleLabels", /* @__PURE__ */ new Set());
46
47
  // 可见标签集合 (如果为空则全部可见,或者由外部控制渲染列表)
47
48
  // 交互
48
- b(this, "selectedHandleIndex", -1);
49
+ _(this, "selectedHandleIndex", -1);
49
50
  // -1: 主体, >=0: 顶点索引, -2: 旋转手柄
50
- b(this, "hoverHandleIndex", -1);
51
+ _(this, "hoverHandleIndex", -1);
51
52
  // 视口
52
- b(this, "scale", 1);
53
- b(this, "offset", { x: 0, y: 0 });
54
- b(this, "listeners", {});
55
- b(this, "imageUrl", "");
53
+ _(this, "scale", 1);
54
+ _(this, "offset", { x: 0, y: 0 });
55
+ _(this, "listeners", {});
56
+ _(this, "imageUrl", "");
56
57
  this.canvas = t;
57
- const e = t.getContext("2d");
58
- if (!e) throw new Error("Could not get 2d context");
59
- this.ctx = e, this.img = new Image(), this.img.crossOrigin = "Anonymous", this.img.onload = () => {
58
+ const i = t.getContext("2d");
59
+ if (!i) throw new Error("Could not get 2d context");
60
+ this.ctx = i, this.img = new Image(), this.img.crossOrigin = "Anonymous", this.img.onload = () => {
60
61
  this.fitImageToCanvas(), this.render();
61
62
  }, this.bindEvents();
62
63
  }
63
64
  // --- 公共 API ---
64
- on(t, e) {
65
- this.listeners[t] || (this.listeners[t] = []), this.listeners[t].push(e);
65
+ on(t, i) {
66
+ this.listeners[t] || (this.listeners[t] = []), this.listeners[t].push(i);
66
67
  }
67
- emit(t, e) {
68
- this.listeners[t] && this.listeners[t].forEach((s) => s(e));
68
+ emit(t, i) {
69
+ this.listeners[t] && this.listeners[t].forEach((n) => n(i));
69
70
  }
70
71
  loadImage(t) {
71
72
  this.imageUrl = t, this.img.src = t, this.activeAnnotation = null, this.isDrawing = !1;
@@ -77,7 +78,7 @@ class mt {
77
78
  return this.annotations;
78
79
  }
79
80
  setTool(t) {
80
- t === "pan" ? (this.currentTool = null, this.isPanning = !1, this.canvas.style.cursor = "grab") : t === "select" ? (this.currentTool = null, this.canvas.style.cursor = "default") : (this.currentTool = t, this.canvas.style.cursor = "crosshair"), this.activeAnnotation = null, this.isDrawing = !1, this.render();
81
+ t === "pan" ? (this.interactionMode = "pan", this.currentTool = null, this.isPanning = !1, this.canvas.style.cursor = "grab") : t === "select" ? (this.interactionMode = "select", this.currentTool = null, this.canvas.style.cursor = "default") : t ? (this.interactionMode = "draw", this.currentTool = t, this.canvas.style.cursor = "crosshair") : (this.interactionMode = "none", this.currentTool = null, this.canvas.style.cursor = "default"), this.activeAnnotation = null, this.isDrawing = !1, this.render();
81
82
  }
82
83
  setLabelStyle(t) {
83
84
  this.currentLabelColor = t;
@@ -86,33 +87,33 @@ class mt {
86
87
  this.visibleLabels = new Set(t), this.render();
87
88
  }
88
89
  zoom(t) {
89
- const s = t > 0 ? this.scale * 1.1 : this.scale / 1.1;
90
- if (s < 0.1 || s > 10) return;
91
- const a = this.canvas.width / 2, n = this.canvas.height / 2, o = this.toImageCoords(a, n);
92
- this.scale = s, this.offset.x = a - o.x * this.scale, this.offset.y = n - o.y * this.scale, this.render();
90
+ const n = t > 0 ? this.scale * 1.1 : this.scale / 1.1;
91
+ if (n < 0.1 || n > 10) return;
92
+ const r = this.canvas.width / 2, o = this.canvas.height / 2, c = this.toImageCoords(r, o);
93
+ this.scale = n, this.offset.x = r - c.x * this.scale, this.offset.y = o - c.y * this.scale, this.render();
93
94
  }
94
95
  resize() {
95
96
  this.fitImageToCanvas(), this.render();
96
97
  }
97
98
  // --- 坐标系统 ---
98
- toImageCoords(t, e) {
99
+ toImageCoords(t, i) {
99
100
  return {
100
101
  x: (t - this.offset.x) / this.scale,
101
- y: (e - this.offset.y) / this.scale
102
+ y: (i - this.offset.y) / this.scale
102
103
  };
103
104
  }
104
- toScreenCoords(t, e) {
105
+ toScreenCoords(t, i) {
105
106
  return {
106
107
  x: t * this.scale + this.offset.x,
107
- y: e * this.scale + this.offset.y
108
+ y: i * this.scale + this.offset.y
108
109
  };
109
110
  }
110
111
  fitImageToCanvas() {
111
112
  const t = this.canvas.parentElement;
112
113
  if (t) {
113
114
  if (this.canvas.width = t.clientWidth, this.canvas.height = t.clientHeight, this.img.width === 0) return;
114
- const e = this.canvas.width / this.img.width, s = this.canvas.height / this.img.height;
115
- this.scale = Math.min(e, s), this.offset.x = (this.canvas.width - this.img.width * this.scale) / 2, this.offset.y = (this.canvas.height - this.img.height * this.scale) / 2;
115
+ const i = this.canvas.width / this.img.width, n = this.canvas.height / this.img.height;
116
+ this.scale = Math.min(i, n), this.offset.x = (this.canvas.width - this.img.width * this.scale) / 2, this.offset.y = (this.canvas.height - this.img.height * this.scale) / 2;
116
117
  }
117
118
  }
118
119
  // --- 事件处理 ---
@@ -120,85 +121,87 @@ class mt {
120
121
  this.canvas.addEventListener("mousedown", this.handleMouseDown.bind(this)), this.canvas.addEventListener("mousemove", this.handleMouseMove.bind(this)), this.canvas.addEventListener("mouseup", this.handleMouseUp.bind(this)), this.canvas.addEventListener("mouseleave", this.handleMouseUp.bind(this)), window.addEventListener("keydown", this.handleKeyDown.bind(this));
121
122
  }
122
123
  handleKeyDown(t) {
123
- (t.key === "Delete" || t.key === "Backspace") && this.activeAnnotation && this.deleteAnnotation(this.activeAnnotation.id);
124
+ this.interactionMode === "select" && (t.key === "Delete" || t.key === "Backspace") && this.activeAnnotation && this.deleteAnnotation(this.activeAnnotation.id);
124
125
  }
125
126
  deleteAnnotation(t) {
126
- const e = this.annotations.findIndex((s) => s.id === t);
127
- if (e > -1) {
128
- const s = this.annotations[e];
129
- this.annotations.splice(e, 1), this.activeAnnotation = null, this.emit("annotationChange", {
127
+ const i = this.annotations.findIndex((n) => n.id === t);
128
+ if (i > -1) {
129
+ const n = this.annotations[i];
130
+ this.annotations.splice(i, 1), this.activeAnnotation = null, this.emit("annotationChange", {
130
131
  action: "delete",
131
- changedItem: s,
132
+ changedItem: n,
132
133
  imageUrl: this.imageUrl
133
134
  }), this.render();
134
135
  }
135
136
  }
136
137
  handleMouseDown(t) {
137
- const e = this.canvas.getBoundingClientRect(), s = t.clientX - e.left, a = t.clientY - e.top, n = this.toImageCoords(s, a);
138
+ const i = this.canvas.getBoundingClientRect(), n = t.clientX - i.left, r = t.clientY - i.top, o = this.toImageCoords(n, r);
138
139
  if (this.canvas.style.cursor === "grab" || this.canvas.style.cursor === "grabbing") {
139
- this.isPanning = !0, this.panStartPoint = { x: s, y: a }, this.canvas.style.cursor = "grabbing";
140
+ this.isPanning = !0, this.panStartPoint = { x: n, y: r }, this.canvas.style.cursor = "grabbing";
140
141
  return;
141
142
  }
142
- if (this.activeAnnotation) {
143
- const r = this.getHitHandle(s, a, this.activeAnnotation);
144
- if (r !== -100) {
145
- this.isDragging = !0, this.dragStartPoint = n, this.selectedHandleIndex = r, this.dragStartAnnotation = JSON.parse(JSON.stringify(this.activeAnnotation));
143
+ if (this.interactionMode === "select" && this.activeAnnotation) {
144
+ const d = this.getHitHandle(n, r, this.activeAnnotation);
145
+ if (d !== -100) {
146
+ this.isDragging = !0, this.dragStartPoint = o, this.selectedHandleIndex = d, this.dragStartAnnotation = JSON.parse(JSON.stringify(this.activeAnnotation));
146
147
  return;
147
148
  }
148
149
  }
149
- const o = this.getHitCategory(s, a);
150
- if (o) {
151
- this.activeAnnotation = o, this.isDragging = !1, this.selectedHandleIndex = -1, this.emit("annotationChange", { action: "select", changedItem: o, imageUrl: this.imageUrl }), this.render();
150
+ const c = this.interactionMode === "select" ? this.getHitCategory(n, r) : null;
151
+ if (c) {
152
+ this.activeAnnotation = c, this.isDragging = !1, this.selectedHandleIndex = -1, this.emit("annotationChange", { action: "select", changedItem: c, imageUrl: this.imageUrl }), this.render();
152
153
  return;
153
154
  }
154
- const i = this.getHitAnnotation(n);
155
- if (this.currentTool) {
155
+ const a = this.getHitAnnotation(o);
156
+ if (this.interactionMode === "select") {
157
+ if (a) {
158
+ if (!(this.visibleLabels.size > 0 && !this.visibleLabels.has(a.label))) {
159
+ this.activeAnnotation = a, this.isDragging = !0, this.dragStartPoint = o, this.selectedHandleIndex = -1, this.dragStartAnnotation = JSON.parse(JSON.stringify(a)), this.emit("annotationChange", { action: "select", changedItem: a, imageUrl: this.imageUrl }), this.render();
160
+ return;
161
+ }
162
+ } else
163
+ this.activeAnnotation = null, this.emit("annotationChange", { action: "select", changedItem: void 0, imageUrl: this.imageUrl }), this.render();
164
+ return;
165
+ }
166
+ if (this.interactionMode === "draw") {
156
167
  if (this.isDrawing && this.currentTool === "polygon" && this.activeAnnotation) {
157
- const r = this.activeAnnotation.coordinates;
158
- if (r.points.length > 2 && W(n, r.points[0]) < 20 / this.scale) {
168
+ const d = this.activeAnnotation.coordinates;
169
+ if (d.points.length > 2 && Q(o, d.points[0]) < 20 / this.scale) {
159
170
  this.finishDrawing();
160
171
  return;
161
172
  }
162
- this.startDrawing(n);
173
+ this.startDrawing(o);
163
174
  return;
164
175
  }
165
176
  if (this.currentTool) {
166
177
  if (this.currentTool === "polygon" && !this.isDrawing) {
167
- this.startDrawing(n);
168
- return;
169
- }
170
- if (i) {
171
- this.activeAnnotation = i, this.isDragging = !0, this.dragStartPoint = n, this.selectedHandleIndex = -1, this.dragStartAnnotation = JSON.parse(JSON.stringify(i)), this.emit("annotationChange", { action: "select", changedItem: i, imageUrl: this.imageUrl }), this.render();
178
+ this.startDrawing(o);
172
179
  return;
173
180
  }
174
- this.startDrawing(n);
175
- } else i ? (this.activeAnnotation = i, this.isDragging = !0, this.dragStartPoint = n, this.selectedHandleIndex = -1, this.dragStartAnnotation = JSON.parse(JSON.stringify(i)), this.emit("annotationChange", { action: "select", changedItem: i, imageUrl: this.imageUrl }), this.render()) : (this.activeAnnotation = null, this.render());
176
- } else if (i) {
177
- if (!(this.visibleLabels.size > 0 && !this.visibleLabels.has(i.label))) {
178
- this.activeAnnotation = i, this.isDragging = !0, this.dragStartPoint = n, this.selectedHandleIndex = -1, this.dragStartAnnotation = JSON.parse(JSON.stringify(i)), this.emit("annotationChange", { action: "select", changedItem: i, imageUrl: this.imageUrl }), this.render();
179
- return;
181
+ this.startDrawing(o);
180
182
  }
181
- } else
182
- this.activeAnnotation = null, this.render();
183
+ return;
184
+ }
185
+ this.activeAnnotation = null, this.render();
183
186
  }
184
187
  handleMouseMove(t) {
185
- const e = this.canvas.getBoundingClientRect(), s = t.clientX - e.left, a = t.clientY - e.top, n = this.toImageCoords(s, a);
188
+ const i = this.canvas.getBoundingClientRect(), n = t.clientX - i.left, r = t.clientY - i.top, o = this.toImageCoords(n, r);
186
189
  if (this.isPanning && this.panStartPoint) {
187
- const o = s - this.panStartPoint.x, i = a - this.panStartPoint.y;
188
- this.offset.x += o, this.offset.y += i, this.panStartPoint = { x: s, y: a }, this.render();
190
+ const c = n - this.panStartPoint.x, a = r - this.panStartPoint.y;
191
+ this.offset.x += c, this.offset.y += a, this.panStartPoint = { x: n, y: r }, this.render();
189
192
  return;
190
193
  }
191
- if (this.lastMouseMovePoint = n, this.isDrawing) {
194
+ if (this.lastMouseMovePoint = o, this.isDrawing) {
192
195
  if (this.currentTool === "polygon" && this.activeAnnotation) {
193
- const o = this.activeAnnotation.coordinates;
194
- if (o.points.length > 2) {
195
- const i = o.points[0], r = W(n, i);
196
- this.isHoveringStartPoint = r < 20 / this.scale;
196
+ const c = this.activeAnnotation.coordinates;
197
+ if (c.points.length > 2) {
198
+ const a = c.points[0], d = Q(o, a);
199
+ this.isHoveringStartPoint = d < 20 / this.scale;
197
200
  } else
198
201
  this.isHoveringStartPoint = !1;
199
202
  }
200
- this.updateDrawing(n);
201
- } else this.isDragging && this.activeAnnotation && this.dragStartPoint ? this.updateDragging(n) : this.checkHover(s, a, n);
203
+ this.updateDrawing(o);
204
+ } else this.isDragging && this.activeAnnotation && this.dragStartPoint ? this.updateDragging(o) : this.checkHover(n, r, o);
202
205
  this.render();
203
206
  }
204
207
  handleMouseUp(t) {
@@ -221,17 +224,17 @@ class mt {
221
224
  }
222
225
  // --- 绘制逻辑 ---
223
226
  // 辅助函数:将 hex 转换为 rgba
224
- hexToRgba(t, e) {
227
+ hexToRgba(t, i) {
225
228
  if (!t.startsWith("#")) return t;
226
- const s = parseInt(t.slice(1, 3), 16), a = parseInt(t.slice(3, 5), 16), n = parseInt(t.slice(5, 7), 16);
227
- return `rgba(${s}, ${a}, ${n}, ${e})`;
229
+ const n = parseInt(t.slice(1, 3), 16), r = parseInt(t.slice(3, 5), 16), o = parseInt(t.slice(5, 7), 16);
230
+ return `rgba(${n}, ${r}, ${o}, ${i})`;
228
231
  }
229
232
  startDrawing(t) {
230
233
  if (!this.currentTool) return;
231
- const e = Date.now().toString();
234
+ const i = Date.now().toString();
232
235
  if (this.hexToRgba(this.currentLabelColor, 0.2), this.currentLabelColor, this.currentTool === "rectangle")
233
236
  this.isDrawing = !0, this.dragStartPoint = t, this.activeAnnotation = {
234
- id: e,
237
+ id: i,
235
238
  type: "rectangle",
236
239
  label: "",
237
240
  // 组件应填充此项
@@ -239,25 +242,25 @@ class mt {
239
242
  style: { strokeColor: this.currentLabelColor }
240
243
  };
241
244
  else if (this.currentTool === "point") {
242
- const s = {
243
- id: e,
245
+ const n = {
246
+ id: i,
244
247
  type: "point",
245
248
  label: "",
246
249
  coordinates: { points: [t] },
247
250
  style: { strokeColor: this.currentLabelColor }
248
251
  };
249
- this.annotations.push(s), this.emit("annotationChange", { action: "add", changedItem: s, imageUrl: this.imageUrl }), this.activeAnnotation = s;
252
+ this.annotations.push(n), this.emit("annotationChange", { action: "add", changedItem: n, imageUrl: this.imageUrl }), this.activeAnnotation = n;
250
253
  } else if (this.currentTool === "polygon")
251
254
  this.activeAnnotation && this.activeAnnotation.type === "polygon" && this.isDrawing ? this.activeAnnotation.coordinates.points.push(t) : (this.isDrawing = !0, this.activeAnnotation = {
252
- id: e,
255
+ id: i,
253
256
  type: "polygon",
254
257
  label: "",
255
258
  coordinates: { points: [t] },
256
259
  style: { strokeColor: this.currentLabelColor }
257
260
  });
258
261
  else if (this.currentTool === "category") {
259
- const s = {
260
- id: e,
262
+ const n = {
263
+ id: i,
261
264
  type: "category",
262
265
  label: "",
263
266
  // 将被填充
@@ -265,9 +268,9 @@ class mt {
265
268
  // 或位置?
266
269
  style: { strokeColor: this.currentLabelColor }
267
270
  };
268
- this.annotations.push(s), this.emit("annotationChange", { action: "add", changedItem: s, imageUrl: this.imageUrl }), this.activeAnnotation = s;
271
+ this.annotations.push(n), this.emit("annotationChange", { action: "add", changedItem: n, imageUrl: this.imageUrl }), this.activeAnnotation = n;
269
272
  } else this.currentTool === "rotatedRect" && (this.isDrawing = !0, this.dragStartPoint = t, this.activeAnnotation = {
270
- id: e,
273
+ id: i,
271
274
  type: "rotatedRect",
272
275
  label: "",
273
276
  coordinates: { x: t.x, y: t.y, width: 0, height: 0, angle: 0 },
@@ -277,11 +280,11 @@ class mt {
277
280
  updateDrawing(t) {
278
281
  if (this.activeAnnotation)
279
282
  if (this.activeAnnotation.type === "rectangle" && this.dragStartPoint) {
280
- const e = this.activeAnnotation.coordinates;
281
- e.x2 = t.x, e.y2 = t.y;
283
+ const i = this.activeAnnotation.coordinates;
284
+ i.x2 = t.x, i.y2 = t.y;
282
285
  } else if (this.activeAnnotation.type === "rotatedRect" && this.dragStartPoint) {
283
- const e = this.activeAnnotation.coordinates, s = Math.abs(t.x - this.dragStartPoint.x), a = Math.abs(t.y - this.dragStartPoint.y);
284
- e.width = s * 2, e.height = a * 2;
286
+ const i = this.activeAnnotation.coordinates, n = Math.abs(t.x - this.dragStartPoint.x), r = Math.abs(t.y - this.dragStartPoint.y);
287
+ i.width = n * 2, i.height = r * 2;
285
288
  } else this.activeAnnotation.type;
286
289
  }
287
290
  finishDrawing() {
@@ -292,8 +295,8 @@ class mt {
292
295
  this.activeAnnotation = null, this.isDrawing = !1;
293
296
  return;
294
297
  }
295
- const e = Math.min(t.x1, t.x2), s = Math.max(t.x1, t.x2), a = Math.min(t.y1, t.y2), n = Math.max(t.y1, t.y2);
296
- t.x1 = e, t.x2 = s, t.y1 = a, t.y2 = n, this.annotations.push(this.activeAnnotation), this.emit("annotationChange", { action: "add", changedItem: this.activeAnnotation, imageUrl: this.imageUrl });
298
+ const i = Math.min(t.x1, t.x2), n = Math.max(t.x1, t.x2), r = Math.min(t.y1, t.y2), o = Math.max(t.y1, t.y2);
299
+ t.x1 = i, t.x2 = n, t.y1 = r, t.y2 = o, this.annotations.push(this.activeAnnotation), this.emit("annotationChange", { action: "add", changedItem: this.activeAnnotation, imageUrl: this.imageUrl });
297
300
  } else if (this.activeAnnotation.type === "polygon") {
298
301
  if (this.activeAnnotation.coordinates.points.length < 3) {
299
302
  this.activeAnnotation = null, this.isDrawing = !1;
@@ -314,89 +317,89 @@ class mt {
314
317
  }
315
318
  updateDragging(t) {
316
319
  if (!this.activeAnnotation || !this.dragStartPoint || !this.dragStartAnnotation) return;
317
- const e = t.x - this.dragStartPoint.x, s = t.y - this.dragStartPoint.y;
318
- this.selectedHandleIndex === -1 ? this.moveAnnotation(this.activeAnnotation, this.dragStartAnnotation, e, s) : this.resizeAnnotation(this.activeAnnotation, this.dragStartAnnotation, this.selectedHandleIndex, t);
320
+ const i = t.x - this.dragStartPoint.x, n = t.y - this.dragStartPoint.y;
321
+ this.selectedHandleIndex === -1 ? this.moveAnnotation(this.activeAnnotation, this.dragStartAnnotation, i, n) : this.resizeAnnotation(this.activeAnnotation, this.dragStartAnnotation, this.selectedHandleIndex, t);
319
322
  }
320
- moveAnnotation(t, e, s, a) {
323
+ moveAnnotation(t, i, n, r) {
321
324
  if (t.type === "rectangle") {
322
- const n = e.coordinates, o = t.coordinates;
323
- o.x1 = n.x1 + s, o.x2 = n.x2 + s, o.y1 = n.y1 + a, o.y2 = n.y2 + a;
325
+ const o = i.coordinates, c = t.coordinates;
326
+ c.x1 = o.x1 + n, c.x2 = o.x2 + n, c.y1 = o.y1 + r, c.y2 = o.y2 + r;
324
327
  } else if (t.type === "point") {
325
- const n = e.coordinates, o = t.coordinates;
326
- o.points = n.points.map((i) => ({ x: i.x + s, y: i.y + a }));
328
+ const o = i.coordinates, c = t.coordinates;
329
+ c.points = o.points.map((a) => ({ x: a.x + n, y: a.y + r }));
327
330
  } else if (t.type === "rotatedRect") {
328
- const n = e.coordinates, o = t.coordinates;
329
- o.x = n.x + s, o.y = n.y + a;
331
+ const o = i.coordinates, c = t.coordinates;
332
+ c.x = o.x + n, c.y = o.y + r;
330
333
  } else if (t.type === "polygon") {
331
- const n = e.coordinates, o = t.coordinates;
332
- o.points = n.points.map((i) => ({ x: i.x + s, y: i.y + a }));
334
+ const o = i.coordinates, c = t.coordinates;
335
+ c.points = o.points.map((a) => ({ x: a.x + n, y: a.y + r }));
333
336
  }
334
337
  }
335
- resizeAnnotation(t, e, s, a) {
338
+ resizeAnnotation(t, i, n, r) {
336
339
  if (t.type === "rectangle") {
337
- const n = t.coordinates;
338
- s === 0 && (n.x1 = a.x, n.y1 = a.y), s === 1 && (n.x2 = a.x, n.y1 = a.y), s === 2 && (n.x2 = a.x, n.y2 = a.y), s === 3 && (n.x1 = a.x, n.y2 = a.y);
340
+ const o = t.coordinates;
341
+ n === 0 && (o.x1 = r.x, o.y1 = r.y), n === 1 && (o.x2 = r.x, o.y1 = r.y), n === 2 && (o.x2 = r.x, o.y2 = r.y), n === 3 && (o.x1 = r.x, o.y2 = r.y);
339
342
  } else if (t.type === "polygon") {
340
- const n = t.coordinates;
341
- s >= 0 && s < n.points.length && (n.points[s] = a);
343
+ const o = t.coordinates;
344
+ n >= 0 && n < o.points.length && (o.points[n] = r);
342
345
  } else if (t.type === "point") {
343
- const n = t.coordinates;
344
- s >= 0 && s < n.points.length && (n.points[s] = a);
346
+ const o = t.coordinates;
347
+ n >= 0 && n < o.points.length && (o.points[n] = r);
345
348
  } else if (t.type === "rotatedRect") {
346
- const n = t.coordinates;
347
- if (s === -2) {
348
- const o = n.x, i = n.y, r = a.x - o, m = a.y - i;
349
- let d = Math.atan2(m, r) * 180 / Math.PI;
350
- d += 90, n.angle = d;
349
+ const o = t.coordinates;
350
+ if (n === -2) {
351
+ const c = o.x, a = o.y, d = r.x - c, y = r.y - a;
352
+ let x = Math.atan2(y, d) * 180 / Math.PI;
353
+ x += 90, o.angle = x;
351
354
  } else {
352
- const o = n.angle * Math.PI / 180, i = Math.cos(-o), r = Math.sin(-o), m = a.x - n.x, d = a.y - n.y, u = m * i - d * r, f = m * r + d * i;
353
- (s === 0 || s === 3) && (n.width / 2, n.width = Math.abs(u) * 2), (s === 1 || s === 2) && (n.width = Math.abs(u) * 2), (s === 0 || s === 1) && (n.height = Math.abs(f) * 2), (s === 2 || s === 3) && (n.height = Math.abs(f) * 2);
355
+ const c = o.angle * Math.PI / 180, a = Math.cos(-c), d = Math.sin(-c), y = r.x - o.x, x = r.y - o.y, u = y * a - x * d, f = y * d + x * a;
356
+ (n === 0 || n === 3) && (o.width / 2, o.width = Math.abs(u) * 2), (n === 1 || n === 2) && (o.width = Math.abs(u) * 2), (n === 0 || n === 1) && (o.height = Math.abs(f) * 2), (n === 2 || n === 3) && (o.height = Math.abs(f) * 2);
354
357
  }
355
358
  }
356
359
  }
357
360
  // --- 命中测试和渲染辅助函数 ---
358
361
  getHitAnnotation(t) {
359
- for (let e = this.annotations.length - 1; e >= 0; e--) {
360
- const s = this.annotations[e];
361
- if (this.isPointInAnnotation(t, s))
362
- return s;
362
+ for (let i = this.annotations.length - 1; i >= 0; i--) {
363
+ const n = this.annotations[i];
364
+ if (this.isPointInAnnotation(t, n))
365
+ return n;
363
366
  }
364
367
  return null;
365
368
  }
366
- isPointInAnnotation(t, e) {
367
- if (e.type === "rectangle") {
368
- const s = e.coordinates;
369
- return t.x >= s.x1 && t.x <= s.x2 && t.y >= s.y1 && t.y <= s.y2;
370
- } else if (e.type === "polygon") {
371
- const s = e.coordinates;
372
- return ut(t, s.points);
373
- } else if (e.type === "rotatedRect") {
374
- const s = e.coordinates, a = K(t, { x: s.x, y: s.y }, -s.angle), n = s.width / 2, o = s.height / 2;
375
- return a.x >= s.x - n && a.x <= s.x + n && a.y >= s.y - o && a.y <= s.y + o;
376
- } else if (e.type === "point")
377
- return e.coordinates.points.some((a) => W(t, a) < 10 / this.scale);
369
+ isPointInAnnotation(t, i) {
370
+ if (i.type === "rectangle") {
371
+ const n = i.coordinates;
372
+ return t.x >= n.x1 && t.x <= n.x2 && t.y >= n.y1 && t.y <= n.y2;
373
+ } else if (i.type === "polygon") {
374
+ const n = i.coordinates;
375
+ return Kt(t, n.points);
376
+ } else if (i.type === "rotatedRect") {
377
+ const n = i.coordinates, r = dt(t, { x: n.x, y: n.y }, -n.angle), o = n.width / 2, c = n.height / 2;
378
+ return r.x >= n.x - o && r.x <= n.x + o && r.y >= n.y - c && r.y <= n.y + c;
379
+ } else if (i.type === "point")
380
+ return i.coordinates.points.some((r) => Q(t, r) < 10 / this.scale);
378
381
  return !1;
379
382
  }
380
- getHitHandle(t, e, s) {
381
- const a = this.getAnnotationHandles(s), n = 6;
382
- for (let o = 0; o < a.length; o++) {
383
- const i = a[o], r = this.toScreenCoords(i.x, i.y);
384
- if (Math.abs(t - r.x) < n && Math.abs(e - r.y) < n)
385
- return s.type === "rotatedRect" && o === 4 ? -2 : o;
383
+ getHitHandle(t, i, n) {
384
+ const r = this.getAnnotationHandles(n), o = 6;
385
+ for (let c = 0; c < r.length; c++) {
386
+ const a = r[c], d = this.toScreenCoords(a.x, a.y);
387
+ if (Math.abs(t - d.x) < o && Math.abs(i - d.y) < o)
388
+ return n.type === "rotatedRect" && c === 4 ? -2 : c;
386
389
  }
387
390
  return -100;
388
391
  }
389
392
  getAnnotationHandles(t) {
390
393
  if (t.type === "rectangle") {
391
- const e = t.coordinates;
394
+ const i = t.coordinates;
392
395
  return [
393
- { x: e.x1, y: e.y1 },
396
+ { x: i.x1, y: i.y1 },
394
397
  // 左上
395
- { x: e.x2, y: e.y1 },
398
+ { x: i.x2, y: i.y1 },
396
399
  // 右上
397
- { x: e.x2, y: e.y2 },
400
+ { x: i.x2, y: i.y2 },
398
401
  // 右下
399
- { x: e.x1, y: e.y2 }
402
+ { x: i.x1, y: i.y2 }
400
403
  // 左下
401
404
  ];
402
405
  } else {
@@ -405,24 +408,24 @@ class mt {
405
408
  if (t.type === "point")
406
409
  return t.coordinates.points;
407
410
  if (t.type === "rotatedRect") {
408
- const e = t.coordinates, s = { x: e.x, y: e.y }, a = e.width / 2, n = e.height / 2, o = { x: e.x - a, y: e.y - n }, i = { x: e.x + a, y: e.y - n }, r = { x: e.x + a, y: e.y + n }, m = { x: e.x - a, y: e.y + n }, d = { x: e.x, y: e.y - n - 20 / this.scale };
409
- return [o, i, r, m, d].map((u) => K(u, s, e.angle));
411
+ const i = t.coordinates, n = { x: i.x, y: i.y }, r = i.width / 2, o = i.height / 2, c = { x: i.x - r, y: i.y - o }, a = { x: i.x + r, y: i.y - o }, d = { x: i.x + r, y: i.y + o }, y = { x: i.x - r, y: i.y + o }, x = { x: i.x, y: i.y - o - 20 / this.scale };
412
+ return [c, a, d, y, x].map((u) => dt(u, n, i.angle));
410
413
  }
411
414
  }
412
415
  return [];
413
416
  }
414
- checkHover(t, e, s) {
415
- const a = this.getHitCategory(t, e);
416
- if (a) {
417
- this.canvas.style.cursor = "pointer", this.hoverAnnotation = a;
417
+ checkHover(t, i, n) {
418
+ const r = this.getHitCategory(t, i);
419
+ if (r) {
420
+ this.canvas.style.cursor = "pointer", this.hoverAnnotation = r;
418
421
  return;
419
422
  }
420
- if (this.activeAnnotation && this.getHitHandle(t, e, this.activeAnnotation) !== -100) {
423
+ if (this.activeAnnotation && this.getHitHandle(t, i, this.activeAnnotation) !== -100) {
421
424
  this.canvas.style.cursor = "pointer";
422
425
  return;
423
426
  }
424
- const n = this.getHitAnnotation(s);
425
- n ? (this.canvas.style.cursor = "move", this.hoverAnnotation = n) : (this.canvas.style.cursor = "default", this.hoverAnnotation = null);
427
+ const o = this.getHitAnnotation(n);
428
+ o ? (this.canvas.style.cursor = "move", this.hoverAnnotation = o) : (this.canvas.style.cursor = "default", this.hoverAnnotation = null);
426
429
  }
427
430
  render() {
428
431
  this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height), this.img.complete && this.img.width > 0 && this.ctx.drawImage(this.img, this.offset.x, this.offset.y, this.img.width * this.scale, this.img.height * this.scale), this.annotations.forEach((t) => {
@@ -430,158 +433,169 @@ class mt {
430
433
  }), this.activeAnnotation && this.drawItem(this.activeAnnotation, !0), this.renderCategories();
431
434
  }
432
435
  renderCategories() {
433
- const t = this.annotations.filter((r) => r.type === "category");
436
+ const t = this.annotations.filter((d) => d.type === "category");
434
437
  if (t.length === 0) return;
435
438
  this.ctx.save(), this.ctx.font = "14px sans-serif", this.ctx.textBaseline = "top";
436
- let e = 10;
437
- const s = 10, a = 8, n = 4, o = 24, i = 8;
438
- t.forEach((r) => {
439
- const m = r.label || "Unlabeled", d = this.ctx.measureText(m).width + a * 2, u = this.activeAnnotation === r, f = this.hoverAnnotation === r;
440
- this.ctx.fillStyle = u ? "#E3F2FD" : f ? "#F5F5F5" : "rgba(255, 255, 255, 0.9)", this.ctx.strokeStyle = u ? "#2196F3" : "#666", this.ctx.lineWidth = u ? 2 : 1, this.ctx.beginPath(), this.ctx.rect(e, s, d, o), this.ctx.fill(), this.ctx.stroke(), this.ctx.fillStyle = u ? "#1976D2" : "#333", this.ctx.fillText(m, e + a, s + n), e += d + i;
439
+ let i = 10;
440
+ const n = 10, r = 8, o = 4, c = 24, a = 8;
441
+ t.forEach((d) => {
442
+ const y = d.label || "Unlabeled", x = this.ctx.measureText(y).width + r * 2, u = this.activeAnnotation === d, f = this.hoverAnnotation === d;
443
+ this.ctx.fillStyle = u ? "#E3F2FD" : f ? "#F5F5F5" : "rgba(255, 255, 255, 0.9)", this.ctx.strokeStyle = u ? "#2196F3" : "#666", this.ctx.lineWidth = u ? 2 : 1, this.ctx.beginPath(), this.ctx.rect(i, n, x, c), this.ctx.fill(), this.ctx.stroke(), this.ctx.fillStyle = u ? "#1976D2" : "#333", this.ctx.fillText(y, i + r, n + o), i += x + a;
441
444
  }), this.ctx.restore();
442
445
  }
443
- getHitCategory(t, e) {
444
- const s = this.annotations.filter((d) => d.type === "category");
445
- if (s.length === 0) return null;
446
+ getHitCategory(t, i) {
447
+ const n = this.annotations.filter((x) => x.type === "category");
448
+ if (n.length === 0) return null;
446
449
  this.ctx.save(), this.ctx.font = "14px sans-serif";
447
- let a = 10;
448
- const n = 10, o = 8, i = 24, r = 8;
449
- let m = null;
450
- for (const d of s) {
451
- const u = d.label || "Unlabeled", f = this.ctx.measureText(u).width + o * 2;
452
- if (t >= a && t <= a + f && e >= n && e <= n + i) {
453
- m = d;
450
+ let r = 10;
451
+ const o = 10, c = 8, a = 24, d = 8;
452
+ let y = null;
453
+ for (const x of n) {
454
+ const u = x.label || "Unlabeled", f = this.ctx.measureText(u).width + c * 2;
455
+ if (t >= r && t <= r + f && i >= o && i <= o + a) {
456
+ y = x;
454
457
  break;
455
458
  }
456
- a += f + r;
459
+ r += f + d;
457
460
  }
458
- return this.ctx.restore(), m;
461
+ return this.ctx.restore(), y;
459
462
  }
460
- drawItem(t, e) {
461
- var n;
462
- if (this.visibleLabels.size > 0 && !this.visibleLabels.has(t.label) && !e)
463
+ drawItem(t, i) {
464
+ var o;
465
+ if (this.visibleLabels.size > 0 && !this.visibleLabels.has(t.label) && !i)
463
466
  return;
464
467
  this.ctx.save();
465
- const s = ((n = t.style) == null ? void 0 : n.strokeColor) || "#FF4081", a = e ? "#00E5FF" : s;
466
- if (this.ctx.strokeStyle = a, this.ctx.lineWidth = 2, e ? this.ctx.fillStyle = "rgba(0, 229, 255, 0.2)" : this.ctx.fillStyle = this.hexToRgba(s, 0.2), t.type === "rectangle") {
467
- const o = t.coordinates, i = this.toScreenCoords(o.x1, o.y1), r = this.toScreenCoords(o.x2, o.y2), m = Math.min(i.x, r.x), d = Math.min(i.y, r.y), u = Math.abs(i.x - r.x), f = Math.abs(i.y - r.y);
468
- this.ctx.strokeRect(m, d, u, f), this.ctx.fillStyle = e ? "rgba(0, 229, 255, 0.2)" : "rgba(255, 64, 129, 0.2)", this.ctx.fillRect(m, d, u, f), e && this.drawHandles(this.getAnnotationHandles(t));
468
+ const n = ((o = t.style) == null ? void 0 : o.strokeColor) || "#FF4081", r = i ? "#00E5FF" : n;
469
+ if (this.ctx.strokeStyle = r, this.ctx.lineWidth = 2, i ? this.ctx.fillStyle = "rgba(0, 229, 255, 0.2)" : this.ctx.fillStyle = this.hexToRgba(n, 0.2), t.type === "rectangle") {
470
+ const c = t.coordinates, a = this.toScreenCoords(c.x1, c.y1), d = this.toScreenCoords(c.x2, c.y2), y = Math.min(a.x, d.x), x = Math.min(a.y, d.y), u = Math.abs(a.x - d.x), f = Math.abs(a.y - d.y);
471
+ this.ctx.strokeRect(y, x, u, f), this.ctx.fillStyle = i ? "rgba(0, 229, 255, 0.2)" : "rgba(255, 64, 129, 0.2)", this.ctx.fillRect(y, x, u, f), i && this.drawHandles(this.getAnnotationHandles(t));
469
472
  } else if (t.type === "polygon") {
470
- const o = t.coordinates;
471
- if (o.points.length === 0) {
473
+ const c = t.coordinates;
474
+ if (c.points.length === 0) {
472
475
  this.ctx.restore();
473
476
  return;
474
477
  }
475
478
  this.ctx.beginPath();
476
- const i = this.toScreenCoords(o.points[0].x, o.points[0].y);
477
- this.ctx.moveTo(i.x, i.y);
478
- for (let r = 1; r < o.points.length; r++) {
479
- const m = this.toScreenCoords(o.points[r].x, o.points[r].y);
480
- this.ctx.lineTo(m.x, m.y);
479
+ const a = this.toScreenCoords(c.points[0].x, c.points[0].y);
480
+ this.ctx.moveTo(a.x, a.y);
481
+ for (let d = 1; d < c.points.length; d++) {
482
+ const y = this.toScreenCoords(c.points[d].x, c.points[d].y);
483
+ this.ctx.lineTo(y.x, y.y);
481
484
  }
482
485
  if (!this.isDrawing || t !== this.activeAnnotation)
483
486
  this.ctx.closePath();
484
487
  else if (this.lastMouseMovePoint) {
485
- let r = this.lastMouseMovePoint;
486
- if (this.isHoveringStartPoint && o.points.length > 0) {
487
- r = o.points[0];
488
- const d = this.toScreenCoords(o.points[0].x, o.points[0].y);
489
- this.ctx.save(), this.ctx.beginPath(), this.ctx.arc(d.x, d.y, 10, 0, Math.PI * 2), this.ctx.fillStyle = "rgba(255, 215, 0, 0.6)", this.ctx.strokeStyle = "#FFFFFF", this.ctx.lineWidth = 2, this.ctx.fill(), this.ctx.stroke(), this.ctx.restore();
488
+ let d = this.lastMouseMovePoint;
489
+ if (this.isHoveringStartPoint && c.points.length > 0) {
490
+ d = c.points[0];
491
+ const x = this.toScreenCoords(c.points[0].x, c.points[0].y);
492
+ this.ctx.save(), this.ctx.beginPath(), this.ctx.arc(x.x, x.y, 10, 0, Math.PI * 2), this.ctx.fillStyle = "rgba(255, 215, 0, 0.6)", this.ctx.strokeStyle = "#FFFFFF", this.ctx.lineWidth = 2, this.ctx.fill(), this.ctx.stroke(), this.ctx.restore();
490
493
  }
491
- const m = this.toScreenCoords(r.x, r.y);
492
- this.ctx.lineTo(m.x, m.y);
494
+ const y = this.toScreenCoords(d.x, d.y);
495
+ this.ctx.lineTo(y.x, y.y);
493
496
  }
494
- this.ctx.stroke(), this.ctx.fillStyle = e ? "rgba(0, 229, 255, 0.2)" : "rgba(255, 64, 129, 0.2)", this.ctx.fill(), e && this.drawHandles(this.getAnnotationHandles(t));
497
+ this.ctx.stroke(), this.ctx.fillStyle = i ? "rgba(0, 229, 255, 0.2)" : "rgba(255, 64, 129, 0.2)", this.ctx.fill(), i && this.drawHandles(this.getAnnotationHandles(t));
495
498
  } else if (t.type === "rotatedRect") {
496
- const o = t.coordinates;
497
- this.ctx.translate(this.toScreenCoords(o.x, o.y).x, this.toScreenCoords(o.x, o.y).y), this.ctx.rotate(o.angle * Math.PI / 180);
498
- const i = o.width * this.scale, r = o.height * this.scale;
499
- this.ctx.strokeRect(-i / 2, -r / 2, i, r), this.ctx.fillStyle = e ? "rgba(0, 229, 255, 0.2)" : "rgba(255, 64, 129, 0.2)", this.ctx.fillRect(-i / 2, -r / 2, i, r), this.ctx.rotate(-o.angle * Math.PI / 180), this.ctx.translate(-this.toScreenCoords(o.x, o.y).x, -this.toScreenCoords(o.x, o.y).y), e && this.drawHandles(this.getAnnotationHandles(t));
500
- } else t.type === "point" && t.coordinates.points.forEach((i) => {
501
- const r = this.toScreenCoords(i.x, i.y);
502
- this.ctx.beginPath(), this.ctx.arc(r.x, r.y, 5, 0, Math.PI * 2), this.ctx.fillStyle = e ? "#00E5FF" : s, this.ctx.fill(), this.ctx.stroke();
499
+ const c = t.coordinates;
500
+ this.ctx.translate(this.toScreenCoords(c.x, c.y).x, this.toScreenCoords(c.x, c.y).y), this.ctx.rotate(c.angle * Math.PI / 180);
501
+ const a = c.width * this.scale, d = c.height * this.scale;
502
+ this.ctx.strokeRect(-a / 2, -d / 2, a, d), this.ctx.fillStyle = i ? "rgba(0, 229, 255, 0.2)" : "rgba(255, 64, 129, 0.2)", this.ctx.fillRect(-a / 2, -d / 2, a, d), this.ctx.rotate(-c.angle * Math.PI / 180), this.ctx.translate(-this.toScreenCoords(c.x, c.y).x, -this.toScreenCoords(c.x, c.y).y), i && this.drawHandles(this.getAnnotationHandles(t));
503
+ } else t.type === "point" && t.coordinates.points.forEach((a) => {
504
+ const d = this.toScreenCoords(a.x, a.y);
505
+ this.ctx.beginPath(), this.ctx.arc(d.x, d.y, 5, 0, Math.PI * 2), this.ctx.fillStyle = i ? "#00E5FF" : n, this.ctx.fill(), this.ctx.stroke();
503
506
  });
504
507
  this.ctx.restore();
505
508
  }
506
509
  drawHandles(t) {
507
- this.ctx.fillStyle = "#FFFFFF", this.ctx.strokeStyle = "#000000", this.ctx.lineWidth = 1, t.forEach((e) => {
508
- const s = this.toScreenCoords(e.x, e.y);
509
- this.ctx.fillRect(s.x - 4, s.y - 4, 8, 8), this.ctx.strokeRect(s.x - 4, s.y - 4, 8, 8);
510
+ this.ctx.fillStyle = "#FFFFFF", this.ctx.strokeStyle = "#000000", this.ctx.lineWidth = 1, t.forEach((i) => {
511
+ const n = this.toScreenCoords(i.x, i.y);
512
+ this.ctx.fillRect(n.x - 4, n.y - 4, 8, 8), this.ctx.strokeRect(n.x - 4, n.y - 4, 8, 8);
510
513
  });
511
514
  }
512
515
  }
513
- const ft = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
516
+ const Gt = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
514
517
  <path d="M512 896a384 384 0 1 0 0-768 384 384 0 0 0 0 768zm0 64a448 448 0 1 1 0-896 448 448 0 0 1 0 896z m0-320a64 64 0 1 0 0-128 64 64 0 0 0 0 128z m0 64a128 128 0 1 1 0-256 128 128 0 0 1 0 256z" fill="currentColor"/>\r
515
- </svg>`, yt = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
518
+ </svg>`, Qt = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
516
519
  <path d="M609.408 149.376l-277.76 277.76a96 96 0 0 0 0 135.68l277.76 277.76a32 32 0 1 0 45.248-45.248L376.96 512l277.76-277.76a32 32 0 0 0-45.248-45.248z" fill="currentColor"/>\r
517
- </svg>`, pt = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
520
+ </svg>`, te = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
518
521
  <path d="M704 192h160v160h-160z m-64-64v288h288V128H640zM160 672h160v160H160z m-64-64v288h288V608H96z m256-320h320v64H352z" fill="currentColor"/>\r
519
- </svg>`, xt = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
522
+ </svg>`, ee = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
520
523
  <path d="M256 256h512v512H256z m-64-64v640h640V192H192z" fill="currentColor"/>\r
521
- </svg>`, bt = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
524
+ </svg>`, ne = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
522
525
  <path d="M160 256h704a32 32 0 1 1 0 64h-64v608a32 32 0 0 1-32 32H256a32 32 0 0 1-32-32V320h-64a32 32 0 1 1 0-64zm128 64v576h448V320H288z m128 0v512a32 32 0 1 1-64 0V320a32 32 0 1 1 64 0zm256 0v512a32 32 0 1 1-64 0V320a32 32 0 1 1 64 0zM352 128h320a32 32 0 0 1 32 32v64H320v-64a32 32 0 0 1 32-32z" fill="currentColor"/>\r
523
- </svg>`, wt = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
526
+ </svg>`, se = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
524
527
  <path d="M512 666.56l-186.88-186.88a32 32 0 0 0-45.248 45.248l209.536 209.536a96 96 0 0 0 135.68 0l209.536-209.536a32 32 0 1 0-45.248-45.248L544 666.56V128a32 32 0 0 0-64 0v538.56zM192 832h640a32 32 0 1 1 0 64H192a32 32 0 1 1 0-64z" fill="currentColor"/>\r
525
- </svg>`, Ct = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
528
+ </svg>`, ie = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
526
529
  <path d="M832 512a32 32 0 1 1 64 0v352a32 32 0 0 1-32 32H160a32 32 0 0 1-32-32V160a32 32 0 0 1 32-32h352a32 32 0 0 1 0 64H192v640h640V512z m-144-320l-480 480v160h160l480-480-160-160z m-114.56 480H256v-117.76L653.44 236.8l117.76 117.76L573.44 672z m208-208l-117.76-117.76 66.56-66.56a32 32 0 0 1 45.248 0l72.512 72.512a32 32 0 0 1 0 45.248l-66.56 66.56z" fill="currentColor"/>\r
527
- </svg>`, _t = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
530
+ </svg>`, oe = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
528
531
  <path d="M940.48 876.16L148.16 83.84a32 32 0 1 0-45.12 45.12L236.8 262.4C163.52 337.28 107.52 429.12 82.56 528.96a32 32 0 0 0 0 20.48C144.384 727.68 314.88 840.96 512 840.96c103.04 0 199.36-30.72 283.52-83.84l99.84 99.84a32 32 0 1 0 45.12-45.12zM512 776.96c-176.64 0-333.44-98.56-402.56-248.96 25.6-56.32 63.36-107.52 110.08-151.04L364.8 522.24a128 128 0 0 0 147.2 147.2l123.52 123.52A445.44 445.44 0 0 1 512 776.96z m373.12-32.64l-64-64C857.6 627.84 879.616 572.16 879.616 512c0-176.64-156.8-328.96-367.616-328.96-58.24 0-113.6 11.52-164.48 32.64l-55.68-55.68C346.88 136.96 427.52 119.04 512 119.04c229.76 0 425.216 142.08 493.44 346.24a32 32 0 0 1 0 20.48 450.56 450.56 0 0 1-120.32 258.56z m-309.12-309.12l-128-128A128 128 0 0 1 576 435.2z" fill="currentColor"/>\r
529
- </svg>`, At = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
532
+ </svg>`, ae = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
530
533
  <path d="M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896zm0 832a384 384 0 1 0 0-768 384 384 0 0 0 0 768zm-48-384H320a32 32 0 0 1 0-64h144V304a32 32 0 1 1 64 0v144h144a32 32 0 1 1 0 64H528v144a32 32 0 1 1-64 0V512z" fill="currentColor"/>\r
531
- </svg>`, kt = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
534
+ </svg>`, le = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
532
535
  <path d="M224 448a32 32 0 0 0 9.536 22.592l416 416a32 32 0 0 0 45.248 0l226.24-226.24a32 32 0 0 0 0-45.248l-416-416A32 32 0 0 0 482.432 192H256a64 64 0 0 0-64 64v192z m64-192h160l384 384-160 160-384-384V256z m64 128a64 64 0 1 0 0-128 64 64 0 0 0 0 128z" fill="currentColor"/>\r
533
- </svg>`, St = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
536
+ </svg>`, re = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
534
537
  <path d="M160 832h704a32 32 0 1 1 0 64H160a32 32 0 1 1 0-64zm0-704h704a32 32 0 1 1 0 64H160a32 32 0 1 1 0-64zm0 352h704a32 32 0 1 1 0 64H160a32 32 0 1 1 0-64z" fill="currentColor"/>\r
535
- </svg>`, It = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
538
+ </svg>`, ce = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
536
539
  <path d="M784.512 230.272v-50.56a32 32 0 1 1 64 0v149.056a32 32 0 0 1-32 32H667.52a32 32 0 1 1 0-64h92.992A320 320 0 1 0 524.8 833.152a320 320 0 0 0 320-320h64a384 384 0 0 1-384 384 384 384 0 0 1-384-384 384 384 0 0 1 643.712-282.88z" fill="currentColor"/>\r
537
- </svg>`, zt = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
540
+ </svg>`, he = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
538
541
  <path d="M340.864 149.376a32 32 0 0 0-45.248 45.248L573.44 512l-277.76 317.376a32 32 0 0 0 45.248 45.248l277.76-277.76a96 96 0 0 0 0-135.68L340.864 149.376z" fill="currentColor"/>\r
539
- </svg>`, Mt = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
542
+ </svg>`, de = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
540
543
  <path d="M512 192c229.76 0 425.216 142.08 493.44 346.24a32 32 0 0 1 0 20.48C937.216 762.88 741.76 904.96 512 904.96S86.784 762.88 18.56 558.72a32 32 0 0 1 0-20.48C86.784 334.08 282.24 192 512 192zm0 64c-197.12 0-367.616 120.32-428.16 296.32C144.384 727.68 314.88 840.96 512 840.96s367.616-113.28 428.16-288.64C879.616 376.32 709.12 256 512 256zm0 160a128 128 0 1 1 0 256 128 128 0 0 1 0-256zm0 64a64 64 0 1 0 0 128 64 64 0 0 0 0-128z" fill="currentColor"/>\r
541
- </svg>`, Ht = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
544
+ </svg>`, ge = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
542
545
  <path d="M637.12 693.376l182.208 182.208a32 32 0 1 1-45.248 45.248L591.872 738.624a352 352 0 1 1 45.248-45.248z m-45.248-45.248A288 288 0 1 0 183.872 240.128a288 288 0 0 0 408 408zM416 448h96a32 32 0 0 1 0 64h-96v96a32 32 0 0 1-64 0v-96h-96a32 32 0 0 1 0-64h96v-96a32 32 0 0 1 64 0v96z" fill="currentColor"/>\r
543
- </svg>`, Lt = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
546
+ </svg>`, ue = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
544
547
  <path d="M637.12 693.376l182.208 182.208a32 32 0 1 1-45.248 45.248L591.872 738.624a352 352 0 1 1 45.248-45.248z m-45.248-45.248A288 288 0 1 0 183.872 240.128a288 288 0 0 0 408 408zM256 448h320a32 32 0 1 1 0 64H256a32 32 0 1 1 0-64z" fill="currentColor"/>\r
545
- </svg>`, Pt = ["innerHTML"], Tt = /* @__PURE__ */ R({
548
+ </svg>`, ve = ["innerHTML"], me = /* @__PURE__ */ X({
546
549
  __name: "SvgIcon",
547
550
  props: {
548
551
  name: {},
549
552
  size: {}
550
553
  },
551
- setup(v) {
552
- const t = v, e = C(""), s = /* @__PURE__ */ Object.assign({ "../assets/svg/aim.svg": ft, "../assets/svg/back.svg": yt, "../assets/svg/connection.svg": pt, "../assets/svg/crop.svg": xt, "../assets/svg/delete.svg": bt, "../assets/svg/download.svg": wt, "../assets/svg/edit.svg": Ct, "../assets/svg/hide.svg": _t, "../assets/svg/pointer.svg": At, "../assets/svg/price-tag.svg": kt, "../assets/svg/rank.svg": St, "../assets/svg/refresh-right.svg": It, "../assets/svg/right.svg": zt, "../assets/svg/view.svg": Mt, "../assets/svg/zoom-in.svg": Ht, "../assets/svg/zoom-out.svg": Lt });
553
- return ht(() => {
554
- const a = `../assets/svg/${t.name}.svg`, n = s[a];
555
- n ? e.value = n : (console.warn(`Icon ${t.name} not found at path ${a}`), e.value = "");
556
- }), (a, n) => (p(), x("i", {
557
- class: T(["svg-icon", [v.size ? `size-${v.size}` : ""]]),
558
- innerHTML: e.value
559
- }, null, 10, Pt));
554
+ setup(m) {
555
+ const t = m, i = I(""), n = /* @__PURE__ */ Object.assign({ "../assets/svg/aim.svg": Gt, "../assets/svg/back.svg": Qt, "../assets/svg/connection.svg": te, "../assets/svg/crop.svg": ee, "../assets/svg/delete.svg": ne, "../assets/svg/download.svg": se, "../assets/svg/edit.svg": ie, "../assets/svg/hide.svg": oe, "../assets/svg/pointer.svg": ae, "../assets/svg/price-tag.svg": le, "../assets/svg/rank.svg": re, "../assets/svg/refresh-right.svg": ce, "../assets/svg/right.svg": he, "../assets/svg/view.svg": de, "../assets/svg/zoom-in.svg": ge, "../assets/svg/zoom-out.svg": ue });
556
+ return Xt(() => {
557
+ const r = `../assets/svg/${t.name}.svg`, o = n[r];
558
+ o ? i.value = o : (console.warn(`Icon ${t.name} not found at path ${r}`), i.value = "");
559
+ }), (r, o) => (p(), b("i", {
560
+ class: U(["svg-icon", [m.size ? `size-${m.size}` : ""]]),
561
+ innerHTML: i.value
562
+ }, null, 10, ve));
560
563
  }
561
- }), B = (v, t) => {
562
- const e = v.__vccOpts || v;
563
- for (const [s, a] of t)
564
- e[s] = a;
565
- return e;
566
- }, k = /* @__PURE__ */ B(Tt, [["__scopeId", "data-v-3928607b"]]), Dt = {
564
+ }), Y = (m, t) => {
565
+ const i = m.__vccOpts || m;
566
+ for (const [n, r] of t)
567
+ i[n] = r;
568
+ return i;
569
+ }, z = /* @__PURE__ */ Y(me, [["__scopeId", "data-v-3928607b"]]), fe = {
567
570
  key: 0,
571
+ class: "image-list-sidebar"
572
+ }, ye = { class: "image-list-title" }, pe = { class: "image-list-scroll" }, be = ["onClick"], xe = { class: "image-list-stage" }, we = ["src", "alt"], Ce = {
573
+ key: 0,
574
+ class: "thumb-overlay-layer"
575
+ }, Ae = {
576
+ key: 1,
577
+ class: "thumb-overlay-svg",
578
+ viewBox: "0 0 100 100",
579
+ preserveAspectRatio: "none"
580
+ }, _e = ["points"], Ie = { class: "image-list-text" }, ke = {
581
+ key: 1,
568
582
  class: "left-sidebar"
569
- }, $t = ["onClick", "title"], Ut = { class: "center-area" }, Ft = {
583
+ }, Se = ["onClick", "title"], Me = { class: "center-area" }, ze = {
570
584
  key: 0,
571
585
  class: "top-bar"
572
- }, Rt = { class: "label-selector" }, Bt = { class: "tags-row" }, Ot = ["onClick"], Vt = {
586
+ }, $e = { class: "label-selector" }, Pe = { class: "tags-row" }, He = ["onClick"], Te = {
573
587
  key: 0,
574
588
  class: "no-labels"
575
- }, Et = {
589
+ }, Le = {
576
590
  key: 1,
577
591
  class: "batch-nav"
578
- }, Nt = ["disabled"], Jt = ["disabled"], Wt = {
579
- key: 1,
580
- class: "right-sidebar"
581
- }, jt = { class: "label-list" }, Xt = { class: "label-row" }, Yt = ["onUpdate:modelValue", "onChange"], Kt = ["title"], qt = ["onClick"], Gt = { class: "action-icon more-actions" }, Qt = ["onClick"], Zt = {
592
+ }, De = ["disabled"], Re = ["disabled"], Ue = {
582
593
  key: 2,
594
+ class: "right-sidebar"
595
+ }, Fe = { class: "label-list" }, Be = { class: "label-row" }, Ee = ["onUpdate:modelValue", "onChange"], Oe = ["title"], Ve = ["onClick"], Ne = { class: "action-icon more-actions" }, We = ["onClick"], Je = {
596
+ key: 3,
583
597
  class: "modal-overlay"
584
- }, te = { class: "modal-content" }, ee = { class: "form-group" }, se = { class: "form-group" }, ne = { class: "color-input-wrapper" }, ie = /* @__PURE__ */ R({
598
+ }, je = { class: "modal-content" }, Xe = { class: "form-group" }, Ye = { class: "form-group" }, qe = { class: "color-input-wrapper" }, Ke = /* @__PURE__ */ X({
585
599
  __name: "ImageAnnotator",
586
600
  props: {
587
601
  annotationTypes: { default: () => ["rectangle", "polygon", "point", "rotatedRect"] },
@@ -589,334 +603,571 @@ const ft = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" widt
589
603
  labels: { default: () => [] },
590
604
  defaultActiveType: {},
591
605
  theme: { default: "light" },
592
- readOnly: { type: Boolean, default: !1 }
606
+ readOnly: { type: Boolean, default: !1 },
607
+ image: {},
608
+ predictionCandidates: {},
609
+ session: {},
610
+ requestId: {},
611
+ minZoom: {},
612
+ maxZoom: {}
593
613
  },
594
- emits: ["annotationChange", "batchChange", "labelChange"],
595
- setup(v, { expose: t, emit: e }) {
596
- const s = v, a = e, n = C(null), o = C(null), i = C(null), r = C(null), m = C(0), d = C([]), u = C(""), f = C(!1), y = C({ name: "", color: "#FF0000" }), w = gt(() => s.annotationTypes.filter((l) => l !== "category")), A = (l) => ({
614
+ emits: ["annotationChange", "batchChange", "labelChange", "ready", "error", "tool:change", "viewport:change", "annotation:add", "annotation:update", "annotation:delete", "annotation:select", "prediction:loaded", "prediction:apply", "prediction:reject"],
615
+ setup(m, { expose: t, emit: i }) {
616
+ const n = m, r = i, o = I(null), c = I(null), a = I(null), d = I(null), y = I(0), x = I(""), u = I([]), f = I(""), C = I(!1), A = I({ name: "", color: "#FF0000" }), S = I("none"), M = I([]), L = I({}), tt = ct(() => d.value === "select" && !!x.value), et = (e) => {
617
+ if (!e || L.value[e]) return;
618
+ const s = new Image();
619
+ s.onload = () => {
620
+ const l = s.naturalWidth || 1, h = s.naturalHeight || 1;
621
+ L.value = {
622
+ ...L.value,
623
+ [e]: { width: l, height: h }
624
+ };
625
+ }, s.src = e;
626
+ }, nt = () => {
627
+ n.batchImages.forEach((e) => {
628
+ et(e.imageUrl);
629
+ });
630
+ }, R = () => {
631
+ var l, h, v, w;
632
+ const e = n.batchImages[y.value], s = (e == null ? void 0 : e.imageUrl) || ((l = n.image) == null ? void 0 : l.url);
633
+ return {
634
+ eventId: `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`,
635
+ timestamp: Date.now(),
636
+ requestId: n.requestId,
637
+ taskId: (h = n.session) == null ? void 0 : h.taskId,
638
+ imageId: ((v = n.image) == null ? void 0 : v.id) || s,
639
+ operator: (w = n.session) == null ? void 0 : w.userId
640
+ };
641
+ }, gt = (e) => {
642
+ var h;
643
+ const s = e == null ? void 0 : e.action;
644
+ if (!s) return;
645
+ const l = {
646
+ meta: R(),
647
+ action: s,
648
+ current: e == null ? void 0 : e.changedItem,
649
+ source: (h = e == null ? void 0 : e.changedItem) != null && h.predictionId ? "prediction" : "manual"
650
+ };
651
+ s === "add" && r("annotation:add", l), s === "update" && r("annotation:update", l), s === "delete" && r("annotation:delete", l), s === "select" && r("annotation:select", l);
652
+ }, ut = ct(() => n.annotationTypes.filter((e) => e !== "category")), vt = (e) => ({
597
653
  rectangle: "crop",
598
654
  polygon: "connection",
599
655
  point: "aim",
600
656
  rotatedRect: "refresh-right",
601
657
  category: "price-tag"
602
- })[l] || l, I = (l) => ({
658
+ })[e] || e, mt = (e) => ({
603
659
  rectangle: "矩形框",
604
660
  polygon: "多边形",
605
661
  point: "关键点",
606
662
  rotatedRect: "旋转矩形",
607
663
  category: "分类标签"
608
- })[l] || l;
609
- dt(() => {
610
- if (n.value) {
611
- i.value = new mt(n.value), i.value.on("annotationChange", (c) => {
612
- if (c.action === "add" && c.changedItem) {
613
- const g = d.value.find((_) => _.id === u.value);
614
- g && (c.changedItem.label = g.name);
664
+ })[e] || e;
665
+ Yt(() => {
666
+ if (nt(), o.value) {
667
+ a.value = new Zt(o.value), a.value.on("annotationChange", (s) => {
668
+ var l, h;
669
+ if (s.action === "add" && s.changedItem) {
670
+ const v = u.value.find((w) => w.id === f.value);
671
+ v && (s.changedItem.label = v.name, s.changedItem.labelId = v.id);
615
672
  }
616
- a("annotationChange", c);
617
- }), $(), L();
618
- const l = new ResizeObserver(() => {
619
- var c;
620
- (c = i.value) == null || c.resize();
673
+ s.action === "select" ? x.value = ((l = s.changedItem) == null ? void 0 : l.id) || "" : s.action === "delete" && ((h = s.changedItem) == null ? void 0 : h.id) === x.value && (x.value = ""), r("annotationChange", s), gt(s);
674
+ }), B(), W();
675
+ const e = new ResizeObserver(() => {
676
+ var s;
677
+ (s = a.value) == null || s.resize();
621
678
  });
622
- o.value && l.observe(o.value);
679
+ c.value && e.observe(c.value), n.defaultActiveType && E(n.defaultActiveType), r("ready", { meta: R() });
623
680
  }
624
681
  });
625
- const L = () => {
626
- if (!i.value) return;
627
- const l = d.value.find((g) => g.id === u.value);
628
- l && i.value.setLabelStyle(l.color);
629
- const c = d.value.filter((g) => g.visible).map((g) => g.name);
630
- i.value.setVisibleLabels(c);
631
- }, $ = () => {
632
- if (i.value && s.batchImages.length > 0) {
633
- const l = s.batchImages[m.value];
634
- i.value.loadImage(l.imageUrl), l.annotations && i.value.setAnnotations(l.annotations);
635
- }
636
- }, O = (l) => {
637
- var c, g;
638
- if (r.value = l, l !== "pan" && l !== "select" && d.value.length === 0) {
682
+ const W = () => {
683
+ if (!a.value) return;
684
+ const e = u.value.find((l) => l.id === f.value);
685
+ e && a.value.setLabelStyle(e.color);
686
+ const s = u.value.filter((l) => l.visible).map((l) => l.name);
687
+ a.value.setVisibleLabels(s);
688
+ }, B = () => {
689
+ var e;
690
+ if (a.value)
691
+ if (x.value = "", n.batchImages.length > 0) {
692
+ const s = n.batchImages[y.value];
693
+ a.value.loadImage(s.imageUrl), s.annotations ? a.value.setAnnotations(s.annotations) : a.value.setAnnotations([]);
694
+ } else (e = n.image) != null && e.url && a.value.loadImage(n.image.url);
695
+ }, E = (e) => {
696
+ var s, l;
697
+ if (d.value = e, x.value = "", e !== "pan" && e !== "select" && u.value.length === 0) {
639
698
  alert("请先创建标签!");
640
699
  return;
641
700
  }
642
- l === "pan" || l === "select" ? (c = i.value) == null || c.setTool(l) : (g = i.value) == null || g.setTool(l);
643
- }, G = () => {
644
- var l;
645
- (l = i.value) != null && l.activeAnnotation && i.value.deleteAnnotation(i.value.activeAnnotation.id);
646
- }, Q = () => {
647
- var l;
648
- return (l = i.value) == null ? void 0 : l.zoom(1);
649
- }, Z = () => {
650
- var l;
651
- return (l = i.value) == null ? void 0 : l.zoom(-1);
652
- }, tt = () => {
653
- y.value = { name: "", color: "#2196F3" }, f.value = !0;
654
- }, X = () => {
655
- f.value = !1;
656
- }, et = () => {
657
- if (!y.value.name.trim()) {
701
+ e === "pan" || e === "select" ? (s = a.value) == null || s.setTool(e) : (l = a.value) == null || l.setTool(e), r("tool:change", { meta: R(), tool: e });
702
+ }, ft = () => {
703
+ var e;
704
+ (e = a.value) != null && e.activeAnnotation && a.value.deleteAnnotation(a.value.activeAnnotation.id);
705
+ }, st = () => {
706
+ a.value && r("viewport:change", {
707
+ meta: R(),
708
+ scale: a.value.scale,
709
+ offset: { ...a.value.offset }
710
+ });
711
+ }, yt = () => {
712
+ var e;
713
+ (e = a.value) == null || e.zoom(1), st();
714
+ }, pt = () => {
715
+ var e;
716
+ (e = a.value) == null || e.zoom(-1), st();
717
+ }, bt = () => {
718
+ A.value = { name: "", color: "#2196F3" }, C.value = !0;
719
+ }, it = () => {
720
+ C.value = !1;
721
+ }, xt = () => {
722
+ if (!A.value.name.trim()) {
658
723
  alert("请输入标签名称");
659
724
  return;
660
725
  }
661
- const c = {
726
+ const s = {
662
727
  id: Date.now().toString(),
663
- name: y.value.name,
664
- color: y.value.color,
728
+ name: A.value.name,
729
+ color: A.value.color,
665
730
  visible: !0
666
731
  };
667
- d.value.push(c), a("labelChange", d.value), d.value.length === 1 && U(c), X();
668
- }, U = (l) => {
669
- var c;
670
- u.value = l.id, (c = i.value) == null || c.setLabelStyle(l.color);
671
- }, st = (l, c) => {
672
- if (!l.startsWith("#")) return l;
673
- let g = 0, _ = 0, M = 0;
674
- return l.length === 4 ? (g = parseInt(l[1] + l[1], 16), _ = parseInt(l[2] + l[2], 16), M = parseInt(l[3] + l[3], 16)) : l.length === 7 && (g = parseInt(l.slice(1, 3), 16), _ = parseInt(l.slice(3, 5), 16), M = parseInt(l.slice(5, 7), 16)), `rgba(${g}, ${_}, ${M}, ${c})`;
675
- }, nt = (l) => {
676
- var c;
677
- if (l.id === u.value && ((c = i.value) == null || c.setLabelStyle(l.color)), i.value) {
678
- const g = i.value.getAnnotations();
679
- let _ = !1;
680
- g.forEach((M) => {
681
- M.label === l.name && (M.style || (M.style = {}), M.style.strokeColor = l.color, M.style.fillColor = st(l.color, 0.2), _ = !0);
682
- }), _ && i.value.render();
732
+ u.value.push(s), r("labelChange", u.value), u.value.length === 1 && O(s), it();
733
+ }, O = (e) => {
734
+ var s;
735
+ f.value = e.id, (s = a.value) == null || s.setLabelStyle(e.color);
736
+ }, wt = (e, s) => {
737
+ if (!e.startsWith("#")) return e;
738
+ let l = 0, h = 0, v = 0;
739
+ return e.length === 4 ? (l = parseInt(e[1] + e[1], 16), h = parseInt(e[2] + e[2], 16), v = parseInt(e[3] + e[3], 16)) : e.length === 7 && (l = parseInt(e.slice(1, 3), 16), h = parseInt(e.slice(3, 5), 16), v = parseInt(e.slice(5, 7), 16)), `rgba(${l}, ${h}, ${v}, ${s})`;
740
+ }, Ct = (e) => {
741
+ var s;
742
+ if (e.id === f.value && ((s = a.value) == null || s.setLabelStyle(e.color)), a.value) {
743
+ const l = a.value.getAnnotations();
744
+ let h = !1;
745
+ l.forEach((v) => {
746
+ v.label === e.name && (v.style || (v.style = {}), v.style.strokeColor = e.color, v.style.fillColor = wt(e.color, 0.2), h = !0);
747
+ }), h && a.value.render();
683
748
  }
684
- a("labelChange", d.value);
685
- }, it = (l) => {
686
- l.visible = !l.visible, L();
687
- }, ot = (l) => {
688
- const c = d.value.findIndex((g) => g.id === l);
689
- c > -1 && (d.value.splice(c, 1), a("labelChange", d.value), u.value === l && (u.value = d.value.length > 0 ? d.value[0].id : "", u.value && U(d.value[0])), L());
749
+ r("labelChange", u.value);
750
+ }, At = (e) => {
751
+ e.visible = !e.visible, W();
752
+ }, _t = (e) => {
753
+ const s = u.value.findIndex((l) => l.id === e);
754
+ s > -1 && (u.value.splice(s, 1), r("labelChange", u.value), f.value === e && (f.value = u.value.length > 0 ? u.value[0].id : "", f.value && O(u.value[0])), W());
690
755
  };
691
- q(() => s.labels, (l) => {
692
- const c = JSON.parse(JSON.stringify(l || []));
693
- if (d.value = c, d.value.length > 0)
694
- if (!u.value || !d.value.find((g) => g.id === u.value))
695
- U(d.value[0]);
756
+ V(() => n.labels, (e) => {
757
+ const s = JSON.parse(JSON.stringify(e || []));
758
+ if (u.value = s, u.value.length > 0)
759
+ if (!f.value || !u.value.find((l) => l.id === f.value))
760
+ O(u.value[0]);
696
761
  else {
697
- const g = d.value.find((_) => _.id === u.value);
698
- g && U(g);
762
+ const l = u.value.find((h) => h.id === f.value);
763
+ l && O(l);
699
764
  }
700
765
  else
701
- u.value = "";
702
- L();
766
+ f.value = "";
767
+ W();
703
768
  }, { immediate: !0, deep: !0 });
704
- const at = () => {
705
- m.value > 0 && (V(), m.value--, $(), E());
706
- }, lt = () => {
707
- m.value < s.batchImages.length - 1 && (V(), m.value++, $(), E());
708
- }, V = () => {
709
- if (i.value) {
710
- const l = i.value.getAnnotations();
711
- s.batchImages[m.value].annotations = l;
769
+ const It = () => {
770
+ y.value > 0 && (q(), y.value--, B(), K());
771
+ }, kt = () => {
772
+ y.value < n.batchImages.length - 1 && (q(), y.value++, B(), K());
773
+ }, q = () => {
774
+ if (a.value) {
775
+ const e = a.value.getAnnotations();
776
+ n.batchImages[y.value].annotations = e;
712
777
  }
713
- }, E = () => {
714
- const l = s.batchImages[m.value];
715
- a("batchChange", {
716
- currentIndex: m.value,
717
- total: s.batchImages.length,
718
- currentImageUrl: l.imageUrl,
719
- currentAnnotations: l.annotations || []
778
+ }, K = () => {
779
+ const e = n.batchImages[y.value];
780
+ r("batchChange", {
781
+ currentIndex: y.value,
782
+ total: n.batchImages.length,
783
+ currentImageUrl: e.imageUrl,
784
+ currentAnnotations: e.annotations || []
720
785
  });
786
+ }, ot = (e = []) => {
787
+ var v;
788
+ if (!a.value) return;
789
+ if (M.value = JSON.parse(JSON.stringify(e)), M.value.length === 0) {
790
+ S.value = "none";
791
+ return;
792
+ }
793
+ S.value = "loaded";
794
+ const l = (a.value.getAnnotations() || []).filter((w) => !w.predictionId), h = M.value.map((w) => {
795
+ const k = JSON.parse(JSON.stringify(w.annotation));
796
+ return k.id = k.id || `pred-${w.id}`, k.predictionId = w.id, k.modelRunId = w.modelRunId || k.modelRunId, k.confidence = w.confidence ?? k.confidence, k.reviewStatus = k.reviewStatus || "draft", k;
797
+ });
798
+ a.value.setAnnotations([...l, ...h]), r("prediction:loaded", {
799
+ meta: R(),
800
+ modelRunId: (v = M.value[0]) == null ? void 0 : v.modelRunId,
801
+ candidates: M.value
802
+ });
803
+ }, St = (e, s) => {
804
+ var v;
805
+ if (!a.value) return [];
806
+ S.value = "applying";
807
+ const h = (a.value.getAnnotations() || []).filter((w) => w.predictionId && e.includes(w.predictionId));
808
+ return h.forEach((w) => {
809
+ w.reviewStatus = "accepted";
810
+ }), S.value = "applied", r("prediction:apply", {
811
+ meta: R(),
812
+ modelRunId: (v = h[0]) == null ? void 0 : v.modelRunId,
813
+ candidateIds: e,
814
+ threshold: s,
815
+ acceptedAnnotations: h
816
+ }), a.value.render(), h;
817
+ }, Mt = (e, s) => {
818
+ var v;
819
+ if (!a.value) return;
820
+ const l = a.value.getAnnotations() || [], h = l.filter((w) => !(w.predictionId && e.includes(w.predictionId)));
821
+ a.value.setAnnotations(h), r("prediction:reject", {
822
+ meta: R(),
823
+ modelRunId: (v = l.find((w) => w.predictionId && e.includes(w.predictionId))) == null ? void 0 : v.modelRunId,
824
+ candidateIds: e,
825
+ reason: s
826
+ });
827
+ }, zt = (e, s = []) => {
828
+ a.value && (a.value.loadImage(e.url), a.value.setAnnotations(s));
829
+ }, $t = (e) => {
830
+ var s;
831
+ (s = a.value) == null || s.setAnnotations(e);
832
+ }, at = () => {
833
+ var e;
834
+ return ((e = a.value) == null ? void 0 : e.getAnnotations()) || [];
835
+ }, Pt = (e = "json") => {
836
+ var l, h;
837
+ const s = at();
838
+ return {
839
+ format: e,
840
+ image: ((l = n.batchImages[y.value]) == null ? void 0 : l.imageUrl) || ((h = n.image) == null ? void 0 : h.url) || "",
841
+ annotations: s
842
+ };
843
+ }, lt = (e) => {
844
+ e >= 0 && e < n.batchImages.length && (q(), y.value = e, B(), K());
845
+ }, Ht = (e) => {
846
+ var s;
847
+ return e === y.value && a.value ? a.value.getAnnotations() || [] : ((s = n.batchImages[e]) == null ? void 0 : s.annotations) || [];
848
+ }, Tt = (e) => e.type === "rectangle", Lt = (e) => e.type === "polygon", Dt = (e) => e.type === "point", Rt = (e) => e.type === "rotatedRect", J = (e) => {
849
+ var l, h;
850
+ const s = (l = u.value.find((v) => v.name === e.label)) == null ? void 0 : l.color;
851
+ return ((h = e.style) == null ? void 0 : h.strokeColor) || s || "#409eff";
852
+ }, rt = (e) => {
853
+ const s = e.coordinates;
854
+ return (s == null ? void 0 : s.points) || [];
855
+ }, j = (e) => {
856
+ const s = n.batchImages[e];
857
+ if (s != null && s.width && (s != null && s.height))
858
+ return { width: s.width, height: s.height };
859
+ const l = s != null && s.imageUrl ? L.value[s.imageUrl] : void 0;
860
+ return l || (s != null && s.imageUrl && et(s.imageUrl), { width: 1, height: 1 });
861
+ }, Ut = (e) => {
862
+ const s = n.batchImages[e];
863
+ return s != null && s.width && (s != null && s.height) ? !0 : s != null && s.imageUrl ? !!L.value[s.imageUrl] : !1;
864
+ }, Ft = (e, s) => {
865
+ const l = s.coordinates, h = j(e), v = J(s), w = Math.min(l.x1, l.x2), k = Math.min(l.y1, l.y2), Nt = Math.max(l.x1, l.x2), Wt = Math.max(l.y1, l.y2);
866
+ return {
867
+ left: `${w / h.width * 100}%`,
868
+ top: `${k / h.height * 100}%`,
869
+ width: `${(Nt - w) / h.width * 100}%`,
870
+ height: `${(Wt - k) / h.height * 100}%`,
871
+ borderColor: v,
872
+ backgroundColor: `${v}22`
873
+ };
874
+ }, Bt = (e, s) => {
875
+ const l = j(e);
876
+ return rt(s).map((h) => `${h.x / l.width * 100},${h.y / l.height * 100}`).join(" ");
877
+ }, Et = (e) => {
878
+ const s = J(e);
879
+ return {
880
+ fill: `${s}33`,
881
+ stroke: s,
882
+ strokeWidth: "1.4"
883
+ };
884
+ }, Ot = (e, s, l) => {
885
+ const h = j(e), v = J(l);
886
+ return {
887
+ left: `${s.x / h.width * 100}%`,
888
+ top: `${s.y / h.height * 100}%`,
889
+ backgroundColor: v
890
+ };
891
+ }, Vt = (e, s) => {
892
+ const l = s.coordinates, h = j(e), v = J(s), w = Math.abs(l.width), k = Math.abs(l.height);
893
+ return {
894
+ left: `${(l.x - w / 2) / h.width * 100}%`,
895
+ top: `${(l.y - k / 2) / h.height * 100}%`,
896
+ width: `${w / h.width * 100}%`,
897
+ height: `${k / h.height * 100}%`,
898
+ transform: `rotate(${l.angle || 0}deg)`,
899
+ borderColor: v,
900
+ backgroundColor: `${v}22`
901
+ };
721
902
  };
722
903
  return t({
723
- jumpTo: (l) => {
724
- l >= 0 && l < s.batchImages.length && (V(), m.value = l, $(), E());
904
+ jumpTo: lt,
905
+ setImage: zt,
906
+ setAnnotations: $t,
907
+ getAnnotations: at,
908
+ selectTool: E,
909
+ loadPredictionCandidates: ot,
910
+ applyPredictions: St,
911
+ rejectPredictions: Mt,
912
+ exportAnnotations: Pt,
913
+ getAllAnnotations: () => {
914
+ var e, s;
915
+ return n.batchImages.length > 0 ? n.batchImages : [{
916
+ imageUrl: ((e = n.image) == null ? void 0 : e.url) || "",
917
+ annotations: ((s = a.value) == null ? void 0 : s.getAnnotations()) || []
918
+ }];
725
919
  },
726
- getAllAnnotations: () => s.batchImages,
727
920
  getCurrentAnnotation: () => {
728
- var l;
921
+ var e, s, l;
729
922
  return {
730
- imageUrl: s.batchImages[m.value].imageUrl,
731
- annotations: ((l = i.value) == null ? void 0 : l.getAnnotations()) || []
923
+ imageUrl: ((e = n.batchImages[y.value]) == null ? void 0 : e.imageUrl) || ((s = n.image) == null ? void 0 : s.url) || "",
924
+ annotations: ((l = a.value) == null ? void 0 : l.getAnnotations()) || []
732
925
  };
733
926
  }
734
- }), (l, c) => (p(), x("div", {
735
- class: T(["annotation-container", v.theme])
927
+ }), V(() => {
928
+ var e;
929
+ return (e = n.image) == null ? void 0 : e.url;
930
+ }, () => {
931
+ var e;
932
+ n.batchImages.length === 0 && ((e = n.image) != null && e.url) && B();
933
+ }), V(() => n.predictionCandidates, (e) => {
934
+ e && ot(e);
935
+ }, { immediate: !0, deep: !0 }), V(
936
+ () => n.batchImages.map((e) => `${e.imageUrl}:${e.width || ""}x${e.height || ""}`),
937
+ () => {
938
+ nt();
939
+ },
940
+ { immediate: !0 }
941
+ ), (e, s) => (p(), b("div", {
942
+ class: U(["annotation-container", m.theme])
736
943
  }, [
737
- v.readOnly ? H("", !0) : (p(), x("div", Dt, [
738
- h("div", {
739
- class: T(["tool-btn", { active: r.value === "pan" }]),
740
- onClick: c[0] || (c[0] = (g) => O("pan")),
944
+ m.batchImages && m.batchImages.length > 0 ? (p(), b("div", fe, [
945
+ g("div", ye, "批量图片(" + P(m.batchImages.length) + ")", 1),
946
+ g("div", pe, [
947
+ (p(!0), b(T, null, D(m.batchImages, (l, h) => (p(), b("button", {
948
+ key: `${l.imageUrl}-${h}`,
949
+ class: U(["image-list-item", { active: h === y.value }]),
950
+ onClick: (v) => lt(h)
951
+ }, [
952
+ g("div", xe, [
953
+ g("img", {
954
+ src: l.imageUrl,
955
+ alt: `第${h + 1}张`,
956
+ class: "image-list-thumb"
957
+ }, null, 8, we),
958
+ Ut(h) ? (p(), b("div", Ce, [
959
+ (p(!0), b(T, null, D(Ht(h), (v) => (p(), b(T, {
960
+ key: v.id
961
+ }, [
962
+ Tt(v) ? (p(), b("div", {
963
+ key: 0,
964
+ class: "thumb-overlay-rect",
965
+ style: F(Ft(h, v))
966
+ }, null, 4)) : Lt(v) ? (p(), b("svg", Ae, [
967
+ g("polygon", {
968
+ points: Bt(h, v),
969
+ style: F(Et(v))
970
+ }, null, 12, _e)
971
+ ])) : Dt(v) ? (p(!0), b(T, { key: 2 }, D(rt(v), (w, k) => (p(), b("div", {
972
+ key: `${v.id}-${k}`,
973
+ class: "thumb-overlay-point",
974
+ style: F(Ot(h, w, v))
975
+ }, null, 4))), 128)) : Rt(v) ? (p(), b("div", {
976
+ key: 3,
977
+ class: "thumb-overlay-rotated",
978
+ style: F(Vt(h, v))
979
+ }, null, 4)) : H("", !0)
980
+ ], 64))), 128))
981
+ ])) : H("", !0)
982
+ ]),
983
+ g("span", Ie, "第 " + P(h + 1) + " 张", 1)
984
+ ], 10, be))), 128))
985
+ ])
986
+ ])) : H("", !0),
987
+ m.readOnly ? H("", !0) : (p(), b("div", ke, [
988
+ g("div", {
989
+ class: U(["tool-btn", { active: d.value === "pan" }]),
990
+ onClick: s[0] || (s[0] = (l) => E("pan")),
741
991
  title: "拖动"
742
992
  }, [
743
- S(k, { name: "rank" })
993
+ $(z, { name: "rank" })
744
994
  ], 2),
745
- h("div", {
746
- class: T(["tool-btn", { active: r.value === "select" }]),
747
- onClick: c[1] || (c[1] = (g) => O("select")),
995
+ g("div", {
996
+ class: U(["tool-btn", { active: d.value === "select" }]),
997
+ onClick: s[1] || (s[1] = (l) => E("select")),
748
998
  title: "选择"
749
999
  }, [
750
- S(k, { name: "pointer" })
1000
+ $(z, { name: "pointer" })
751
1001
  ], 2),
752
- c[4] || (c[4] = h("div", { class: "divider" }, null, -1)),
753
- (p(!0), x(P, null, D(w.value, (g) => (p(), x("div", {
754
- key: g,
755
- class: T(["tool-btn", { active: r.value === g }]),
756
- onClick: (_) => O(g),
757
- title: I(g)
1002
+ s[4] || (s[4] = g("div", { class: "divider" }, null, -1)),
1003
+ (p(!0), b(T, null, D(ut.value, (l) => (p(), b("div", {
1004
+ key: l,
1005
+ class: U(["tool-btn", { active: d.value === l }]),
1006
+ onClick: (h) => E(l),
1007
+ title: mt(l)
758
1008
  }, [
759
- S(k, {
760
- name: A(g)
1009
+ $(z, {
1010
+ name: vt(l)
761
1011
  }, null, 8, ["name"])
762
- ], 10, $t))), 128)),
763
- c[5] || (c[5] = h("div", { class: "divider" }, null, -1)),
764
- h("div", {
1012
+ ], 10, Se))), 128)),
1013
+ s[5] || (s[5] = g("div", { class: "divider" }, null, -1)),
1014
+ g("div", {
765
1015
  class: "tool-btn",
766
- onClick: Q,
1016
+ onClick: yt,
767
1017
  title: "放大"
768
1018
  }, [
769
- S(k, { name: "zoom-in" })
1019
+ $(z, { name: "zoom-in" })
770
1020
  ]),
771
- h("div", {
1021
+ g("div", {
772
1022
  class: "tool-btn",
773
- onClick: Z,
1023
+ onClick: pt,
774
1024
  title: "缩小"
775
1025
  }, [
776
- S(k, { name: "zoom-out" })
1026
+ $(z, { name: "zoom-out" })
777
1027
  ]),
778
- c[6] || (c[6] = h("div", { class: "divider" }, null, -1)),
779
- h("div", {
1028
+ s[6] || (s[6] = g("div", { class: "divider" }, null, -1)),
1029
+ tt.value ? (p(), b("div", {
1030
+ key: 0,
780
1031
  class: "tool-btn",
781
- onClick: G,
1032
+ onClick: ft,
782
1033
  title: "删除选中"
783
1034
  }, [
784
- S(k, { name: "delete" })
785
- ])
1035
+ $(z, { name: "delete" })
1036
+ ])) : H("", !0)
786
1037
  ])),
787
- h("div", Ut, [
788
- v.readOnly ? H("", !0) : (p(), x("div", Ft, [
789
- h("div", Rt, [
790
- c[7] || (c[7] = h("span", { class: "label-text" }, "当前标签:", -1)),
791
- h("div", Bt, [
792
- (p(!0), x(P, null, D(d.value, (g) => (p(), x("div", {
793
- key: g.id,
794
- class: T(["tag-chip", { active: u.value === g.id }]),
795
- style: j({ backgroundColor: g.color, borderColor: g.color }),
796
- onClick: (_) => U(g)
797
- }, z(g.name), 15, Ot))), 128)),
798
- d.value.length === 0 ? (p(), x("div", Vt, "请在右侧创建标签")) : H("", !0)
1038
+ g("div", Me, [
1039
+ m.readOnly ? H("", !0) : (p(), b("div", ze, [
1040
+ g("div", $e, [
1041
+ s[7] || (s[7] = g("span", { class: "label-text" }, "当前标签:", -1)),
1042
+ g("div", Pe, [
1043
+ (p(!0), b(T, null, D(u.value, (l) => (p(), b("div", {
1044
+ key: l.id,
1045
+ class: U(["tag-chip", { active: f.value === l.id }]),
1046
+ style: F({ backgroundColor: l.color, borderColor: l.color }),
1047
+ onClick: (h) => O(l)
1048
+ }, P(l.name), 15, He))), 128)),
1049
+ u.value.length === 0 ? (p(), b("div", Te, "请在右侧创建标签")) : H("", !0)
799
1050
  ])
800
1051
  ])
801
1052
  ])),
802
- h("div", {
1053
+ g("div", {
803
1054
  class: "canvas-wrapper",
804
1055
  ref_key: "canvasWrapper",
805
- ref: o
1056
+ ref: c
806
1057
  }, [
807
- h("canvas", {
1058
+ g("canvas", {
808
1059
  ref_key: "canvasRef",
809
- ref: n
1060
+ ref: o
810
1061
  }, null, 512)
811
1062
  ], 512),
812
- v.batchImages && v.batchImages.length > 0 ? (p(), x("div", Et, [
813
- h("button", {
814
- onClick: at,
815
- disabled: m.value <= 0
1063
+ m.batchImages && m.batchImages.length > 0 ? (p(), b("div", Le, [
1064
+ g("button", {
1065
+ onClick: It,
1066
+ disabled: y.value <= 0
816
1067
  }, [
817
- S(k, { name: "back" }),
818
- c[8] || (c[8] = F(" 上一张 ", -1))
819
- ], 8, Nt),
820
- h("span", null, z(m.value + 1) + " / " + z(v.batchImages.length), 1),
821
- h("button", {
822
- onClick: lt,
823
- disabled: m.value >= v.batchImages.length - 1
1068
+ $(z, { name: "back" }),
1069
+ s[8] || (s[8] = N(" 上一张 ", -1))
1070
+ ], 8, De),
1071
+ g("span", null, P(y.value + 1) + " / " + P(m.batchImages.length), 1),
1072
+ g("button", {
1073
+ onClick: kt,
1074
+ disabled: y.value >= m.batchImages.length - 1
824
1075
  }, [
825
- c[9] || (c[9] = F(" 下一张 ", -1)),
826
- S(k, { name: "right" })
827
- ], 8, Jt)
1076
+ s[9] || (s[9] = N(" 下一张 ", -1)),
1077
+ $(z, { name: "right" })
1078
+ ], 8, Re)
828
1079
  ])) : H("", !0)
829
1080
  ]),
830
- v.readOnly ? H("", !0) : (p(), x("div", Wt, [
831
- h("div", { class: "sidebar-header" }, [
832
- c[10] || (c[10] = h("h3", null, "标签管理", -1)),
833
- h("button", {
1081
+ m.readOnly ? H("", !0) : (p(), b("div", Ue, [
1082
+ g("div", { class: "sidebar-header" }, [
1083
+ s[10] || (s[10] = g("h3", null, "标签管理", -1)),
1084
+ g("button", {
834
1085
  class: "add-btn",
835
- onClick: tt
1086
+ onClick: bt
836
1087
  }, "添加标签")
837
1088
  ]),
838
- h("div", jt, [
839
- (p(!0), x(P, null, D(d.value, (g) => (p(), x("div", {
840
- key: g.id,
1089
+ g("div", Fe, [
1090
+ (p(!0), b(T, null, D(u.value, (l) => (p(), b("div", {
1091
+ key: l.id,
841
1092
  class: "label-item"
842
1093
  }, [
843
- h("div", Xt, [
844
- h("label", {
1094
+ g("div", Be, [
1095
+ g("label", {
845
1096
  class: "color-wrapper",
846
- style: j({ backgroundColor: g.color })
1097
+ style: F({ backgroundColor: l.color })
847
1098
  }, [
848
- N(h("input", {
1099
+ Z(g("input", {
849
1100
  type: "color",
850
- "onUpdate:modelValue": (_) => g.color = _,
851
- onChange: (_) => nt(g),
1101
+ "onUpdate:modelValue": (h) => l.color = h,
1102
+ onChange: (h) => Ct(l),
852
1103
  style: { visibility: "hidden", width: "0", height: "0" }
853
- }, null, 40, Yt), [
854
- [J, g.color]
1104
+ }, null, 40, Ee), [
1105
+ [G, l.color]
855
1106
  ])
856
1107
  ], 4),
857
- h("span", {
1108
+ g("span", {
858
1109
  class: "label-name",
859
- title: g.name
860
- }, z(g.name), 9, Kt),
861
- h("span", {
1110
+ title: l.name
1111
+ }, P(l.name), 9, Oe),
1112
+ g("span", {
862
1113
  class: "action-icon eye",
863
- onClick: (_) => it(g)
1114
+ onClick: (h) => At(l)
864
1115
  }, [
865
- g.visible ? (p(), Y(k, {
1116
+ l.visible ? (p(), ht(z, {
866
1117
  key: 0,
867
1118
  name: "view"
868
- })) : (p(), Y(k, {
1119
+ })) : (p(), ht(z, {
869
1120
  key: 1,
870
1121
  name: "hide"
871
1122
  }))
872
- ], 8, qt),
873
- h("div", Gt, [
874
- c[11] || (c[11] = h("span", { class: "dots" }, "•••", -1)),
875
- h("span", {
1123
+ ], 8, Ve),
1124
+ g("div", Ne, [
1125
+ s[11] || (s[11] = g("span", { class: "dots" }, "•••", -1)),
1126
+ g("span", {
876
1127
  class: "delete-btn",
877
- onClick: (_) => ot(g.id),
1128
+ onClick: (h) => _t(l.id),
878
1129
  title: "删除"
879
1130
  }, [
880
- S(k, { name: "delete" })
881
- ], 8, Qt)
1131
+ $(z, { name: "delete" })
1132
+ ], 8, We)
882
1133
  ])
883
1134
  ])
884
1135
  ]))), 128))
885
1136
  ])
886
1137
  ])),
887
- f.value ? (p(), x("div", Zt, [
888
- h("div", te, [
889
- c[14] || (c[14] = h("h3", null, "新增标签", -1)),
890
- h("div", ee, [
891
- c[12] || (c[12] = h("label", null, "名称", -1)),
892
- N(h("input", {
893
- "onUpdate:modelValue": c[2] || (c[2] = (g) => y.value.name = g),
1138
+ C.value ? (p(), b("div", Je, [
1139
+ g("div", je, [
1140
+ s[14] || (s[14] = g("h3", null, "新增标签", -1)),
1141
+ g("div", Xe, [
1142
+ s[12] || (s[12] = g("label", null, "名称", -1)),
1143
+ Z(g("input", {
1144
+ "onUpdate:modelValue": s[2] || (s[2] = (l) => A.value.name = l),
894
1145
  placeholder: "请输入标签名称",
895
1146
  class: "modal-input"
896
1147
  }, null, 512), [
897
- [J, y.value.name]
1148
+ [G, A.value.name]
898
1149
  ])
899
1150
  ]),
900
- h("div", se, [
901
- c[13] || (c[13] = h("label", null, "颜色", -1)),
902
- h("div", ne, [
903
- N(h("input", {
1151
+ g("div", Ye, [
1152
+ s[13] || (s[13] = g("label", null, "颜色", -1)),
1153
+ g("div", qe, [
1154
+ Z(g("input", {
904
1155
  type: "color",
905
- "onUpdate:modelValue": c[3] || (c[3] = (g) => y.value.color = g),
1156
+ "onUpdate:modelValue": s[3] || (s[3] = (l) => A.value.color = l),
906
1157
  class: "modal-color-picker"
907
1158
  }, null, 512), [
908
- [J, y.value.color]
1159
+ [G, A.value.color]
909
1160
  ]),
910
- h("span", null, z(y.value.color), 1)
1161
+ g("span", null, P(A.value.color), 1)
911
1162
  ])
912
1163
  ]),
913
- h("div", { class: "modal-actions" }, [
914
- h("button", {
915
- onClick: X,
1164
+ g("div", { class: "modal-actions" }, [
1165
+ g("button", {
1166
+ onClick: it,
916
1167
  class: "cancel-btn"
917
1168
  }, "取消"),
918
- h("button", {
919
- onClick: et,
1169
+ g("button", {
1170
+ onClick: xt,
920
1171
  class: "confirm-btn"
921
1172
  }, "确认")
922
1173
  ])
@@ -924,13 +1175,13 @@ const ft = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" widt
924
1175
  ])) : H("", !0)
925
1176
  ], 2));
926
1177
  }
927
- }), oe = /* @__PURE__ */ B(ie, [["__scopeId", "data-v-fe1b36c0"]]), ae = {
1178
+ }), Ze = /* @__PURE__ */ Y(Ke, [["__scopeId", "data-v-22c2957b"]]), Ge = {
928
1179
  class: "thumbnail-wrapper",
929
1180
  ref: "wrapper"
930
- }, le = ["src", "alt"], re = ["viewBox"], ce = ["x", "y", "width", "height", "stroke"], he = ["points", "stroke"], ge = ["x", "y", "fill"], de = {
1181
+ }, Qe = ["src", "alt"], tn = ["viewBox"], en = ["x", "y", "width", "height", "stroke"], nn = ["points", "stroke"], sn = ["x", "y", "fill"], on = {
931
1182
  key: 1,
932
1183
  class: "loading-placeholder"
933
- }, ve = /* @__PURE__ */ R({
1184
+ }, an = /* @__PURE__ */ X({
934
1185
  __name: "AnnotationThumbnail",
935
1186
  props: {
936
1187
  src: {},
@@ -938,23 +1189,23 @@ const ft = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" widt
938
1189
  alt: {},
939
1190
  labels: {}
940
1191
  },
941
- setup(v) {
942
- const t = v, e = C(null), s = C(!1), a = C(0), n = C(0), o = () => {
943
- e.value && (a.value = e.value.naturalWidth, n.value = e.value.naturalHeight, s.value = !0);
944
- }, i = (u) => {
1192
+ setup(m) {
1193
+ const t = m, i = I(null), n = I(!1), r = I(0), o = I(0), c = () => {
1194
+ i.value && (r.value = i.value.naturalWidth, o.value = i.value.naturalHeight, n.value = !0);
1195
+ }, a = (u) => {
945
1196
  var f;
946
1197
  if ((f = u.style) != null && f.strokeColor) return u.style.strokeColor;
947
1198
  if (t.labels) {
948
- const y = t.labels.find((w) => w.name === u.label);
949
- if (y) return y.color;
1199
+ const C = t.labels.find((A) => A.name === u.label);
1200
+ if (C) return C.color;
950
1201
  }
951
1202
  return "#FF0000";
952
- }, r = (u) => {
953
- const f = u.coordinates, y = Math.min(f.x1, f.x2), w = Math.min(f.y1, f.y2), A = Math.abs(f.x1 - f.x2), I = Math.abs(f.y1 - f.y2);
954
- return { x: y, y: w, width: A, height: I };
955
- }, m = (u) => u.coordinates.points.map((y) => `${y.x},${y.y}`).join(" "), d = (u) => {
1203
+ }, d = (u) => {
1204
+ const f = u.coordinates, C = Math.min(f.x1, f.x2), A = Math.min(f.y1, f.y2), S = Math.abs(f.x1 - f.x2), M = Math.abs(f.y1 - f.y2);
1205
+ return { x: C, y: A, width: S, height: M };
1206
+ }, y = (u) => u.coordinates.points.map((C) => `${C.x},${C.y}`).join(" "), x = (u) => {
956
1207
  if (u.type === "rectangle") {
957
- const f = r(u);
1208
+ const f = d(u);
958
1209
  return { x: f.x, y: f.y - 5 };
959
1210
  } else if (u.type === "polygon") {
960
1211
  const f = u.coordinates.points;
@@ -962,171 +1213,171 @@ const ft = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" widt
962
1213
  }
963
1214
  return { x: 0, y: 0 };
964
1215
  };
965
- return (u, f) => (p(), x("div", ae, [
966
- h("img", {
1216
+ return (u, f) => (p(), b("div", Ge, [
1217
+ g("img", {
967
1218
  ref_key: "img",
968
- ref: e,
969
- src: v.src,
1219
+ ref: i,
1220
+ src: m.src,
970
1221
  class: "thumbnail-image",
971
- onLoad: o,
972
- alt: v.alt
973
- }, null, 40, le),
974
- s.value ? (p(), x("svg", {
1222
+ onLoad: c,
1223
+ alt: m.alt
1224
+ }, null, 40, Qe),
1225
+ n.value ? (p(), b("svg", {
975
1226
  key: 0,
976
1227
  class: "annotation-overlay",
977
- viewBox: `0 0 ${a.value} ${n.value}`,
1228
+ viewBox: `0 0 ${r.value} ${o.value}`,
978
1229
  preserveAspectRatio: "none"
979
1230
  }, [
980
- (p(!0), x(P, null, D(v.annotations, (y) => (p(), x(P, {
981
- key: y.id
1231
+ (p(!0), b(T, null, D(m.annotations, (C) => (p(), b(T, {
1232
+ key: C.id
982
1233
  }, [
983
- y.type === "rectangle" ? (p(), x("rect", {
1234
+ C.type === "rectangle" ? (p(), b("rect", {
984
1235
  key: 0,
985
- x: r(y).x,
986
- y: r(y).y,
987
- width: r(y).width,
988
- height: r(y).height,
989
- stroke: i(y),
1236
+ x: d(C).x,
1237
+ y: d(C).y,
1238
+ width: d(C).width,
1239
+ height: d(C).height,
1240
+ stroke: a(C),
990
1241
  "stroke-width": "2",
991
1242
  fill: "transparent"
992
- }, null, 8, ce)) : H("", !0),
993
- y.type === "polygon" ? (p(), x("polygon", {
1243
+ }, null, 8, en)) : H("", !0),
1244
+ C.type === "polygon" ? (p(), b("polygon", {
994
1245
  key: 1,
995
- points: m(y),
996
- stroke: i(y),
1246
+ points: y(C),
1247
+ stroke: a(C),
997
1248
  "stroke-width": "2",
998
1249
  fill: "transparent"
999
- }, null, 8, he)) : H("", !0),
1000
- y.label ? (p(), x("text", {
1250
+ }, null, 8, nn)) : H("", !0),
1251
+ C.label ? (p(), b("text", {
1001
1252
  key: 2,
1002
- x: d(y).x,
1003
- y: d(y).y,
1004
- fill: i(y),
1253
+ x: x(C).x,
1254
+ y: x(C).y,
1255
+ fill: a(C),
1005
1256
  "font-size": "14",
1006
1257
  "font-weight": "bold",
1007
1258
  class: "anno-label"
1008
- }, z(y.label), 9, ge)) : H("", !0)
1259
+ }, P(C.label), 9, sn)) : H("", !0)
1009
1260
  ], 64))), 128))
1010
- ], 8, re)) : (p(), x("div", de, "Loading..."))
1261
+ ], 8, tn)) : (p(), b("div", on, "Loading..."))
1011
1262
  ], 512));
1012
1263
  }
1013
- }), ue = /* @__PURE__ */ B(ve, [["__scopeId", "data-v-78bcbe0c"]]), me = { class: "batch-annotator" }, fe = {
1264
+ }), ln = /* @__PURE__ */ Y(an, [["__scopeId", "data-v-78bcbe0c"]]), rn = { class: "batch-annotator" }, cn = {
1014
1265
  key: 0,
1015
1266
  class: "gallery-view"
1016
- }, ye = { class: "gallery-header" }, pe = { class: "label-summary" }, xe = { class: "gallery-grid" }, be = ["onClick"], we = { class: "thumbnail-wrapper" }, Ce = { class: "img-meta" }, _e = { class: "img-index" }, Ae = { class: "anno-count" }, ke = { class: "bottom-bar" }, Se = {
1267
+ }, hn = { class: "gallery-header" }, dn = { class: "label-summary" }, gn = { class: "gallery-grid" }, un = ["onClick"], vn = { class: "thumbnail-wrapper" }, mn = { class: "img-meta" }, fn = { class: "img-index" }, yn = { class: "anno-count" }, pn = { class: "bottom-bar" }, bn = {
1017
1268
  key: 1,
1018
1269
  class: "editor-view"
1019
- }, Ie = { class: "editor-header" }, ze = { class: "header-left" }, Me = { class: "editor-title" }, He = { class: "editor-content" }, Le = /* @__PURE__ */ R({
1270
+ }, xn = { class: "editor-header" }, wn = { class: "header-left" }, Cn = { class: "editor-title" }, An = { class: "editor-content" }, _n = /* @__PURE__ */ X({
1020
1271
  __name: "BatchAnnotator",
1021
1272
  props: {
1022
1273
  images: {},
1023
1274
  labels: {}
1024
1275
  },
1025
1276
  emits: ["export", "update:images"],
1026
- setup(v, { emit: t }) {
1027
- const e = v, s = t, a = C("gallery"), n = C([]), o = C(0), i = C(null);
1028
- q(() => e.images, (w) => {
1029
- n.value = JSON.parse(JSON.stringify(w));
1277
+ setup(m, { emit: t }) {
1278
+ const i = m, n = t, r = I("gallery"), o = I([]), c = I(0), a = I(null);
1279
+ V(() => i.images, (A) => {
1280
+ o.value = JSON.parse(JSON.stringify(A));
1030
1281
  }, { immediate: !0, deep: !0 });
1031
- const r = (w) => {
1032
- o.value = w, a.value = "editor", vt(() => {
1033
- i.value && i.value.jumpTo && i.value.jumpTo(w);
1282
+ const d = (A) => {
1283
+ c.value = A, r.value = "editor", qt(() => {
1284
+ a.value && a.value.jumpTo && a.value.jumpTo(A);
1034
1285
  });
1035
- }, m = () => {
1036
- if (i.value && i.value.getCurrentAnnotation) {
1037
- const w = i.value.getCurrentAnnotation();
1038
- n.value[o.value] && (n.value[o.value].annotations = w.annotations);
1286
+ }, y = () => {
1287
+ if (a.value && a.value.getCurrentAnnotation) {
1288
+ const A = a.value.getCurrentAnnotation();
1289
+ o.value[c.value] && (o.value[c.value].annotations = A.annotations);
1039
1290
  }
1040
- a.value = "gallery";
1041
- }, d = () => {
1042
- s("export", n.value);
1043
- }, u = (w) => {
1044
- o.value = w.currentIndex, n.value[w.currentIndex] && (n.value[w.currentIndex].annotations = w.currentAnnotations);
1045
- }, f = (w) => {
1046
- if (i.value && i.value.getCurrentAnnotation) {
1047
- const A = i.value.getCurrentAnnotation();
1048
- n.value[o.value] && (n.value[o.value].annotations = A.annotations, s("update:images", n.value));
1291
+ r.value = "gallery";
1292
+ }, x = () => {
1293
+ n("export", o.value);
1294
+ }, u = (A) => {
1295
+ c.value = A.currentIndex, o.value[A.currentIndex] && (o.value[A.currentIndex].annotations = A.currentAnnotations);
1296
+ }, f = (A) => {
1297
+ if (a.value && a.value.getCurrentAnnotation) {
1298
+ const S = a.value.getCurrentAnnotation();
1299
+ o.value[c.value] && (o.value[c.value].annotations = S.annotations, n("update:images", o.value));
1049
1300
  }
1050
- }, y = (w) => {
1301
+ }, C = (A) => {
1051
1302
  };
1052
- return (w, A) => (p(), x("div", me, [
1053
- a.value === "gallery" ? (p(), x("div", fe, [
1054
- h("div", ye, [
1055
- h("h3", null, "批量查看与标注 (" + z(n.value.length) + " 张)", 1),
1056
- h("div", pe, [
1057
- (p(!0), x(P, null, D(v.labels, (I) => (p(), x("span", {
1058
- key: I.id,
1303
+ return (A, S) => (p(), b("div", rn, [
1304
+ r.value === "gallery" ? (p(), b("div", cn, [
1305
+ g("div", hn, [
1306
+ g("h3", null, "批量查看与标注 (" + P(o.value.length) + " 张)", 1),
1307
+ g("div", dn, [
1308
+ (p(!0), b(T, null, D(m.labels, (M) => (p(), b("span", {
1309
+ key: M.id,
1059
1310
  class: "label-badge",
1060
- style: j({ backgroundColor: I.color })
1061
- }, z(I.name), 5))), 128))
1311
+ style: F({ backgroundColor: M.color })
1312
+ }, P(M.name), 5))), 128))
1062
1313
  ])
1063
1314
  ]),
1064
- h("div", xe, [
1065
- (p(!0), x(P, null, D(n.value, (I, L) => (p(), x("div", {
1315
+ g("div", gn, [
1316
+ (p(!0), b(T, null, D(o.value, (M, L) => (p(), b("div", {
1066
1317
  key: L,
1067
1318
  class: "gallery-item",
1068
- onClick: ($) => r(L)
1319
+ onClick: (tt) => d(L)
1069
1320
  }, [
1070
- h("div", we, [
1071
- S(ue, {
1072
- src: I.imageUrl,
1073
- annotations: I.annotations || [],
1074
- labels: v.labels
1321
+ g("div", vn, [
1322
+ $(ln, {
1323
+ src: M.imageUrl,
1324
+ annotations: M.annotations || [],
1325
+ labels: m.labels
1075
1326
  }, null, 8, ["src", "annotations", "labels"])
1076
1327
  ]),
1077
- h("div", Ce, [
1078
- h("span", _e, "#" + z(L + 1), 1),
1079
- h("span", Ae, z((I.annotations || []).length) + " 标注", 1)
1328
+ g("div", mn, [
1329
+ g("span", fn, "#" + P(L + 1), 1),
1330
+ g("span", yn, P((M.annotations || []).length) + " 标注", 1)
1080
1331
  ])
1081
- ], 8, be))), 128))
1332
+ ], 8, un))), 128))
1082
1333
  ]),
1083
- h("div", ke, [
1084
- h("button", {
1334
+ g("div", pn, [
1335
+ g("button", {
1085
1336
  class: "action-btn primary",
1086
- onClick: A[0] || (A[0] = (I) => r(0))
1337
+ onClick: S[0] || (S[0] = (M) => d(0))
1087
1338
  }, [
1088
- S(k, { name: "edit" }),
1089
- A[1] || (A[1] = F(" 手动标注 ", -1))
1339
+ $(z, { name: "edit" }),
1340
+ S[1] || (S[1] = N(" 手动标注 ", -1))
1090
1341
  ]),
1091
- h("button", {
1342
+ g("button", {
1092
1343
  class: "action-btn success",
1093
- onClick: d
1344
+ onClick: x
1094
1345
  }, [
1095
- S(k, { name: "download" }),
1096
- A[2] || (A[2] = F(" 导出 ", -1))
1346
+ $(z, { name: "download" }),
1347
+ S[2] || (S[2] = N(" 导出 ", -1))
1097
1348
  ])
1098
1349
  ])
1099
- ])) : (p(), x("div", Se, [
1100
- h("div", Ie, [
1101
- h("div", ze, [
1102
- h("button", {
1350
+ ])) : (p(), b("div", bn, [
1351
+ g("div", xn, [
1352
+ g("div", wn, [
1353
+ g("button", {
1103
1354
  class: "back-btn",
1104
- onClick: m
1355
+ onClick: y
1105
1356
  }, [
1106
- S(k, { name: "back" }),
1107
- A[3] || (A[3] = F(" 返回列表 ", -1))
1357
+ $(z, { name: "back" }),
1358
+ S[3] || (S[3] = N(" 返回列表 ", -1))
1108
1359
  ]),
1109
- h("span", Me, "正在标注: " + z(o.value + 1) + " / " + z(n.value.length), 1)
1360
+ g("span", Cn, "正在标注: " + P(c.value + 1) + " / " + P(o.value.length), 1)
1110
1361
  ])
1111
1362
  ]),
1112
- h("div", He, [
1113
- S(oe, {
1363
+ g("div", An, [
1364
+ $(Ze, {
1114
1365
  ref_key: "annotatorRef",
1115
- ref: i,
1116
- batchImages: n.value,
1117
- labels: v.labels,
1366
+ ref: a,
1367
+ batchImages: o.value,
1368
+ labels: m.labels,
1118
1369
  annotationTypes: ["rectangle", "polygon", "point", "rotatedRect"],
1119
1370
  onBatchChange: u,
1120
1371
  onAnnotationChange: f,
1121
- onLabelChange: y
1372
+ onLabelChange: C
1122
1373
  }, null, 8, ["batchImages", "labels"])
1123
1374
  ])
1124
1375
  ]))
1125
1376
  ]));
1126
1377
  }
1127
- }), $e = /* @__PURE__ */ B(Le, [["__scopeId", "data-v-87f3e002"]]);
1378
+ }), Sn = /* @__PURE__ */ Y(_n, [["__scopeId", "data-v-87f3e002"]]);
1128
1379
  export {
1129
- $e as BatchAnnotator,
1130
- oe as ImageAnnotator,
1131
- $e as default
1380
+ Sn as BatchAnnotator,
1381
+ Ze as ImageAnnotator,
1382
+ Sn as default
1132
1383
  };