luo-image-annotator 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,33 +1,33 @@
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
1
+ (function(I,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],t):(I=typeof globalThis<"u"?globalThis:I||self,t(I.VueImageAnnotator={},I.Vue))})(this,(function(I,t){"use strict";var en=Object.defineProperty;var nn=(I,t,V)=>t in I?en(I,t,{enumerable:!0,configurable:!0,writable:!0,value:V}):I[t]=V;var k=(I,t,V)=>nn(I,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)),G=(p,e)=>{let i=!1;for(let s=0,c=e.length-1;s<e.length;c=s++){const a=e[s].x,h=e[s].y,l=e[c].x,g=e[c].y;h>p.y!=g>p.y&&p.x<(l-a)*(p.y-h)/(g-h)+a&&(i=!i)}return i},R=(p,e,i)=>{const s=i*(Math.PI/180),c=Math.cos(s),a=Math.sin(s),h=p.x-e.x,l=p.y-e.y;return{x:e.x+(h*c-l*a),y:e.y+(h*a+l*c)}};class Q{constructor(e){k(this,"canvas");k(this,"ctx");k(this,"img");k(this,"annotations",[]);k(this,"currentTool",null);k(this,"interactionMode","none");k(this,"activeAnnotation",null);k(this,"hoverAnnotation",null);k(this,"isDrawing",!1);k(this,"isDragging",!1);k(this,"isPanning",!1);k(this,"panStartPoint",null);k(this,"dragStartPoint",null);k(this,"dragStartAnnotation",null);k(this,"lastMouseMovePoint",null);k(this,"isHoveringStartPoint",!1);k(this,"currentLabelColor","#FF4081");k(this,"visibleLabels",new Set);k(this,"selectedHandleIndex",-1);k(this,"hoverHandleIndex",-1);k(this,"scale",1);k(this,"offset",{x:0,y:0});k(this,"listeners",{});k(this,"imageUrl","");this.canvas=e;const i=e.getContext("2d");if(!i)throw new Error("Could not get 2d context");this.ctx=i,this.img=new Image,this.img.crossOrigin="Anonymous",this.img.onload=()=>{this.fitImageToCanvas(),this.render()},this.bindEvents()}on(e,i){this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].push(i)}emit(e,i){this.listeners[e]&&this.listeners[e].forEach(s=>s(i))}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.interactionMode="pan",this.currentTool=null,this.isPanning=!1,this.canvas.style.cursor="grab"):e==="select"?(this.interactionMode="select",this.currentTool=null,this.canvas.style.cursor="default"):e?(this.interactionMode="draw",this.currentTool=e,this.canvas.style.cursor="crosshair"):(this.interactionMode="none",this.currentTool=null,this.canvas.style.cursor="default"),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 s=e>0?this.scale*1.1:this.scale/1.1;if(s<.1||s>10)return;const c=this.canvas.width/2,a=this.canvas.height/2,h=this.toImageCoords(c,a);this.scale=s,this.offset.x=c-h.x*this.scale,this.offset.y=a-h.y*this.scale,this.render()}resize(){this.fitImageToCanvas(),this.render()}toImageCoords(e,i){return{x:(e-this.offset.x)/this.scale,y:(i-this.offset.y)/this.scale}}toScreenCoords(e,i){return{x:e*this.scale+this.offset.x,y:i*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 i=this.canvas.width/this.img.width,s=this.canvas.height/this.img.height;this.scale=Math.min(i,s),this.offset.x=(this.canvas.width-this.img.width*this.scale)/2,this.offset.y=(this.canvas.height-this.img.height*this.scale)/2}}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){this.interactionMode==="select"&&(e.key==="Delete"||e.key==="Backspace")&&this.activeAnnotation&&this.deleteAnnotation(this.activeAnnotation.id)}deleteAnnotation(e){const i=this.annotations.findIndex(s=>s.id===e);if(i>-1){const s=this.annotations[i];this.annotations.splice(i,1),this.activeAnnotation=null,this.emit("annotationChange",{action:"delete",changedItem:s,imageUrl:this.imageUrl}),this.render()}}handleMouseDown(e){const i=this.canvas.getBoundingClientRect(),s=e.clientX-i.left,c=e.clientY-i.top,a=this.toImageCoords(s,c);if(this.canvas.style.cursor==="grab"||this.canvas.style.cursor==="grabbing"){this.isPanning=!0,this.panStartPoint={x:s,y:c},this.canvas.style.cursor="grabbing";return}if(this.interactionMode==="select"&&this.activeAnnotation){const g=this.getHitHandle(s,c,this.activeAnnotation);if(g!==-100){this.isDragging=!0,this.dragStartPoint=a,this.selectedHandleIndex=g,this.dragStartAnnotation=JSON.parse(JSON.stringify(this.activeAnnotation));return}}const h=this.interactionMode==="select"?this.getHitCategory(s,c):null;if(h){this.activeAnnotation=h,this.isDragging=!1,this.selectedHandleIndex=-1,this.emit("annotationChange",{action:"select",changedItem:h,imageUrl:this.imageUrl}),this.render();return}const l=this.getHitAnnotation(a);if(this.interactionMode==="select"){if(l){if(!(this.visibleLabels.size>0&&!this.visibleLabels.has(l.label))){this.activeAnnotation=l,this.isDragging=!0,this.dragStartPoint=a,this.selectedHandleIndex=-1,this.dragStartAnnotation=JSON.parse(JSON.stringify(l)),this.emit("annotationChange",{action:"select",changedItem:l,imageUrl:this.imageUrl}),this.render();return}}else this.activeAnnotation=null,this.emit("annotationChange",{action:"select",changedItem:void 0,imageUrl:this.imageUrl}),this.render();return}if(this.interactionMode==="draw"){if(this.isDrawing&&this.currentTool==="polygon"&&this.activeAnnotation){const g=this.activeAnnotation.coordinates;if(g.points.length>2&&V(a,g.points[0])<20/this.scale){this.finishDrawing();return}this.startDrawing(a);return}if(this.currentTool){if(this.currentTool==="polygon"&&!this.isDrawing){this.startDrawing(a);return}this.startDrawing(a)}return}this.activeAnnotation=null,this.render()}handleMouseMove(e){const i=this.canvas.getBoundingClientRect(),s=e.clientX-i.left,c=e.clientY-i.top,a=this.toImageCoords(s,c);if(this.isPanning&&this.panStartPoint){const h=s-this.panStartPoint.x,l=c-this.panStartPoint.y;this.offset.x+=h,this.offset.y+=l,this.panStartPoint={x:s,y:c},this.render();return}if(this.lastMouseMovePoint=a,this.isDrawing){if(this.currentTool==="polygon"&&this.activeAnnotation){const h=this.activeAnnotation.coordinates;if(h.points.length>2){const l=h.points[0],g=V(a,l);this.isHoveringStartPoint=g<20/this.scale}else this.isHoveringStartPoint=!1}this.updateDrawing(a)}else this.isDragging&&this.activeAnnotation&&this.dragStartPoint?this.updateDragging(a):this.checkHover(s,c,a);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,i){if(!e.startsWith("#"))return e;const s=parseInt(e.slice(1,3),16),c=parseInt(e.slice(3,5),16),a=parseInt(e.slice(5,7),16);return`rgba(${s}, ${c}, ${a}, ${i})`}startDrawing(e){if(!this.currentTool)return;const i=Date.now().toString();if(this.hexToRgba(this.currentLabelColor,.2),this.currentLabelColor,this.currentTool==="rectangle")this.isDrawing=!0,this.dragStartPoint=e,this.activeAnnotation={id:i,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 s={id:i,type:"point",label:"",coordinates:{points:[e]},style:{strokeColor:this.currentLabelColor}};this.annotations.push(s),this.emit("annotationChange",{action:"add",changedItem:s,imageUrl:this.imageUrl}),this.activeAnnotation=s}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:i,type:"polygon",label:"",coordinates:{points:[e]},style:{strokeColor:this.currentLabelColor}});else if(this.currentTool==="category"){const s={id:i,type:"category",label:"",coordinates:null,style:{strokeColor:this.currentLabelColor}};this.annotations.push(s),this.emit("annotationChange",{action:"add",changedItem:s,imageUrl:this.imageUrl}),this.activeAnnotation=s}else this.currentTool==="rotatedRect"&&(this.isDrawing=!0,this.dragStartPoint=e,this.activeAnnotation={id:i,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 i=this.activeAnnotation.coordinates;i.x2=e.x,i.y2=e.y}else if(this.activeAnnotation.type==="rotatedRect"&&this.dragStartPoint){const i=this.activeAnnotation.coordinates,s=Math.abs(e.x-this.dragStartPoint.x),c=Math.abs(e.y-this.dragStartPoint.y);i.width=s*2,i.height=c*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 i=Math.min(e.x1,e.x2),s=Math.max(e.x1,e.x2),c=Math.min(e.y1,e.y2),a=Math.max(e.y1,e.y2);e.x1=i,e.x2=s,e.y1=c,e.y2=a,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 i=e.x-this.dragStartPoint.x,s=e.y-this.dragStartPoint.y;this.selectedHandleIndex===-1?this.moveAnnotation(this.activeAnnotation,this.dragStartAnnotation,i,s):this.resizeAnnotation(this.activeAnnotation,this.dragStartAnnotation,this.selectedHandleIndex,e)}moveAnnotation(e,i,s,c){if(e.type==="rectangle"){const a=i.coordinates,h=e.coordinates;h.x1=a.x1+s,h.x2=a.x2+s,h.y1=a.y1+c,h.y2=a.y2+c}else if(e.type==="point"){const a=i.coordinates,h=e.coordinates;h.points=a.points.map(l=>({x:l.x+s,y:l.y+c}))}else if(e.type==="rotatedRect"){const a=i.coordinates,h=e.coordinates;h.x=a.x+s,h.y=a.y+c}else if(e.type==="polygon"){const a=i.coordinates,h=e.coordinates;h.points=a.points.map(l=>({x:l.x+s,y:l.y+c}))}}resizeAnnotation(e,i,s,c){if(e.type==="rectangle"){const a=e.coordinates;s===0&&(a.x1=c.x,a.y1=c.y),s===1&&(a.x2=c.x,a.y1=c.y),s===2&&(a.x2=c.x,a.y2=c.y),s===3&&(a.x1=c.x,a.y2=c.y)}else if(e.type==="polygon"){const a=e.coordinates;s>=0&&s<a.points.length&&(a.points[s]=c)}else if(e.type==="point"){const a=e.coordinates;s>=0&&s<a.points.length&&(a.points[s]=c)}else if(e.type==="rotatedRect"){const a=e.coordinates;if(s===-2){const h=a.x,l=a.y,g=c.x-h,y=c.y-l;let v=Math.atan2(y,g)*180/Math.PI;v+=90,a.angle=v}else{const h=a.angle*Math.PI/180,l=Math.cos(-h),g=Math.sin(-h),y=c.x-a.x,v=c.y-a.y,m=y*l-v*g,u=y*g+v*l;(s===0||s===3)&&(a.width/2,a.width=Math.abs(m)*2),(s===1||s===2)&&(a.width=Math.abs(m)*2),(s===0||s===1)&&(a.height=Math.abs(u)*2),(s===2||s===3)&&(a.height=Math.abs(u)*2)}}}getHitAnnotation(e){for(let i=this.annotations.length-1;i>=0;i--){const s=this.annotations[i];if(this.isPointInAnnotation(e,s))return s}return null}isPointInAnnotation(e,i){if(i.type==="rectangle"){const s=i.coordinates;return e.x>=s.x1&&e.x<=s.x2&&e.y>=s.y1&&e.y<=s.y2}else if(i.type==="polygon"){const s=i.coordinates;return G(e,s.points)}else if(i.type==="rotatedRect"){const s=i.coordinates,c=R(e,{x:s.x,y:s.y},-s.angle),a=s.width/2,h=s.height/2;return c.x>=s.x-a&&c.x<=s.x+a&&c.y>=s.y-h&&c.y<=s.y+h}else if(i.type==="point")return i.coordinates.points.some(c=>V(e,c)<10/this.scale);return!1}getHitHandle(e,i,s){const c=this.getAnnotationHandles(s),a=6;for(let h=0;h<c.length;h++){const l=c[h],g=this.toScreenCoords(l.x,l.y);if(Math.abs(e-g.x)<a&&Math.abs(i-g.y)<a)return s.type==="rotatedRect"&&h===4?-2:h}return-100}getAnnotationHandles(e){if(e.type==="rectangle"){const i=e.coordinates;return[{x:i.x1,y:i.y1},{x:i.x2,y:i.y1},{x:i.x2,y:i.y2},{x:i.x1,y:i.y2}]}else{if(e.type==="polygon")return e.coordinates.points;if(e.type==="point")return e.coordinates.points;if(e.type==="rotatedRect"){const i=e.coordinates,s={x:i.x,y:i.y},c=i.width/2,a=i.height/2,h={x:i.x-c,y:i.y-a},l={x:i.x+c,y:i.y-a},g={x:i.x+c,y:i.y+a},y={x:i.x-c,y:i.y+a},v={x:i.x,y:i.y-a-20/this.scale};return[h,l,g,y,v].map(m=>R(m,s,i.angle))}}return[]}checkHover(e,i,s){const c=this.getHitCategory(e,i);if(c){this.canvas.style.cursor="pointer",this.hoverAnnotation=c;return}if(this.activeAnnotation&&this.getHitHandle(e,i,this.activeAnnotation)!==-100){this.canvas.style.cursor="pointer";return}const a=this.getHitAnnotation(s);a?(this.canvas.style.cursor="move",this.hoverAnnotation=a):(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(g=>g.type==="category");if(e.length===0)return;this.ctx.save(),this.ctx.font="14px sans-serif",this.ctx.textBaseline="top";let i=10;const s=10,c=8,a=4,h=24,l=8;e.forEach(g=>{const y=g.label||"Unlabeled",v=this.ctx.measureText(y).width+c*2,m=this.activeAnnotation===g,u=this.hoverAnnotation===g;this.ctx.fillStyle=m?"#E3F2FD":u?"#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(i,s,v,h),this.ctx.fill(),this.ctx.stroke(),this.ctx.fillStyle=m?"#1976D2":"#333",this.ctx.fillText(y,i+c,s+a),i+=v+l}),this.ctx.restore()}getHitCategory(e,i){const s=this.annotations.filter(v=>v.type==="category");if(s.length===0)return null;this.ctx.save(),this.ctx.font="14px sans-serif";let c=10;const a=10,h=8,l=24,g=8;let y=null;for(const v of s){const m=v.label||"Unlabeled",u=this.ctx.measureText(m).width+h*2;if(e>=c&&e<=c+u&&i>=a&&i<=a+l){y=v;break}c+=u+g}return this.ctx.restore(),y}drawItem(e,i){var a;if(this.visibleLabels.size>0&&!this.visibleLabels.has(e.label)&&!i)return;this.ctx.save();const s=((a=e.style)==null?void 0:a.strokeColor)||"#FF4081",c=i?"#00E5FF":s;if(this.ctx.strokeStyle=c,this.ctx.lineWidth=2,i?this.ctx.fillStyle="rgba(0, 229, 255, 0.2)":this.ctx.fillStyle=this.hexToRgba(s,.2),e.type==="rectangle"){const h=e.coordinates,l=this.toScreenCoords(h.x1,h.y1),g=this.toScreenCoords(h.x2,h.y2),y=Math.min(l.x,g.x),v=Math.min(l.y,g.y),m=Math.abs(l.x-g.x),u=Math.abs(l.y-g.y);this.ctx.strokeRect(y,v,m,u),this.ctx.fillStyle=i?"rgba(0, 229, 255, 0.2)":"rgba(255, 64, 129, 0.2)",this.ctx.fillRect(y,v,m,u),i&&this.drawHandles(this.getAnnotationHandles(e))}else if(e.type==="polygon"){const h=e.coordinates;if(h.points.length===0){this.ctx.restore();return}this.ctx.beginPath();const l=this.toScreenCoords(h.points[0].x,h.points[0].y);this.ctx.moveTo(l.x,l.y);for(let g=1;g<h.points.length;g++){const y=this.toScreenCoords(h.points[g].x,h.points[g].y);this.ctx.lineTo(y.x,y.y)}if(!this.isDrawing||e!==this.activeAnnotation)this.ctx.closePath();else if(this.lastMouseMovePoint){let g=this.lastMouseMovePoint;if(this.isHoveringStartPoint&&h.points.length>0){g=h.points[0];const v=this.toScreenCoords(h.points[0].x,h.points[0].y);this.ctx.save(),this.ctx.beginPath(),this.ctx.arc(v.x,v.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 y=this.toScreenCoords(g.x,g.y);this.ctx.lineTo(y.x,y.y)}this.ctx.stroke(),this.ctx.fillStyle=i?"rgba(0, 229, 255, 0.2)":"rgba(255, 64, 129, 0.2)",this.ctx.fill(),i&&this.drawHandles(this.getAnnotationHandles(e))}else if(e.type==="rotatedRect"){const h=e.coordinates;this.ctx.translate(this.toScreenCoords(h.x,h.y).x,this.toScreenCoords(h.x,h.y).y),this.ctx.rotate(h.angle*Math.PI/180);const l=h.width*this.scale,g=h.height*this.scale;this.ctx.strokeRect(-l/2,-g/2,l,g),this.ctx.fillStyle=i?"rgba(0, 229, 255, 0.2)":"rgba(255, 64, 129, 0.2)",this.ctx.fillRect(-l/2,-g/2,l,g),this.ctx.rotate(-h.angle*Math.PI/180),this.ctx.translate(-this.toScreenCoords(h.x,h.y).x,-this.toScreenCoords(h.x,h.y).y),i&&this.drawHandles(this.getAnnotationHandles(e))}else e.type==="point"&&e.coordinates.points.forEach(l=>{const g=this.toScreenCoords(l.x,l.y);this.ctx.beginPath(),this.ctx.arc(g.x,g.y,5,0,Math.PI*2),this.ctx.fillStyle=i?"#00E5FF":s,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(i=>{const s=this.toScreenCoords(i.x,i.y);this.ctx.fillRect(s.x-4,s.y-4,8,8),this.ctx.strokeRect(s.x-4,s.y-4,8,8)})}}const tt=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
2
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
3
+ </svg>`,et=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
4
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
5
+ </svg>`,nt=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
6
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
7
+ </svg>`,st=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
8
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
9
+ </svg>`,ot=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
10
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
11
+ </svg>`,it=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
12
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
13
+ </svg>`,at=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
14
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
15
+ </svg>`,lt=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
16
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
17
+ </svg>`,rt=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
18
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
19
+ </svg>`,ct=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
20
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
21
+ </svg>`,ht=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
22
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
23
+ </svg>`,dt=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
24
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
25
+ </svg>`,gt=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
26
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
27
+ </svg>`,mt=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
28
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
29
+ </svg>`,ft=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
30
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
31
+ </svg>`,ut=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">\r
32
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"}})}));
33
+ </svg>`,yt=["innerHTML"],pt=t.defineComponent({__name:"SvgIcon",props:{name:{},size:{}},setup(p){const e=p,i=t.ref(""),s=Object.assign({"../assets/svg/aim.svg":tt,"../assets/svg/back.svg":et,"../assets/svg/connection.svg":nt,"../assets/svg/crop.svg":st,"../assets/svg/delete.svg":ot,"../assets/svg/download.svg":it,"../assets/svg/edit.svg":at,"../assets/svg/hide.svg":lt,"../assets/svg/pointer.svg":rt,"../assets/svg/price-tag.svg":ct,"../assets/svg/rank.svg":ht,"../assets/svg/refresh-right.svg":dt,"../assets/svg/right.svg":gt,"../assets/svg/view.svg":mt,"../assets/svg/zoom-in.svg":ft,"../assets/svg/zoom-out.svg":ut});return t.watchEffect(()=>{const c=`../assets/svg/${e.name}.svg`,a=s[c];a?i.value=a:(console.warn(`Icon ${e.name} not found at path ${c}`),i.value="")}),(c,a)=>(t.openBlock(),t.createElementBlock("i",{class:t.normalizeClass(["svg-icon",[p.size?`size-${p.size}`:""]]),innerHTML:i.value},null,10,yt))}}),$=(p,e)=>{const i=p.__vccOpts||p;for(const[s,c]of e)i[s]=c;return i},E=$(pt,[["__scopeId","data-v-3928607b"]]),vt={key:0,class:"image-list-sidebar"},bt={class:"image-list-title"},xt={class:"image-list-scroll"},wt=["onClick"],kt={class:"image-list-stage"},Ct=["src","alt"],_t={key:0,class:"thumb-overlay-layer"},At={key:1,class:"thumb-overlay-svg",viewBox:"0 0 100 100",preserveAspectRatio:"none"},It=["points"],Et={class:"image-list-text"},St={key:1,class:"left-sidebar"},Vt=["onClick","title"],Bt={class:"center-area"},Nt={key:0,class:"top-bar"},zt={class:"label-selector"},Mt={class:"tags-row"},$t=["onClick"],Tt={key:0,class:"no-labels"},Pt={key:1,class:"batch-nav"},Lt=["disabled"],Dt=["disabled"],Ht={key:2,class:"right-sidebar"},Rt={class:"label-list"},Ut={class:"label-row"},Ft=["onUpdate:modelValue","onChange"],Ot=["title"],Wt=["onClick"],jt={class:"action-icon more-actions"},Jt=["onClick"],Xt={key:3,class:"modal-overlay"},Yt={class:"modal-content"},qt={class:"form-group"},Kt={class:"form-group"},Zt={class:"color-input-wrapper"},U=$(t.defineComponent({__name:"ImageAnnotator",props:{annotationTypes:{default:()=>["rectangle","polygon","point","rotatedRect"]},batchImages:{default:()=>[]},labels:{default:()=>[]},defaultActiveType:{},theme:{default:"light"},readOnly:{type:Boolean,default:!1},image:{},predictionCandidates:{},session:{},requestId:{},minZoom:{},maxZoom:{}},emits:["annotationChange","batchChange","labelChange","ready","error","tool:change","viewport:change","annotation:add","annotation:update","annotation:delete","annotation:select","prediction:loaded","prediction:apply","prediction:reject"],setup(p,{expose:e,emit:i}){const s=p,c=i,a=t.ref(null),h=t.ref(null),l=t.ref(null),g=t.ref(null),y=t.ref(0),v=t.ref(""),m=t.ref([]),u=t.ref(""),x=t.ref(!1),w=t.ref({name:"",color:"#FF0000"}),_=t.ref("none"),A=t.ref([]),S=t.ref({}),O=t.computed(()=>g.value==="select"&&!!v.value),W=n=>{if(!n||S.value[n])return;const o=new Image;o.onload=()=>{const r=o.naturalWidth||1,d=o.naturalHeight||1;S.value={...S.value,[n]:{width:r,height:d}}},o.src=n},j=()=>{s.batchImages.forEach(n=>{W(n.imageUrl)})},B=()=>{var r,d,f,b;const n=s.batchImages[y.value],o=(n==null?void 0:n.imageUrl)||((r=s.image)==null?void 0:r.url);return{eventId:`${Date.now()}-${Math.random().toString(36).slice(2,10)}`,timestamp:Date.now(),requestId:s.requestId,taskId:(d=s.session)==null?void 0:d.taskId,imageId:((f=s.image)==null?void 0:f.id)||o,operator:(b=s.session)==null?void 0:b.userId}},ke=n=>{var d;const o=n==null?void 0:n.action;if(!o)return;const r={meta:B(),action:o,current:n==null?void 0:n.changedItem,source:(d=n==null?void 0:n.changedItem)!=null&&d.predictionId?"prediction":"manual"};o==="add"&&c("annotation:add",r),o==="update"&&c("annotation:update",r),o==="delete"&&c("annotation:delete",r),o==="select"&&c("annotation:select",r)},Ce=t.computed(()=>s.annotationTypes.filter(n=>n!=="category")),_e=n=>({rectangle:"crop",polygon:"connection",point:"aim",rotatedRect:"refresh-right",category:"price-tag"})[n]||n,Ae=n=>({rectangle:"矩形框",polygon:"多边形",point:"关键点",rotatedRect:"旋转矩形",category:"分类标签"})[n]||n;t.onMounted(()=>{if(j(),a.value){l.value=new Q(a.value),l.value.on("annotationChange",o=>{var r,d;if(o.action==="add"&&o.changedItem){const f=m.value.find(b=>b.id===u.value);f&&(o.changedItem.label=f.name,o.changedItem.labelId=f.id)}o.action==="select"?v.value=((r=o.changedItem)==null?void 0:r.id)||"":o.action==="delete"&&((d=o.changedItem)==null?void 0:d.id)===v.value&&(v.value=""),c("annotationChange",o),ke(o)}),N(),T();const n=new ResizeObserver(()=>{var o;(o=l.value)==null||o.resize()});h.value&&n.observe(h.value),s.defaultActiveType&&z(s.defaultActiveType),c("ready",{meta:B()})}});const T=()=>{if(!l.value)return;const n=m.value.find(r=>r.id===u.value);n&&l.value.setLabelStyle(n.color);const o=m.value.filter(r=>r.visible).map(r=>r.name);l.value.setVisibleLabels(o)},N=()=>{var n;if(l.value)if(v.value="",s.batchImages.length>0){const o=s.batchImages[y.value];l.value.loadImage(o.imageUrl),o.annotations?l.value.setAnnotations(o.annotations):l.value.setAnnotations([])}else(n=s.image)!=null&&n.url&&l.value.loadImage(s.image.url)},z=n=>{var o,r;if(g.value=n,v.value="",n!=="pan"&&n!=="select"&&m.value.length===0){alert("请先创建标签!");return}n==="pan"||n==="select"?(o=l.value)==null||o.setTool(n):(r=l.value)==null||r.setTool(n),c("tool:change",{meta:B(),tool:n})},Ie=()=>{var n;(n=l.value)!=null&&n.activeAnnotation&&l.value.deleteAnnotation(l.value.activeAnnotation.id)},J=()=>{l.value&&c("viewport:change",{meta:B(),scale:l.value.scale,offset:{...l.value.offset}})},Ee=()=>{var n;(n=l.value)==null||n.zoom(1),J()},Se=()=>{var n;(n=l.value)==null||n.zoom(-1),J()},Ve=()=>{w.value={name:"",color:"#2196F3"},x.value=!0},X=()=>{x.value=!1},Be=()=>{if(!w.value.name.trim()){alert("请输入标签名称");return}const o={id:Date.now().toString(),name:w.value.name,color:w.value.color,visible:!0};m.value.push(o),c("labelChange",m.value),m.value.length===1&&M(o),X()},M=n=>{var o;u.value=n.id,(o=l.value)==null||o.setLabelStyle(n.color)},Ne=(n,o)=>{if(!n.startsWith("#"))return n;let r=0,d=0,f=0;return n.length===4?(r=parseInt(n[1]+n[1],16),d=parseInt(n[2]+n[2],16),f=parseInt(n[3]+n[3],16)):n.length===7&&(r=parseInt(n.slice(1,3),16),d=parseInt(n.slice(3,5),16),f=parseInt(n.slice(5,7),16)),`rgba(${r}, ${d}, ${f}, ${o})`},ze=n=>{var o;if(n.id===u.value&&((o=l.value)==null||o.setLabelStyle(n.color)),l.value){const r=l.value.getAnnotations();let d=!1;r.forEach(f=>{f.label===n.name&&(f.style||(f.style={}),f.style.strokeColor=n.color,f.style.fillColor=Ne(n.color,.2),d=!0)}),d&&l.value.render()}c("labelChange",m.value)},Me=n=>{n.visible=!n.visible,T()},$e=n=>{const o=m.value.findIndex(r=>r.id===n);o>-1&&(m.value.splice(o,1),c("labelChange",m.value),u.value===n&&(u.value=m.value.length>0?m.value[0].id:"",u.value&&M(m.value[0])),T())};t.watch(()=>s.labels,n=>{const o=JSON.parse(JSON.stringify(n||[]));if(m.value=o,m.value.length>0)if(!u.value||!m.value.find(r=>r.id===u.value))M(m.value[0]);else{const r=m.value.find(d=>d.id===u.value);r&&M(r)}else u.value="";T()},{immediate:!0,deep:!0});const Te=()=>{y.value>0&&(D(),y.value--,N(),H())},Pe=()=>{y.value<s.batchImages.length-1&&(D(),y.value++,N(),H())},D=()=>{if(l.value){const n=l.value.getAnnotations();s.batchImages[y.value].annotations=n}},H=()=>{const n=s.batchImages[y.value];c("batchChange",{currentIndex:y.value,total:s.batchImages.length,currentImageUrl:n.imageUrl,currentAnnotations:n.annotations||[]})},Y=(n=[])=>{var f;if(!l.value)return;if(A.value=JSON.parse(JSON.stringify(n)),A.value.length===0){_.value="none";return}_.value="loaded";const r=(l.value.getAnnotations()||[]).filter(b=>!b.predictionId),d=A.value.map(b=>{const C=JSON.parse(JSON.stringify(b.annotation));return C.id=C.id||`pred-${b.id}`,C.predictionId=b.id,C.modelRunId=b.modelRunId||C.modelRunId,C.confidence=b.confidence??C.confidence,C.reviewStatus=C.reviewStatus||"draft",C});l.value.setAnnotations([...r,...d]),c("prediction:loaded",{meta:B(),modelRunId:(f=A.value[0])==null?void 0:f.modelRunId,candidates:A.value})},Le=(n,o)=>{var f;if(!l.value)return[];_.value="applying";const d=(l.value.getAnnotations()||[]).filter(b=>b.predictionId&&n.includes(b.predictionId));return d.forEach(b=>{b.reviewStatus="accepted"}),_.value="applied",c("prediction:apply",{meta:B(),modelRunId:(f=d[0])==null?void 0:f.modelRunId,candidateIds:n,threshold:o,acceptedAnnotations:d}),l.value.render(),d},De=(n,o)=>{var f;if(!l.value)return;const r=l.value.getAnnotations()||[],d=r.filter(b=>!(b.predictionId&&n.includes(b.predictionId)));l.value.setAnnotations(d),c("prediction:reject",{meta:B(),modelRunId:(f=r.find(b=>b.predictionId&&n.includes(b.predictionId)))==null?void 0:f.modelRunId,candidateIds:n,reason:o})},He=(n,o=[])=>{l.value&&(l.value.loadImage(n.url),l.value.setAnnotations(o))},Re=n=>{var o;(o=l.value)==null||o.setAnnotations(n)},q=()=>{var n;return((n=l.value)==null?void 0:n.getAnnotations())||[]},Ue=(n="json")=>{var r,d;const o=q();return{format:n,image:((r=s.batchImages[y.value])==null?void 0:r.imageUrl)||((d=s.image)==null?void 0:d.url)||"",annotations:o}},K=n=>{n>=0&&n<s.batchImages.length&&(D(),y.value=n,N(),H())},Fe=n=>{var o;return n===y.value&&l.value?l.value.getAnnotations()||[]:((o=s.batchImages[n])==null?void 0:o.annotations)||[]},Oe=n=>n.type==="rectangle",We=n=>n.type==="polygon",je=n=>n.type==="point",Je=n=>n.type==="rotatedRect",P=n=>{var r,d;const o=(r=m.value.find(f=>f.name===n.label))==null?void 0:r.color;return((d=n.style)==null?void 0:d.strokeColor)||o||"#409eff"},Z=n=>{const o=n.coordinates;return(o==null?void 0:o.points)||[]},L=n=>{const o=s.batchImages[n];if(o!=null&&o.width&&(o!=null&&o.height))return{width:o.width,height:o.height};const r=o!=null&&o.imageUrl?S.value[o.imageUrl]:void 0;return r||(o!=null&&o.imageUrl&&W(o.imageUrl),{width:1,height:1})},Xe=n=>{const o=s.batchImages[n];return o!=null&&o.width&&(o!=null&&o.height)?!0:o!=null&&o.imageUrl?!!S.value[o.imageUrl]:!1},Ye=(n,o)=>{const r=o.coordinates,d=L(n),f=P(o),b=Math.min(r.x1,r.x2),C=Math.min(r.y1,r.y2),Qe=Math.max(r.x1,r.x2),tn=Math.max(r.y1,r.y2);return{left:`${b/d.width*100}%`,top:`${C/d.height*100}%`,width:`${(Qe-b)/d.width*100}%`,height:`${(tn-C)/d.height*100}%`,borderColor:f,backgroundColor:`${f}22`}},qe=(n,o)=>{const r=L(n);return Z(o).map(d=>`${d.x/r.width*100},${d.y/r.height*100}`).join(" ")},Ke=n=>{const o=P(n);return{fill:`${o}33`,stroke:o,strokeWidth:"1.4"}},Ze=(n,o,r)=>{const d=L(n),f=P(r);return{left:`${o.x/d.width*100}%`,top:`${o.y/d.height*100}%`,backgroundColor:f}},Ge=(n,o)=>{const r=o.coordinates,d=L(n),f=P(o),b=Math.abs(r.width),C=Math.abs(r.height);return{left:`${(r.x-b/2)/d.width*100}%`,top:`${(r.y-C/2)/d.height*100}%`,width:`${b/d.width*100}%`,height:`${C/d.height*100}%`,transform:`rotate(${r.angle||0}deg)`,borderColor:f,backgroundColor:`${f}22`}};return e({jumpTo:K,setImage:He,setAnnotations:Re,getAnnotations:q,selectTool:z,loadPredictionCandidates:Y,applyPredictions:Le,rejectPredictions:De,exportAnnotations:Ue,getAllAnnotations:()=>{var n,o;return s.batchImages.length>0?s.batchImages:[{imageUrl:((n=s.image)==null?void 0:n.url)||"",annotations:((o=l.value)==null?void 0:o.getAnnotations())||[]}]},getCurrentAnnotation:()=>{var n,o,r;return{imageUrl:((n=s.batchImages[y.value])==null?void 0:n.imageUrl)||((o=s.image)==null?void 0:o.url)||"",annotations:((r=l.value)==null?void 0:r.getAnnotations())||[]}}}),t.watch(()=>{var n;return(n=s.image)==null?void 0:n.url},()=>{var n;s.batchImages.length===0&&((n=s.image)!=null&&n.url)&&N()}),t.watch(()=>s.predictionCandidates,n=>{n&&Y(n)},{immediate:!0,deep:!0}),t.watch(()=>s.batchImages.map(n=>`${n.imageUrl}:${n.width||""}x${n.height||""}`),()=>{j()},{immediate:!0}),(n,o)=>(t.openBlock(),t.createElementBlock("div",{class:t.normalizeClass(["annotation-container",p.theme])},[p.batchImages&&p.batchImages.length>0?(t.openBlock(),t.createElementBlock("div",vt,[t.createElementVNode("div",bt,"批量图片("+t.toDisplayString(p.batchImages.length)+")",1),t.createElementVNode("div",xt,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(p.batchImages,(r,d)=>(t.openBlock(),t.createElementBlock("button",{key:`${r.imageUrl}-${d}`,class:t.normalizeClass(["image-list-item",{active:d===y.value}]),onClick:f=>K(d)},[t.createElementVNode("div",kt,[t.createElementVNode("img",{src:r.imageUrl,alt:`第${d+1}张`,class:"image-list-thumb"},null,8,Ct),Xe(d)?(t.openBlock(),t.createElementBlock("div",_t,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(Fe(d),f=>(t.openBlock(),t.createElementBlock(t.Fragment,{key:f.id},[Oe(f)?(t.openBlock(),t.createElementBlock("div",{key:0,class:"thumb-overlay-rect",style:t.normalizeStyle(Ye(d,f))},null,4)):We(f)?(t.openBlock(),t.createElementBlock("svg",At,[t.createElementVNode("polygon",{points:qe(d,f),style:t.normalizeStyle(Ke(f))},null,12,It)])):je(f)?(t.openBlock(!0),t.createElementBlock(t.Fragment,{key:2},t.renderList(Z(f),(b,C)=>(t.openBlock(),t.createElementBlock("div",{key:`${f.id}-${C}`,class:"thumb-overlay-point",style:t.normalizeStyle(Ze(d,b,f))},null,4))),128)):Je(f)?(t.openBlock(),t.createElementBlock("div",{key:3,class:"thumb-overlay-rotated",style:t.normalizeStyle(Ge(d,f))},null,4)):t.createCommentVNode("",!0)],64))),128))])):t.createCommentVNode("",!0)]),t.createElementVNode("span",Et,"第 "+t.toDisplayString(d+1)+" 张",1)],10,wt))),128))])])):t.createCommentVNode("",!0),p.readOnly?t.createCommentVNode("",!0):(t.openBlock(),t.createElementBlock("div",St,[t.createElementVNode("div",{class:t.normalizeClass(["tool-btn",{active:g.value==="pan"}]),onClick:o[0]||(o[0]=r=>z("pan")),title:"拖动"},[t.createVNode(E,{name:"rank"})],2),t.createElementVNode("div",{class:t.normalizeClass(["tool-btn",{active:g.value==="select"}]),onClick:o[1]||(o[1]=r=>z("select")),title:"选择"},[t.createVNode(E,{name:"pointer"})],2),o[4]||(o[4]=t.createElementVNode("div",{class:"divider"},null,-1)),(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(Ce.value,r=>(t.openBlock(),t.createElementBlock("div",{key:r,class:t.normalizeClass(["tool-btn",{active:g.value===r}]),onClick:d=>z(r),title:Ae(r)},[t.createVNode(E,{name:_e(r)},null,8,["name"])],10,Vt))),128)),o[5]||(o[5]=t.createElementVNode("div",{class:"divider"},null,-1)),t.createElementVNode("div",{class:"tool-btn",onClick:Ee,title:"放大"},[t.createVNode(E,{name:"zoom-in"})]),t.createElementVNode("div",{class:"tool-btn",onClick:Se,title:"缩小"},[t.createVNode(E,{name:"zoom-out"})]),o[6]||(o[6]=t.createElementVNode("div",{class:"divider"},null,-1)),O.value?(t.openBlock(),t.createElementBlock("div",{key:0,class:"tool-btn",onClick:Ie,title:"删除选中"},[t.createVNode(E,{name:"delete"})])):t.createCommentVNode("",!0)])),t.createElementVNode("div",Bt,[p.readOnly?t.createCommentVNode("",!0):(t.openBlock(),t.createElementBlock("div",Nt,[t.createElementVNode("div",zt,[o[7]||(o[7]=t.createElementVNode("span",{class:"label-text"},"当前标签:",-1)),t.createElementVNode("div",Mt,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(m.value,r=>(t.openBlock(),t.createElementBlock("div",{key:r.id,class:t.normalizeClass(["tag-chip",{active:u.value===r.id}]),style:t.normalizeStyle({backgroundColor:r.color,borderColor:r.color}),onClick:d=>M(r)},t.toDisplayString(r.name),15,$t))),128)),m.value.length===0?(t.openBlock(),t.createElementBlock("div",Tt,"请在右侧创建标签")):t.createCommentVNode("",!0)])])])),t.createElementVNode("div",{class:"canvas-wrapper",ref_key:"canvasWrapper",ref:h},[t.createElementVNode("canvas",{ref_key:"canvasRef",ref:a},null,512)],512),p.batchImages&&p.batchImages.length>0?(t.openBlock(),t.createElementBlock("div",Pt,[t.createElementVNode("button",{onClick:Te,disabled:y.value<=0},[t.createVNode(E,{name:"back"}),o[8]||(o[8]=t.createTextVNode(" 上一张 ",-1))],8,Lt),t.createElementVNode("span",null,t.toDisplayString(y.value+1)+" / "+t.toDisplayString(p.batchImages.length),1),t.createElementVNode("button",{onClick:Pe,disabled:y.value>=p.batchImages.length-1},[o[9]||(o[9]=t.createTextVNode(" 下一张 ",-1)),t.createVNode(E,{name:"right"})],8,Dt)])):t.createCommentVNode("",!0)]),p.readOnly?t.createCommentVNode("",!0):(t.openBlock(),t.createElementBlock("div",Ht,[t.createElementVNode("div",{class:"sidebar-header"},[o[10]||(o[10]=t.createElementVNode("h3",null,"标签管理",-1)),t.createElementVNode("button",{class:"add-btn",onClick:Ve},"添加标签")]),t.createElementVNode("div",Rt,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(m.value,r=>(t.openBlock(),t.createElementBlock("div",{key:r.id,class:"label-item"},[t.createElementVNode("div",Ut,[t.createElementVNode("label",{class:"color-wrapper",style:t.normalizeStyle({backgroundColor:r.color})},[t.withDirectives(t.createElementVNode("input",{type:"color","onUpdate:modelValue":d=>r.color=d,onChange:d=>ze(r),style:{visibility:"hidden",width:"0",height:"0"}},null,40,Ft),[[t.vModelText,r.color]])],4),t.createElementVNode("span",{class:"label-name",title:r.name},t.toDisplayString(r.name),9,Ot),t.createElementVNode("span",{class:"action-icon eye",onClick:d=>Me(r)},[r.visible?(t.openBlock(),t.createBlock(E,{key:0,name:"view"})):(t.openBlock(),t.createBlock(E,{key:1,name:"hide"}))],8,Wt),t.createElementVNode("div",jt,[o[11]||(o[11]=t.createElementVNode("span",{class:"dots"},"•••",-1)),t.createElementVNode("span",{class:"delete-btn",onClick:d=>$e(r.id),title:"删除"},[t.createVNode(E,{name:"delete"})],8,Jt)])])]))),128))])])),x.value?(t.openBlock(),t.createElementBlock("div",Xt,[t.createElementVNode("div",Yt,[o[14]||(o[14]=t.createElementVNode("h3",null,"新增标签",-1)),t.createElementVNode("div",qt,[o[12]||(o[12]=t.createElementVNode("label",null,"名称",-1)),t.withDirectives(t.createElementVNode("input",{"onUpdate:modelValue":o[2]||(o[2]=r=>w.value.name=r),placeholder:"请输入标签名称",class:"modal-input"},null,512),[[t.vModelText,w.value.name]])]),t.createElementVNode("div",Kt,[o[13]||(o[13]=t.createElementVNode("label",null,"颜色",-1)),t.createElementVNode("div",Zt,[t.withDirectives(t.createElementVNode("input",{type:"color","onUpdate:modelValue":o[3]||(o[3]=r=>w.value.color=r),class:"modal-color-picker"},null,512),[[t.vModelText,w.value.color]]),t.createElementVNode("span",null,t.toDisplayString(w.value.color),1)])]),t.createElementVNode("div",{class:"modal-actions"},[t.createElementVNode("button",{onClick:X,class:"cancel-btn"},"取消"),t.createElementVNode("button",{onClick:Be,class:"confirm-btn"},"确认")])])])):t.createCommentVNode("",!0)],2))}}),[["__scopeId","data-v-22c2957b"]]),Gt={class:"thumbnail-wrapper",ref:"wrapper"},Qt=["src","alt"],te=["viewBox"],ee=["x","y","width","height","stroke"],ne=["points","stroke"],se=["x","y","fill"],oe={key:1,class:"loading-placeholder"},ie=$(t.defineComponent({__name:"AnnotationThumbnail",props:{src:{},annotations:{},alt:{},labels:{}},setup(p){const e=p,i=t.ref(null),s=t.ref(!1),c=t.ref(0),a=t.ref(0),h=()=>{i.value&&(c.value=i.value.naturalWidth,a.value=i.value.naturalHeight,s.value=!0)},l=m=>{var u;if((u=m.style)!=null&&u.strokeColor)return m.style.strokeColor;if(e.labels){const x=e.labels.find(w=>w.name===m.label);if(x)return x.color}return"#FF0000"},g=m=>{const u=m.coordinates,x=Math.min(u.x1,u.x2),w=Math.min(u.y1,u.y2),_=Math.abs(u.x1-u.x2),A=Math.abs(u.y1-u.y2);return{x,y:w,width:_,height:A}},y=m=>m.coordinates.points.map(x=>`${x.x},${x.y}`).join(" "),v=m=>{if(m.type==="rectangle"){const u=g(m);return{x:u.x,y:u.y-5}}else if(m.type==="polygon"){const u=m.coordinates.points;if(u.length>0)return{x:u[0].x,y:u[0].y-5}}return{x:0,y:0}};return(m,u)=>(t.openBlock(),t.createElementBlock("div",Gt,[t.createElementVNode("img",{ref_key:"img",ref:i,src:p.src,class:"thumbnail-image",onLoad:h,alt:p.alt},null,40,Qt),s.value?(t.openBlock(),t.createElementBlock("svg",{key:0,class:"annotation-overlay",viewBox:`0 0 ${c.value} ${a.value}`,preserveAspectRatio:"none"},[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(p.annotations,x=>(t.openBlock(),t.createElementBlock(t.Fragment,{key:x.id},[x.type==="rectangle"?(t.openBlock(),t.createElementBlock("rect",{key:0,x:g(x).x,y:g(x).y,width:g(x).width,height:g(x).height,stroke:l(x),"stroke-width":"2",fill:"transparent"},null,8,ee)):t.createCommentVNode("",!0),x.type==="polygon"?(t.openBlock(),t.createElementBlock("polygon",{key:1,points:y(x),stroke:l(x),"stroke-width":"2",fill:"transparent"},null,8,ne)):t.createCommentVNode("",!0),x.label?(t.openBlock(),t.createElementBlock("text",{key:2,x:v(x).x,y:v(x).y,fill:l(x),"font-size":"14","font-weight":"bold",class:"anno-label"},t.toDisplayString(x.label),9,se)):t.createCommentVNode("",!0)],64))),128))],8,te)):(t.openBlock(),t.createElementBlock("div",oe,"Loading..."))],512))}}),[["__scopeId","data-v-78bcbe0c"]]),ae={class:"batch-annotator"},le={key:0,class:"gallery-view"},re={class:"gallery-header"},ce={class:"label-summary"},he={class:"gallery-grid"},de=["onClick"],ge={class:"thumbnail-wrapper"},me={class:"img-meta"},fe={class:"img-index"},ue={class:"anno-count"},ye={class:"bottom-bar"},pe={key:1,class:"editor-view"},ve={class:"editor-header"},be={class:"header-left"},xe={class:"editor-title"},we={class:"editor-content"},F=$(t.defineComponent({__name:"BatchAnnotator",props:{images:{},labels:{}},emits:["export","update:images"],setup(p,{emit:e}){const i=p,s=e,c=t.ref("gallery"),a=t.ref([]),h=t.ref(0),l=t.ref(null);t.watch(()=>i.images,w=>{a.value=JSON.parse(JSON.stringify(w))},{immediate:!0,deep:!0});const g=w=>{h.value=w,c.value="editor",t.nextTick(()=>{l.value&&l.value.jumpTo&&l.value.jumpTo(w)})},y=()=>{if(l.value&&l.value.getCurrentAnnotation){const w=l.value.getCurrentAnnotation();a.value[h.value]&&(a.value[h.value].annotations=w.annotations)}c.value="gallery"},v=()=>{s("export",a.value)},m=w=>{h.value=w.currentIndex,a.value[w.currentIndex]&&(a.value[w.currentIndex].annotations=w.currentAnnotations)},u=w=>{if(l.value&&l.value.getCurrentAnnotation){const _=l.value.getCurrentAnnotation();a.value[h.value]&&(a.value[h.value].annotations=_.annotations,s("update:images",a.value))}},x=w=>{};return(w,_)=>(t.openBlock(),t.createElementBlock("div",ae,[c.value==="gallery"?(t.openBlock(),t.createElementBlock("div",le,[t.createElementVNode("div",re,[t.createElementVNode("h3",null,"批量查看与标注 ("+t.toDisplayString(a.value.length)+" 张)",1),t.createElementVNode("div",ce,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(p.labels,A=>(t.openBlock(),t.createElementBlock("span",{key:A.id,class:"label-badge",style:t.normalizeStyle({backgroundColor:A.color})},t.toDisplayString(A.name),5))),128))])]),t.createElementVNode("div",he,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(a.value,(A,S)=>(t.openBlock(),t.createElementBlock("div",{key:S,class:"gallery-item",onClick:O=>g(S)},[t.createElementVNode("div",ge,[t.createVNode(ie,{src:A.imageUrl,annotations:A.annotations||[],labels:p.labels},null,8,["src","annotations","labels"])]),t.createElementVNode("div",me,[t.createElementVNode("span",fe,"#"+t.toDisplayString(S+1),1),t.createElementVNode("span",ue,t.toDisplayString((A.annotations||[]).length)+" 标注",1)])],8,de))),128))]),t.createElementVNode("div",ye,[t.createElementVNode("button",{class:"action-btn primary",onClick:_[0]||(_[0]=A=>g(0))},[t.createVNode(E,{name:"edit"}),_[1]||(_[1]=t.createTextVNode(" 手动标注 ",-1))]),t.createElementVNode("button",{class:"action-btn success",onClick:v},[t.createVNode(E,{name:"download"}),_[2]||(_[2]=t.createTextVNode(" 导出 ",-1))])])])):(t.openBlock(),t.createElementBlock("div",pe,[t.createElementVNode("div",ve,[t.createElementVNode("div",be,[t.createElementVNode("button",{class:"back-btn",onClick:y},[t.createVNode(E,{name:"back"}),_[3]||(_[3]=t.createTextVNode(" 返回列表 ",-1))]),t.createElementVNode("span",xe,"正在标注: "+t.toDisplayString(h.value+1)+" / "+t.toDisplayString(a.value.length),1)])]),t.createElementVNode("div",we,[t.createVNode(U,{ref_key:"annotatorRef",ref:l,batchImages:a.value,labels:p.labels,annotationTypes:["rectangle","polygon","point","rotatedRect"],onBatchChange:m,onAnnotationChange:u,onLabelChange:x},null,8,["batchImages","labels"])])]))]))}}),[["__scopeId","data-v-87f3e002"]]);I.BatchAnnotator=F,I.ImageAnnotator=U,I.default=F,Object.defineProperties(I,{__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",
3
+ "version": "0.0.5",
4
4
  "description": "A simple image annotation component for Vue 3",
5
5
  "scripts": {
6
6
  "dev": "vite",