4

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

第一次转换很容易:

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可能会有所不同。是否有一个公式如何将变换与不同的变换原点结合起来?

4

2 回答 2

9

您不必学习矩阵数学。根据CSS 变换规范

  1. 从单位矩阵开始。
  2. 通过“transform-origin”的计算 X、Y 和 Z 值进行转换。
  3. 依次乘以“变换”属性中的每个变换函数
  4. 通过 'transform-origin' 的否定计算 X、Y 和 Z 值进行转换</li>

换句话说,transform-origin: A; transform: B与 相同transform: 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)

变成

  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)

现在您可以将它们组合起来,因为它们都同意原产地(即无原产地)

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)

或者你可以翻出你的数学课本,计算出最终的变换矩阵

编辑:变换从右到左应用。

于 2012-07-14T22:31:46.860 回答
1

您必须处理矩阵转换。

每个线性运算都可以用一个 3x3 矩阵和一个 3x1 向量表示,您可以将它们应用于平面的点。如果p是一个点,M是矩阵,q是另一个向量,则每个线性变换都可以表示为Mp + q

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

对于翻译,矩阵就是单位矩阵。向量q是平移向量。

对于缩放,M就像

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

其中ab分别是xy的比例因子。向量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).

于 2012-07-14T22:15:05.083 回答