Canvas进阶篇:鼠标交互动画

Canvas进阶篇:鼠标交互动画

前言

在上一篇文章Canvas进阶篇:基本动画详解 中,我们讲述了在Canvas中实现动画的基本步骤和动画的绘制方法。本文将进一步讲述如何通过鼠标事件增加动画和用户的交互,包括捕获鼠标的点击和拖动事件,获取鼠标在 Canvas 中坐标等。

获取鼠标坐标

在进行鼠标交互时,最主要的是要获取鼠标在Canvas中画布中的坐标。通常我们获取到的鼠标坐标都是相对于浏览器窗口的;如果想要获取相对于 Canvas 画布的坐标,就需要进行坐标转换,可以通过以下方式实现:

javascript 复制代码
function getCanvasCoordinates(event) {
  const rect = canvas.getBoundingClientRect();
  const x = event.clientX - rect.left;
  const y = event.clientY - rect.top;
  return { x, y };
}

上述代码中,canvas.getBoundingClientRect()方法返回 Canvas 在浏览器窗口中的位置和尺寸信息,通过用鼠标相对于窗口的坐标减去 Canvas 左上角相对于窗口的坐标,就得到了鼠标在 Canvas 中的坐标。

鼠标事件

鼠标事件一共分为4类:鼠标点击事件click、鼠标按下事件mousedown、鼠标移动事件mousemove和鼠标松开事件mouseup

点击事件监听

利用点击事件,我们可以在鼠标点击的位置绘制各种图形,比如圆形等,示例代码如下:

代码示例

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>鼠标点击画圆</title>
		<style>
			#canvas {
				border: 1px solid #000;
			}
		</style>
	</head>
	<body>
		<canvas id="canvas" width="600" height="600"></canvas>
		<script>
			const canvas = document.getElementById('canvas');
			const ctx = canvas.getContext('2d');
			
			function getCanvasCoordinates(event) {
			  const rect = canvas.getBoundingClientRect();
			  const x = event.clientX - rect.left;
			  const y = event.clientY - rect.top;
			  return { x, y };
			}

			function handleClick(event) {
				const {
					x,
					y
				} = getCanvasCoordinates(event);
				ctx.beginPath();
				ctx.arc(x, y, 20, 0, 2 * Math.PI);
				ctx.fillStyle = 'red';
				ctx.fill();
			}

			// 绑定鼠标点击事件
			canvas.addEventListener('click', handleClick);
		</script>
	</body>
</html>

效果预览

拖动事件监听

实现拖动元素的功能,需要结合mousedownmousemovemouseup三个事件,我们以拖动一个矩形为例:

代码示例

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>鼠标拖动矩形</title>
		<style>
			#canvas {
				border: 1px solid #000;
			}
		</style>
	</head>
	<body>
		<canvas id="canvas" width="600" height="600"></canvas>
		<script>
			const canvas = document.getElementById('canvas');
			const ctx = canvas.getContext('2d');

			function getCanvasCoordinates(event) {
				const rect = canvas.getBoundingClientRect();
				const x = event.clientX - rect.left;
				const y = event.clientY - rect.top;
				return {
					x,
					y
				};
			}

			// 矩形数组
			let rectangles = [];

			// 拖拽状态
			let isDragging = false;
			let startX, startY;
			let offsetX, offsetY;
			let draggedRect = null;

			function handleMouseDown(event) {
				const {
					x,
					y
				} = getCanvasCoordinates(event);
				for (const rect of rectangles) {
					if (x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height) {
						isDragging = true;
						draggedRect = rect;
						startX = x;
						startY = y;
						offsetX = x - rect.x;
						offsetY = y - rect.y;
						break;
					}
				}
			}

			function handleMouseMove(event) {
				if (isDragging) {
					const {
						x,
						y
					} = getCanvasCoordinates(event);
					if (draggedRect) {
						draggedRect.x = x - offsetX;
						draggedRect.y = y - offsetY;
						drawCanvas();
					}
				}
			}

			function handleMouseUp() {
				isDragging = false;
				draggedRect = null;
			}

			function drawCanvas() {
				ctx.clearRect(0, 0, canvas.width, canvas.height);
				for (const rect of rectangles) {
					ctx.beginPath();
					ctx.rect(rect.x, rect.y, rect.width, rect.height);
					ctx.fillStyle = 'blue';
					ctx.fill();
				}
			}

            // 绘制矩形
			function addRectangle() {
				const rect = {
					x: Math.random() * (canvas.width - 100),
					y: Math.random() * (canvas.height - 100),
					width: 80 + Math.random() * 40,
					height: 60 + Math.random() * 40,
					color: `hsl(${Math.random() * 360}, 70%, 60%)`
				};
				rectangles.push(rect);
				drawCanvas();
			}

			// 绑定鼠标按下事件,用于拖动起始
			canvas.addEventListener('mousedown', handleMouseDown);
			// 绑定鼠标移动事件,用于拖动过程
			canvas.addEventListener('mousemove', handleMouseMove);
			// 绑定鼠标松开事件,用于拖动结束
			canvas.addEventListener('mouseup', handleMouseUp);
			addRectangle();
		</script>
	</body>
</html>

效果预览

结语

本文主要介绍了在 Canvas 中处理鼠标点击和拖动事件的方法,对于文章中错误的地方或者有任何问题,欢迎在评论区留言分享!

相关推荐
avi91115 小时前
[AI教做人]AI平台做2项目;一个3D模型展示,另一个框架多人
javascript·人工智能·ai·3d模型·3d引擎·顶点和法线
kyriewen5 小时前
我用Claude Code两天干完了团队两周的排期——周报发出去那一刻我就后悔了
前端·javascript·ai编程
用户938515635076 小时前
手写一个 LLM Harness 框架:用工程化手段把大模型幻觉踩在脚下
javascript·人工智能·后端
油丶酸萝卜别吃7 小时前
jquery-ajax.js 说明文档
前端·javascript·jquery
windliang7 小时前
Claude Code 源码分析(九):子 Agent 如何分叉、继续与回到父会话
前端·javascript·面试
柒和远方8 小时前
V063: TS 面试必考:interface 与 type 的四大差异,与 LLM Harness 的自动化择优
前端·javascript
汉堡大王95278 小时前
Vue 3 + TS + Element Plus 实战:如何从零搭建企业级违章记录管理 SaaS 前端
前端·javascript·vue.js
海天鹰8 小时前
屏幕颜色检测
javascript·html5
用户7917286761979 小时前
opencode-plugin-peers完全指南:OpenCode如何实现 Claude Code式跨会话消息
javascript
andr_gale11 小时前
02_uniapp自定义上凸效果的底部TabBar
前端·javascript·uni-app·移动端