@zzalai/leafer-point-annotation 1.1.2 → 1.1.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/docs/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>Leafer Point Annotation</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-DJUbn3Yd.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-BICV4seT.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="app"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zzalai/leafer-point-annotation",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "A Vue3 component for point annotation and brush painting on images using LeaferJS, supporting COCO/YOLO/JSON export, designed for AI model training dataset annotation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
package/src/App.vue
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="app">
|
|
3
3
|
<h1>LeaferJS Point Annotation Test</h1>
|
|
4
4
|
|
|
5
|
-
<div class="editor-container">
|
|
5
|
+
<div class="editor-container" :class="{ 'multi-instance': enableMultiInstance }">
|
|
6
6
|
<PointAnnotation
|
|
7
7
|
ref="pointAnnotation"
|
|
8
8
|
:imageSource="imageSource"
|
|
@@ -14,6 +14,13 @@
|
|
|
14
14
|
@loadError="handleLoadError"
|
|
15
15
|
@update:currentLayer="handleLayerChange"
|
|
16
16
|
/>
|
|
17
|
+
<PointAnnotation
|
|
18
|
+
v-if="enableMultiInstance"
|
|
19
|
+
ref="pointAnnotation2"
|
|
20
|
+
:imageSource="imageSource2"
|
|
21
|
+
:options="editorOptions2"
|
|
22
|
+
@pointChange="handlePointChange2"
|
|
23
|
+
/>
|
|
17
24
|
</div>
|
|
18
25
|
|
|
19
26
|
<div class="controls">
|
|
@@ -73,6 +80,7 @@
|
|
|
73
80
|
<label><input type="checkbox" v-model="showToolbar" /> 显示组件工具栏</label>
|
|
74
81
|
<label><input type="checkbox" v-model="showZoomController" /> 显示缩放控制器</label>
|
|
75
82
|
<label><input type="checkbox" v-model="enableBrush" /> 启用笔刷功能</label>
|
|
83
|
+
<label><input type="checkbox" v-model="enableMultiInstance" /> 双实例测试(验证多实例快捷键不冲突)</label>
|
|
76
84
|
</div>
|
|
77
85
|
<div class="multi-layer-row">
|
|
78
86
|
<label>背景色: <input type="color" v-model="canvasBackground" style="width: 40px; height: 28px; vertical-align: middle; margin-left: 6px;" /></label>
|
|
@@ -315,6 +323,35 @@ const canvasBackground = ref('#f6f6f6')
|
|
|
315
323
|
const zoomMin = ref(0.2)
|
|
316
324
|
const zoomMax = ref(4)
|
|
317
325
|
const enableBrush = ref(true)
|
|
326
|
+
const enableMultiInstance = ref(false)
|
|
327
|
+
|
|
328
|
+
const imageSource2 = computed(() => {
|
|
329
|
+
if (!imageUrl.value) return undefined
|
|
330
|
+
return { id: 'test-image-2', url: imageUrl.value }
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
const editorOptions2 = computed<OptionsSource>(() => {
|
|
334
|
+
return {
|
|
335
|
+
pointStyle: {
|
|
336
|
+
circleFill: '#00ff00',
|
|
337
|
+
circleStroke: '#fff',
|
|
338
|
+
selectedCircleFill: '#ff0',
|
|
339
|
+
selectedCircleStroke: '#000'
|
|
340
|
+
},
|
|
341
|
+
brushStyle: {
|
|
342
|
+
color: '#00ff00',
|
|
343
|
+
opacity: 0.55,
|
|
344
|
+
size: 100
|
|
345
|
+
},
|
|
346
|
+
showToolbar: true,
|
|
347
|
+
showZoomController: true,
|
|
348
|
+
enableBrush: enableBrush.value
|
|
349
|
+
}
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
const handlePointChange2 = (points: any[]) => {
|
|
353
|
+
console.log('Editor 2 - Points changed:', points)
|
|
354
|
+
}
|
|
318
355
|
|
|
319
356
|
const editorOptions = computed<OptionsSource>(() => {
|
|
320
357
|
if (useMultiLayer.value) {
|
|
@@ -757,6 +794,22 @@ h1 {
|
|
|
757
794
|
margin-bottom: 30px;
|
|
758
795
|
}
|
|
759
796
|
|
|
797
|
+
.editor-container.multi-instance {
|
|
798
|
+
display: flex;
|
|
799
|
+
gap: 12px;
|
|
800
|
+
height: auto;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
.editor-container.multi-instance > :deep(.point-annotation),
|
|
804
|
+
.editor-container.multi-instance > .point-annotation {
|
|
805
|
+
flex: 1;
|
|
806
|
+
min-width: 0;
|
|
807
|
+
height: 600px;
|
|
808
|
+
border: 1px solid #ddd;
|
|
809
|
+
border-radius: 8px;
|
|
810
|
+
overflow: hidden;
|
|
811
|
+
}
|
|
812
|
+
|
|
760
813
|
.controls {
|
|
761
814
|
margin-bottom: 30px;
|
|
762
815
|
padding: 20px;
|
|
@@ -524,6 +524,9 @@ const isDrawing = ref(false);
|
|
|
524
524
|
// 撤销/重做管理器
|
|
525
525
|
let commandManager: CommandManager | null = null;
|
|
526
526
|
|
|
527
|
+
// 🔧 多实例支持:tinykeys 解绑函数(保存在组件作用域,避免多个实例互相覆盖 window.__pointAnnotationHotkeysUnsubscribe)
|
|
528
|
+
let hotkeysUnsubscribe: (() => void) | null = null;
|
|
529
|
+
|
|
527
530
|
// 根据配置强制【标注点】不跟随画布Scale变化
|
|
528
531
|
const changePointScaleRelativeCanvas = (pointAnnotationLayer: Group | null) => {
|
|
529
532
|
// 检查是否开启固定大小功能
|
|
@@ -1091,7 +1094,8 @@ onMounted(() => {
|
|
|
1091
1094
|
},
|
|
1092
1095
|
});
|
|
1093
1096
|
|
|
1094
|
-
|
|
1097
|
+
// 🔧 多实例支持:unsubscribe 保存在当前组件作用域,不再使用全局 window 存储
|
|
1098
|
+
hotkeysUnsubscribe = unsubscribe;
|
|
1095
1099
|
});
|
|
1096
1100
|
});
|
|
1097
1101
|
|
|
@@ -1179,9 +1183,10 @@ onUnmounted(() => {
|
|
|
1179
1183
|
window.removeEventListener("mousemove", handleMouseMove);
|
|
1180
1184
|
window.removeEventListener('focusout', handleFocusOut);
|
|
1181
1185
|
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1186
|
+
// 🔧 多实例支持:调用当前实例自己的 unsubscribe,不再使用全局 window
|
|
1187
|
+
if (hotkeysUnsubscribe) {
|
|
1188
|
+
hotkeysUnsubscribe();
|
|
1189
|
+
hotkeysUnsubscribe = null;
|
|
1185
1190
|
}
|
|
1186
1191
|
});
|
|
1187
1192
|
|
|
@@ -1194,7 +1199,7 @@ const selectTool = () => {
|
|
|
1194
1199
|
app.editor.config.resizeable = false
|
|
1195
1200
|
app.editor.config.multipleSelect = true
|
|
1196
1201
|
Object.values(canvasBrushesByLayer.value).forEach(brush => brush.setPointerEvents(false));
|
|
1197
|
-
updateLabelEditable(
|
|
1202
|
+
updateLabelEditable(false);
|
|
1198
1203
|
};
|
|
1199
1204
|
|
|
1200
1205
|
const pointTool = () => {
|
|
@@ -1204,7 +1209,7 @@ const pointTool = () => {
|
|
|
1204
1209
|
app.editor.config.moveable = true
|
|
1205
1210
|
app.editor.config.multipleSelect = false
|
|
1206
1211
|
Object.values(canvasBrushesByLayer.value).forEach(brush => brush.setPointerEvents(false));
|
|
1207
|
-
updateLabelEditable(
|
|
1212
|
+
updateLabelEditable(false);
|
|
1208
1213
|
};
|
|
1209
1214
|
|
|
1210
1215
|
const brushTool = (openPanel?: boolean) => {
|