從matrix變換函數矩陣來說明CSS Transform的原理和操作

文章以二維變換爲例說明,三維變換採用類似的操作理解即可。

變換的座標系統

默認的變換座標系統,變換原點爲元素中心,x軸與y軸與web中定義的一致。其中,變換原點可以用transform-origin屬性來設置。transform是以該座標系統爲參考,對變換中圖形上每個點的座標進行更新,來得到變換後的圖形。

線性變換

線性變換需要滿足兩個條件:

  1. 不改變座標原點
  2. 每個點的座標在更新時,採用線性函數來更新。用數學中的線性方程表達如下{x=ax+cyy=bx+dy\begin{cases}x\prime =&ax+cy\\ y\prime =&bx+dy\end{cases}
    用矩陣的形式表示爲[xy]=[acbd][xy]\begin{bmatrix}x\prime \\ y\prime \end{bmatrix} =\begin{bmatrix}a&c\\ b&d\end{bmatrix} \begin{bmatrix}x\\ y\end{bmatrix}
    CSS Transform中,除了translate變換外,其他都屬於線性變換。因此,除了translate外,其他變換可以用2*2的矩陣描述如下[acbd]\begin{bmatrix}a&c\\ b&d\end{bmatrix} ,而translate變換需要額外描述,因此CSS Transform的矩陣描述如下[acebdf001]\begin{bmatrix}a&c&e\\ b&d&f\\ 0&0&1\end{bmatrix} 其中,[acebdf]\begin{bmatrix}a&c&e\\ b&d&f\end{bmatrix} 其實足夠描述二維變換了,最後一行是爲了矩陣運算而補充的。e和f就是爲了translate而增加的額外描述,e用來描述translateX,f用來描述translateY。

matrix()函數

CSS Transform中的所有變換,實際上都是matrix()函數的封裝,爲了便於記憶和使用。在二維變換中,matrix()函數接收6個參數爲matrix(a, b, c, d, e, f),即爲上文中的矩陣元素。matrix()函數本質上就是上文中的變換矩陣,對於不同的變換,6個參數各不相同。
下列變換中,假設沒有變換時,圖形上點的座標爲(x, y),變換後爲(x’, y’)。爲了方便運算,點的座標額外增加一行爲1;

沒有變換

matrix矩陣爲[100010001]\begin{bmatrix}1&0&0\\ 0&1&0\\ 0&0&1\end{bmatrix} ,爲一個3*3的單位矩陣。因此,所有點的座標沒有任何變化。

translate變換

translate變換隻是給e和f賦值,其中translateX()給e賦值,translateY()給f賦值,此時matrix矩陣爲[10e01f001]\begin{bmatrix}1&0&e\\ 0&1&f\\ 0&0&1\end{bmatrix}
變換的過程表示爲[xy1]=[10e01f001][xy1]\begin{bmatrix}x\prime \\ y\prime \\ 1\end{bmatrix} =\begin{bmatrix}1&0&e\\ 0&1&f\\ 0&0&1\end{bmatrix} \begin{bmatrix}x\\ y\\ 1\end{bmatrix} 線性方程爲
{x=x+ey=y+f\begin{cases}x\prime =&x+e\\ y\prime =&y+f\end{cases}
可以看出,translate變換相當於在原來座標系統下,每個點的x座標增加e,y座標增加f,得到了新的座標。

改變座標原點的理解:也可以這樣理解,讓e和f都等於0,此時每個點的座標都不變,而座標系統的原點從(0, 0)移動到了(e, f)。從這個角度來看,translate改變了座標原點的位置。也就是說,原來的圖形座標都不用變,只要把座標原點移動到(e, f)的位置即可。注意:(e, f)這個位置座標是以原座標系統爲參考點的。用這種方式理解的前提是,原來的座標系統用來定位新的座標系統,新的座標系統用來定位圖形的座標。

rotate變換

rotate()變換是指圍繞原點,旋轉某個角度α,正數表示順時針旋轉,負數表示逆時針旋轉。對應於matrix矩陣,指的是[cosαsinα0sinαcosα0001]\begin{bmatrix}cos\alpha &-sin\alpha &0\\ sin\alpha &cos\alpha &0\\ 0&0&1\end{bmatrix} 變換的過程表示爲[xy1]=[cosαsinα0sinαcosα0001][xy1]\begin{bmatrix}x\prime \\ y\prime \\ 1\end{bmatrix} =\begin{bmatrix}cos\alpha &-sin\alpha &0\\ sin\alpha &cos\alpha &0\\ 0&0&1\end{bmatrix} \begin{bmatrix}x\\ y\\ 1\end{bmatrix} 線性方程爲{x=xcosαysinαy=xsinα+ycosα\begin{cases}x\prime =&x\cos \alpha -y\sin \alpha \\ y\prime =&x\sin \alpha +y\cos \alpha \end{cases}
可以看出,旋轉變換是對x和y座標進行三角函數運算

scale變換

scale()變換是指對圖形的縮放,按照某個比例放大或縮小圖形。縮放是對x軸和y軸座標刻度的更改,因此對應於matrix矩陣,指的是[a000d0001]\begin{bmatrix}a&0&0\\ 0&d&0\\ 0&0&1\end{bmatrix} a表示x軸的縮放比例,d表示y軸的縮放比例。變換的過程爲[xy1]=[a000d0001][xy1]\begin{bmatrix}x\prime \\ y\prime \\ 1\end{bmatrix} =\begin{bmatrix}a&0&0\\ 0&d&0\\ 0&0&1\end{bmatrix} \begin{bmatrix}x\\ y\\ 1\end{bmatrix} 線性方程爲{x=axy=dy\begin{cases}x\prime =&ax\\ y\prime =&dy\end{cases} 可以看出,的確是將x座標乘以a,將y座標乘以d。

skew變換

skew()變換指的是將圖形的水平線或垂直線做一定程度的傾斜,即看起來變歪了。由於傾斜涉及到角度,因此matrix矩陣爲[1tanθx0tanθy10001]\begin{bmatrix}1&\tan \theta_{x} &0\\ \tan \theta_{y} &1&0\\ 0&0&1\end{bmatrix} 其中,θx和θy分別爲skewX()和skewY()的參數,θx表示垂直線傾斜角(正數表示向x軸正半軸傾斜),θy表示水平線傾斜角(正數表示向y軸正半軸傾斜)。這一點從線性方程中可以看出。變換過程爲[xy1]=[1tanθx0tanθy10001][xy1]\begin{bmatrix}x\prime \\ y\prime \\ 1\end{bmatrix} =\begin{bmatrix}1&\tan \theta_{x} &0\\ \tan \theta_{y} &1&0\\ 0&0&1\end{bmatrix} \begin{bmatrix}x\\ y\\ 1\end{bmatrix} 線性方程爲{x=x+ytanθxy=y+xtanθy\begin{cases}x\prime =&x+y\tan \theta_{x} \\ y\prime =&y+x\tan \theta_{y} \end{cases} 從中可以看出,x和y座標都是在原來基礎上,增加了一部分由角度決定的量,結果就是變歪了。

複合變換

這裏的複合變換,指的是一個transform屬性中,包含以上幾個變換,由以上幾個變換按順序組成。這裏的順序非常重要,因爲順序不同,最後得到的matrix矩陣會不同。尤其在包含translate變換的情況下,因爲translate的非線性,導致的變換差異很大。
複合變換的規則是,transform屬性中,按從左向右的順序,將代表各個變換的matrix矩陣依次相乘,得到最終的matrix矩陣。由於矩陣乘法不滿足交換律,因此這裏的順序很重要。另外,translate如果放在其他變換的右邊,其他變換就會連translate變換一起變換。聽起來很亂吧,下面用matrix矩陣相乘的法則來演示。

transform: rotate(α) translate(e, f)

以上面的變換爲例,這意味着先進行translate變換,再進行rotate變換。變換過程爲[xy1]=[cosαsinα0sinαcosα0001][10e01f001][xy1]\begin{bmatrix}x\prime \\ y\prime \\ 1\end{bmatrix} =\begin{bmatrix}\cos \alpha &-\sin \alpha &0\\ \sin \alpha &\cos \alpha &0\\ 0&0&1\end{bmatrix} \begin{bmatrix}1&0&e\\ 0&1&f\\ 0&0&1\end{bmatrix} \begin{bmatrix}x\\ y\\ 1\end{bmatrix} 把中間的matrix矩陣計算一下[cosαsinα0sinαcosα0001][10e01f001]=[cosαsinαecosαfsinαsinαcosαesinα+fcosα001]\begin{bmatrix}\cos \alpha &-\sin \alpha &0\\ \sin \alpha &\cos \alpha &0\\ 0&0&1\end{bmatrix} \begin{bmatrix}1&0&e\\ 0&1&f\\ 0&0&1\end{bmatrix} =\begin{bmatrix}\cos \alpha &-\sin \alpha &e\cos \alpha -f\sin \alpha \\ \sin \alpha &\cos \alpha &e\sin \alpha +f\cos \alpha \\ 0&0&1\end{bmatrix} 線性方程爲{x=xcosαysinα+ecosαfsinαy=xsinα+ycosα+esinα+fcosα\begin{cases}x\prime =&x\cos \alpha -y\sin \alpha +e\cos \alpha -f\sin \alpha \\ y\prime =&x\sin \alpha +y\cos \alpha +e\sin \alpha +f\cos \alpha \end{cases}

理解方式1:座標原點不變

從這裏可以看出,變換後的座標相當於對原座標做rotate變換,加上對translate增加的座標做的rotate變換。如果我們寫成{x=(x+e)cosα(y+f)sinαy=(x+e)sinα+(y+f)cosα\begin{cases}x\prime =&\left( x+e\right) \cos \alpha -\left( y+f\right) \sin \alpha \\ y\prime =&\left( x+e\right) \sin \alpha +\left( y+f\right) \cos \alpha \end{cases} 可以看出,先做translate變換,然後將變換後的座標整體再做rotate變換。我們的座標系統沒有變,座標原點仍然是(0, 0),將translate所做變換後的座標,再一起做rotate變換。對應到圖形上,就是讓圖形先做translate變換,然後變換後的圖形再做rotate變換(座標原點爲(0, 0) )。

理解方式2:座標原點隨translate改變

根據translate變換會更改座標原點的方式,座標原點變爲[ecosαfsinαesinα+fcosα]\begin{bmatrix}e\cos \alpha -f\sin \alpha \\ e\sin \alpha +f\cos \alpha \end{bmatrix} ,此時圖形的座標相對於新的座標系,則線性方程變爲{x=xcosαysinαy=xsinα+ycosα\begin{cases}x\prime =&x\cos \alpha -y\sin \alpha \\ y\prime =&x\sin \alpha +y\cos \alpha \end{cases}
此時的操作相當於,對座標原點進行平移translate(e, f),然後再rotate(α),最後再對圖形在新座標原點上做rotate(α)。因此,translate變換如果在其他變換的右邊,則其他變換要加在translate變換上再對座標原點做變換。其實,用座標原點跟隨translate改變的理解方式比較複雜。

因此,複合變換中,translate變換如果出現在其他變換的右邊,那麼該複合變換不是變換之間簡單的線性疊加,而是translate變換會與其他變換進行線性疊加(應用到座標原點,從而得到新的座標原點),再將其他變換線性疊加(直接給圖形在新座標系應用這些變換)
transform: translate(e, f) rotate(α)

作爲對比,來看一下順序相反的情況。計算得到最終的matrix矩陣爲[cosαsinαesinαcosαf001]\begin{bmatrix}\cos \alpha &-\sin \alpha &e\\ \sin \alpha &\cos \alpha &f\\ 0&0&1\end{bmatrix} 線性方程爲{x=xcosαysinα+ey=xsinα+ycosα+f\begin{cases}x\prime =&x\cos \alpha -y\sin \alpha +e\\ y\prime =&x\sin \alpha +y\cos \alpha +f\end{cases} 可以看出,先rotate操作,再直接加上translate(e, f)座標增量即可,不會出現上方的對translate()座標增量也要rotate的操作。

transform: skew(θx, θy) rotate(α)與transform: rotate(α) skew(θx, θy)的對比

由於不涉及translate變換,所以我們用2*2的矩陣表示就可以了。
transform: skew(θx, θy) rotate(α)對應的matrix矩陣爲[1tanθxtanθy1][cosαsinαsinαcosα]=[cosα+sinαtanθxsinα+cosαtanθxsinα+cosαtanθycosαsinαtanθy]\begin{bmatrix}1&\tan \theta_{x} \\ \tan \theta_{y} &1\end{bmatrix} \begin{bmatrix}\cos \alpha &-\sin \alpha \\ \sin \alpha &\cos \alpha \end{bmatrix} =\begin{bmatrix}\cos \alpha +\sin \alpha \tan \theta_{x} &-\sin \alpha +\cos \alpha \tan \theta_{x} \\ \sin \alpha +\cos \alpha \tan \theta_{y} &\cos \alpha -\sin \alpha \tan \theta_{y} \end{bmatrix}
線性方程爲{x=(xcosαysinα)+(xsinα+ycosα)tanθxy=(xsinα+ycosα)+(xcosαysinα)tanθy\begin{cases}x\prime =&\left( x\cos \alpha -y\sin \alpha \right) +\left( x\sin \alpha +y\cos \alpha \right) \tan \theta_{x} \\ y\prime =&\left( x\sin \alpha +y\cos \alpha \right) +\left( x\cos \alpha -y\sin \alpha \right) \tan \theta_{y} \end{cases} 可以發現,正好是rotate後的座標再進行skew()的過程。如果我們定義xr和yr爲rotate後的座標,可以清晰地發現這一點。rotate後的座標如下{xr=xcosαysinαyr=xsinα+ycosα\begin{cases}x_{r}=&x\cos \alpha -y\sin \alpha \\ y_{r}=&x\sin \alpha +y\cos \alpha \end{cases} 再進行skew的座標如下{x=xr+yrtanθyy=yr+xrtanθx\begin{cases}x\prime =&x_{r}+y_{r}\tan \theta_{y} \\ y\prime =&y_{r}+x_{r}\tan \theta x\end{cases}
transform: rotate(α) skew(θx, θy)對應的matrix矩陣爲[cosαsinαsinαcosα][1tanθxtanθy1]=[cosαsinαtanθysinα+cosαtanθxsinα+cosαtanθycosα+sinαtanθx]\begin{bmatrix}\cos \alpha &-\sin \alpha \\ \sin \alpha &\cos \alpha \end{bmatrix} \begin{bmatrix}1&\tan \theta_{x} \\ \tan \theta_{y} &1\end{bmatrix} =\begin{bmatrix}\cos \alpha -\sin \alpha \tan \theta_{y} &-\sin \alpha +\cos \alpha \tan \theta_{x} \\ \sin \alpha +\cos \alpha \tan \theta_{y} &\cos \alpha +\sin \alpha \tan \theta_{x} \end{bmatrix} 線性方程爲{x=xr+yrtanθxyr=yr+xrtanθy\begin{cases}x\prime =&x_{r}+y_{r}\tan \theta_{x} \\ y_{r}=&y_{r}+x_{r}\tan \theta y\end{cases}

這說明,線性變換之間的順序不會引入對座標原點的變換,只要按照順序依次應用變換即可。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章