Canvas之图形变换

Canvas之图形变换

图形变换可以分为移动,旋转,放缩,以及矩阵斜切。

图形移动

js 复制代码
ctx.fillRect(0,0,100,100)
ctx.translate(100, 100);
ctx.beginPath();
ctx.moveTo(-400, 0);
ctx.lineTo(400, 0);
ctx.moveTo(0, -400);
ctx.lineTo(0, 400);
ctx.stroke();

ctx.beginPath();
ctx.arc(0, 0, 6, 0, Math.PI * 2)
ctx.fill()

ctx.beginPath();
for(let i=-400; i<=400; i+=10){
    ctx.moveTo(i, -5);
    ctx.lineTo(i, 5);
    ctx.moveTo(-5, i);
    ctx.lineTo(5, i);
    ctx.stroke();
}

ctx.fillRect(100, 100, 100, 100)

这里模拟了一个坐标系,可以看到,当使用 ctx.translate 时,整个坐标系都会进行移动,第一个参数是x偏移,第二个参数是y偏移。这种移动是进行位置变化,是瞬间完成的,不是动画。

当整个坐标系都跟着移动时,可以发现,设置在 translate 之前的图形不受影响,并没有发生移动。

图形放缩

js 复制代码
ctx.translate(0, 400);
ctx.scale(1, -1);

可以使用 ctx.scale 进行图形放缩,参数为x,y放缩比例。还是对坐标系进行放缩,如果小于1,表示缩小,大于1,表示放大。如果是负数,则改变了原来的坐标系方向。

上面的代码代表了将计算机坐标系变换为数学坐标系。只需要进行y轴坐标系的反转。

图像旋转

js 复制代码
ctx.beginPath();
// ctx.strokeStyle = '#f00';
// ctx.setLineDash([10]);
ctx.strokeRect(100, 100, 50, 50)

ctx.translate(125, 125);
ctx.rotate(Math.PI / 4);

ctx.fillRect(-25, -25, 50, 50)

可以进行图形旋转,旋转和 css 类似,不过旋转的是坐标系。传入需要旋转的角度,逻辑上需要角度,实际上传入弧度。旋转时按顺时针旋转。

由于是坐标系进行旋转,所以设置移动和旋转的顺序不同,最后的效果也不相同。并且要根据实际情况改变坐标系的位置以及图形的坐标。

矩阵变换

想要更好地实现变换效果需要使用矩阵变换。矩阵变换就是将一个原始的坐标通过一定的规则变为一个新坐标。这个新坐标为了更好的实现平移操作,将原来的坐标变为了齐次坐标,也就是增加了一个维度,最后一个维度和平移相关。

text 复制代码
|x|	  |a	c	e|		|x'|
|y|	* |b	d	f|	=	|y'|
|1|	  |0	0	1|		|1 |

x' = x*a + y*c + 1*e
y' = x*b + y*d * 1*f
1 =  x*0 + y*0 + 1*1

一列坐标对应一行矩阵,三行矩阵对应三个结果。为了保证两个坐标的x,y坐标一致,所以最后的一行统一为 0 0 1 。

使用 ctx.transform(a , b , c , d , e , f) 来进行一一对应。斜切只能通过矩阵变换的方式实现。

text 复制代码
1 0 e
0 1 f

平移变换,不改变x,y的大小,只改变最后的数值大小。

text 复制代码
a 0 0
0 d 0

放缩变换,x行和y行都对应具体的放缩大小。

text 复制代码
	1		tan(angle)	0
tan(angle) 		1		0

斜切变换,沿着x轴或者y轴进行拉扯,拉扯之后会有一个对应角度,x行会后一个y的拉扯角度,y行也一样。

text 复制代码
和角公式
sin(a+b) = sin(a) * cos(b) + cos(a) * sin(b)
cos(a+b) = cos(a) * cos(b) - sin(a) * sin(b)

cos(angle) -sin(angle) 0
sin(angle) cos(angle) 0

旋转变换,需要用到和角公式。a为原位置的旋转角度,b为原位置与x轴的夹角。因为旋转从x轴正方向开始,沿着顺时针进行旋转。

第一行x是余弦的和角公式,第二行y是正弦的和角公式,保留了旋转的角度对应的三角函数,原始位置的角度被消掉。

相关推荐
卸任7 小时前
Vibe coding工具使用心得
前端·ai编程
brien98 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance8 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M8 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写8 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李8 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易9 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
清晨Coding9 小时前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
风骏时光牛马9 小时前
前沿视界
前端
kyriewen9 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员