canvas实现图片缩放+涂鸦

文章介绍了如何利用HTML5Canvas实现缩放时保持绘制内容清晰的效果。通过创建缓存canvas保存原始内容,在缩放时清空当前canvas并重新绘制缓存canvas内容,确保等比例缩放。文中提供了详细的代码示例和操作步骤,虽然作者承认自己对CanvasAPI有些生疏,但通过实践解决了这个问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这两天有人问了上面这个标题的问题,老实说,我一个后端程序员,感觉还是有一点难度的,主要是好多东西都忘记了。正好星期天了,抽时间弄一个简单的实现出来,正好也能写一篇博客了。

效果演示

在这里插入图片描述

分析

创建一个缓存的canvas对象,保存当前canvas中的内容,在屏幕canvas上绘制图像时,同时也在缓存canvas中进行等比例的绘制。然后,在缩放操作时,首先要清空当前 canvas 的内容,然后把缓存 canvas 的内容,绘制到当前canvas中,即可实现该效果了。这里的难点在于等比例绘制时的对应关系。我在当前canvas上设置的是红色画笔,但是缓存 canvas 中,没有设置(默认是黑色),所以你可以看到我缩放的时候,所显示的画笔颜色里面变黑了。实际上不是变成黑色了,而是当前的 canvas 被缓存的 canvas 内容覆盖了,因为是等比例绘制,所以看起来的感觉是画笔变黑了(哈哈,已绘制的线条是无法变黑的,这是canvas的机制决定的,立即模式)。

代码

通过 http 协议在浏览器访问这个页面即可(同目录下放一张图片,注意名字和代码里面的一致)。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style type="text/css">
			* {
				margin: 0;
				padding: 0;
			}
			#cas {
				clear: left;
				width: 800px;
				border: #e90d0d 1px solid;
			}
		</style>
	</head>
	<body>
		<div id="cas">
			<canvas id="cs" width="800" height="800"></canvas>
		</div>

		<script type="text/javascript">				
			var canvas = document.getElementById("cs");       //获取画布
			var ctx = canvas.getContext("2d");
			var cacheCanvas = document.createElement("canvas"); // 缓存画布
			var cacheCtx = cacheCanvas.getContext("2d");
			cacheCanvas.width = canvas.width;
			cacheCanvas.height = canvas.height;
			ctx.lineWidth = 10;
			ctx.strokeStyle = "#e90d0d"

            var img = new Image();
            img.src = "./husky.png";
            img.onload = () => {
                ctx.drawImage(img, 0, 0);
				cacheCtx.drawImage(canvas, 0, 0);  // 加载完即将当前画布内容写入缓存画布
            }
			
			/* 用户绘制的动作,可以分解为如下操作:
				1.按下鼠标
				2.移动鼠标
				3.松开鼠标
				
			   它们分别对应于鼠标的onmousedown、onmousemove和onmouseup事件。
			   并且上述操作必然是有想后顺序的,因为人的操作必然是几个操作
			   集合中的一种。所以我们需要来限定以下,过滤用户的无效操作,
			   只对按照上诉顺序的操作进行响应。
			*/
			let isDowned = false;  // 是否按下鼠标,默认是false,如果为false,则不响应任何事件。

			// 开始添加鼠标事件
			canvas.onmousedown = (e) => {
				let x = e.clientX - canvas.offsetLeft;
				let y = e.clientY - canvas.offsetTop;
				isDowned = true;   // 设置isDowned为true,可以响应鼠标移动事件
				console.log("当前鼠标点击的坐标为:(", x + ", " + y + ")");
				ctx.beginPath();    // 开始一个新的路径
				ctx.moveTo(x, y);   // 移动画笔到鼠标的点击位置

				// 在缓存canvas中按照比例进行等比例缩小绘制
				cacheCtx.lineWidth = ctx.lineWidth/ZOOM[zoom_pos];
				cacheCtx.beginPath();
				let pos = getScalePos(ZOOM[zoom_pos], x, y);
				cacheCtx.moveTo(pos.x, pos.y);
			}
			
			canvas.onmousemove = (e) => {
				if (!isDowned) {
					return ;
				}
				let x = e.clientX - canvas.offsetLeft;
				let y = e.clientY - canvas.offsetTop;
				ctx.lineTo(x, y);    // 移动画笔绘制线条
				ctx.stroke();


				// 在缓存canvas中按照比例进行等比例缩小绘制
				let pos = getScalePos(ZOOM[zoom_pos], x, y);
				cacheCtx.lineTo(pos.x, pos.y);
				cacheCtx.stroke();
			}

			function getScalePos(size, x , y) {
				// 计算放大后,等比例对应的位置,这里需要多理解。
				return {
					x: (canvas.width*(size-1)/2+x)/size,
					y: (canvas.height*(size-1)/2+y)/size
				}
			}
			
			canvas.onmouseup = (e) => {
				isDowned = false;
			}
			
			/*
				在按下鼠标移动的过程中,如果移出了画布,则无法触发鼠标松开事件,即onmouseup。
				所以需要在鼠标移出画布时,设置isDowned为false。
			*/
			canvas.onmouseout = (e) => {
				isDowned = false;
			}


			// 定义一个缩放数组,初始在 1.0 位置
			const ZOOM = [1.0, 1.2, 1.4, 1.6, 1.8, 2.0];
			let zoom_pos = 0;

            canvas.onmousewheel  = (e) =>  {  
				let x = e.clientX - canvas.offsetLeft;
				let y = e.clientY - canvas.offsetTop;              
                delta = e.wheelDelta;
                if (delta > 0) {
                    if (zoom_pos + 1 < ZOOM.length) {
						zoom_pos += 1;
					} else {
						zoom_pos = ZOOM.length - 1;
					}
                } else {
                    if (zoom_pos - 1 >= 0) {
						zoom_pos -= 1;
					} else {
						zoom_pos = 0;
					}
                }

				let xx = 0, yy = 0, dd = 0, hh = 0;
				let size = ZOOM[zoom_pos];
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                ctx.save();
				// 简单的等比例扩大,以canvas为中心。
				ctx.drawImage(cacheCanvas, (1-size)*canvas.width/2, (1-size)*canvas.height/2, canvas.width*size, canvas.height*size);
                ctx.restore();
				console.log(size);
            }
			
		</script>
	</body>
	
</html>

不足

我自己都有大半年没有接触 Canvas 了,里面的 api 我都快忘记了,不过这个问题蛮有趣的,我想了好久,也看了一些资料。不过,基本上只有缩放,或者只有绘制的,两种结合的没有。可能也是搜索的方式不太对吧。这个博客写得很急,代码也很乱,不过看思路就好了。代码,说不定还有 bug 没有发现呢,哈哈。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值