欣仔最近在爲廠裏設計一個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關注吧。