CSS3 transform 中的 matrix

CSS的transforn詳解

位移,旋轉,偏移,縮放分別使用translate/rotate/skew/scale的方式來控制元素變換,也可以使用matrix。

使用translate/rotate/skew/scale

.demo{
  transform:translate(10px, 20px) rotate(30deg) scale(1.5, 2); 
}

matrix

.demo{
  transform:matrix(0.75, 0.8, -0.8, 1.2, 10, 20)
}

Matrix的中文是矩陣,在計算機科學中,會用矩陣來對向量進行變換,在css3的transform屬性中,可以使用矩陣對圖像進行變換。

matrix與矩陣對應

css3里面可以用矩陣表示2D和3D轉換

.demo{
  transform:matrix(a,b,c,d,e,f)
}
矩陣

2D的轉換是由一個3*3的矩陣表示的,前兩行代表轉換的值,分別是 a b c d e f ,要注意是豎著排的,第一行代表的是X軸變化,第二行代表的是Y軸的變化,第三行代表的是Z軸的變化,2D不涉及到Z軸,這里使用 0 0 1

假設一個問題

創建一個寬高為200px的div ,div 里面有一個紅色的點,位置是{x:181px y:50px}

矩陣

倘若將這個div向右平移20px,旋轉37°,x軸縮放1.5倍,y軸縮放2倍

transform:tranlate(10px,20px) rotate(37deg) scale(1.5, 2)
矩陣

縮放scale(x,y)

縮放對應的是矩陣中的adx軸的縮放比例對應a,y軸的縮放比例對應d

transform:scale(x,y)
a = x
d = y

所以scale(1.5, 2)對應的矩陣是

matrix:(1.5,0,0,0,2,0)
(矩陣).png

如果元素沒有被縮放,默認a = 1 d =1

平移 translate(10, 20)

平移對應的是矩陣中 ef,平移的xf分別對應 ef

transform:translate(10, 20)
e = 10
f = 20 

對應:transform: matrix(a, b, c, d ,10, 20);

結合縮放:transform: matrix(1.5 0, 0, 2, 10, 20)

旋轉 rotate(0deg)

旋轉影響的是a/b/c/d四個值,分別是什么呢?

transform: rotate(θdeg)

a=cosθ

b=sinθ

c=-sinθ

d=cosθ

如果要計算 30° 的sin值:

首先我們要將 30° 轉換為弧度,傳遞給三角函數計算。用 JS 計算就是下面的樣子了。

// 弧度和角度的轉換公式:弧度=π/180×角度 
const radian = Math.PI / 180 * 30 // 算出弧度
const sin = Math.sin(radian) // 計算 sinθ
const cos = Math.cos(radian) // 計算 cosθ
console.log(sin, cos) // 輸出 ≈ 0.5, 0.866
transform: rotate(30deg)

a=0.866

b=0.5

c=-0.5

d=0.866

transform: matrix(0.866, 0.5, -0.5, 0.866, 0, 0);
矩陣

偏移 skew(20deg, 30deg)

上面的題目中沒有出現出現偏移值,偏移值也是由兩個參數組成,x 軸和 y 軸,分別對應矩陣中的 c 和 b。是 x 對應 c,y 對應 b, 這個對應并不是相等,需要對 skew 的 x 值 和 y 值進行 tan 運算。

transform: skew(20deg, 30deg);

b=tan30°

c=tan20°

注意 y 對應的是 c,x 對應的是 b。
transform: matrix(a, tan(30deg), tan(20deg), d, e, f)

使用 JS 來算出 tan20 和 tan30

// 先創建一個方法,直接返回角度的tan值
function tan (deg) {
    const radian = Math.PI / 180 * deg
    return Math.tan(radian)
}
const b = tan(30)
const c = tan(20)
console.log(b, c) // 輸出 ≈ 0.577, 0.364

b=0.577 c=0.364
transform: matrix(1, 0.577, 0.364, 1, 0, 0)

旋轉+縮放+偏移+位移怎么辦?

如果我們既要旋轉又要縮放又要偏移,我們需要將旋轉和縮放和偏移和位移多個矩陣相乘,要按照transform里面rotate/scale/skew/translate所寫的順序相乘。
這里我們先考慮旋轉和縮放,需要將旋轉的矩陣和縮放的矩陣相乘

實在是用語言解釋不清楚如何去乘,用一張圖解釋吧:

這里我用小寫字母代表第一個矩陣中的值,大寫字母代表第二個矩陣里的值


1.png

將我們的已經得到的矩陣帶入到公式


2.png

得出:

transform: rotate(30) scale(1.5 2);

轉換為 matrix 表示為:

transform: matrix(1.299, 0.75, -1, 1.732, 0, 0);

找到這次轉換的矩陣

div 的 transform 值如下

transform: translate(10px, 20px) rotate(37deg) scale(1.5, 2);

#### translate(10px, 20px)

x 平移 10px,y 平移 20px,所以 e=10,f=20。


(矩陣

rotate(37deg)

sin37° ≈ 0.6

cos37° ≈ 0.8

根據 a 對應 cos b,對應 sin,c 對應 -sin,d 對應 cos 的值

得到:

a=0.8,b=0.6,c=-0.6,d=0.8
1.png

scale(1.5, 2)

x 軸縮放 1.5,y 軸縮放 2,所以 a=1.5,d=2

1.png

結合

transform: translate(10px, 20px) rotate(37deg) scale(1.5, 2);

我們使用 位移矩陣 旋轉矩陣 縮放矩陣(根據transform中的變換類型書寫的順序)

可以使用矩陣計算器進行計算

從左往右依次計算

10.png

所以最終得到矩陣


11.png
matrix(1.2, 0.9, -1.2 1.6, 10, 20)

驗證一下

transform: matrix(1.2, 0.9, -1.2 1.6, 10, 20)

transform: translate(10px, 20px) rotate(37deg) scale(1.5, 2);

效果是一樣的

如何對一個坐標進行矩陣變換

我們已經知道了這個矩陣,如何通過矩陣對一個坐標進行變化,找到這個坐標變化后的位置呢?

我們用之前得出的變換矩陣去乘以這一個坐標組成的3*1(三排一列)矩陣。


2.png

上面已經介紹過如何進行矩陣乘法了,這里在介紹一遍

3.png

上圖中左右兩個矩陣顏色相同的位置相乘后相加,每一行都進行這樣的計算:

4.png

得到一個3*1的矩陣,第一行是轉換后的 x 值,第二行是轉換后的 y 值,第三行是轉換后的 z 值(2d不考慮z值)。

前面講到,矩陣的第一行影響 x,第二行影響 y,也體現在這個地方。

假設我們的坐標是(50, 80),這里還沒有針對我們提出的問題上面的點進行計算。

我們把坐標寫成矩陣的形式,設置 z 軸是1:

5.png

然后進行乘法計算:


6.png

通過我們計算出來的矩陣變換得到新的位置(46, 172)

繼續剛剛問題

坐標是需要基于一個坐標系存在的,我們需要找到正確的坐標系才能算出準確的坐標。 在 CSS transform 中,有個屬性是 transform-origin,來設置變換所基于的點,默認是transform-origin: 50% 50%,基于中間元素的中心點。我們需要以這個點建立坐標系。

在網頁中,坐標系是 x 軸向右,y 軸向下。

轉換前:


7 (1).png

轉換后:


8.1.png

根據題目我們知道,這個點相對于綠色div左上角的坐標是(181, 50) 綠色div的寬高為200 基于綠色div中心點建立的坐標系,這個點的坐標是(81, -50)

將坐標代入公式進行計算:


9.png

得到坐標約為(167, 13)

再將這個坐標轉換成頁面坐標系(267,113)

最終我們得到了這個點在經過轉換后的坐標

參考文章: https://fanmingfei.com/post/CSS3_Transform_Matrix_Intro.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容