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 中处理鼠标点击和拖动事件的方法,对于文章中错误的地方或者有任何问题,欢迎在评论区留言分享!

相关推荐
boooooooom5 分钟前
手把手做一个图 RAG 烹饪问答系统:Neo4j + Milvus + LLM 的工程实践
前端·javascript·后端
染指11103 小时前
103.RAG-LLamaIndex后端rag问答-聊天接口
前端·javascript·vue.js·人工智能
单线程_0111 小时前
从案例分析 Vue3 Tokenizer+Parser 源码三
前端·javascript·vue.js
小磊哥er13 小时前
深入解构Claude Code - 第 8 篇 · 数据放哪、钱怎么算
javascript·ai编程
kyriewen14 小时前
我装了30多个Skill,给AI安排了8个岗位
前端·javascript·ai编程
默_笙16 小时前
🔥 让 AI 帮我写完整个 Next.js 博客:框架就是 AI 的"上下文 buff"
前端·javascript
牧艺17 小时前
登录页还在用渐变?我一口气做了 5 个能摸的背景动效:吹蒲公英、滴墨染水、点熔岩闷裂
前端·canvas·交互设计
喵本喵叁肆19 小时前
06-M6-部门过滤与综合研判-从问答机到研判助手
前端·javascript·jquery
এ慕ོ冬℘゜20 小时前
JavaScript学习心得:从只会语法,到真正会写业务逻辑
开发语言·javascript·ecmascript