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