canvas模拟鼠标拉框;画折线;(基于VUE)

<template>
<div
ref="mouseDiv"
style="background-color:transparent;width: 100%;height: 100%;position: absolute;top:0;left: 0;z-index: 2023;"
>
<div class="camera-tool">
<el-tooltip
:content="activeName === 'spatialMeasure' ? '关闭画线' : '开启画线'"
placement="left"
effect="light"
>
<div
:class="['camera-tool-item', activeName === 'spatialMeasure' ? 'spatialMeasure-active' : 'spatialMeasure']"
@click.prevent="handleSpatialClick('spatialMeasure')"
></div>
</el-tooltip>
</div>
<canvas
v-show="activeName !== 'spatialMeasure'"
id="myCanvas"
ref="myCanvas"
@mousedown.prevent="mousedown"
@mouseup.prevent="mouseup"
@mousemove.prevent="mousemove"
>
</canvas>
<canvas
v-show="activeName === 'spatialMeasure'"
id="myCanvasLine"
ref="myCanvasLine"
@mousedown.prevent="mousedownLine($event)"
@dblclick.prevent="handleDBClickLine"
@mousemove.prevent="mousemoveLine"
>
</canvas>
</div>
</template>

<script>
export default {
name:"MouseDiv",
data() {
return {
flag: false,
x: 0,
y: 0,
startx: 0,
starty: 0,
endx: 0,
endy: 0,
activeName: '',
// 以下是画线的变量
ctx: "", //dom节点
canvas: null,
tempPointArr: [], //临时存储每次点击的位置
moveStatus: false,
savePointArr: [], //保存每次点击的位置
};
},
watch: {},
created() {

},
mounted() {
let self = this;
this.$nextTick(() => {
self.canvas = self.$refs.myCanvasLine;
self.ctx = self.canvas.getContext("2d");
self.$refs.myCanvas.width = self.$refs.mouseDiv.offsetWidth;
self.$refs.myCanvas.height = self.$refs.mouseDiv.offsetHeight;
self.$refs.myCanvasLine.width = self.$refs.mouseDiv.offsetWidth;
self.$refs.myCanvasLine.height = self.$refs.mouseDiv.offsetHeight;
})
},
methods: {
mousedown(e){
this.clearAll();
this.flag = true;
this.x = e.offsetX; // 鼠标落下时的X
this.y = e.offsetY; // 鼠标落下时的Y

this.startx = e.offsetX;
this.starty = e.offsetY;

},
mouseup(e){
this.flag = false;
this.endx = e.offsetX;
this.endy = e.offsetY;

console.log(`开始坐标:${this.startx},${this.starty}, 结束坐标:${this.endx},${this.endy}`)

this.clearAll();
},
mousemove(e){
this.drawRect(e);
},
drawRect(e){
if(this.flag){
const canvas = this.$refs.myCanvas;
var ctx = canvas.getContext("2d");
let x = this.x;
let y = this.y;

ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();

//设置线条颜色,必须放在绘制之前
ctx.strokeStyle = '#ff0000';
// 线宽设置,必须放在绘制之前
ctx.lineWidth = 2;

ctx.strokeRect(x,y,e.offsetX-x,e.offsetY-y);
}
},
clearCanvas() {
const canvas = this.$refs.myCanvas;
var ctx = canvas.getContext("2d");
let x = this.x;
let y = this.y;
ctx.clearRect(0,0,canvas.width,canvas.height);
},
clearVariables() {
this.flag = false;
this.x = 0;
this.y = 0;
this.startx = 0;
this.starty = 0;
this.endx = 0;
this.endy = 0;
},
clearAll() {
this.clearCanvas();
this.clearVariables();
this.clearLine();
},
handleSpatialClick(activeName) {
this.activeName = this.activeName === activeName ? '' : activeName;
this.clearAll();
},
// 放下鼠标
mousedownLine(e) {
clearTimeout(this.timer);
this.moveStatus = true;
this.timer = setTimeout(() => {
// 每次点击,保存点击的位置
this.tempPointArr.push([e.offsetX, e.offsetY]);
// 绘制矩形小点
this.ctx.fillStyle = "#FF0000";
this.ctx.fillRect(e.offsetX - 0.5, e.offsetY - 0.5, 1, 1);
if (this.tempPointArr.length <= 1) return;
// 设置线宽
this.ctx.lineWidth = 2;
// 连线
this.ctx.beginPath();
this.ctx.strokeStyle = "#FF0000";
// 找到需要连线的那个点
this.ctx.moveTo(
this.tempPointArr[this.tempPointArr.length - 2][0],
this.tempPointArr[this.tempPointArr.length - 2][1]
);
// 画线
this.ctx.lineTo(
this.tempPointArr[this.tempPointArr.length - 1][0],
this.tempPointArr[this.tempPointArr.length - 1][1]
);
this.ctx.stroke();
}, 100);
},
// 移动鼠标,实现线跟随鼠标移动
mousemoveLine(e) {
if (this.moveStatus) {
let point = [e.offsetX, e.offsetY];
// 先清除每次移动画出的线
if (this.tempPointArr.length < 1) return;
this.clearLine();
// // 将点过的点之前的连线回显出来
this.echoTempPoint(this.tempPointArr, false);
this.ctx.fillStyle = "#FF0000";
this.ctx.lineWidth = 2;
// 连线
this.ctx.beginPath();
this.ctx.strokeStyle = "#FF0000";
// 找到需要连线的那个点
this.ctx.moveTo(
this.tempPointArr[this.tempPointArr.length - 1][0],
this.tempPointArr[this.tempPointArr.length - 1][1]
);
this.ctx.lineTo(point[0], point[1]);
this.ctx.stroke();
}
},
// 回显之前画的点之间的连线
echoTempPoint(cur, status) {
for (let i = 0; i < cur.length; i++) {
// 绘制矩形小点
this.ctx.fillStyle = "#FF0000";
this.ctx.fillRect(cur[i][0] - 0.5, cur[i][1] - 0.5, 1, 1);
this.ctx.lineWidth = 2;
// 连线
this.ctx.beginPath();
this.ctx.strokeStyle = "#FF0000";

if (i !== 0) {
// 找到需要连线的那个点
this.ctx.moveTo(cur[i - 1][0], cur[i - 1][1]);
this.ctx.lineTo(cur[i][0], cur[i][1]);
}
// status判断回显时是否连接最后一个点和第一个点
if (status) {
if (i === cur.length - 1) {
this.ctx.moveTo(cur[i][0], cur[i][1]);
this.ctx.lineTo(cur[0][0], cur[0][1]);
}
}
this.ctx.stroke();
}
},
//清除画布
clearLine() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
//双击保存数据,并链接最后一个点和第一个点
handleDBClickLine() {

let self = this;
clearTimeout(this.timer);
if(this.tempPointArr[this.tempPointArr.length - 1].toString() === this.tempPointArr[this.tempPointArr.length - 2].toString()){
console.log('去掉最后重复的点了');
this.tempPointArr.pop();
}
if (this.tempPointArr.length <= 1) {
this.$message.warning("至少需要2个点");
} else {
this.savePointArr = [...this.tempPointArr];
/* this.ctx.moveTo(
this.tempPointArr[this.tempPointArr.length - 1][0],
this.tempPointArr[this.tempPointArr.length - 1][1]
);
this.ctx.lineTo(this.tempPointArr[0][0], this.tempPointArr[0][1]);
this.ctx.stroke();*/
this.moveStatus = false;
this.tempPointArr = [];
}
},
}
};
</script>

<style scoped lang="scss">
#myCanvas, #myCanvasLine{
background-color: transparent;
}
.camera-tool {
position: absolute;
z-index: 9999;
right: 15px;
top: 0;
width: 25px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.camera-tool-item {
width: 25px;
height: 25px;
cursor: pointer;
background-size: 100% 100%;
margin-top: 10px;
}
.spatialMeasure{
background-image: url("~@/assets/images/measure.png");
}
.spatialMeasure-active{
background-image: url("~@/assets/images/measure_active.png");
}
</style>
posted @ 2023-02-10 08:23  一两米  阅读(266)  评论(0编辑  收藏  举报