<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>跟随鼠标绘制矩形框</title>
<style>
#canvas {
border: 1px solid red;
}
</style>
</head>
<body>
<canvas id="canvas" width="640" height="480"></canvas>
<select name="mode" id="mode">
<option value="point">标记关键点</option>
<option value="rect">绘制矩形框</option>
</select>
<button id="undo" onclick="undo()">撤销</button>
<script>
const canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
pointArray = [],
history = []
let dragging = false,
mode = 'point',
mousedown = null
function Point(x, y, type) {
this.x = x
this.y = y
this.type = type // 左击 1 右击 3
}
// 坐标转化为canvas坐标
function windowToCanvas(x, y, type) {
//返回元素的大小以及位置
var bbox = canvas.getBoundingClientRect();
// bbox 的宽度会加上 canvas 的 border 会影响精度
return new Point(x - bbox.left * (canvas.width / bbox.width),
y - bbox.top * (canvas.height / bbox.height), type)
}
function drawPoint(point) {
context.save()
context.fillStyle = point['type'] === 3 ? 'red' : 'green'
context.beginPath();
context.arc(point.x, point.y, 3, 0, Math.PI * 2, true)
context.fill()
context.font = "20px serif";
context.fillText((pointArray.length).toString(), point.x - 5, point.y - 10)
context.restore()
pointArray.push(point)
}
function updateRect(point) {
let w = Math.abs(point.x - mousedown.x)
let h = Math.abs(point.y - mousedown.y)
let left = point.x > mousedown.x ? mousedown.x : point.x
let top = point.y > mousedown.y ? mousedown.y : point.y
context.save();
context.beginPath();
context.rect(left, top, w, h);
context.stroke();
context.restore();
}
function showLastHistory() {
context.putImageData(history[history.length - 1]['data'], 0, 0)
}
function undo() {
if (history.length > 1) {
history[history.length - 1]['mode'] === 'point' && pointArray.pop()
history.pop()
showLastHistory()
}
}
function addHistoy(data) {
history.push({
mode,
data: context.getImageData(0, 0, canvas.width, canvas.height)
})
}
document.getElementById('mode').onchange = function(e) {
mode = e.target.value
}
// 鼠标事件
canvas.onmousedown = function(e) {
e.preventDefault();
mousedown = windowToCanvas(e.clientX, e.clientY, e.which)
dragging = true
}
canvas.onmousemove = function(e) {
e.preventDefault();
if (dragging && mode === 'rect') { // 只有绘制矩形框时有效果
showLastHistory() // 每次绘制先清除上一次
updateRect(windowToCanvas(e.clientX, e.clientY, e.which))
}
}
addHistoy() // 添加一张默认的数据
canvas.onmouseup = function(e) {
e.preventDefault();
dragging = false
mode === 'point' && drawPoint(mousedown)
addHistoy() // 保存上一次数据
}
// 阻止页面的右击菜单栏
canvas.oncontextmenu = function(e) {
e.preventDefault()
}
</script>
</body>
</html>