<template>
<div class="set-area-root">
<el-dialog
title="设置判别区域"
:visible="dialogVisible"
width="50%"
@close="handleClose"
>
<div class="dialog-container">
<div
class="canvas-box"
@mousedown="boxMouseDown"
@mousemove="boxMouseMove"
@mouseup="boxMouseUp"
>
<img :src="imgUrl" alt="" />
<canvas id="rect_canvas" @mousedown.stop="mousedownHandle"></canvas>
<div
v-for="pointItem in points"
:key="pointItem.id"
class="point-item"
:data-id="pointItem.id"
:style="{
left: pointItem.x - 5 + 'px',
top: pointItem.y - 5 + 'px',
}"
></div>
</div>
<div class="btns">
<el-button @click="handleClose">取消</el-button>
<el-button @click="resetClick">重置</el-button>
<el-button type="primary" @click="sureClick">确定</el-button>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
props: {
dialogVisible: {
type: Boolean,
default: false,
},
pointList: {
type: Array,
default: () => [],
},
},
data() {
return {
imgUrl:
'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg',
ctx: null,
canvasDom: null,
imgNaturalSize: {},
points: [],
activPoint: {}, // 当前点击的点
moveStart: false,
};
},
watch: {
dialogVisible: {
handler(newval) {
if (newval) {
if (this.pointList.length) {
this.points = this.calcXY(1, this.pointList);
}
this.$nextTick(() => {
this.init();
});
}
},
immediate: true,
},
},
methods: {
handleClose() {
this.$emit('update:dialogVisible', false);
this.clearRect();
this.points = [];
},
init() {
this.canvasDom = document.querySelector('#rect_canvas');
this.canvasDom.width = this.canvasDom.clientWidth;
this.canvasDom.height = this.canvasDom.clientHeight;
this.ctx = this.canvasDom.getContext('2d');
this.getImgSize();
// 如果是回显
if (this.points.length) {
this.points.forEach((pointItem) => {
this.drawPoint(pointItem.x, pointItem.y);
});
this.drawLine();
}
},
// 获取图片实际尺寸
getImgSize() {
let img = new Image();
img.onload = () => {
this.imgNaturalSize = {
width: img.naturalWidth,
height: img.naturalHeight,
};
};
img.src = this.imgUrl;
},
// 绘制点
drawPoint(x, y) {
this.ctx.beginPath();
this.ctx.arc(x, y, 5, 0, 2 * Math.PI);
this.ctx.fillStyle = 'red';
this.ctx.fill();
this.ctx.closePath();
},
// 将点相连接
drawLine() {
let firstPoint = this.points[0];
this.ctx.beginPath();
this.ctx.strokeStyle = 'red';
this.ctx.moveTo(firstPoint.x, firstPoint.y);
this.points.forEach((item) => {
this.ctx.lineTo(item.x, item.y);
this.ctx.stroke();
});
this.ctx.lineTo(firstPoint.x, firstPoint.y);
this.ctx.stroke();
this.ctx.closePath();
},
// claer canvas
clearRect() {
this.ctx.clearRect(
0,
0,
this.canvasDom.clientWidth,
this.canvasDom.clientHeight
);
},
/**
* 根据当前canvas的宽度和高度与标点时的宽度高度对比就算 x,y
* @param {number} type 1,代表计算页面上显示的x, y; 2,代表计算图片原尺寸上 x, y坐标
* @param {array} list 点的集合
*/
calcXY(type, list) {
let newList = JSON.parse(JSON.stringify(list));
newList.forEach((element) => {
let nowWidth = this.canvasDom.clientWidth;
let nowHeight = this.canvasDom.clientHeight;
if (type === 1) {
let { imgNaturalWidth, imgNaturalHeight } = element;
element.x = Math.round((nowWidth / imgNaturalWidth) * element.x);
element.y = Math.round((nowHeight / imgNaturalHeight) * element.y);
} else if (type === 2) {
let { width, height } = this.imgNaturalSize;
element.x = Math.round((width / nowWidth) * element.x);
element.y = Math.round((height / nowHeight) * element.y);
element.imgNaturalWidth = width;
element.imgNaturalHeight = height;
}
});
return newList;
},
// canvas mousedown event
mousedownHandle(e) {
let event = e || window.event;
event.preventDefault();
if (this.points.length >= 4) {
this.showNotify('只能选择4个点', 'warning');
return;
}
let postion = {
x: event.offsetX,
y: event.offsetY,
id: this.points.length,
};
this.drawPoint(postion.x, postion.y);
this.points.push(postion);
if (this.points.length === 4) this.drawLine();
},
// box mousedown event
boxMouseDown(e) {
if (this.points.length !== 4) {
this.showNotify('请确定是否选择了4个点', 'warning');
return;
}
let params = e.target.dataset;
if (params.id) {
this.activPoint = this.points.find((el) => el.id === Number(params.id));
this.moveStart = true;
}
},
// box mousemove event
boxMouseMove(e) {
if (this.moveStart) {
let clientx = e.clientX;
let clienty = e.clientY;
let { left, top, width, height } =
this.canvasDom.getBoundingClientRect();
let x = Math.round(clientx - left) < 0 ? 0 : Math.round(clientx - left);
let y = Math.round(clienty - top) < 0 ? 0 : Math.round(clienty - top);
this.activPoint.x = x > width ? Math.round(width) : x;
this.activPoint.y = y > height ? Math.round(height) : y;
this.clearRect();
this.points.forEach((pointItem) => {
this.drawPoint(pointItem.x, pointItem.y);
});
this.drawLine();
}
},
// box mouseup event
boxMouseUp() {
this.activPoint = {};
this.moveStart = false;
},
// 提示框
showNotify(message, type) {
this.$notify({
title: '提示',
message,
type,
});
},
// reset
resetClick() {
this.clearRect();
this.points = [];
this.init();
},
// sure
sureClick() {
console.log(this.calcXY(2, this.points), this.points);
},
},
};
</script>
<style lang="scss" scoped>
.dialog-container {
text-align: center;
.canvas-box {
position: relative;
width: 100%;
height: 500px;
canvas {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 20;
}
& > img {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.point-item {
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
background: transparent;
cursor: pointer;
z-index: 1111;
}
}
.btns {
text-align: center;
margin-top: 12px;
}
}
</style>
效果图:
image.png
网友评论