js 鼠标拖动canvas画布
功能点:
- 鼠标拖拽canvas画布移动
- 鼠标检测rect
- 鼠标检测circle
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>鼠标移动画布-事件检测</title>
<style>
html,
body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
overflow: hidden;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
const canvas = document.getElementById('canvas');
const { clientWidth: width, clientHeight: height } = document.body;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// 储累积的偏移量
let totalOffsetX = 0;
let totalOffsetY = 0;
// 缩放系数
let scale = 1;
// 图形数据
const shapes = [
{
type: 'rect',
x: 100,
y: 100,
width: 20,
height: 20,
strokeStyle: '#000',
fillStyle: '#f00',
},
{
type: 'circle',
x: 200,
y: 200,
radius: 10,
strokeStyle: '#000',
fillStyle: '#0f0',
},
{
type: 'polyline',
points: [
{ x: 200, y: 100 },
{ x: 150, y: 100 },
{ x: 200, y: 150 },
],
strokeStyle: '#000',
fillStyle: '#00f',
},
];
function render(offsetX, offsetY) {
// 绘制时需要使用beginPath,否则无法使用clearRect清空画布
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = '#999';
ctx.fillRect(0, 0, width, height);
ctx.fill();
ctx.translate(totalOffsetX, totalOffsetY);
ctx.scale(scale, scale);
shapes.forEach((shape) => {
const { type, x, y, width, height, radius, points } = shape;
ctx.fillStyle = shape.fillStyle;
ctx.beginPath();
if (type === 'rect') {
ctx.fillRect(x, y, width, height);
} else if (type === 'circle') {
ctx.arc(x, y, radius, 0, Math.PI * 2);
} else if (type === 'polyline') {
ctx.moveTo(points[0].x, points[0].y);
points.slice(1).forEach((point) => {
ctx.lineTo(point.x, point.y);
});
ctx.closePath();
}
ctx.fill();
});
ctx.resetTransform();
}
render();
canvas.addEventListener('mousedown', onMouseDown);
canvas.addEventListener('mousemove', onMouseMove);
canvas.addEventListener('mouseup', onMouseUp);
canvas.addEventListener('mouseleave', onMouseLeave);
canvas.addEventListener('wheel', onWheel);
let isMouseDown = false;
let startX, startY;
function onMouseDown(e) {
canvas.style.cursor = 'grab';
isMouseDown = true;
startX = e.offsetX;
startY = e.offsetY;
}
function onMouseMove(e) {
isShapePoint(e);
if (isMouseDown) {
totalOffsetX += e.offsetX - startX;
totalOffsetY += e.offsetY - startY;
startX = e.offsetX;
startY = e.offsetY;
requestAnimationFrame(render);
}
}
function onMouseUp(e) {
isMouseDown = false;
}
function onMouseLeave(e) {
isMouseDown = false;
}
function onWheel(e) {
// 缩放,最大5倍,最小0.2倍
if (e.deltaY === -100) {
if (scale + 0.1 > 5) return;
// 放大
scale += 0.1;
} else {
if (scale - 0.1 <= 0.2) return;
// 缩小
scale -= 0.1;
}
requestAnimationFrame(render);
}
// 检测设备
function isShapePoint(e) {
const { offsetX, offsetY } = e;
let check = false;
shapes.forEach((shape) => {
// 检测rect
if (shape.type === 'rect') {
const { type, x, y, width, height } = shape;
const transformedX = (offsetX - totalOffsetX) / scale;
const transformedY = (offsetY - totalOffsetY) / scale;
if (
transformedX >= x &&
transformedX <= x + width &&
transformedY >= y &&
transformedY <= y + height
) {
check = true;
}
} else if (shape.type === 'circle') {
// 检测圆形
const { x, y, radius } = shape;
const transformedX = (offsetX - totalOffsetX) / scale;
const transformedY = (offsetY - totalOffsetY) / scale;
const circleX = x;
const circleY = y;
// 计算光标与圆心的距离
const distance = Math.sqrt(
(transformedX - circleX) ** 2 + (transformedY - circleY) ** 2
);
if (radius >= distance) {
check = true;
}
} else if (shape.type === 'polyline') {
const { points: polygon } = shape;
let inside = false;
const transformedX = (offsetX - totalOffsetX) / scale;
const transformedY = (offsetY - totalOffsetY) / scale;
for (
let i = 0, j = polygon.length - 1;
i < polygon.length;
j = i++
) {
const xi = polygon[i].x,
yi = polygon[i].y;
const xj = polygon[j].x,
yj = polygon[j].y;
const intersect =
yi > transformedY !== yj > transformedY &&
transformedX <
((xj - xi) * (transformedY - yi)) / (yj - yi) + xi;
if (intersect) {
inside = !inside;
if (inside) {
check = true;
} else {
check = false;
}
}
}
}
});
if (check) {
canvas.style.cursor = 'move';
} else {
canvas.style.cursor = 'grab';
}
}
</script>
</body>
</html>