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

相关推荐
夏鹏今天学习了吗4 小时前
【性能优化】前端高性能优化策略
前端·性能优化
weixin_427771618 小时前
css font-size 的妙用
前端·css
凤凰战士芭比Q8 小时前
web中间件——Nginx
前端·nginx·中间件
一 乐9 小时前
点餐|智能点餐系统|基于java+ Springboot的动端的点餐系统小程序(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·小程序·论文
视图猿人9 小时前
RxJS基本使用及在next.js中使用的例子
开发语言·javascript
bitbitDown9 小时前
从零打造一个 Vite 脚手架工具:比你想象的简单多了
前端·javascript·面试
liangshanbo121510 小时前
CSS 数学函数完全指南:从基础计算到高级动画
前端·css
码上成长11 小时前
GraphQL:让前端自己决定要什么数据
前端·后端·graphql
冴羽11 小时前
为什么在 JavaScript 中 NaN !== NaN?背后藏着 40 年的技术故事
前端·javascript·node.js
久爱@勿忘11 小时前
vue下载项目内静态文件
前端·javascript·vue.js