如何组合元素转换?

时间:2012-07-14 21:48:39

标签: javascript css html5 linear-algebra css-transforms

在HTML5中,我想将转换功能实现为canvas元素,因此用户可以translate(移动),scale(放大/缩小)和rotate canvas元素。每个这样的变换都可以用不同的变换原点来完成。

第一次转型很容易:

function transform(el, value, origin) {
  el.style.Transform = value;
  el.style.MozTransform = value;
  el.style.msTransform = value;
  el.style.OTransform = value;
  el.style.webkitTransform = value;
  el.style.TransformOrigin = origin;
  el.style.MozTransformOrigin = origin;
  el.style.msTransformOrigin = origin;
  el.style.OTransformOrigin = origin;
  el.style.webkitTransformOrigin = origin;
}

transform(myCanvas, 'translate('+ dx +'px, ' + dy + 'px) ' +
                    'scale(' + zoom + ', ' + zoom + ') ' +
                    'rotate(' + angle + 'deg)',
                    cx + 'px ' + cy + 'px');

用户将移动或缩放或旋转元素,而不是一次性所有内容,因此某些转换参数将保持默认(dx = 0,dy = 0,zoom = 1,angle = 0)

在这样的转换之后,如果用户想要进行另一次转换(和另一个转换,另一个......),我如何将(dx1,dy1,zoom1,angle1,cx1,cy1)(dx2,dy2,zoom2,angle2,cx2,cy2)以获得可以在以后与新的转换参数组合的最终值?我无法将另一个转换附加到transform参数,因为tranform-origin可能不同。是否有一个公式如何将转换与不同的变换原点组合?

2 个答案:

答案 0 :(得分:8)

您不必学习矩阵数学。根据{{​​3}}

  
      
  1. 从身份矩阵开始。
  2.   
  3. 通过计算的'transform-origin'的X,Y和Z值进行翻译。
  4.   
  5. 依次乘以'transform'属性中的每个变换函数
  6.   
  7. 通过'transform-origin'
  8. 的否定计算的X,Y和Z值进行翻译   

换句话说,transform-origin: A; transform: Btransform: translate(-A) B translate(A)相同。 (转换从右到左适用,所以你想要发生的第一件事就在最后。)

所以使用上面的规则来消除transform-origin,现在你只需要连接的简单转换。

示例:

  1. transform-origin: 5px 5px; transform: translate(10px, 40px)
  2. transform-origin: 25px 30px; transform: scale(2)
  3. transform-origin: 10px 10px; transform: rotate(30deg)
  4. 变为

    1. transform: translate(-5px, -5px) translate(10px, 40px) translate(5px, 5px)
    2. transform: translate(-25px, -30px) scale(2) translate(25px, 30px)
    3. transform: translate(-10px, -10px) rotate(30deg) translate(10px, 10px)
    4. 现在你可以将它们结合起来,因为它们都同意原点(即没有原点)

      transform: translate(-5px, -5px) translate(10px, 40px) translate(5px, 5px) translate(-25px, -30px) scale(2) translate(25px, 30px) translate(-10px, -10px) rotate(30deg) translate(10px, 10px)

      当然,如果你想要

      ,你可以折叠连续的翻译

      transform: translate(-15px, 10px) scale(2) translate(15px, 20px) rotate(30deg) translate(10px, 10px)

      或者你可以挖出你的数学教科书和the CSS Transform specification

      修改:转换适用于从右到左。

答案 1 :(得分:1)

你必须处理矩阵变换。

每个线性操作都可以用3x3矩阵和3x1矢量表示,您可以在平面上应用它。如果 p 是一个点, M 是矩阵而 q 是另一个矩阵,则每个线性变换都可以表示为 Mp + q < / em>的

如果你有一个2d点,那么它的向量将是[ x; Ÿ; 1 ](垂直向量),而矩阵可以有多种形式。

对于翻译,矩阵只是单位矩阵。向量 q 是翻译向量。

对于缩放, M 就像

    [a 0 0]
M = [0 b 0]
    [0 0 1]

其中 a b 分别是 x y 的缩放系数。向量 q 为空。

对于旋转,比如角度 a ,你会得到

    [cos(a) -sin(a) 0]
M = [sin(a)  cos(a) 0]
    [  0       0    1]

q 再次为空。

也存在倾斜的矩阵。因此,如果必须应用三个连续变换,则必须应用这些线性变换。你的问题是你必须处理起源,所以你必须从 p 中减去向量 o ,而不是应用 M ,再次添加 q 然后再添加 o

假设你有这些转换( M1,q1,o1 )和( M2,q2,o2 )。当你申请第一个时,你得到了

p1 = M1 * (p - o1) + q1 + o1

然后你必须应用第二个转换:

p2 = M2 * (p1 - o2) + q2 + o2

最后你会得到:

p2 = M2 * (M1 * (p - o1) + q1 + o1 - o2) + q2 + o2

以及最终的第三个( M3,q3,o3 )。

一团糟?看起来像。但是如果你知道矩阵是什么样子的话,可以简单地解决一些问题。

现在,进行数学计算,并将其应用于transform: matrix(a, b, c, d, tx, ty)