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(矩阵)应该是有比较大问题的。

文中屡次出现方向不明、坐标轴错误的坐标系,若是有看到建议改下。

相关文章
相关标签/搜索