在图片上绘制区域并获取坐标数据(VUE版)
在图片上绘制区域并获取坐标数据
·
<template>
<div>
<div class="tool-box">
<el-button size="mini" :type="isDrawing ? 'warning' : 'primary'" @click="startDraw">绘制区域</el-button>
<el-button size="mini" type="danger" :disabled="isDrawing" @click="clearAll">全部清除</el-button>
<el-button size="mini" type="success" :disabled="isDrawing" @click="savePoints">保存</el-button>
</div>
<div class="canvas-wrap">
<canvas id="imgCanvas" ref="canvaxbox"></canvas>
<!--用来和鼠标进行交互操作的canvas-->
<canvas id="drawCanvas" ref="canvas" :style="{cursor: isDrawing?'crosshair': 'default'}"> </canvas>
<!--存储已生成的点线,避免被清空-->
<canvas id="saveCanvas" ref="canvasSave"></canvas>
</div>
</div>
</template>
<script>
// import OldJs from './oldJs.js'
export default {
// mixins: [OldJs],
data() {
return {
imgUrl: 'img/code/wechat-code.jpg',
isDrawing: false, // 是否正在绘制
ratio: 1,
imgWidth: 3020,
imgHeight: 1080,
wrapWidth: 300,
wrapHeight: 300,
canvasWidth: 300,
canvasHeight: 300,
drawingPoints: [],
drawedPoints: [],
imgCanvas: null,
imgCtx: null,
drawCanvas: null,
drawCtx: null,
saveCanvas: null,
saveCtx: null,
submitData: [
// {"polygon":{"x1":0,"y1":0,"x2":1920,"y2":0,"x3":1920,"y3":1080,"x4":0,"y4":1080}},
{"polygon":{"x1":700,"y1":273,"x2":975,"y2":278,"x3":1107,"y3":368,"x4":718,"y4":354}},
{"polygon":{"x1":49,"y1":32,"x2":183,"y2":35,"x3":181,"y3":100,"x4":55,"y4":97}},
{"polygon":{"x1":433,"y1":250,"x2":706,"y2":253,"x3":707,"y3":392,"x4":435,"y4":393}},
{"polygon":{"x1":45,"y1":539,"x2":193,"y2":538,"x3":192,"y3":622,"x4":41,"y4":623,"x5":42,"y5":623}}
]
// [
// {"polygon": {"x1":700,"y1":273,"x2":975,"y2":278,"x3":1107,"y3":368,"x4":718,"y4":354}}
// ]
}
},
mounted() {
this.initCanvas()
this.getImage()
},
methods: {
initCanvas() { // 初始化canvas画布
let canvasWrap = document.getElementsByClassName('canvas-wrap')
this.wrapWidth = canvasWrap [0].clientWidth
this.wrapHeight = canvasWrap [0].clientHeight
this.imgCanvas = document.getElementById('imgCanvas')
this.imgCtx = imgCanvas.getContext('2d')
// 绘制canvas
this.drawCanvas = document.getElementById('drawCanvas')
this.drawCtx = drawCanvas.getContext('2d')
// 保存绘制区域 saveCanvas
this.saveCanvas = document.getElementById('saveCanvas')
this.saveCtx = saveCanvas.getContext('2d')
// this.initImgCanvas()
},
initImgCanvas() {
// 计算宽高比
let ww = this.wrapWidth // 画布宽度
let wh = this.wrapHeight // 画布高度
let iw = this.imgWidth // 图片宽度
let ih = this.imgHeight // 图片高度
if (iw/ih < ww/wh) { // 以高为主
this.ratio = ih / wh
this.canvasHeight = wh
this.canvasWidth = wh * iw/ih
} else { // 以宽为主
this.ratio = iw / ww
this.canvasWidth = ww
this.canvasHeight = ww * ih/iw
}
// 初始化画布大小
imgCanvas.width = this.canvasWidth
imgCanvas.height = this.canvasHeight
drawCanvas.width = this.canvasWidth
drawCanvas.height = this.canvasHeight
saveCanvas.width = this.canvasWidth
saveCanvas.height = this.canvasHeight
// 图片加载绘制
let img = document.createElement('img')
img.src = this.imgUrl
img.onload = () => {
console.log('图片已加载')
this.imgCtx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight)
this.renderDatas() // 渲染原有数据
}
},
startDraw() { // 绘制区域
if (this.isDrawing) return
this.isDrawing = true
// 绘制逻辑
drawCanvas.addEventListener("click", this.drawImageClickFn)
drawCanvas.addEventListener("dblclick", this.drawImageDblClickFn)
drawCanvas.addEventListener("mousemove", this.drawImageMoveFn)
},
clearAll() { // 清空所有绘制区域
this.saveCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
this.drawedPoints = []
},
getImage() { // 请求图片
axios.post('/dsj/screenshot/', {
"source":"rtsp://admin:admin12345@10.10.42.251:554/cam/realmonitor?channel=1&subtype=0"
}).then(res => {
this.imgUrl = res.data.img
this.imgWidth = res.data.width
this.imgHeight = res.data.height
this.imgUrl && this.initImgCanvas()
})
},
drawImageClickFn(e) {
let drawCtx = this.drawCtx
if (e.offsetX || e.layerX) {
let pointX = e.offsetX == undefined ? e.layerX : e.offsetX;
let pointY = e.offsetY == undefined ? e.layerY : e.offsetY;
let lastPoint = this.drawingPoints[this.drawingPoints.length-1] || []
if (lastPoint[0] !== pointX || lastPoint[1] !== pointY) {
this.drawingPoints.push([pointX, pointY])
}
}
},
drawImageMoveFn(e) {
let drawCtx = this.drawCtx
if (e.offsetX || e.layerX) {
let pointX = e.offsetX == undefined ? e.layerX : e.offsetX;
let pointY = e.offsetY == undefined ? e.layerY : e.offsetY;
// 绘制
drawCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
// 绘制点
drawCtx.fillStyle = 'blue'
this.drawingPoints.forEach((item, i) => {
drawCtx.beginPath();
drawCtx.arc(...item, 6, 0, 180)
drawCtx.fill(); //填充
})
// 绘制动态区域
drawCtx.save()
drawCtx.beginPath();
this.drawingPoints.forEach((item, i) => {
drawCtx.lineTo(...item)
})
drawCtx.lineTo(pointX, pointY)
drawCtx.lineWidth = "3";
drawCtx.strokeStyle= "blue";
drawCtx.fillStyle = 'rgba(255, 0, 0, 0.3)'
drawCtx.stroke();
drawCtx.fill(); //填充
drawCtx.restore()
}
},
drawImageDblClickFn(e) {
let drawCtx = this.drawCtx
let saveCtx = this.saveCtx
if (e.offsetX || e.layerX) {
let pointX = e.offsetX == undefined ? e.layerX : e.offsetX;
let pointY = e.offsetY == undefined ? e.layerY : e.offsetY;
let lastPoint = this.drawingPoints[this.drawingPoints.length-1] || []
if (lastPoint[0] !== pointX || lastPoint[1] !== pointY) {
this.drawingPoints.push([pointX, pointY])
}
}
// 清空绘制图层
drawCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
// 绘制区域至保存图层
this.drawSaveArea(this.drawingPoints)
this.drawedPoints.push(this.drawingPoints)
this.drawingPoints = []
this.isDrawing = false
// 绘制结束逻辑
drawCanvas.removeEventListener("click", this.drawImageClickFn)
drawCanvas.removeEventListener("dblclick", this.drawImageDblClickFn)
drawCanvas.removeEventListener("mousemove", this.drawImageMoveFn)
},
drawSaveArea(points) {
if(!points instanceof Array || points.length === 0) return
this.saveCtx.save()
this.saveCtx.beginPath();
points.forEach((item, i) => {
this.saveCtx.lineTo(...item)
})
this.saveCtx.closePath()
this.saveCtx.lineWidth="2";
this.saveCtx.fillStyle = 'rgba(255,0, 255, 0.3)'
this.saveCtx.strokeStyle= "red";
this.saveCtx.stroke();
this.saveCtx.fill(); //填充
this.saveCtx.restore()
},
savePoints() { // 将画布坐标数据转换成提交数据
let objectPoints = []
// "object": [{"polygon": {"x1":700,"y1":273,"x2":975,"y2":278,"x3":1107,"y3":368,"x4":718,"y4":354} }]
objectPoints = this.drawedPoints.map(area => {
let polygon = {}
area.forEach((point, i) => {
polygon[`x${i+1}`] = Math.round(point[0] * this.ratio)
polygon[`y${i+1}`] = Math.round(point[1] * this.ratio)
})
return {
"polygon": polygon
}
})
this.submitData = objectPoints
console.log('最终提交数据', objectPoints)
},
renderDatas() { // 将提交数据数据转换成画布坐标
this.drawedPoints = this.submitData.map(item => {
let polygon = item.polygon
let points = []
for(let i=1; i< Object.keys(polygon).length/2 + 1; i++) {
if (!isNaN(polygon[`x${i}`]) && !isNaN(polygon[`y${i}`])) {
points.push([polygon[`x${i}`]/this.ratio, polygon[`y${i}`]/this.ratio])
}
}
this.drawSaveArea(points)
return points
})
}
}
};
</script>
<style lang="scss" scoped>
.tool-box {
width: 60vw;
height: 40px;
padding: 5px 30px;
margin: 20px auto 0;
box-sizing: border-box;
text-align: right;
}
.canvas-wrap {
// width: 80vw;
// height: 45vw;
width: 60vw;
height: 33.75vw;
margin: 0px auto;
background-color: #000;//#fff;
border: 3px;
border-color: #333;
position: relative;
}
#imgCanvas, #drawCanvas, #saveCanvas {
background: rgba(255, 0, 255, 0);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
#drawCanvas {
z-index: 2;
}
</style>
大体思路:
三层canvas,图片canvas、绘制canvas和绘制区域保存canvas。
canvas画布大小根据加载的图片大小按比例适配至页面操作区域。
submitData为后端数据存储格式,可根据要求适当调整。
更多推荐
已为社区贡献1条内容
所有评论(0)