一 :图片标注功能的实现简介
1:需要标注的图片放在底层
2:svg层正好覆盖需要标注的图片
3:由svg来画出相应的轨迹
注释: svg的坐标系:
1:以左上角为坐标系的原点(0,0)
2:X 轴的正方向向右,从 0,0 点开始向右, x 逐渐增大。Y 轴的正方向向下,从 0,0 点开始向下, y 逐 渐增大
3:坐标以像素为单位
二:标注的效果图
三: 核心代码
HTML:

1 <div class="Labeling-canvas"> 2 <div class="image"> 3 <img src="@/assets/404.png" ref="imgLabel" id="labelValue"/><!-- 需要标注的图片 --> 4 </div> 5 <svg class="svglabel" ref="svglabel" @mousedown="mouseDown($event)" @mousemove="mouseMove($event)" @mouseup="onmouseup($event)" :style="{width: 100 + '%', height: 100 + '%' }"> 6 <g v-for="(rectData, index) in svgLabelShow" :key="index"> 7 <rect v-if="rectData" :x="getXPostion(rectData,27,1)" :y="rectData.ulY" :width="27" :height="26" 8 style="fill: #00FFFF; stroke-opacity: 1; stroke: #00FFFF; stroke-dasharray: none; stroke-width: 1;"> 9 </rect> 10 <text v-if="rectData" :x='getXPostion(rectData,18,8)' :y='parseFloat(rectData.ulY)+16'font-size='16'> 11 {{index+1}} 12 </text> 13 <rect v-if="rectData" :x="getXPostion(rectData,27,1)" :y="parseFloat(rectData.ulY)+26" :width="27" :height="24" 14 style="fill: #FFFFFF; stroke-opacity: 1; stroke: #00FFFF; stroke-dasharray: none; stroke-width: 1;"></rect> 15 <image v-if="rectData" @click="deleteLabel(svgLabelShow,index)" :x='getXPostion(rectData,19,7)' :y='parseFloat(rectData.ulY)+29' width='13' 16 height='14' xlink:href='@/assets/delete.svg'></image> 17 <rect v-if="rectData" :x="rectData.ulX" :y="rectData.ulY" :width="rectData.width" :height="rectData.height" 18 style="fill: none; stroke-opacity: 1; stroke: #00FFFF; stroke-dasharray: none; stroke-width: 1;"></rect> 19 </g> 20 </svg> 21 </div>
VUE:

1 data () { 2 return { 3 isclick: true, 4 drawColor: '#00FFFF', 5 drawElement: null, //当前移动的对象 6 svgLabelShow: [],//显示数据,需按比例转换 7 } 8 }, 9 methods: { 10 //mouseDown,mouseMove,onmouseup 新建标注核心代码 11 mouseDown (e) { 12 if (!this.isclick) {//防止点击过快 13 return false; 14 } else { 15 this.clickQuick(); 16 } 17 //e.button==0 没有按键或者是没有初始化 18 if (e.button == 0) {//当前为画图操作 19 const currentX = e.offsetX;//offsetX,offsetY相对于带有定位的父盒子的x,y坐标 20 const currentY = e.offsetY; 21 this.drawElement = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); 22 this.drawElement.setAttribute('x', currentX); 23 this.drawElement.setAttribute('y', currentY); 24 this.drawElement.setAttribute('width', 0); 25 this.drawElement.setAttribute('height', 0); 26 this.drawElement.dataset.dataType = 'markRect'; 27 this.$refs.svglabel.appendChild(this.drawElement); 28 this.drawElementStyle(this.drawElement); 29 } 30 }, 31 mouseMove (e) { 32 if (this.drawElement == null || this.corpusActionType != 'label') { 33 return false; 34 } 35 if (e.button == 0) {//当前为画图操作 36 const currentX = e.offsetX; 37 const currentY = e.offsetY; 38 const startX = this.drawElement.getAttribute('x'); 39 const startY = this.drawElement.getAttribute('y'); 40 const rectX =startX; 41 const rectY =startY; 42 const rectWith = Math.abs(currentX - startX); 43 const rectHeight = Math.abs(currentY - startY); 44 this.drawElement.setAttribute('x', rectX); 45 this.drawElement.setAttribute('y', rectY); 46 this.drawElement.setAttribute('width', rectWith); 47 this.drawElement.setAttribute('height', rectHeight); 48 } 49 }, 50 onmouseup (e) { 51 if (this.drawElement == null) { 52 return; 53 } 54 if (e.button == 0) { 55 const rectX = this.drawElement.getAttribute('x'); 56 const rectY = this.drawElement.getAttribute('y'); 57 const rectWidth = this.drawElement.getAttribute('width'); 58 const rectHeight = this.drawElement.getAttribute('height'); 59 if (rectWidth == 0 || rectHeight == 0 || !rectX || !rectY) {//不符合条件的矩形取消 60 this.drawElement.parentNode.removeChild(this.drawElement); 61 this.drawElement = null; 62 } else { 63 this.svgLabelShow.push({ulX: rectX, ulY: rectY, width: rectWidth, height: rectHeight, labelName: 'table'}); 64 console.log('this.svgLabelShow', this.svgLabelShow); 65 this.drawElementStyle(e.target); 66 this.drawElement.parentNode.removeChild(this.drawElement); 67 this.drawElement = null; 68 } 69 } 70 }, 71 //设置标注框的样式 0:正常状态 1: 高亮状态 2: 可编辑状态 72 drawElementStyle (drawElement) { 73 drawElement.style.fill = 'none'; 74 drawElement.style.strokeOpacity = 1; 75 drawElement.style.stroke = this.drawColor; 76 drawElement.style.strokeDasharray = 'none'; 77 drawElement.style.strokeWidth = 1; 78 }, 79 clickQuick () { 80 if (this.isclick) { 81 this.isclick = false; 82 setTimeout(() => { 83 this.isclick = true; 84 }, 500); 85 } 86 }, 87 getXPostion (labelData, xPostion, left) { 88 if (parseFloat(labelData.ulX) < 27) { 89 return parseFloat(labelData.ulX) + parseFloat(labelData.width) + left; 90 } else { 91 return parseFloat(labelData.ulX) - xPostion; 92 } 93 }, 94 }