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是正弦的和角公式,保留了旋转的角度对应的三角函数,原始位置的角度被消掉。

相关推荐
林太白10 分钟前
npm多组件发布Vue3+TS版本,快来像Antd一样搭建属于你的UI库吧
前端·javascript·node.js
Juchecar17 分钟前
如何避免Node.js项目node_modules重复占用空间
前端
百罹鸟29 分钟前
nestjs 从零开始 一步一步实践
前端·node.js·nestjs
袁煦丞36 分钟前
Wiki.js团队知识大脑/个人笔记管家:cpolar内网穿透实验室第496个成功挑战
前端·程序员·远程工作
Alporal1 小时前
【前端学习】背闭包快疯了?我用实际场景搞懂了!
javascript
维他AD钙1 小时前
2025 年前端性能优化实战:从加载到渲染的全链路优化指南
前端
大米饭消灭者1 小时前
markdown-it是怎么将markdown转为html的
前端·面试
1024小神1 小时前
在vue/react项目中单独引入一个js文件,在js文件中使用DOMContentLoaded函数querySelectorAll为空数组解决办法
前端
moyu842 小时前
前端请求封装实战解析:基于Axios的封装技巧
前端