luo-image-annotator 0.0.2 → 0.0.3
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 +2 -19
- package/dist/luo-image-annotator.css +1 -1
- package/dist/luo-image-annotator.es.js +603 -623
- package/dist/luo-image-annotator.umd.js +33 -1
- package/package.json +2 -5
|
@@ -1 +1,33 @@
|
|
|
1
|
-
(function(A,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],t):(A=typeof globalThis<"u"?globalThis:A||self,t(A.VueImageAnnotator={},A.Vue))})(this,(function(A,t){"use strict";var te=Object.defineProperty;var ee=(A,t,V)=>t in A?te(A,t,{enumerable:!0,configurable:!0,writable:!0,value:V}):A[t]=V;var b=(A,t,V)=>ee(A,typeof t!="symbol"?t+"":t,V);const V=(p,e)=>Math.sqrt(Math.pow(p.x-e.x,2)+Math.pow(p.y-e.y,2)),z=(p,e)=>{let o=!1;for(let n=0,l=e.length-1;n<e.length;l=n++){const i=e[n].x,a=e[n].y,s=e[l].x,c=e[l].y;a>p.y!=c>p.y&&p.x<(s-i)*(p.y-a)/(c-a)+i&&(o=!o)}return o},H=(p,e,o)=>{const n=o*(Math.PI/180),l=Math.cos(n),i=Math.sin(n),a=p.x-e.x,s=p.y-e.y;return{x:e.x+(a*l-s*i),y:e.y+(a*i+s*l)}};class J{constructor(e){b(this,"canvas");b(this,"ctx");b(this,"img");b(this,"annotations",[]);b(this,"currentTool",null);b(this,"activeAnnotation",null);b(this,"hoverAnnotation",null);b(this,"isDrawing",!1);b(this,"isDragging",!1);b(this,"isPanning",!1);b(this,"panStartPoint",null);b(this,"dragStartPoint",null);b(this,"dragStartAnnotation",null);b(this,"lastMouseMovePoint",null);b(this,"isHoveringStartPoint",!1);b(this,"currentLabelColor","#FF4081");b(this,"visibleLabels",new Set);b(this,"selectedHandleIndex",-1);b(this,"hoverHandleIndex",-1);b(this,"scale",1);b(this,"offset",{x:0,y:0});b(this,"listeners",{});b(this,"imageUrl","");this.canvas=e;const o=e.getContext("2d");if(!o)throw new Error("Could not get 2d context");this.ctx=o,this.img=new Image,this.img.crossOrigin="Anonymous",this.img.onload=()=>{this.fitImageToCanvas(),this.render()},this.bindEvents()}on(e,o){this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].push(o)}emit(e,o){this.listeners[e]&&this.listeners[e].forEach(n=>n(o))}loadImage(e){this.imageUrl=e,this.img.src=e,this.activeAnnotation=null,this.isDrawing=!1}setAnnotations(e){this.annotations=JSON.parse(JSON.stringify(e)),this.render()}getAnnotations(){return this.annotations}setTool(e){e==="pan"?(this.currentTool=null,this.isPanning=!1,this.canvas.style.cursor="grab"):e==="select"?(this.currentTool=null,this.canvas.style.cursor="default"):(this.currentTool=e,this.canvas.style.cursor="crosshair"),this.activeAnnotation=null,this.isDrawing=!1,this.render()}setLabelStyle(e){this.currentLabelColor=e}setVisibleLabels(e){this.visibleLabels=new Set(e),this.render()}zoom(e){const n=e>0?this.scale*1.1:this.scale/1.1;if(n<.1||n>10)return;const l=this.canvas.width/2,i=this.canvas.height/2,a=this.toImageCoords(l,i);this.scale=n,this.offset.x=l-a.x*this.scale,this.offset.y=i-a.y*this.scale,this.render()}resize(){this.fitImageToCanvas(),this.render()}toImageCoords(e,o){return{x:(e-this.offset.x)/this.scale,y:(o-this.offset.y)/this.scale}}toScreenCoords(e,o){return{x:e*this.scale+this.offset.x,y:o*this.scale+this.offset.y}}fitImageToCanvas(){const e=this.canvas.parentElement;if(e){if(this.canvas.width=e.clientWidth,this.canvas.height=e.clientHeight,this.img.width===0)return;const o=this.canvas.width/this.img.width,n=this.canvas.height/this.img.height;this.scale=Math.min(o,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}}bindEvents(){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))}handleKeyDown(e){(e.key==="Delete"||e.key==="Backspace")&&this.activeAnnotation&&this.deleteAnnotation(this.activeAnnotation.id)}deleteAnnotation(e){const o=this.annotations.findIndex(n=>n.id===e);if(o>-1){const n=this.annotations[o];this.annotations.splice(o,1),this.activeAnnotation=null,this.emit("annotationChange",{action:"delete",changedItem:n,imageUrl:this.imageUrl}),this.render()}}handleMouseDown(e){const o=this.canvas.getBoundingClientRect(),n=e.clientX-o.left,l=e.clientY-o.top,i=this.toImageCoords(n,l);if(this.canvas.style.cursor==="grab"||this.canvas.style.cursor==="grabbing"){this.isPanning=!0,this.panStartPoint={x:n,y:l},this.canvas.style.cursor="grabbing";return}if(this.activeAnnotation){const c=this.getHitHandle(n,l,this.activeAnnotation);if(c!==-100){this.isDragging=!0,this.dragStartPoint=i,this.selectedHandleIndex=c,this.dragStartAnnotation=JSON.parse(JSON.stringify(this.activeAnnotation));return}}const a=this.getHitCategory(n,l);if(a){this.activeAnnotation=a,this.isDragging=!1,this.selectedHandleIndex=-1,this.emit("annotationChange",{action:"select",changedItem:a,imageUrl:this.imageUrl}),this.render();return}const s=this.getHitAnnotation(i);if(this.currentTool){if(this.isDrawing&&this.currentTool==="polygon"&&this.activeAnnotation){const c=this.activeAnnotation.coordinates;if(c.points.length>2&&V(i,c.points[0])<20/this.scale){this.finishDrawing();return}this.startDrawing(i);return}if(this.currentTool){if(this.currentTool==="polygon"&&!this.isDrawing){this.startDrawing(i);return}if(s){this.activeAnnotation=s,this.isDragging=!0,this.dragStartPoint=i,this.selectedHandleIndex=-1,this.dragStartAnnotation=JSON.parse(JSON.stringify(s)),this.emit("annotationChange",{action:"select",changedItem:s,imageUrl:this.imageUrl}),this.render();return}this.startDrawing(i)}else s?(this.activeAnnotation=s,this.isDragging=!0,this.dragStartPoint=i,this.selectedHandleIndex=-1,this.dragStartAnnotation=JSON.parse(JSON.stringify(s)),this.emit("annotationChange",{action:"select",changedItem:s,imageUrl:this.imageUrl}),this.render()):(this.activeAnnotation=null,this.render())}else if(s){if(!(this.visibleLabels.size>0&&!this.visibleLabels.has(s.label))){this.activeAnnotation=s,this.isDragging=!0,this.dragStartPoint=i,this.selectedHandleIndex=-1,this.dragStartAnnotation=JSON.parse(JSON.stringify(s)),this.emit("annotationChange",{action:"select",changedItem:s,imageUrl:this.imageUrl}),this.render();return}}else this.activeAnnotation=null,this.render()}handleMouseMove(e){const o=this.canvas.getBoundingClientRect(),n=e.clientX-o.left,l=e.clientY-o.top,i=this.toImageCoords(n,l);if(this.isPanning&&this.panStartPoint){const a=n-this.panStartPoint.x,s=l-this.panStartPoint.y;this.offset.x+=a,this.offset.y+=s,this.panStartPoint={x:n,y:l},this.render();return}if(this.lastMouseMovePoint=i,this.isDrawing){if(this.currentTool==="polygon"&&this.activeAnnotation){const a=this.activeAnnotation.coordinates;if(a.points.length>2){const s=a.points[0],c=V(i,s);this.isHoveringStartPoint=c<20/this.scale}else this.isHoveringStartPoint=!1}this.updateDrawing(i)}else this.isDragging&&this.activeAnnotation&&this.dragStartPoint?this.updateDragging(i):this.checkHover(n,l,i);this.render()}handleMouseUp(e){if(this.isPanning){this.isPanning=!1,this.panStartPoint=null,this.canvas.style.cursor="grab";return}if(this.isDrawing){if(this.currentTool==="polygon"){this.render();return}this.finishDrawing()}else this.isDragging&&this.activeAnnotation&&this.emit("annotationChange",{action:"update",changedItem:this.activeAnnotation,imageUrl:this.imageUrl});this.currentTool!=="polygon"&&(this.isDrawing=!1),this.isDragging=!1,this.dragStartPoint=null,this.selectedHandleIndex=-1,this.render()}hexToRgba(e,o){if(!e.startsWith("#"))return e;const n=parseInt(e.slice(1,3),16),l=parseInt(e.slice(3,5),16),i=parseInt(e.slice(5,7),16);return`rgba(${n}, ${l}, ${i}, ${o})`}startDrawing(e){if(!this.currentTool)return;const o=Date.now().toString();if(this.hexToRgba(this.currentLabelColor,.2),this.currentLabelColor,this.currentTool==="rectangle")this.isDrawing=!0,this.dragStartPoint=e,this.activeAnnotation={id:o,type:"rectangle",label:"",coordinates:{x1:e.x,y1:e.y,x2:e.x,y2:e.y},style:{strokeColor:this.currentLabelColor}};else if(this.currentTool==="point"){const n={id:o,type:"point",label:"",coordinates:{points:[e]},style:{strokeColor:this.currentLabelColor}};this.annotations.push(n),this.emit("annotationChange",{action:"add",changedItem:n,imageUrl:this.imageUrl}),this.activeAnnotation=n}else if(this.currentTool==="polygon")this.activeAnnotation&&this.activeAnnotation.type==="polygon"&&this.isDrawing?this.activeAnnotation.coordinates.points.push(e):(this.isDrawing=!0,this.activeAnnotation={id:o,type:"polygon",label:"",coordinates:{points:[e]},style:{strokeColor:this.currentLabelColor}});else if(this.currentTool==="category"){const n={id:o,type:"category",label:"",coordinates:null,style:{strokeColor:this.currentLabelColor}};this.annotations.push(n),this.emit("annotationChange",{action:"add",changedItem:n,imageUrl:this.imageUrl}),this.activeAnnotation=n}else this.currentTool==="rotatedRect"&&(this.isDrawing=!0,this.dragStartPoint=e,this.activeAnnotation={id:o,type:"rotatedRect",label:"",coordinates:{x:e.x,y:e.y,width:0,height:0,angle:0},style:{strokeColor:this.currentLabelColor}})}updateDrawing(e){if(this.activeAnnotation)if(this.activeAnnotation.type==="rectangle"&&this.dragStartPoint){const o=this.activeAnnotation.coordinates;o.x2=e.x,o.y2=e.y}else if(this.activeAnnotation.type==="rotatedRect"&&this.dragStartPoint){const o=this.activeAnnotation.coordinates,n=Math.abs(e.x-this.dragStartPoint.x),l=Math.abs(e.y-this.dragStartPoint.y);o.width=n*2,o.height=l*2}else this.activeAnnotation.type}finishDrawing(){if(this.activeAnnotation){if(this.activeAnnotation.type==="rectangle"){const e=this.activeAnnotation.coordinates;if(Math.abs(e.x1-e.x2)<2||Math.abs(e.y1-e.y2)<2){this.activeAnnotation=null,this.isDrawing=!1;return}const o=Math.min(e.x1,e.x2),n=Math.max(e.x1,e.x2),l=Math.min(e.y1,e.y2),i=Math.max(e.y1,e.y2);e.x1=o,e.x2=n,e.y1=l,e.y2=i,this.annotations.push(this.activeAnnotation),this.emit("annotationChange",{action:"add",changedItem:this.activeAnnotation,imageUrl:this.imageUrl})}else if(this.activeAnnotation.type==="polygon"){if(this.activeAnnotation.coordinates.points.length<3){this.activeAnnotation=null,this.isDrawing=!1;return}this.annotations.push(this.activeAnnotation),this.emit("annotationChange",{action:"add",changedItem:this.activeAnnotation,imageUrl:this.imageUrl})}else if(this.activeAnnotation.type==="rotatedRect"){const e=this.activeAnnotation.coordinates;if(e.width<2||e.height<2){this.activeAnnotation=null,this.isDrawing=!1;return}this.annotations.push(this.activeAnnotation),this.emit("annotationChange",{action:"add",changedItem:this.activeAnnotation,imageUrl:this.imageUrl})}this.activeAnnotation.type}this.isDrawing=!1}updateDragging(e){if(!this.activeAnnotation||!this.dragStartPoint||!this.dragStartAnnotation)return;const o=e.x-this.dragStartPoint.x,n=e.y-this.dragStartPoint.y;this.selectedHandleIndex===-1?this.moveAnnotation(this.activeAnnotation,this.dragStartAnnotation,o,n):this.resizeAnnotation(this.activeAnnotation,this.dragStartAnnotation,this.selectedHandleIndex,e)}moveAnnotation(e,o,n,l){if(e.type==="rectangle"){const i=o.coordinates,a=e.coordinates;a.x1=i.x1+n,a.x2=i.x2+n,a.y1=i.y1+l,a.y2=i.y2+l}else if(e.type==="point"){const i=o.coordinates,a=e.coordinates;a.points=i.points.map(s=>({x:s.x+n,y:s.y+l}))}else if(e.type==="rotatedRect"){const i=o.coordinates,a=e.coordinates;a.x=i.x+n,a.y=i.y+l}else if(e.type==="polygon"){const i=o.coordinates,a=e.coordinates;a.points=i.points.map(s=>({x:s.x+n,y:s.y+l}))}}resizeAnnotation(e,o,n,l){if(e.type==="rectangle"){const i=e.coordinates;n===0&&(i.x1=l.x,i.y1=l.y),n===1&&(i.x2=l.x,i.y1=l.y),n===2&&(i.x2=l.x,i.y2=l.y),n===3&&(i.x1=l.x,i.y2=l.y)}else if(e.type==="polygon"){const i=e.coordinates;n>=0&&n<i.points.length&&(i.points[n]=l)}else if(e.type==="point"){const i=e.coordinates;n>=0&&n<i.points.length&&(i.points[n]=l)}else if(e.type==="rotatedRect"){const i=e.coordinates;if(n===-2){const a=i.x,s=i.y,c=l.x-a,m=l.y-s;let d=Math.atan2(m,c)*180/Math.PI;d+=90,i.angle=d}else{const a=i.angle*Math.PI/180,s=Math.cos(-a),c=Math.sin(-a),m=l.x-i.x,d=l.y-i.y,g=m*s-d*c,f=m*c+d*s;(n===0||n===3)&&(i.width/2,i.width=Math.abs(g)*2),(n===1||n===2)&&(i.width=Math.abs(g)*2),(n===0||n===1)&&(i.height=Math.abs(f)*2),(n===2||n===3)&&(i.height=Math.abs(f)*2)}}}getHitAnnotation(e){for(let o=this.annotations.length-1;o>=0;o--){const n=this.annotations[o];if(this.isPointInAnnotation(e,n))return n}return null}isPointInAnnotation(e,o){if(o.type==="rectangle"){const n=o.coordinates;return e.x>=n.x1&&e.x<=n.x2&&e.y>=n.y1&&e.y<=n.y2}else if(o.type==="polygon"){const n=o.coordinates;return z(e,n.points)}else if(o.type==="rotatedRect"){const n=o.coordinates,l=H(e,{x:n.x,y:n.y},-n.angle),i=n.width/2,a=n.height/2;return l.x>=n.x-i&&l.x<=n.x+i&&l.y>=n.y-a&&l.y<=n.y+a}else if(o.type==="point")return o.coordinates.points.some(l=>V(e,l)<10/this.scale);return!1}getHitHandle(e,o,n){const l=this.getAnnotationHandles(n),i=6;for(let a=0;a<l.length;a++){const s=l[a],c=this.toScreenCoords(s.x,s.y);if(Math.abs(e-c.x)<i&&Math.abs(o-c.y)<i)return n.type==="rotatedRect"&&a===4?-2:a}return-100}getAnnotationHandles(e){if(e.type==="rectangle"){const o=e.coordinates;return[{x:o.x1,y:o.y1},{x:o.x2,y:o.y1},{x:o.x2,y:o.y2},{x:o.x1,y:o.y2}]}else{if(e.type==="polygon")return e.coordinates.points;if(e.type==="point")return e.coordinates.points;if(e.type==="rotatedRect"){const o=e.coordinates,n={x:o.x,y:o.y},l=o.width/2,i=o.height/2,a={x:o.x-l,y:o.y-i},s={x:o.x+l,y:o.y-i},c={x:o.x+l,y:o.y+i},m={x:o.x-l,y:o.y+i},d={x:o.x,y:o.y-i-20/this.scale};return[a,s,c,m,d].map(g=>H(g,n,o.angle))}}return[]}checkHover(e,o,n){const l=this.getHitCategory(e,o);if(l){this.canvas.style.cursor="pointer",this.hoverAnnotation=l;return}if(this.activeAnnotation&&this.getHitHandle(e,o,this.activeAnnotation)!==-100){this.canvas.style.cursor="pointer";return}const i=this.getHitAnnotation(n);i?(this.canvas.style.cursor="move",this.hoverAnnotation=i):(this.canvas.style.cursor="default",this.hoverAnnotation=null)}render(){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(e=>{e!==this.activeAnnotation&&this.drawItem(e,!1)}),this.activeAnnotation&&this.drawItem(this.activeAnnotation,!0),this.renderCategories()}renderCategories(){const e=this.annotations.filter(c=>c.type==="category");if(e.length===0)return;this.ctx.save(),this.ctx.font="14px sans-serif",this.ctx.textBaseline="top";let o=10;const n=10,l=8,i=4,a=24,s=8;e.forEach(c=>{const m=c.label||"Unlabeled",d=this.ctx.measureText(m).width+l*2,g=this.activeAnnotation===c,f=this.hoverAnnotation===c;this.ctx.fillStyle=g?"#E3F2FD":f?"#F5F5F5":"rgba(255, 255, 255, 0.9)",this.ctx.strokeStyle=g?"#2196F3":"#666",this.ctx.lineWidth=g?2:1,this.ctx.beginPath(),this.ctx.rect(o,n,d,a),this.ctx.fill(),this.ctx.stroke(),this.ctx.fillStyle=g?"#1976D2":"#333",this.ctx.fillText(m,o+l,n+i),o+=d+s}),this.ctx.restore()}getHitCategory(e,o){const n=this.annotations.filter(d=>d.type==="category");if(n.length===0)return null;this.ctx.save(),this.ctx.font="14px sans-serif";let l=10;const i=10,a=8,s=24,c=8;let m=null;for(const d of n){const g=d.label||"Unlabeled",f=this.ctx.measureText(g).width+a*2;if(e>=l&&e<=l+f&&o>=i&&o<=i+s){m=d;break}l+=f+c}return this.ctx.restore(),m}drawItem(e,o){var i;if(this.visibleLabels.size>0&&!this.visibleLabels.has(e.label)&&!o)return;this.ctx.save();const n=((i=e.style)==null?void 0:i.strokeColor)||"#FF4081",l=o?"#00E5FF":n;if(this.ctx.strokeStyle=l,this.ctx.lineWidth=2,o?this.ctx.fillStyle="rgba(0, 229, 255, 0.2)":this.ctx.fillStyle=this.hexToRgba(n,.2),e.type==="rectangle"){const a=e.coordinates,s=this.toScreenCoords(a.x1,a.y1),c=this.toScreenCoords(a.x2,a.y2),m=Math.min(s.x,c.x),d=Math.min(s.y,c.y),g=Math.abs(s.x-c.x),f=Math.abs(s.y-c.y);this.ctx.strokeRect(m,d,g,f),this.ctx.fillStyle=o?"rgba(0, 229, 255, 0.2)":"rgba(255, 64, 129, 0.2)",this.ctx.fillRect(m,d,g,f),o&&this.drawHandles(this.getAnnotationHandles(e))}else if(e.type==="polygon"){const a=e.coordinates;if(a.points.length===0){this.ctx.restore();return}this.ctx.beginPath();const s=this.toScreenCoords(a.points[0].x,a.points[0].y);this.ctx.moveTo(s.x,s.y);for(let c=1;c<a.points.length;c++){const m=this.toScreenCoords(a.points[c].x,a.points[c].y);this.ctx.lineTo(m.x,m.y)}if(!this.isDrawing||e!==this.activeAnnotation)this.ctx.closePath();else if(this.lastMouseMovePoint){let c=this.lastMouseMovePoint;if(this.isHoveringStartPoint&&a.points.length>0){c=a.points[0];const d=this.toScreenCoords(a.points[0].x,a.points[0].y);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()}const m=this.toScreenCoords(c.x,c.y);this.ctx.lineTo(m.x,m.y)}this.ctx.stroke(),this.ctx.fillStyle=o?"rgba(0, 229, 255, 0.2)":"rgba(255, 64, 129, 0.2)",this.ctx.fill(),o&&this.drawHandles(this.getAnnotationHandles(e))}else if(e.type==="rotatedRect"){const a=e.coordinates;this.ctx.translate(this.toScreenCoords(a.x,a.y).x,this.toScreenCoords(a.x,a.y).y),this.ctx.rotate(a.angle*Math.PI/180);const s=a.width*this.scale,c=a.height*this.scale;this.ctx.strokeRect(-s/2,-c/2,s,c),this.ctx.fillStyle=o?"rgba(0, 229, 255, 0.2)":"rgba(255, 64, 129, 0.2)",this.ctx.fillRect(-s/2,-c/2,s,c),this.ctx.rotate(-a.angle*Math.PI/180),this.ctx.translate(-this.toScreenCoords(a.x,a.y).x,-this.toScreenCoords(a.x,a.y).y),o&&this.drawHandles(this.getAnnotationHandles(e))}else e.type==="point"&&e.coordinates.points.forEach(s=>{const c=this.toScreenCoords(s.x,s.y);this.ctx.beginPath(),this.ctx.arc(c.x,c.y,5,0,Math.PI*2),this.ctx.fillStyle=o?"#00E5FF":n,this.ctx.fill(),this.ctx.stroke()});this.ctx.restore()}drawHandles(e){this.ctx.fillStyle="#FFFFFF",this.ctx.strokeStyle="#000000",this.ctx.lineWidth=1,e.forEach(o=>{const n=this.toScreenCoords(o.x,o.y);this.ctx.fillRect(n.x-4,n.y-4,8,8),this.ctx.strokeRect(n.x-4,n.y-4,8,8)})}}const W={key:0,class:"left-sidebar"},j=["onClick","title"],X={class:"center-area"},Y={key:0,class:"top-bar"},Z={class:"label-selector"},q={class:"tags-row"},K=["onClick"],G={key:0,class:"no-labels"},Q={key:1,class:"batch-nav"},tt=["disabled"],et=["disabled"],nt={key:1,class:"right-sidebar"},ot={class:"label-list"},it={class:"label-row"},st=["onUpdate:modelValue","onChange"],at=["title"],lt=["onClick"],rt={class:"action-icon more-actions"},ct=["onClick"],ht={key:2,class:"modal-overlay"},dt={class:"modal-content"},gt={class:"form-group"},mt={class:"form-group"},ft={class:"color-input-wrapper"},yt=t.defineComponent({__name:"ImageAnnotator",props:{annotationTypes:{default:()=>["rectangle","polygon","point","rotatedRect"]},batchImages:{default:()=>[]},labels:{default:()=>[]},defaultActiveType:{},theme:{default:"light"},readOnly:{type:Boolean,default:!1}},emits:["annotationChange","batchChange","labelChange"],setup(p,{expose:e,emit:o}){const n=p,l=o,i=t.ref(null),a=t.ref(null),s=t.ref(null),c=t.ref(null),m=t.ref(0),d=t.ref([]),g=t.ref(""),f=t.ref(!1),y=t.ref({name:"",color:"#FF0000"}),k=t.computed(()=>n.annotationTypes.filter(r=>r!=="category")),v=r=>({rectangle:"Crop",polygon:"Connection",point:"Aim",rotatedRect:"RefreshRight",category:"PriceTag"})[r]||r,I=r=>({rectangle:"矩形框",polygon:"多边形",point:"关键点",rotatedRect:"旋转矩形",category:"分类标签"})[r]||r;t.onMounted(()=>{if(i.value){s.value=new J(i.value),s.value.on("annotationChange",h=>{if(h.action==="add"&&h.changedItem){const u=d.value.find(C=>C.id===g.value);u&&(h.changedItem.label=u.name)}l("annotationChange",h)}),E(),_();const r=new ResizeObserver(()=>{var h;(h=s.value)==null||h.resize()});a.value&&r.observe(a.value)}});const _=()=>{if(!s.value)return;const r=d.value.find(u=>u.id===g.value);r&&s.value.setLabelStyle(r.color);const h=d.value.filter(u=>u.visible).map(u=>u.name);s.value.setVisibleLabels(h)},E=()=>{if(s.value&&n.batchImages.length>0){const r=n.batchImages[m.value];s.value.loadImage(r.imageUrl),r.annotations&&s.value.setAnnotations(r.annotations)}},B=r=>{var h,u;if(c.value=r,r!=="pan"&&r!=="select"&&d.value.length===0){alert("请先创建标签!");return}r==="pan"||r==="select"?(h=s.value)==null||h.setTool(r):(u=s.value)==null||u.setTool(r)},N=()=>{var r;(r=s.value)!=null&&r.activeAnnotation&&s.value.deleteAnnotation(s.value.activeAnnotation.id)},D=()=>{var r;return(r=s.value)==null?void 0:r.zoom(1)},R=()=>{var r;return(r=s.value)==null?void 0:r.zoom(-1)},Rt=()=>{y.value={name:"",color:"#2196F3"},f.value=!0},U=()=>{f.value=!1},Ut=()=>{if(!y.value.name.trim()){alert("请输入标签名称");return}const h={id:Date.now().toString(),name:y.value.name,color:y.value.color,visible:!0};d.value.push(h),l("labelChange",d.value),d.value.length===1&&T(h),U()},T=r=>{var h;g.value=r.id,(h=s.value)==null||h.setLabelStyle(r.color)},Ot=(r,h)=>{if(!r.startsWith("#"))return r;let u=0,C=0,w=0;return r.length===4?(u=parseInt(r[1]+r[1],16),C=parseInt(r[2]+r[2],16),w=parseInt(r[3]+r[3],16)):r.length===7&&(u=parseInt(r.slice(1,3),16),C=parseInt(r.slice(3,5),16),w=parseInt(r.slice(5,7),16)),`rgba(${u}, ${C}, ${w}, ${h})`},zt=r=>{var h;if(r.id===g.value&&((h=s.value)==null||h.setLabelStyle(r.color)),s.value){const u=s.value.getAnnotations();let C=!1;u.forEach(w=>{w.label===r.name&&(w.style||(w.style={}),w.style.strokeColor=r.color,w.style.fillColor=Ot(r.color,.2),C=!0)}),C&&s.value.render()}l("labelChange",d.value)},Jt=r=>{r.visible=!r.visible,_()},Wt=r=>{const h=d.value.findIndex(u=>u.id===r);h>-1&&(d.value.splice(h,1),l("labelChange",d.value),g.value===r&&(g.value=d.value.length>0?d.value[0].id:"",g.value&&T(d.value[0])),_())};t.watch(()=>n.labels,r=>{const h=JSON.parse(JSON.stringify(r||[]));if(d.value=h,d.value.length>0)if(!g.value||!d.value.find(u=>u.id===g.value))T(d.value[0]);else{const u=d.value.find(C=>C.id===g.value);u&&T(u)}else g.value="";_()},{immediate:!0,deep:!0});const jt=()=>{m.value>0&&(L(),m.value--,E(),M())},Xt=()=>{m.value<n.batchImages.length-1&&(L(),m.value++,E(),M())},L=()=>{if(s.value){const r=s.value.getAnnotations();n.batchImages[m.value].annotations=r}},M=()=>{const r=n.batchImages[m.value];l("batchChange",{currentIndex:m.value,total:n.batchImages.length,currentImageUrl:r.imageUrl,currentAnnotations:r.annotations||[]})};return e({jumpTo:r=>{r>=0&&r<n.batchImages.length&&(L(),m.value=r,E(),M())},getAllAnnotations:()=>n.batchImages,getCurrentAnnotation:()=>{var r;return{imageUrl:n.batchImages[m.value].imageUrl,annotations:((r=s.value)==null?void 0:r.getAnnotations())||[]}}}),(r,h)=>{const u=t.resolveComponent("Rank"),C=t.resolveComponent("el-icon"),w=t.resolveComponent("Pointer"),Yt=t.resolveComponent("ZoomIn"),Zt=t.resolveComponent("ZoomOut"),O=t.resolveComponent("Delete"),qt=t.resolveComponent("Back"),Kt=t.resolveComponent("Right"),Gt=t.resolveComponent("View"),Qt=t.resolveComponent("Hide");return t.openBlock(),t.createElementBlock("div",{class:t.normalizeClass(["annotation-container",p.theme])},[p.readOnly?t.createCommentVNode("",!0):(t.openBlock(),t.createElementBlock("div",W,[t.createElementVNode("div",{class:t.normalizeClass(["tool-btn",{active:c.value==="pan"}]),onClick:h[0]||(h[0]=x=>B("pan")),title:"拖动"},[t.createVNode(C,null,{default:t.withCtx(()=>[t.createVNode(u)]),_:1})],2),t.createElementVNode("div",{class:t.normalizeClass(["tool-btn",{active:c.value==="select"}]),onClick:h[1]||(h[1]=x=>B("select")),title:"选择"},[t.createVNode(C,null,{default:t.withCtx(()=>[t.createVNode(w)]),_:1})],2),h[4]||(h[4]=t.createElementVNode("div",{class:"divider"},null,-1)),(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(k.value,x=>(t.openBlock(),t.createElementBlock("div",{key:x,class:t.normalizeClass(["tool-btn",{active:c.value===x}]),onClick:S=>B(x),title:I(x)},[t.createVNode(C,null,{default:t.withCtx(()=>[(t.openBlock(),t.createBlock(t.resolveDynamicComponent(v(x))))]),_:2},1024)],10,j))),128)),h[5]||(h[5]=t.createElementVNode("div",{class:"divider"},null,-1)),t.createElementVNode("div",{class:"tool-btn",onClick:D,title:"放大"},[t.createVNode(C,null,{default:t.withCtx(()=>[t.createVNode(Yt)]),_:1})]),t.createElementVNode("div",{class:"tool-btn",onClick:R,title:"缩小"},[t.createVNode(C,null,{default:t.withCtx(()=>[t.createVNode(Zt)]),_:1})]),h[6]||(h[6]=t.createElementVNode("div",{class:"divider"},null,-1)),t.createElementVNode("div",{class:"tool-btn",onClick:N,title:"删除选中"},[t.createVNode(C,null,{default:t.withCtx(()=>[t.createVNode(O)]),_:1})])])),t.createElementVNode("div",X,[p.readOnly?t.createCommentVNode("",!0):(t.openBlock(),t.createElementBlock("div",Y,[t.createElementVNode("div",Z,[h[7]||(h[7]=t.createElementVNode("span",{class:"label-text"},"当前标签:",-1)),t.createElementVNode("div",q,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(d.value,x=>(t.openBlock(),t.createElementBlock("div",{key:x.id,class:t.normalizeClass(["tag-chip",{active:g.value===x.id}]),style:t.normalizeStyle({backgroundColor:x.color,borderColor:x.color}),onClick:S=>T(x)},t.toDisplayString(x.name),15,K))),128)),d.value.length===0?(t.openBlock(),t.createElementBlock("div",G,"请在右侧创建标签")):t.createCommentVNode("",!0)])])])),t.createElementVNode("div",{class:"canvas-wrapper",ref_key:"canvasWrapper",ref:a},[t.createElementVNode("canvas",{ref_key:"canvasRef",ref:i},null,512)],512),p.batchImages&&p.batchImages.length>0?(t.openBlock(),t.createElementBlock("div",Q,[t.createElementVNode("button",{onClick:jt,disabled:m.value<=0},[t.createVNode(C,null,{default:t.withCtx(()=>[t.createVNode(qt)]),_:1}),h[8]||(h[8]=t.createTextVNode(" 上一张 ",-1))],8,tt),t.createElementVNode("span",null,t.toDisplayString(m.value+1)+" / "+t.toDisplayString(p.batchImages.length),1),t.createElementVNode("button",{onClick:Xt,disabled:m.value>=p.batchImages.length-1},[h[9]||(h[9]=t.createTextVNode(" 下一张 ",-1)),t.createVNode(C,null,{default:t.withCtx(()=>[t.createVNode(Kt)]),_:1})],8,et)])):t.createCommentVNode("",!0)]),p.readOnly?t.createCommentVNode("",!0):(t.openBlock(),t.createElementBlock("div",nt,[t.createElementVNode("div",{class:"sidebar-header"},[h[10]||(h[10]=t.createElementVNode("h3",null,"标签管理",-1)),t.createElementVNode("button",{class:"add-btn",onClick:Rt},"添加标签")]),t.createElementVNode("div",ot,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(d.value,x=>(t.openBlock(),t.createElementBlock("div",{key:x.id,class:"label-item"},[t.createElementVNode("div",it,[t.createElementVNode("label",{class:"color-wrapper",style:t.normalizeStyle({backgroundColor:x.color})},[t.withDirectives(t.createElementVNode("input",{type:"color","onUpdate:modelValue":S=>x.color=S,onChange:S=>zt(x),style:{visibility:"hidden",width:"0",height:"0"}},null,40,st),[[t.vModelText,x.color]])],4),t.createElementVNode("span",{class:"label-name",title:x.name},t.toDisplayString(x.name),9,at),t.createElementVNode("span",{class:"action-icon eye",onClick:S=>Jt(x)},[x.visible?(t.openBlock(),t.createBlock(C,{key:0},{default:t.withCtx(()=>[t.createVNode(Gt)]),_:1})):(t.openBlock(),t.createBlock(C,{key:1},{default:t.withCtx(()=>[t.createVNode(Qt)]),_:1}))],8,lt),t.createElementVNode("div",rt,[h[11]||(h[11]=t.createElementVNode("span",{class:"dots"},"•••",-1)),t.createElementVNode("span",{class:"delete-btn",onClick:S=>Wt(x.id),title:"删除"},[t.createVNode(C,null,{default:t.withCtx(()=>[t.createVNode(O)]),_:1})],8,ct)])])]))),128))])])),f.value?(t.openBlock(),t.createElementBlock("div",ht,[t.createElementVNode("div",dt,[h[14]||(h[14]=t.createElementVNode("h3",null,"新增标签",-1)),t.createElementVNode("div",gt,[h[12]||(h[12]=t.createElementVNode("label",null,"名称",-1)),t.withDirectives(t.createElementVNode("input",{"onUpdate:modelValue":h[2]||(h[2]=x=>y.value.name=x),placeholder:"请输入标签名称",class:"modal-input"},null,512),[[t.vModelText,y.value.name]])]),t.createElementVNode("div",mt,[h[13]||(h[13]=t.createElementVNode("label",null,"颜色",-1)),t.createElementVNode("div",ft,[t.withDirectives(t.createElementVNode("input",{type:"color","onUpdate:modelValue":h[3]||(h[3]=x=>y.value.color=x),class:"modal-color-picker"},null,512),[[t.vModelText,y.value.color]]),t.createElementVNode("span",null,t.toDisplayString(y.value.color),1)])]),t.createElementVNode("div",{class:"modal-actions"},[t.createElementVNode("button",{onClick:U,class:"cancel-btn"},"取消"),t.createElementVNode("button",{onClick:Ut,class:"confirm-btn"},"确认")])])])):t.createCommentVNode("",!0)],2)}}}),P=(p,e)=>{const o=p.__vccOpts||p;for(const[n,l]of e)o[n]=l;return o},$=P(yt,[["__scopeId","data-v-d3dc5a63"]]),pt={class:"thumbnail-wrapper",ref:"wrapper"},xt=["src","alt"],ut=["viewBox"],bt=["x","y","width","height","stroke"],Ct=["points","stroke"],kt=["x","y","fill"],At={key:1,class:"loading-placeholder"},vt=P(t.defineComponent({__name:"AnnotationThumbnail",props:{src:{},annotations:{},alt:{},labels:{}},setup(p){const e=p,o=t.ref(null),n=t.ref(!1),l=t.ref(0),i=t.ref(0),a=()=>{o.value&&(l.value=o.value.naturalWidth,i.value=o.value.naturalHeight,n.value=!0)},s=g=>{var f;if((f=g.style)!=null&&f.strokeColor)return g.style.strokeColor;if(e.labels){const y=e.labels.find(k=>k.name===g.label);if(y)return y.color}return"#FF0000"},c=g=>{const f=g.coordinates,y=Math.min(f.x1,f.x2),k=Math.min(f.y1,f.y2),v=Math.abs(f.x1-f.x2),I=Math.abs(f.y1-f.y2);return{x:y,y:k,width:v,height:I}},m=g=>g.coordinates.points.map(y=>`${y.x},${y.y}`).join(" "),d=g=>{if(g.type==="rectangle"){const f=c(g);return{x:f.x,y:f.y-5}}else if(g.type==="polygon"){const f=g.coordinates.points;if(f.length>0)return{x:f[0].x,y:f[0].y-5}}return{x:0,y:0}};return(g,f)=>(t.openBlock(),t.createElementBlock("div",pt,[t.createElementVNode("img",{ref_key:"img",ref:o,src:p.src,class:"thumbnail-image",onLoad:a,alt:p.alt},null,40,xt),n.value?(t.openBlock(),t.createElementBlock("svg",{key:0,class:"annotation-overlay",viewBox:`0 0 ${l.value} ${i.value}`,preserveAspectRatio:"none"},[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(p.annotations,y=>(t.openBlock(),t.createElementBlock(t.Fragment,{key:y.id},[y.type==="rectangle"?(t.openBlock(),t.createElementBlock("rect",{key:0,x:c(y).x,y:c(y).y,width:c(y).width,height:c(y).height,stroke:s(y),"stroke-width":"2",fill:"transparent"},null,8,bt)):t.createCommentVNode("",!0),y.type==="polygon"?(t.openBlock(),t.createElementBlock("polygon",{key:1,points:m(y),stroke:s(y),"stroke-width":"2",fill:"transparent"},null,8,Ct)):t.createCommentVNode("",!0),y.label?(t.openBlock(),t.createElementBlock("text",{key:2,x:d(y).x,y:d(y).y,fill:s(y),"font-size":"14","font-weight":"bold",class:"anno-label"},t.toDisplayString(y.label),9,kt)):t.createCommentVNode("",!0)],64))),128))],8,ut)):(t.openBlock(),t.createElementBlock("div",At,"Loading..."))],512))}}),[["__scopeId","data-v-78bcbe0c"]]),wt={class:"batch-annotator"},Nt={key:0,class:"gallery-view"},Vt={class:"gallery-header"},_t={class:"label-summary"},Et={class:"gallery-grid"},St=["onClick"],It={class:"thumbnail-wrapper"},Bt={class:"img-meta"},Dt={class:"img-index"},Tt={class:"anno-count"},Pt={class:"bottom-bar"},Lt={key:1,class:"editor-view"},Mt={class:"editor-header"},Ht={class:"header-left"},$t={class:"editor-title"},Ft={class:"editor-content"},F=P(t.defineComponent({__name:"BatchAnnotator",props:{images:{},labels:{}},emits:["export","update:images"],setup(p,{emit:e}){const o=p,n=e,l=t.ref("gallery"),i=t.ref([]),a=t.ref(0),s=t.ref(null);t.watch(()=>o.images,k=>{i.value=JSON.parse(JSON.stringify(k))},{immediate:!0,deep:!0});const c=k=>{a.value=k,l.value="editor",t.nextTick(()=>{s.value&&s.value.jumpTo&&s.value.jumpTo(k)})},m=()=>{if(s.value&&s.value.getCurrentAnnotation){const k=s.value.getCurrentAnnotation();i.value[a.value]&&(i.value[a.value].annotations=k.annotations)}l.value="gallery"},d=()=>{n("export",i.value)},g=k=>{a.value=k.currentIndex,i.value[k.currentIndex]&&(i.value[k.currentIndex].annotations=k.currentAnnotations)},f=k=>{if(s.value&&s.value.getCurrentAnnotation){const v=s.value.getCurrentAnnotation();i.value[a.value]&&(i.value[a.value].annotations=v.annotations,n("update:images",i.value))}},y=k=>{};return(k,v)=>{const I=t.resolveComponent("Edit"),_=t.resolveComponent("el-icon"),E=t.resolveComponent("Download"),B=t.resolveComponent("Back");return t.openBlock(),t.createElementBlock("div",wt,[l.value==="gallery"?(t.openBlock(),t.createElementBlock("div",Nt,[t.createElementVNode("div",Vt,[t.createElementVNode("h3",null,"批量查看与标注 ("+t.toDisplayString(i.value.length)+" 张)",1),t.createElementVNode("div",_t,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(p.labels,N=>(t.openBlock(),t.createElementBlock("span",{key:N.id,class:"label-badge",style:t.normalizeStyle({backgroundColor:N.color})},t.toDisplayString(N.name),5))),128))])]),t.createElementVNode("div",Et,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(i.value,(N,D)=>(t.openBlock(),t.createElementBlock("div",{key:D,class:"gallery-item",onClick:R=>c(D)},[t.createElementVNode("div",It,[t.createVNode(vt,{src:N.imageUrl,annotations:N.annotations||[],labels:p.labels},null,8,["src","annotations","labels"])]),t.createElementVNode("div",Bt,[t.createElementVNode("span",Dt,"#"+t.toDisplayString(D+1),1),t.createElementVNode("span",Tt,t.toDisplayString((N.annotations||[]).length)+" 标注",1)])],8,St))),128))]),t.createElementVNode("div",Pt,[t.createElementVNode("button",{class:"action-btn primary",onClick:v[0]||(v[0]=N=>c(0))},[t.createVNode(_,null,{default:t.withCtx(()=>[t.createVNode(I)]),_:1}),v[1]||(v[1]=t.createTextVNode(" 手动标注 ",-1))]),t.createElementVNode("button",{class:"action-btn success",onClick:d},[t.createVNode(_,null,{default:t.withCtx(()=>[t.createVNode(E)]),_:1}),v[2]||(v[2]=t.createTextVNode(" 导出 ",-1))])])])):(t.openBlock(),t.createElementBlock("div",Lt,[t.createElementVNode("div",Mt,[t.createElementVNode("div",Ht,[t.createElementVNode("button",{class:"back-btn",onClick:m},[t.createVNode(_,null,{default:t.withCtx(()=>[t.createVNode(B)]),_:1}),v[3]||(v[3]=t.createTextVNode(" 返回列表 ",-1))]),t.createElementVNode("span",$t,"正在标注: "+t.toDisplayString(a.value+1)+" / "+t.toDisplayString(i.value.length),1)])]),t.createElementVNode("div",Ft,[t.createVNode($,{ref_key:"annotatorRef",ref:s,batchImages:i.value,labels:p.labels,annotationTypes:["rectangle","polygon","point","rotatedRect"],onBatchChange:g,onAnnotationChange:f,onLabelChange:y},null,8,["batchImages","labels"])])]))])}}}),[["__scopeId","data-v-4cf50076"]]);A.BatchAnnotator=F,A.ImageAnnotator=$,A.default=F,Object.defineProperties(A,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
|
1
|
+
(function(w,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],t):(w=typeof globalThis<"u"?globalThis:w||self,t(w.VueImageAnnotator={},w.Vue))})(this,(function(w,t){"use strict";var ce=Object.defineProperty;var he=(w,t,E)=>t in w?ce(w,t,{enumerable:!0,configurable:!0,writable:!0,value:E}):w[t]=E;var x=(w,t,E)=>he(w,typeof t!="symbol"?t+"":t,E);const E=(y,e)=>Math.sqrt(Math.pow(y.x-e.x,2)+Math.pow(y.y-e.y,2)),P=(y,e)=>{let s=!1;for(let n=0,l=e.length-1;n<e.length;l=n++){const i=e[n].x,a=e[n].y,o=e[l].x,c=e[l].y;a>y.y!=c>y.y&&y.x<(o-i)*(y.y-a)/(c-a)+i&&(s=!s)}return s},H=(y,e,s)=>{const n=s*(Math.PI/180),l=Math.cos(n),i=Math.sin(n),a=y.x-e.x,o=y.y-e.y;return{x:e.x+(a*l-o*i),y:e.y+(a*i+o*l)}};class ${constructor(e){x(this,"canvas");x(this,"ctx");x(this,"img");x(this,"annotations",[]);x(this,"currentTool",null);x(this,"activeAnnotation",null);x(this,"hoverAnnotation",null);x(this,"isDrawing",!1);x(this,"isDragging",!1);x(this,"isPanning",!1);x(this,"panStartPoint",null);x(this,"dragStartPoint",null);x(this,"dragStartAnnotation",null);x(this,"lastMouseMovePoint",null);x(this,"isHoveringStartPoint",!1);x(this,"currentLabelColor","#FF4081");x(this,"visibleLabels",new Set);x(this,"selectedHandleIndex",-1);x(this,"hoverHandleIndex",-1);x(this,"scale",1);x(this,"offset",{x:0,y:0});x(this,"listeners",{});x(this,"imageUrl","");this.canvas=e;const s=e.getContext("2d");if(!s)throw new Error("Could not get 2d context");this.ctx=s,this.img=new Image,this.img.crossOrigin="Anonymous",this.img.onload=()=>{this.fitImageToCanvas(),this.render()},this.bindEvents()}on(e,s){this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].push(s)}emit(e,s){this.listeners[e]&&this.listeners[e].forEach(n=>n(s))}loadImage(e){this.imageUrl=e,this.img.src=e,this.activeAnnotation=null,this.isDrawing=!1}setAnnotations(e){this.annotations=JSON.parse(JSON.stringify(e)),this.render()}getAnnotations(){return this.annotations}setTool(e){e==="pan"?(this.currentTool=null,this.isPanning=!1,this.canvas.style.cursor="grab"):e==="select"?(this.currentTool=null,this.canvas.style.cursor="default"):(this.currentTool=e,this.canvas.style.cursor="crosshair"),this.activeAnnotation=null,this.isDrawing=!1,this.render()}setLabelStyle(e){this.currentLabelColor=e}setVisibleLabels(e){this.visibleLabels=new Set(e),this.render()}zoom(e){const n=e>0?this.scale*1.1:this.scale/1.1;if(n<.1||n>10)return;const l=this.canvas.width/2,i=this.canvas.height/2,a=this.toImageCoords(l,i);this.scale=n,this.offset.x=l-a.x*this.scale,this.offset.y=i-a.y*this.scale,this.render()}resize(){this.fitImageToCanvas(),this.render()}toImageCoords(e,s){return{x:(e-this.offset.x)/this.scale,y:(s-this.offset.y)/this.scale}}toScreenCoords(e,s){return{x:e*this.scale+this.offset.x,y:s*this.scale+this.offset.y}}fitImageToCanvas(){const e=this.canvas.parentElement;if(e){if(this.canvas.width=e.clientWidth,this.canvas.height=e.clientHeight,this.img.width===0)return;const s=this.canvas.width/this.img.width,n=this.canvas.height/this.img.height;this.scale=Math.min(s,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}}bindEvents(){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))}handleKeyDown(e){(e.key==="Delete"||e.key==="Backspace")&&this.activeAnnotation&&this.deleteAnnotation(this.activeAnnotation.id)}deleteAnnotation(e){const s=this.annotations.findIndex(n=>n.id===e);if(s>-1){const n=this.annotations[s];this.annotations.splice(s,1),this.activeAnnotation=null,this.emit("annotationChange",{action:"delete",changedItem:n,imageUrl:this.imageUrl}),this.render()}}handleMouseDown(e){const s=this.canvas.getBoundingClientRect(),n=e.clientX-s.left,l=e.clientY-s.top,i=this.toImageCoords(n,l);if(this.canvas.style.cursor==="grab"||this.canvas.style.cursor==="grabbing"){this.isPanning=!0,this.panStartPoint={x:n,y:l},this.canvas.style.cursor="grabbing";return}if(this.activeAnnotation){const c=this.getHitHandle(n,l,this.activeAnnotation);if(c!==-100){this.isDragging=!0,this.dragStartPoint=i,this.selectedHandleIndex=c,this.dragStartAnnotation=JSON.parse(JSON.stringify(this.activeAnnotation));return}}const a=this.getHitCategory(n,l);if(a){this.activeAnnotation=a,this.isDragging=!1,this.selectedHandleIndex=-1,this.emit("annotationChange",{action:"select",changedItem:a,imageUrl:this.imageUrl}),this.render();return}const o=this.getHitAnnotation(i);if(this.currentTool){if(this.isDrawing&&this.currentTool==="polygon"&&this.activeAnnotation){const c=this.activeAnnotation.coordinates;if(c.points.length>2&&E(i,c.points[0])<20/this.scale){this.finishDrawing();return}this.startDrawing(i);return}if(this.currentTool){if(this.currentTool==="polygon"&&!this.isDrawing){this.startDrawing(i);return}if(o){this.activeAnnotation=o,this.isDragging=!0,this.dragStartPoint=i,this.selectedHandleIndex=-1,this.dragStartAnnotation=JSON.parse(JSON.stringify(o)),this.emit("annotationChange",{action:"select",changedItem:o,imageUrl:this.imageUrl}),this.render();return}this.startDrawing(i)}else o?(this.activeAnnotation=o,this.isDragging=!0,this.dragStartPoint=i,this.selectedHandleIndex=-1,this.dragStartAnnotation=JSON.parse(JSON.stringify(o)),this.emit("annotationChange",{action:"select",changedItem:o,imageUrl:this.imageUrl}),this.render()):(this.activeAnnotation=null,this.render())}else if(o){if(!(this.visibleLabels.size>0&&!this.visibleLabels.has(o.label))){this.activeAnnotation=o,this.isDragging=!0,this.dragStartPoint=i,this.selectedHandleIndex=-1,this.dragStartAnnotation=JSON.parse(JSON.stringify(o)),this.emit("annotationChange",{action:"select",changedItem:o,imageUrl:this.imageUrl}),this.render();return}}else this.activeAnnotation=null,this.render()}handleMouseMove(e){const s=this.canvas.getBoundingClientRect(),n=e.clientX-s.left,l=e.clientY-s.top,i=this.toImageCoords(n,l);if(this.isPanning&&this.panStartPoint){const a=n-this.panStartPoint.x,o=l-this.panStartPoint.y;this.offset.x+=a,this.offset.y+=o,this.panStartPoint={x:n,y:l},this.render();return}if(this.lastMouseMovePoint=i,this.isDrawing){if(this.currentTool==="polygon"&&this.activeAnnotation){const a=this.activeAnnotation.coordinates;if(a.points.length>2){const o=a.points[0],c=E(i,o);this.isHoveringStartPoint=c<20/this.scale}else this.isHoveringStartPoint=!1}this.updateDrawing(i)}else this.isDragging&&this.activeAnnotation&&this.dragStartPoint?this.updateDragging(i):this.checkHover(n,l,i);this.render()}handleMouseUp(e){if(this.isPanning){this.isPanning=!1,this.panStartPoint=null,this.canvas.style.cursor="grab";return}if(this.isDrawing){if(this.currentTool==="polygon"){this.render();return}this.finishDrawing()}else this.isDragging&&this.activeAnnotation&&this.emit("annotationChange",{action:"update",changedItem:this.activeAnnotation,imageUrl:this.imageUrl});this.currentTool!=="polygon"&&(this.isDrawing=!1),this.isDragging=!1,this.dragStartPoint=null,this.selectedHandleIndex=-1,this.render()}hexToRgba(e,s){if(!e.startsWith("#"))return e;const n=parseInt(e.slice(1,3),16),l=parseInt(e.slice(3,5),16),i=parseInt(e.slice(5,7),16);return`rgba(${n}, ${l}, ${i}, ${s})`}startDrawing(e){if(!this.currentTool)return;const s=Date.now().toString();if(this.hexToRgba(this.currentLabelColor,.2),this.currentLabelColor,this.currentTool==="rectangle")this.isDrawing=!0,this.dragStartPoint=e,this.activeAnnotation={id:s,type:"rectangle",label:"",coordinates:{x1:e.x,y1:e.y,x2:e.x,y2:e.y},style:{strokeColor:this.currentLabelColor}};else if(this.currentTool==="point"){const n={id:s,type:"point",label:"",coordinates:{points:[e]},style:{strokeColor:this.currentLabelColor}};this.annotations.push(n),this.emit("annotationChange",{action:"add",changedItem:n,imageUrl:this.imageUrl}),this.activeAnnotation=n}else if(this.currentTool==="polygon")this.activeAnnotation&&this.activeAnnotation.type==="polygon"&&this.isDrawing?this.activeAnnotation.coordinates.points.push(e):(this.isDrawing=!0,this.activeAnnotation={id:s,type:"polygon",label:"",coordinates:{points:[e]},style:{strokeColor:this.currentLabelColor}});else if(this.currentTool==="category"){const n={id:s,type:"category",label:"",coordinates:null,style:{strokeColor:this.currentLabelColor}};this.annotations.push(n),this.emit("annotationChange",{action:"add",changedItem:n,imageUrl:this.imageUrl}),this.activeAnnotation=n}else this.currentTool==="rotatedRect"&&(this.isDrawing=!0,this.dragStartPoint=e,this.activeAnnotation={id:s,type:"rotatedRect",label:"",coordinates:{x:e.x,y:e.y,width:0,height:0,angle:0},style:{strokeColor:this.currentLabelColor}})}updateDrawing(e){if(this.activeAnnotation)if(this.activeAnnotation.type==="rectangle"&&this.dragStartPoint){const s=this.activeAnnotation.coordinates;s.x2=e.x,s.y2=e.y}else if(this.activeAnnotation.type==="rotatedRect"&&this.dragStartPoint){const s=this.activeAnnotation.coordinates,n=Math.abs(e.x-this.dragStartPoint.x),l=Math.abs(e.y-this.dragStartPoint.y);s.width=n*2,s.height=l*2}else this.activeAnnotation.type}finishDrawing(){if(this.activeAnnotation){if(this.activeAnnotation.type==="rectangle"){const e=this.activeAnnotation.coordinates;if(Math.abs(e.x1-e.x2)<2||Math.abs(e.y1-e.y2)<2){this.activeAnnotation=null,this.isDrawing=!1;return}const s=Math.min(e.x1,e.x2),n=Math.max(e.x1,e.x2),l=Math.min(e.y1,e.y2),i=Math.max(e.y1,e.y2);e.x1=s,e.x2=n,e.y1=l,e.y2=i,this.annotations.push(this.activeAnnotation),this.emit("annotationChange",{action:"add",changedItem:this.activeAnnotation,imageUrl:this.imageUrl})}else if(this.activeAnnotation.type==="polygon"){if(this.activeAnnotation.coordinates.points.length<3){this.activeAnnotation=null,this.isDrawing=!1;return}this.annotations.push(this.activeAnnotation),this.emit("annotationChange",{action:"add",changedItem:this.activeAnnotation,imageUrl:this.imageUrl})}else if(this.activeAnnotation.type==="rotatedRect"){const e=this.activeAnnotation.coordinates;if(e.width<2||e.height<2){this.activeAnnotation=null,this.isDrawing=!1;return}this.annotations.push(this.activeAnnotation),this.emit("annotationChange",{action:"add",changedItem:this.activeAnnotation,imageUrl:this.imageUrl})}this.activeAnnotation.type}this.isDrawing=!1}updateDragging(e){if(!this.activeAnnotation||!this.dragStartPoint||!this.dragStartAnnotation)return;const s=e.x-this.dragStartPoint.x,n=e.y-this.dragStartPoint.y;this.selectedHandleIndex===-1?this.moveAnnotation(this.activeAnnotation,this.dragStartAnnotation,s,n):this.resizeAnnotation(this.activeAnnotation,this.dragStartAnnotation,this.selectedHandleIndex,e)}moveAnnotation(e,s,n,l){if(e.type==="rectangle"){const i=s.coordinates,a=e.coordinates;a.x1=i.x1+n,a.x2=i.x2+n,a.y1=i.y1+l,a.y2=i.y2+l}else if(e.type==="point"){const i=s.coordinates,a=e.coordinates;a.points=i.points.map(o=>({x:o.x+n,y:o.y+l}))}else if(e.type==="rotatedRect"){const i=s.coordinates,a=e.coordinates;a.x=i.x+n,a.y=i.y+l}else if(e.type==="polygon"){const i=s.coordinates,a=e.coordinates;a.points=i.points.map(o=>({x:o.x+n,y:o.y+l}))}}resizeAnnotation(e,s,n,l){if(e.type==="rectangle"){const i=e.coordinates;n===0&&(i.x1=l.x,i.y1=l.y),n===1&&(i.x2=l.x,i.y1=l.y),n===2&&(i.x2=l.x,i.y2=l.y),n===3&&(i.x1=l.x,i.y2=l.y)}else if(e.type==="polygon"){const i=e.coordinates;n>=0&&n<i.points.length&&(i.points[n]=l)}else if(e.type==="point"){const i=e.coordinates;n>=0&&n<i.points.length&&(i.points[n]=l)}else if(e.type==="rotatedRect"){const i=e.coordinates;if(n===-2){const a=i.x,o=i.y,c=l.x-a,f=l.y-o;let g=Math.atan2(f,c)*180/Math.PI;g+=90,i.angle=g}else{const a=i.angle*Math.PI/180,o=Math.cos(-a),c=Math.sin(-a),f=l.x-i.x,g=l.y-i.y,m=f*o-g*c,p=f*c+g*o;(n===0||n===3)&&(i.width/2,i.width=Math.abs(m)*2),(n===1||n===2)&&(i.width=Math.abs(m)*2),(n===0||n===1)&&(i.height=Math.abs(p)*2),(n===2||n===3)&&(i.height=Math.abs(p)*2)}}}getHitAnnotation(e){for(let s=this.annotations.length-1;s>=0;s--){const n=this.annotations[s];if(this.isPointInAnnotation(e,n))return n}return null}isPointInAnnotation(e,s){if(s.type==="rectangle"){const n=s.coordinates;return e.x>=n.x1&&e.x<=n.x2&&e.y>=n.y1&&e.y<=n.y2}else if(s.type==="polygon"){const n=s.coordinates;return P(e,n.points)}else if(s.type==="rotatedRect"){const n=s.coordinates,l=H(e,{x:n.x,y:n.y},-n.angle),i=n.width/2,a=n.height/2;return l.x>=n.x-i&&l.x<=n.x+i&&l.y>=n.y-a&&l.y<=n.y+a}else if(s.type==="point")return s.coordinates.points.some(l=>E(e,l)<10/this.scale);return!1}getHitHandle(e,s,n){const l=this.getAnnotationHandles(n),i=6;for(let a=0;a<l.length;a++){const o=l[a],c=this.toScreenCoords(o.x,o.y);if(Math.abs(e-c.x)<i&&Math.abs(s-c.y)<i)return n.type==="rotatedRect"&&a===4?-2:a}return-100}getAnnotationHandles(e){if(e.type==="rectangle"){const s=e.coordinates;return[{x:s.x1,y:s.y1},{x:s.x2,y:s.y1},{x:s.x2,y:s.y2},{x:s.x1,y:s.y2}]}else{if(e.type==="polygon")return e.coordinates.points;if(e.type==="point")return e.coordinates.points;if(e.type==="rotatedRect"){const s=e.coordinates,n={x:s.x,y:s.y},l=s.width/2,i=s.height/2,a={x:s.x-l,y:s.y-i},o={x:s.x+l,y:s.y-i},c={x:s.x+l,y:s.y+i},f={x:s.x-l,y:s.y+i},g={x:s.x,y:s.y-i-20/this.scale};return[a,o,c,f,g].map(m=>H(m,n,s.angle))}}return[]}checkHover(e,s,n){const l=this.getHitCategory(e,s);if(l){this.canvas.style.cursor="pointer",this.hoverAnnotation=l;return}if(this.activeAnnotation&&this.getHitHandle(e,s,this.activeAnnotation)!==-100){this.canvas.style.cursor="pointer";return}const i=this.getHitAnnotation(n);i?(this.canvas.style.cursor="move",this.hoverAnnotation=i):(this.canvas.style.cursor="default",this.hoverAnnotation=null)}render(){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(e=>{e!==this.activeAnnotation&&this.drawItem(e,!1)}),this.activeAnnotation&&this.drawItem(this.activeAnnotation,!0),this.renderCategories()}renderCategories(){const e=this.annotations.filter(c=>c.type==="category");if(e.length===0)return;this.ctx.save(),this.ctx.font="14px sans-serif",this.ctx.textBaseline="top";let s=10;const n=10,l=8,i=4,a=24,o=8;e.forEach(c=>{const f=c.label||"Unlabeled",g=this.ctx.measureText(f).width+l*2,m=this.activeAnnotation===c,p=this.hoverAnnotation===c;this.ctx.fillStyle=m?"#E3F2FD":p?"#F5F5F5":"rgba(255, 255, 255, 0.9)",this.ctx.strokeStyle=m?"#2196F3":"#666",this.ctx.lineWidth=m?2:1,this.ctx.beginPath(),this.ctx.rect(s,n,g,a),this.ctx.fill(),this.ctx.stroke(),this.ctx.fillStyle=m?"#1976D2":"#333",this.ctx.fillText(f,s+l,n+i),s+=g+o}),this.ctx.restore()}getHitCategory(e,s){const n=this.annotations.filter(g=>g.type==="category");if(n.length===0)return null;this.ctx.save(),this.ctx.font="14px sans-serif";let l=10;const i=10,a=8,o=24,c=8;let f=null;for(const g of n){const m=g.label||"Unlabeled",p=this.ctx.measureText(m).width+a*2;if(e>=l&&e<=l+p&&s>=i&&s<=i+o){f=g;break}l+=p+c}return this.ctx.restore(),f}drawItem(e,s){var i;if(this.visibleLabels.size>0&&!this.visibleLabels.has(e.label)&&!s)return;this.ctx.save();const n=((i=e.style)==null?void 0:i.strokeColor)||"#FF4081",l=s?"#00E5FF":n;if(this.ctx.strokeStyle=l,this.ctx.lineWidth=2,s?this.ctx.fillStyle="rgba(0, 229, 255, 0.2)":this.ctx.fillStyle=this.hexToRgba(n,.2),e.type==="rectangle"){const a=e.coordinates,o=this.toScreenCoords(a.x1,a.y1),c=this.toScreenCoords(a.x2,a.y2),f=Math.min(o.x,c.x),g=Math.min(o.y,c.y),m=Math.abs(o.x-c.x),p=Math.abs(o.y-c.y);this.ctx.strokeRect(f,g,m,p),this.ctx.fillStyle=s?"rgba(0, 229, 255, 0.2)":"rgba(255, 64, 129, 0.2)",this.ctx.fillRect(f,g,m,p),s&&this.drawHandles(this.getAnnotationHandles(e))}else if(e.type==="polygon"){const a=e.coordinates;if(a.points.length===0){this.ctx.restore();return}this.ctx.beginPath();const o=this.toScreenCoords(a.points[0].x,a.points[0].y);this.ctx.moveTo(o.x,o.y);for(let c=1;c<a.points.length;c++){const f=this.toScreenCoords(a.points[c].x,a.points[c].y);this.ctx.lineTo(f.x,f.y)}if(!this.isDrawing||e!==this.activeAnnotation)this.ctx.closePath();else if(this.lastMouseMovePoint){let c=this.lastMouseMovePoint;if(this.isHoveringStartPoint&&a.points.length>0){c=a.points[0];const g=this.toScreenCoords(a.points[0].x,a.points[0].y);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()}const f=this.toScreenCoords(c.x,c.y);this.ctx.lineTo(f.x,f.y)}this.ctx.stroke(),this.ctx.fillStyle=s?"rgba(0, 229, 255, 0.2)":"rgba(255, 64, 129, 0.2)",this.ctx.fill(),s&&this.drawHandles(this.getAnnotationHandles(e))}else if(e.type==="rotatedRect"){const a=e.coordinates;this.ctx.translate(this.toScreenCoords(a.x,a.y).x,this.toScreenCoords(a.x,a.y).y),this.ctx.rotate(a.angle*Math.PI/180);const o=a.width*this.scale,c=a.height*this.scale;this.ctx.strokeRect(-o/2,-c/2,o,c),this.ctx.fillStyle=s?"rgba(0, 229, 255, 0.2)":"rgba(255, 64, 129, 0.2)",this.ctx.fillRect(-o/2,-c/2,o,c),this.ctx.rotate(-a.angle*Math.PI/180),this.ctx.translate(-this.toScreenCoords(a.x,a.y).x,-this.toScreenCoords(a.x,a.y).y),s&&this.drawHandles(this.getAnnotationHandles(e))}else e.type==="point"&&e.coordinates.points.forEach(o=>{const c=this.toScreenCoords(o.x,o.y);this.ctx.beginPath(),this.ctx.arc(c.x,c.y,5,0,Math.PI*2),this.ctx.fillStyle=s?"#00E5FF":n,this.ctx.fill(),this.ctx.stroke()});this.ctx.restore()}drawHandles(e){this.ctx.fillStyle="#FFFFFF",this.ctx.strokeStyle="#000000",this.ctx.lineWidth=1,e.forEach(s=>{const n=this.toScreenCoords(s.x,s.y);this.ctx.fillRect(n.x-4,n.y-4,8,8),this.ctx.strokeRect(n.x-4,n.y-4,8,8)})}}const F=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
2
|
+
<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
|
|
3
|
+
</svg>`,U=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
4
|
+
<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
|
|
5
|
+
</svg>`,R=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
6
|
+
<path d="M704 192h160v160h-160z m-64-64v288h288V128H640zM160 672h160v160H160z m-64-64v288h288V608H96z m256-320h320v64H352z" fill="currentColor"/>\r
|
|
7
|
+
</svg>`,O=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
8
|
+
<path d="M256 256h512v512H256z m-64-64v640h640V192H192z" fill="currentColor"/>\r
|
|
9
|
+
</svg>`,J=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
10
|
+
<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
|
|
11
|
+
</svg>`,W=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
12
|
+
<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
|
|
13
|
+
</svg>`,j=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
14
|
+
<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
|
|
15
|
+
</svg>`,X=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
16
|
+
<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
|
|
17
|
+
</svg>`,Y=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
18
|
+
<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
|
|
19
|
+
</svg>`,q=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
20
|
+
<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
|
|
21
|
+
</svg>`,K=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
22
|
+
<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
|
|
23
|
+
</svg>`,G=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
24
|
+
<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
|
|
25
|
+
</svg>`,Q=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
26
|
+
<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
|
|
27
|
+
</svg>`,Z=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
28
|
+
<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
|
|
29
|
+
</svg>`,tt=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
30
|
+
<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
|
|
31
|
+
</svg>`,et=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
|
|
32
|
+
<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
|
|
33
|
+
</svg>`,nt=["innerHTML"],st=t.defineComponent({__name:"SvgIcon",props:{name:{},size:{}},setup(y){const e=y,s=t.ref(""),n=Object.assign({"../assets/svg/aim.svg":F,"../assets/svg/back.svg":U,"../assets/svg/connection.svg":R,"../assets/svg/crop.svg":O,"../assets/svg/delete.svg":J,"../assets/svg/download.svg":W,"../assets/svg/edit.svg":j,"../assets/svg/hide.svg":X,"../assets/svg/pointer.svg":Y,"../assets/svg/price-tag.svg":q,"../assets/svg/rank.svg":K,"../assets/svg/refresh-right.svg":G,"../assets/svg/right.svg":Q,"../assets/svg/view.svg":Z,"../assets/svg/zoom-in.svg":tt,"../assets/svg/zoom-out.svg":et});return t.watchEffect(()=>{const l=`../assets/svg/${e.name}.svg`,i=n[l];i?s.value=i:(console.warn(`Icon ${e.name} not found at path ${l}`),s.value="")}),(l,i)=>(t.openBlock(),t.createElementBlock("i",{class:t.normalizeClass(["svg-icon",[y.size?`size-${y.size}`:""]]),innerHTML:s.value},null,10,nt))}}),B=(y,e)=>{const s=y.__vccOpts||y;for(const[n,l]of e)s[n]=l;return s},C=B(st,[["__scopeId","data-v-3928607b"]]),it={key:0,class:"left-sidebar"},ot=["onClick","title"],at={class:"center-area"},lt={key:0,class:"top-bar"},rt={class:"label-selector"},ct={class:"tags-row"},ht=["onClick"],dt={key:0,class:"no-labels"},gt={key:1,class:"batch-nav"},mt=["disabled"],ft=["disabled"],yt={key:1,class:"right-sidebar"},pt={class:"label-list"},vt={class:"label-row"},xt=["onUpdate:modelValue","onChange"],ut=["title"],bt=["onClick"],wt={class:"action-icon more-actions"},Ct=["onClick"],kt={key:2,class:"modal-overlay"},_t={class:"modal-content"},At={class:"form-group"},Et={class:"form-group"},Vt={class:"color-input-wrapper"},L=B(t.defineComponent({__name:"ImageAnnotator",props:{annotationTypes:{default:()=>["rectangle","polygon","point","rotatedRect"]},batchImages:{default:()=>[]},labels:{default:()=>[]},defaultActiveType:{},theme:{default:"light"},readOnly:{type:Boolean,default:!1}},emits:["annotationChange","batchChange","labelChange"],setup(y,{expose:e,emit:s}){const n=y,l=s,i=t.ref(null),a=t.ref(null),o=t.ref(null),c=t.ref(null),f=t.ref(0),g=t.ref([]),m=t.ref(""),p=t.ref(!1),v=t.ref({name:"",color:"#FF0000"}),u=t.computed(()=>n.annotationTypes.filter(r=>r!=="category")),k=r=>({rectangle:"crop",polygon:"connection",point:"aim",rotatedRect:"refresh-right",category:"price-tag"})[r]||r,_=r=>({rectangle:"矩形框",polygon:"多边形",point:"关键点",rotatedRect:"旋转矩形",category:"分类标签"})[r]||r;t.onMounted(()=>{if(i.value){o.value=new $(i.value),o.value.on("annotationChange",h=>{if(h.action==="add"&&h.changedItem){const d=g.value.find(b=>b.id===m.value);d&&(h.changedItem.label=d.name)}l("annotationChange",h)}),S(),V();const r=new ResizeObserver(()=>{var h;(h=o.value)==null||h.resize()});a.value&&r.observe(a.value)}});const V=()=>{if(!o.value)return;const r=g.value.find(d=>d.id===m.value);r&&o.value.setLabelStyle(r.color);const h=g.value.filter(d=>d.visible).map(d=>d.name);o.value.setVisibleLabels(h)},S=()=>{if(o.value&&n.batchImages.length>0){const r=n.batchImages[f.value];o.value.loadImage(r.imageUrl),r.annotations&&o.value.setAnnotations(r.annotations)}},I=r=>{var h,d;if(c.value=r,r!=="pan"&&r!=="select"&&g.value.length===0){alert("请先创建标签!");return}r==="pan"||r==="select"?(h=o.value)==null||h.setTool(r):(d=o.value)==null||d.setTool(r)},Qt=()=>{var r;(r=o.value)!=null&&r.activeAnnotation&&o.value.deleteAnnotation(o.value.activeAnnotation.id)},Zt=()=>{var r;return(r=o.value)==null?void 0:r.zoom(1)},te=()=>{var r;return(r=o.value)==null?void 0:r.zoom(-1)},ee=()=>{v.value={name:"",color:"#2196F3"},p.value=!0},D=()=>{p.value=!1},ne=()=>{if(!v.value.name.trim()){alert("请输入标签名称");return}const h={id:Date.now().toString(),name:v.value.name,color:v.value.color,visible:!0};g.value.push(h),l("labelChange",g.value),g.value.length===1&&N(h),D()},N=r=>{var h;m.value=r.id,(h=o.value)==null||h.setLabelStyle(r.color)},se=(r,h)=>{if(!r.startsWith("#"))return r;let d=0,b=0,A=0;return r.length===4?(d=parseInt(r[1]+r[1],16),b=parseInt(r[2]+r[2],16),A=parseInt(r[3]+r[3],16)):r.length===7&&(d=parseInt(r.slice(1,3),16),b=parseInt(r.slice(3,5),16),A=parseInt(r.slice(5,7),16)),`rgba(${d}, ${b}, ${A}, ${h})`},ie=r=>{var h;if(r.id===m.value&&((h=o.value)==null||h.setLabelStyle(r.color)),o.value){const d=o.value.getAnnotations();let b=!1;d.forEach(A=>{A.label===r.name&&(A.style||(A.style={}),A.style.strokeColor=r.color,A.style.fillColor=se(r.color,.2),b=!0)}),b&&o.value.render()}l("labelChange",g.value)},oe=r=>{r.visible=!r.visible,V()},ae=r=>{const h=g.value.findIndex(d=>d.id===r);h>-1&&(g.value.splice(h,1),l("labelChange",g.value),m.value===r&&(m.value=g.value.length>0?g.value[0].id:"",m.value&&N(g.value[0])),V())};t.watch(()=>n.labels,r=>{const h=JSON.parse(JSON.stringify(r||[]));if(g.value=h,g.value.length>0)if(!m.value||!g.value.find(d=>d.id===m.value))N(g.value[0]);else{const d=g.value.find(b=>b.id===m.value);d&&N(d)}else m.value="";V()},{immediate:!0,deep:!0});const le=()=>{f.value>0&&(z(),f.value--,S(),M())},re=()=>{f.value<n.batchImages.length-1&&(z(),f.value++,S(),M())},z=()=>{if(o.value){const r=o.value.getAnnotations();n.batchImages[f.value].annotations=r}},M=()=>{const r=n.batchImages[f.value];l("batchChange",{currentIndex:f.value,total:n.batchImages.length,currentImageUrl:r.imageUrl,currentAnnotations:r.annotations||[]})};return e({jumpTo:r=>{r>=0&&r<n.batchImages.length&&(z(),f.value=r,S(),M())},getAllAnnotations:()=>n.batchImages,getCurrentAnnotation:()=>{var r;return{imageUrl:n.batchImages[f.value].imageUrl,annotations:((r=o.value)==null?void 0:r.getAnnotations())||[]}}}),(r,h)=>(t.openBlock(),t.createElementBlock("div",{class:t.normalizeClass(["annotation-container",y.theme])},[y.readOnly?t.createCommentVNode("",!0):(t.openBlock(),t.createElementBlock("div",it,[t.createElementVNode("div",{class:t.normalizeClass(["tool-btn",{active:c.value==="pan"}]),onClick:h[0]||(h[0]=d=>I("pan")),title:"拖动"},[t.createVNode(C,{name:"rank"})],2),t.createElementVNode("div",{class:t.normalizeClass(["tool-btn",{active:c.value==="select"}]),onClick:h[1]||(h[1]=d=>I("select")),title:"选择"},[t.createVNode(C,{name:"pointer"})],2),h[4]||(h[4]=t.createElementVNode("div",{class:"divider"},null,-1)),(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(u.value,d=>(t.openBlock(),t.createElementBlock("div",{key:d,class:t.normalizeClass(["tool-btn",{active:c.value===d}]),onClick:b=>I(d),title:_(d)},[t.createVNode(C,{name:k(d)},null,8,["name"])],10,ot))),128)),h[5]||(h[5]=t.createElementVNode("div",{class:"divider"},null,-1)),t.createElementVNode("div",{class:"tool-btn",onClick:Zt,title:"放大"},[t.createVNode(C,{name:"zoom-in"})]),t.createElementVNode("div",{class:"tool-btn",onClick:te,title:"缩小"},[t.createVNode(C,{name:"zoom-out"})]),h[6]||(h[6]=t.createElementVNode("div",{class:"divider"},null,-1)),t.createElementVNode("div",{class:"tool-btn",onClick:Qt,title:"删除选中"},[t.createVNode(C,{name:"delete"})])])),t.createElementVNode("div",at,[y.readOnly?t.createCommentVNode("",!0):(t.openBlock(),t.createElementBlock("div",lt,[t.createElementVNode("div",rt,[h[7]||(h[7]=t.createElementVNode("span",{class:"label-text"},"当前标签:",-1)),t.createElementVNode("div",ct,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(g.value,d=>(t.openBlock(),t.createElementBlock("div",{key:d.id,class:t.normalizeClass(["tag-chip",{active:m.value===d.id}]),style:t.normalizeStyle({backgroundColor:d.color,borderColor:d.color}),onClick:b=>N(d)},t.toDisplayString(d.name),15,ht))),128)),g.value.length===0?(t.openBlock(),t.createElementBlock("div",dt,"请在右侧创建标签")):t.createCommentVNode("",!0)])])])),t.createElementVNode("div",{class:"canvas-wrapper",ref_key:"canvasWrapper",ref:a},[t.createElementVNode("canvas",{ref_key:"canvasRef",ref:i},null,512)],512),y.batchImages&&y.batchImages.length>0?(t.openBlock(),t.createElementBlock("div",gt,[t.createElementVNode("button",{onClick:le,disabled:f.value<=0},[t.createVNode(C,{name:"back"}),h[8]||(h[8]=t.createTextVNode(" 上一张 ",-1))],8,mt),t.createElementVNode("span",null,t.toDisplayString(f.value+1)+" / "+t.toDisplayString(y.batchImages.length),1),t.createElementVNode("button",{onClick:re,disabled:f.value>=y.batchImages.length-1},[h[9]||(h[9]=t.createTextVNode(" 下一张 ",-1)),t.createVNode(C,{name:"right"})],8,ft)])):t.createCommentVNode("",!0)]),y.readOnly?t.createCommentVNode("",!0):(t.openBlock(),t.createElementBlock("div",yt,[t.createElementVNode("div",{class:"sidebar-header"},[h[10]||(h[10]=t.createElementVNode("h3",null,"标签管理",-1)),t.createElementVNode("button",{class:"add-btn",onClick:ee},"添加标签")]),t.createElementVNode("div",pt,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(g.value,d=>(t.openBlock(),t.createElementBlock("div",{key:d.id,class:"label-item"},[t.createElementVNode("div",vt,[t.createElementVNode("label",{class:"color-wrapper",style:t.normalizeStyle({backgroundColor:d.color})},[t.withDirectives(t.createElementVNode("input",{type:"color","onUpdate:modelValue":b=>d.color=b,onChange:b=>ie(d),style:{visibility:"hidden",width:"0",height:"0"}},null,40,xt),[[t.vModelText,d.color]])],4),t.createElementVNode("span",{class:"label-name",title:d.name},t.toDisplayString(d.name),9,ut),t.createElementVNode("span",{class:"action-icon eye",onClick:b=>oe(d)},[d.visible?(t.openBlock(),t.createBlock(C,{key:0,name:"view"})):(t.openBlock(),t.createBlock(C,{key:1,name:"hide"}))],8,bt),t.createElementVNode("div",wt,[h[11]||(h[11]=t.createElementVNode("span",{class:"dots"},"•••",-1)),t.createElementVNode("span",{class:"delete-btn",onClick:b=>ae(d.id),title:"删除"},[t.createVNode(C,{name:"delete"})],8,Ct)])])]))),128))])])),p.value?(t.openBlock(),t.createElementBlock("div",kt,[t.createElementVNode("div",_t,[h[14]||(h[14]=t.createElementVNode("h3",null,"新增标签",-1)),t.createElementVNode("div",At,[h[12]||(h[12]=t.createElementVNode("label",null,"名称",-1)),t.withDirectives(t.createElementVNode("input",{"onUpdate:modelValue":h[2]||(h[2]=d=>v.value.name=d),placeholder:"请输入标签名称",class:"modal-input"},null,512),[[t.vModelText,v.value.name]])]),t.createElementVNode("div",Et,[h[13]||(h[13]=t.createElementVNode("label",null,"颜色",-1)),t.createElementVNode("div",Vt,[t.withDirectives(t.createElementVNode("input",{type:"color","onUpdate:modelValue":h[3]||(h[3]=d=>v.value.color=d),class:"modal-color-picker"},null,512),[[t.vModelText,v.value.color]]),t.createElementVNode("span",null,t.toDisplayString(v.value.color),1)])]),t.createElementVNode("div",{class:"modal-actions"},[t.createElementVNode("button",{onClick:D,class:"cancel-btn"},"取消"),t.createElementVNode("button",{onClick:ne,class:"confirm-btn"},"确认")])])])):t.createCommentVNode("",!0)],2))}}),[["__scopeId","data-v-fe1b36c0"]]),St={class:"thumbnail-wrapper",ref:"wrapper"},Nt=["src","alt"],Bt=["viewBox"],It=["x","y","width","height","stroke"],zt=["points","stroke"],Mt=["x","y","fill"],Ht={key:1,class:"loading-placeholder"},Lt=B(t.defineComponent({__name:"AnnotationThumbnail",props:{src:{},annotations:{},alt:{},labels:{}},setup(y){const e=y,s=t.ref(null),n=t.ref(!1),l=t.ref(0),i=t.ref(0),a=()=>{s.value&&(l.value=s.value.naturalWidth,i.value=s.value.naturalHeight,n.value=!0)},o=m=>{var p;if((p=m.style)!=null&&p.strokeColor)return m.style.strokeColor;if(e.labels){const v=e.labels.find(u=>u.name===m.label);if(v)return v.color}return"#FF0000"},c=m=>{const p=m.coordinates,v=Math.min(p.x1,p.x2),u=Math.min(p.y1,p.y2),k=Math.abs(p.x1-p.x2),_=Math.abs(p.y1-p.y2);return{x:v,y:u,width:k,height:_}},f=m=>m.coordinates.points.map(v=>`${v.x},${v.y}`).join(" "),g=m=>{if(m.type==="rectangle"){const p=c(m);return{x:p.x,y:p.y-5}}else if(m.type==="polygon"){const p=m.coordinates.points;if(p.length>0)return{x:p[0].x,y:p[0].y-5}}return{x:0,y:0}};return(m,p)=>(t.openBlock(),t.createElementBlock("div",St,[t.createElementVNode("img",{ref_key:"img",ref:s,src:y.src,class:"thumbnail-image",onLoad:a,alt:y.alt},null,40,Nt),n.value?(t.openBlock(),t.createElementBlock("svg",{key:0,class:"annotation-overlay",viewBox:`0 0 ${l.value} ${i.value}`,preserveAspectRatio:"none"},[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(y.annotations,v=>(t.openBlock(),t.createElementBlock(t.Fragment,{key:v.id},[v.type==="rectangle"?(t.openBlock(),t.createElementBlock("rect",{key:0,x:c(v).x,y:c(v).y,width:c(v).width,height:c(v).height,stroke:o(v),"stroke-width":"2",fill:"transparent"},null,8,It)):t.createCommentVNode("",!0),v.type==="polygon"?(t.openBlock(),t.createElementBlock("polygon",{key:1,points:f(v),stroke:o(v),"stroke-width":"2",fill:"transparent"},null,8,zt)):t.createCommentVNode("",!0),v.label?(t.openBlock(),t.createElementBlock("text",{key:2,x:g(v).x,y:g(v).y,fill:o(v),"font-size":"14","font-weight":"bold",class:"anno-label"},t.toDisplayString(v.label),9,Mt)):t.createCommentVNode("",!0)],64))),128))],8,Bt)):(t.openBlock(),t.createElementBlock("div",Ht,"Loading..."))],512))}}),[["__scopeId","data-v-78bcbe0c"]]),Tt={class:"batch-annotator"},Dt={key:0,class:"gallery-view"},Pt={class:"gallery-header"},$t={class:"label-summary"},Ft={class:"gallery-grid"},Ut=["onClick"],Rt={class:"thumbnail-wrapper"},Ot={class:"img-meta"},Jt={class:"img-index"},Wt={class:"anno-count"},jt={class:"bottom-bar"},Xt={key:1,class:"editor-view"},Yt={class:"editor-header"},qt={class:"header-left"},Kt={class:"editor-title"},Gt={class:"editor-content"},T=B(t.defineComponent({__name:"BatchAnnotator",props:{images:{},labels:{}},emits:["export","update:images"],setup(y,{emit:e}){const s=y,n=e,l=t.ref("gallery"),i=t.ref([]),a=t.ref(0),o=t.ref(null);t.watch(()=>s.images,u=>{i.value=JSON.parse(JSON.stringify(u))},{immediate:!0,deep:!0});const c=u=>{a.value=u,l.value="editor",t.nextTick(()=>{o.value&&o.value.jumpTo&&o.value.jumpTo(u)})},f=()=>{if(o.value&&o.value.getCurrentAnnotation){const u=o.value.getCurrentAnnotation();i.value[a.value]&&(i.value[a.value].annotations=u.annotations)}l.value="gallery"},g=()=>{n("export",i.value)},m=u=>{a.value=u.currentIndex,i.value[u.currentIndex]&&(i.value[u.currentIndex].annotations=u.currentAnnotations)},p=u=>{if(o.value&&o.value.getCurrentAnnotation){const k=o.value.getCurrentAnnotation();i.value[a.value]&&(i.value[a.value].annotations=k.annotations,n("update:images",i.value))}},v=u=>{};return(u,k)=>(t.openBlock(),t.createElementBlock("div",Tt,[l.value==="gallery"?(t.openBlock(),t.createElementBlock("div",Dt,[t.createElementVNode("div",Pt,[t.createElementVNode("h3",null,"批量查看与标注 ("+t.toDisplayString(i.value.length)+" 张)",1),t.createElementVNode("div",$t,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(y.labels,_=>(t.openBlock(),t.createElementBlock("span",{key:_.id,class:"label-badge",style:t.normalizeStyle({backgroundColor:_.color})},t.toDisplayString(_.name),5))),128))])]),t.createElementVNode("div",Ft,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(i.value,(_,V)=>(t.openBlock(),t.createElementBlock("div",{key:V,class:"gallery-item",onClick:S=>c(V)},[t.createElementVNode("div",Rt,[t.createVNode(Lt,{src:_.imageUrl,annotations:_.annotations||[],labels:y.labels},null,8,["src","annotations","labels"])]),t.createElementVNode("div",Ot,[t.createElementVNode("span",Jt,"#"+t.toDisplayString(V+1),1),t.createElementVNode("span",Wt,t.toDisplayString((_.annotations||[]).length)+" 标注",1)])],8,Ut))),128))]),t.createElementVNode("div",jt,[t.createElementVNode("button",{class:"action-btn primary",onClick:k[0]||(k[0]=_=>c(0))},[t.createVNode(C,{name:"edit"}),k[1]||(k[1]=t.createTextVNode(" 手动标注 ",-1))]),t.createElementVNode("button",{class:"action-btn success",onClick:g},[t.createVNode(C,{name:"download"}),k[2]||(k[2]=t.createTextVNode(" 导出 ",-1))])])])):(t.openBlock(),t.createElementBlock("div",Xt,[t.createElementVNode("div",Yt,[t.createElementVNode("div",qt,[t.createElementVNode("button",{class:"back-btn",onClick:f},[t.createVNode(C,{name:"back"}),k[3]||(k[3]=t.createTextVNode(" 返回列表 ",-1))]),t.createElementVNode("span",Kt,"正在标注: "+t.toDisplayString(a.value+1)+" / "+t.toDisplayString(i.value.length),1)])]),t.createElementVNode("div",Gt,[t.createVNode(L,{ref_key:"annotatorRef",ref:o,batchImages:i.value,labels:y.labels,annotationTypes:["rectangle","polygon","point","rotatedRect"],onBatchChange:m,onAnnotationChange:p,onLabelChange:v},null,8,["batchImages","labels"])])]))]))}}),[["__scopeId","data-v-87f3e002"]]);w.BatchAnnotator=T,w.ImageAnnotator=L,w.default=T,Object.defineProperties(w,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "luo-image-annotator",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "A simple image annotation component for Vue 3",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "vite",
|
|
@@ -24,9 +24,7 @@
|
|
|
24
24
|
"./style.css": "./dist/luo-image-annotator.css"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"vue": "^3.2.0"
|
|
28
|
-
"element-plus": "^2.0.0",
|
|
29
|
-
"@element-plus/icons-vue": "^2.0.0"
|
|
27
|
+
"vue": "^3.2.0"
|
|
30
28
|
},
|
|
31
29
|
"author": "Luo Luo",
|
|
32
30
|
"license": "MIT",
|
|
@@ -36,7 +34,6 @@
|
|
|
36
34
|
"canvas",
|
|
37
35
|
"typescript"
|
|
38
36
|
],
|
|
39
|
-
"dependencies": {},
|
|
40
37
|
"devDependencies": {
|
|
41
38
|
"@types/node": "^25.4.0",
|
|
42
39
|
"@vitejs/plugin-vue": "^5.2.4",
|