1. 实现效果如图所示
2. 技术栈
Vue3 + LeaderLine
3. 主要代码
<template>
<div id="image-detail">
<el-image :src="imageUrl" style="height: 800px; width: 600px" ref="canvasRef" @mousedown="startDrawing" @mousemove="drawLine" @mouseup="stopDrawing"/>
</div>
</template>
<script>
import LeaderLine from 'leader-line'
import $ from 'jquery'
export default {
components: {
},
data() {
return {
imageUrl: 'https://picsum.photos/800/600',
isDrawing: false,
lastX: '',
lastY: '',
lineRef: null,
lines: [],
index: 0
}
},
methods: {
markPoint(offsetX, offsetY, tag) {
let nameIndex = this.index;
// 点击多个点,生成多个值
let div = document.createElement("div" + nameIndex + tag);
div.className = "marker";
div.id = "marker" + nameIndex + tag;
if (tag !== 'middle') {
// 红点的宽
div.style.width = "5px";
// 红点的高
div.style.height = "5px";
} else {
div.style.width = 0
div.style.height = 0
}
// 红点颜色
div.style.backgroundColor = "red";
div.style.left = offsetX + "px";
div.style.top = offsetY + "px";
div.style.position = "absolute";
// 边框半径百分比
div.style.borderRadius = "50%";
document.getElementById("image-detail").appendChild(div);
},
startDrawing(event) {
if (this.isDrawing) return;
this.isDrawing = true;
this.lastX = event.clientX;
this.lastY = event.clientY;
this.markPoint(this.lastX, this.lastY, 'start')
},
drawLine(event) {
if (!this.isDrawing) return;
let nameIndex = this.index
let dom1 = document.getElementById('marker' + nameIndex + 'start')
let dom2 = document.getElementById('marker' + nameIndex + "middle")
if (dom2 === null) {
this.markPoint(event.clientX, event.clientY, 'middle')
dom2 = document.getElementById('marker' + nameIndex + "middle")
this.lineRef = new LeaderLine(dom1, dom2,
{
'color': 'red', 'path': 'straight'});
this.lineRef.show()
} else {
$('#marker' + nameIndex + "middle").css({
'left': event.clientX, 'top': event.clientY})
this.lineRef.position()
}
},
stopDrawing(event) {
if (!this.isDrawing) return;
let nameIndex = this.index
$('#marker' + nameIndex + "middle").css({
'left': event.clientX, 'top': event.clientY})
// TODO 计算距离
this.lineRef.setOptions({
'endLabel': 'end'})
this.lineRef.position()
this.isDrawing = false;
if (this.lineRef) {
this.lines.push(this.lineRef);
}
this.index++
}
}
}
</script>
<style lang="scss" scoped>
</style>
4. 针对报错处理
vue.config.js中配置如下
const {
defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
configureWebpack: config => {
let path = require('path')
config.module.rules.push({
test: path.resolve(__dirname, 'node_modules/leader-line/'),
use: [
{
// 解决leader-line报错问题
loader: 'skeleton-loader',
options: {
procedure: content => `${
content}export default LeaderLine`
}
}
]
})
}
})
欢迎关注公众号算法小生与我沟通交流