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

相关推荐
二十雨辰1 分钟前
vite快速上手
前端
Dxy12393102169 分钟前
Python对图片进行加密,js前端进行解密
前端·javascript·python
支付宝体验科技10 分钟前
SEE Conf 2025 来啦,一起探索 AI 时代的用户体验与工程实践!
前端
江城开朗的豌豆22 分钟前
路由对决:Vue Router vs React Router,谁是你的菜?
前端·javascript·react.js
建群新人小猿23 分钟前
客户标签自动管理:标签自动化运营,画像持久保鲜
android·java·大数据·前端·git
代码797224 分钟前
【无标题】使用 Playwright 实现跨 Chromium、Firefox、WebKit 浏览器自动化操作
运维·前端·深度学习·华为·自动化
Zuckjet_26 分钟前
第 5 篇:WebGL 从 2D 到 3D - 坐标系、透视与相机
前端·javascript·3d·webgl
天蓝色的鱼鱼26 分钟前
高效开发之选:六款优秀的Vue3开源后台模板全面解析
前端·vue.js
江城开朗的豌豆30 分钟前
Redux工作流大揭秘:数据管理的"三重奏"
前端·javascript·react.js
大鱼前端33 分钟前
告别 Electron 的臃肿:用 Tauri 打造「轻如鸿毛」的桌面应用
前端