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