实现的效果
身为一个三线小城市的开发者,平时就是使用各种框架画个按钮,表单,图表之类的东西,如果突然有一天面临一个非主流的需求,虽然看起来并不是很难,但需要学习很多canvas相关的知识才能实现。
在此强烈推荐大名鼎鼎的echarts底层图形框架zrender,你可能从来没听说过zrender,但是如此牛逼的echarts就是用它实现的,完全可以放心使用。
它没有直接用canvas那么生涩,也不会像各种应用层框架那么死板,看完文档以后,很快就能上手,实现一些自由度要求很高的需求。
功能的实现
哪怕先不看官方文档,直接看我这个入门小例程应该也不会吃力。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>markup-pig</title>
<script src="./zrender.min.js"></script>
<style>
#pointList {
list-style: none;
}
#canvas {
border: 1px solid #aaa;
}
</style>
</head>
<body>
<h1>猪圈标注</h1>
<canvas id="canvas" width="1920" height="1080"></canvas>
<div id="panel">
<button id="markup">完成标注</button>
<button id="clearAll">清除标注</button>
<input type="file" id="openImg" accept="image/jpeg,image/bmp">
</div>
<ul id="pointList"></ul>
<script>
//全局变量
let dataArr = []
let _dataArr = []
let clickIndex = 0
let imgSrc = ''
//初始化canvas
var mycanvas = document.getElementById('canvas')
//初始化zrender
var zr = zrender.init(mycanvas)
//加载猪的图片
function addImg() {
var imgPig = new zrender.Image({
style: {
image: imgSrc,
x: 0,
y: 0,
width: 1920,
height: 1080
}
})
zr.add(imgPig)
}
// canvas点击事件
mycanvas.onclick = (function (e) {
e.preventDefault()
// console.log(e)
let pointX = e.offsetX
let pointY = e.offsetY
addPoint( pointX, pointY )
addLi( pointX, pointY )
addData( pointX, pointY )
if (clickIndex) {
addLine(_dataArr[clickIndex-1],_dataArr[clickIndex])
}
clickIndex++
})
//切换图片
let inputImg = document.getElementById('openImg')
inputImg.onchange = function (e) {
if (e.target.files.length) {
let file = e.target.files[0]
let fileType = file.type
imgSrc = URL.createObjectURL(file)
addImg()
initData()
}
}
//添加点
function addPoint(x=0,y=0) {
var circle = new zrender.Circle({
shape: {
cx: x,
cy: y,
r: 5
},
style: {
fill: '#7FFF00',
stroke: '#7FFF00'
}
})
zr.add(circle)
circle.animateTo({ //不需要再手动调用start(),可写多个属性
shape: {
r: 10
}
},100)
}
//添加直线
function addLine(point1,point2) {
var line = new zrender.Line({
shape: {
x1: point1[0],
y1: point1[1],
x2: point2[0],
y2: point2[1]
},
style: {
stroke: '#FF0000',
lineWidth: 4
}
})
zr.add(line)
}
//添加li
var myUl = document.getElementById('pointList')
function addLi(x,y) {
let myLi = document.createElement('li')
myLi.innerText = `X: ${x} Y: ${y}`
myUl.appendChild(myLi)
}
// 添加数据
function addData(x,y) {
dataArr.push(x,y)
_dataArr.push([x,y])
}
// 完成本张图片标注
var markupBtn = document.getElementById('markup')
markupBtn.onclick = function () {
if (!dataArr.length) {
alert('请先标注')
return
}
console.log(dataArr)
}
//清楚所有标注,重新开始
var clearAllBtn = document.getElementById('clearAll')
clearAllBtn.onclick = function () {
zr.clear()
addImg()
initData()
}
//初始化所有数据
function initData() {
dataArr = []
_dataArr = []
clickIndex = 0
myUl.innerHTML = ""
}
</script>
</body>
</html>
将打开的图片文件转换成临时的URL资源,将点击的点坐标数据最终保存到一个数组中去。后端根据坐标点裁剪图片,供算法识别使用.