CSS3 2D Transform Matrix

給本身出了一道題以下:css

題目

在某個大矩形中心有一個黃色的矩形,對該黃色矩形進行一系列transform變換獲得灰色矩形;html

以大矩形中心爲座標原點,屏幕水平向左爲X 軸正方向,屏幕垂直向上爲Y 軸正方向,黃色矩形初始位置中心在座標原點,根據其寬高能夠獲得其初始位置四個頂點的座標initPointscss3

那麼求黃色矩形通過一系列變換後新的頂點座標。git

在線地址:newbieyoung.github.io/CSS_learn/t…github

解答

其實無論 CSS3 transform 屬性 有多複雜,都是能夠經過getComputedStyle直接得到最終變換矩陣的,具體方法實現以下:web

//得到transform屬性對應的矩陣形式
function getTransformMatrix(transform){
    var $div = document.createElement('div');
    $div.style.visibility = 'hidden';
    $div.style.position = 'fixed';

    //處理transform屬性的兼容性
    var transformProperty = 'transform';
    if('transform' in $div.style){
        transformProperty='transform'
    } else if( 'WebkitTransform' in $div.style ){
        transformProperty='webkitTransform'
    } else if('MozTransform' in $div.style){
        transformProperty='MozTransform'
    } else if('OTransform' in $div.style){
        transformProperty='OTransform'
    }

    $div.style[transformProperty] = transform;
    document.body.appendChild($div);

    var style = window.getComputedStyle($div);
    var matrix = style[transformProperty];

    document.body.removeChild($div);

    return matrix;
}
複製代碼

經過getTransformMatrix函數能夠得到如下形式的變換矩陣:bash

matrix(a, b, c, d, e, f);

matrix(0.430963, 1.01542, -0.234879, 1.76697, 5, 40)
複製代碼

轉換爲三階矩陣:app

[a, c, e,
 b, d, f,
 0, 0, 1];
複製代碼

不知道你們想過沒有,明明是2D變換,轉換爲三階矩陣幹啥?wordpress

其實這裏是引入了一個齊次座標的概念,用N+1維的向量來表示N維向量;函數

好比在2D座標系中某個點(x, y)能夠在邏輯上表示爲(x*w, y*w, w)w即爲新增的那個量。

引入齊次座標的好處在於能夠把縮放旋轉平移等變換都統一轉換成矩陣乘法的形式,這樣無論進行多少次變換,均可以表示成矩陣連乘的形式了。

若是某個 2D 座標系中點爲(x, y),轉換爲齊次座標(x, y, 1),那麼通過上述變換後的新座標爲(nx, ny, nz)

nx = a * x + c * y + 1 * e;
ny = b * x + d * y + 1 * f;
nz = 0 + 0 + 1;
複製代碼

再把齊次座標還原,最終座標爲(nx, ny)

具體方法實現以下:

//計算矩陣變換後的座標點
function getMatrixPoints(p,matrix){
    var mat = matrixAnalyze(matrix);

    // var mat3 = [mat[0],mat[2],mat[4],
    //             mat[1],mat[3],mat[5],
    //             0,0,1];

    // var mat3 = [a,c,e,
    //             b,d,f,
    //             0,0,1];

    // var newX = a * x + c * y + 1 * e;
    // var newY = b * x + d * y + 1 * f;
    // var newZ = 0 + 0 +1;

    //計算變換後點座標
    var newX = mat[0] * p.x + mat[2] * p.y + 1 * mat[4];
    var newY = mat[1] * p.x + mat[3] * p.y + 1 * mat[5];
    var newZ = 0 + 0 +1;

    return {x:newX/newZ,y:newY/newZ};
}
複製代碼

已知初始座標initPoints和變換矩陣matrix相乘便可獲得matrixPoints,到這裏我覺得這個題目已經解完了;

直到我嘗試着在大矩形中用紅色直線把計算獲得的matrixPoints連起來才發現:新座標鏈接獲得的圖形和 CSS3 transform 變換獲得灰色圖形並不重合

這也就意味着上述計算過程有問題

在走了很多彎路以後我才意識到一個問題:CSS3 2D transform 座標系和題目中設定的座標系的 Y 軸正方向是相反的

題目中設置的座標系 Y 軸正方向是屏幕垂直向上而 CSS3 2D transform 座標系的 Y 軸正方向是屏幕垂直向下。

所以在計算新座標以前,須要對getComputedStyle獲得的變換矩陣進行鏡像變換,從而轉換爲題目中設定座標系的變換矩陣,也就是示例中fixedMatrix,最後計算的新座標爲fixedPoints

藍色直線繪製出來就能夠看到和灰色圖形徹底重合了。

總結

聊矩陣不聊座標系都是耍流氓!

此外張鑫旭大神2012年的這篇文章理解CSS3 transform中的Matrix(矩陣)應該是有比較大問題的。

文中屢次出現方向不明、座標軸錯誤的座標系,若是有看到建議改下。

相關文章
相關標籤/搜索