canvas在transform的时候都作了些啥?

欣仔最近在为厂里设计一个canvas框架,这个框架的目的是为了让vue 或者react 的脚手架在构建应用而且须要引用外部canvas框架的时候,使得框架和当前构建环境自己可以更好的融合,以及,这个框架支持webgl渲染。前端

固然在此期间以前有些曾经用到过但也是一带而过的技术点,顺带此次也跟着夯实了一下。vue

这篇文章讲述的是一些原理性的东西,若是做为开发人员你的你可以比较有耐性的看完,说明你有很大的潜力在“35”岁以后继续从事这份职业,或许还能保持一点相对的高薪,想必也是极好的。node


因此仍是要 WARNNING 一下:react

数学很差者退散!!!

你们都知道canvas现现在在H5项目中扮演的角色,也都大概知道canvas的一些基本的操做,常规的诸如:程序员

context.moveTo(100,100);
contect.lineTo(100,200);复制代码

这样的用法欣仔就很少说了,若是还有人不知道的,若是你已经不是初学者了,那对于这样的基本操做还不了解的话,那天然是不可原谅的了,自打300大板而后面壁思过以后去查漏补缺吧。。。web

说到这里,大家认为做为新时代的“前端开发者”,须要了解nodejs么?
canvas

欣仔今天话风比较收不住,厂里面隔壁中心的某产品与我对接工做的时候,说到他们组的前端不会nodejs。
bash

因而我就随口说了一句:“如今的前端不会nodejs是要被淘汰掉的”。。以后,他再也没有回我,大概是我说错话了。框架



固然我如今还不能保证个人组员每一个人都可以掌握nodejs的相关操做,可是我也在引导他们往这条路上前行。webgl

不过回到主题,欣仔在这篇文章中想要说的是诸如

context.translate(100,100);
context.scale(0.5);
context.rotate(20)复制代码

这些操做是如何影响到绘图的时候点的坐标的,其中的原理虽然不须要各位开发常规H5的时候去付诸实现,可是其却在其余场景中扮演者极其重要的功能,包括色阶的计算,滤镜的计算,以及更接近于底层的opengl/webgl的对应功能的运算原理都是一致的,市面上的3D引擎内三角块儿的顶点坐标的运算,也都是经过同样的方式实现的。

大概大家想不到(大佬除外)若是是一个

x+1//x坐标加1复制代码

这样一个明眼人都可以知道的很是简单的操做,在

translateX(x+1)复制代码

的时候都,内部都经历了些啥?

这里欣仔不经联想到了一种叫“认知隔阂”的东西,啥叫“认知隔阂”?欣仔我本身瞎掰的。。。大概意思就是,你所认为的简单的功能,实现起来比你想象得要复杂的多。

那实现一个x位移的数值加一有什么复杂的?的确不复杂,可是要实现一整套相似的功能集,好比x坐标的旋转,x坐标的缩放等操做,就相对比较繁琐,特别是处理一整块坐标集的时候。

其实程序员自己对于本身不了解的领域,依然也会有认知隔阂,有时候甚至也会有点想固然。这像极了产品经理或者account妹子相对于欣仔这样的程序员沟通的时候产生的认知隔阂。


回归正题:

context.translate(100,100);复制代码

这段代码的字面意思是画布的绘制区域移动分别移动至坐标(100,100)的位置,而后开始绘制。

这大概就是认知给咱们形成的一种假象,由于字面意思和最终效果的呈现能够完美的匹配。但实际上他是怎么去实现位置的变换的呢?

前人的科学家以他们的聪明才智,给了咱们一套不太为人知,却又高效的内在实现机制:矩阵运算,学术上叫。。。额。。。。线性代数。

当咱们认为的坐标(100,100)在矩阵中能够描述为:

|100, 0,  0,|
|0,  100, 0,|
|tx, ty,  1 |复制代码

x,y的值分别取了这个“矩阵”的‘00’位置和‘11’位置的值,分别再在对应的数值上加上tx 和 ty 。初始状况下,一个未作过变换的矩阵信息是:

|100, 0,  0,|
|0,  100, 0,|
|0,   0,  1 |复制代码

即:tx,ty都为0。针对于当前矩形,应用于他的元素的坐标的x和y分别都是

100+0复制代码

这只是利用矩阵计算坐标信息的一种约定方式,你看到的一个坐标的信息实际上包含了这么多数据,若是你想给一个元素设置一个具体的坐标,除了直观的x,y的直接赋值,还能够经过给他这样一个矩阵,让 x,y 作标与之创建关系映射。

那么当咱们想让(100,100)这个坐标变成(120,150)的时候,经过矩阵该怎么实现呢?

矩阵相乘

这是几乎全部我所见过的关于位移,以及像素颜色处理的基本公式。一个3x3的矩阵,与另一个3*3的矩阵相乘,获得另一个3*3的矩阵,更复杂的会是也会有4x4的矩阵相乘。

在这里呢,获得的那个结果矩阵,就根据上面欣仔提到的一个关系关联到对应的坐标。

好比:

|100, 0, 0,|
|0, 100 ,  0|
|0, 0, 1,|  
     x 
|1, 0 , 0| 
|0, 1, 0 |    
|tx,ty,1 |复制代码

这样的一个乘法,会获得一个什么样的结果?

根据矩阵的运算规则,以下简单的描述



由于自己这篇不是用来科普矩阵运算的,因此关于其计算过程也只能一笔带过了,如要欣仔去科普更多的东西,那也超过欣仔的知识范围了。固然若是你们有兴趣的话能够去搜一下线性代数的基础,但愿有所收获。现现在的线性代数已经大量的应用于人工智能相关的计算中了,这大概就是线性代数的魅力所在吧。固然咱们没有处在研究领域,因此只需知道相关的应用方式便可啦。

再次回归正题:我上面提到的相乘得过程应该是


|100, 0, 0,|
|, 100 , 0|
|0, 0, 1 ,| 
        x 
|1, 0 , 0|
|0, 1, 1 |
|tx, ty,1 |复制代码

简化的结果为:

|100,0, 0 |
|0, 100,0 |
|tx,ty, 1 |复制代码

根据上面提到的赋值方式,实际的结果就是(100+tx,100+ty)。

目标点若是是(120,150)的话,tx和ty分别就是20 和 50.

求乘矩阵就是


|1,   0,  0 |
|0,   1,  0 |
|20,  50, 1 |复制代码


由于默认状况下,左边的矩阵对应的元素默认的位置信息,tx和ty默认为0,右边的求乘矩形(如下都成为求乘矩阵)用于变换相乘,3x3的矩阵任何一个位置均可以赋值,结合这个公式,能够作出成各类各样的变换。

看起来是个很是复杂的过程,以致于包括欣仔在内的大部分人来讲,见到这样的场景也是须要先深吸一口气的。但稍加琢磨发现其也并非特别复杂不是么。特别是当你想要作一些高级的动效的时候,利用矩阵去计算会是一个很是不错的方法。

上面说了移动,接下来讲

缩放

当咱们须要将(100,100)缩放到(50,50)的时候,结合与上面的矩阵关系,咱们只须要进行矩阵运算

|100, 0,  0,|
|0.5, 0 , 0|
|0,  100, 0,|  
x 
|0, 0.5 , 0|
|0,   0,  1 |
|0,  0,  1 |  
 =
|50,0, 0 |
|0, 50,0 |
|0,0, 1  |复制代码

缩放的概念须要结合点集才能有效的表现,好比有10000个分布在画布上的点坐标构成了一个猫的形状,当这些坐标的数值统一缩放0.5倍,则能够获得一个缩放一半的的猫的形状。


说完缩放说说坐标转换


坐标转换是一个相对比较复杂的运算,坐标转换的需求能够用下面的图示表示:假设我如今的坐标点是A(x,y),旋转了特定的角度到C(c,d),目前只知道角度的大小angle,求出C的坐标。

(能看到这里吐血的人也退下吧,欣仔我对不住了。。。)


推导的过程我也很少说了,就直接用下面这个公式

c=cos(angle)*x-sin(angle)*y;
d=cos(angle)*y+sin(angle)*x;复制代码

若是把相同的因子用单独的变量表示以下

let cos=cos(angle);
let sin=sin(angle);
x1=cos*x-sin*y;y1=cos*y+sin*x;复制代码

把他放到咱们的矩阵的计算结果中描述以下:

|cos*x-sin*y,  0,      0|
|0,        cos*y+sin*x,0|
|0,            0,      1|   复制代码

那么再往上推导,能够得出求乘矩阵就是


|cos,sin, 0 |
|-sin,cos,0 |
|0,   0,  1 |复制代码

因此咱们要作一个坐标转换的功能,只需用上诉得出的求乘矩阵作一个这样的运算就能够了:


|100, 0,  0,|
|0, 100 ,  0|
|0,  0, 1,| 
 x 
|cos, -sin , 0|
|sin,   cos,  1 | 
|0,     0,  1 |  
=
|cos*x-sin*y,  0,      0|
|0,        cos*y+sin*x,0|
|0,            0,      1|复制代码


很感谢可以看到这里的同窗。。按照欣仔的认知范围,可以看到这里的人。。大概也就寥寥无几了,大概各自的心理也如同”人生太过艰辛,求放过“这样的感慨。只是想到那可怜巴巴的阅读数,欣仔的心也在滴血啊。



因此当我须要对点同时缩放,旋转,以及移动的是时候,原矩阵用三个不一样的矩阵作三次乘法。假设场景为:缩放0.5,旋转60度,以及向左向下平移100像素,计算过程以下:

原矩阵
|100, 0,  0,|
|0,  100, 0,|
|0,   0,  1 |     
X
平移矩阵
|1,   0,  0 |
|0,   1,  0 |
|100, 100,1 |     
X     
旋转矩阵
|cos(60),-sin(60), 0 |
|sin(60),cos(60),0 |
|0,      0,       1 |     
X     
缩放矩阵
|0.5,   0,  0 |
|0,   0.5,  0 |
|0,     0,  1 |复制代码

结果是那种做为读者的你第一眼没法看出端倪的矩阵值,因此就不贴出来了。

欣仔含着泪写到这里,也不想再多写了,生怕再写下去,就有人要取关了,因此我也要当心翼翼的结尾了。

后面的分享将结合以上所说的原理,作一篇实操的分享。将利用你们一致在争论的“TS究竟有什么用”这个话题的主角:TypeScript 去作一次开发分享给大家,但愿对你们有所帮助。

若是喜欢还没关注的话,就请扫描一下金光闪闪的QRCODE关注吧。

相关文章
相关标签/搜索