最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to combine element transformations? - Stack Overflow

programmeradmin3浏览0评论

In HTML5 I want to implement transform functionality to canvas element, so user can translate (move), scale (zoom in/out) and rotate the canvas element. Each such tranformation can be done with different transform-origin point.

First tranformation is easy:

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');

User will move or zoom or rotate the element, not everything at once, so some parameters of tranformation will stay default (dx = 0, dy = 0, zoom = 1, angle = 0).

After such tranformation, if user wants to make another transformation (and antother, and another...), how can I bine (dx1, dy1, zoom1, angle1, cx1, cy1) with (dx2, dy2, zoom2, angle2, cx2, cy2) to get final values that can be bine later with new tranformation parameters? I cannot append another tranformation to transform parameter, because tranform-origin may be different. Is there a formula how to bine tranformations with different transform-origin points?

In HTML5 I want to implement transform functionality to canvas element, so user can translate (move), scale (zoom in/out) and rotate the canvas element. Each such tranformation can be done with different transform-origin point.

First tranformation is easy:

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');

User will move or zoom or rotate the element, not everything at once, so some parameters of tranformation will stay default (dx = 0, dy = 0, zoom = 1, angle = 0).

After such tranformation, if user wants to make another transformation (and antother, and another...), how can I bine (dx1, dy1, zoom1, angle1, cx1, cy1) with (dx2, dy2, zoom2, angle2, cx2, cy2) to get final values that can be bine later with new tranformation parameters? I cannot append another tranformation to transform parameter, because tranform-origin may be different. Is there a formula how to bine tranformations with different transform-origin points?

Share Improve this question edited Jul 29, 2012 at 8:55 Rich Bradshaw 73.1k46 gold badges188 silver badges241 bronze badges asked Jul 14, 2012 at 21:48 ΩmegaΩmega 43.7k35 gold badges142 silver badges212 bronze badges 3
  • Have you tried to visualize it? Draw a box on a paper. Then, consider what happens when you want to translate/rotate/scale the box. And again. – Rob W Commented Jul 14, 2012 at 21:52
  • @RobW - I tried a lot for over a week :-/ I am able to bine unlimited move (translate) and zoom (scale) tranformations, but once I have rotation involved, I am lost... – Ωmega Commented Jul 14, 2012 at 22:00
  • I'm not sure the linear-algebra tag belongs on this question. It's more about bining CSS properties than using linear algebra. – TylerH Commented Jun 7, 2015 at 18:15
Add a ment  | 

2 Answers 2

Reset to default 9

You don't have to learn matrix math. According to the CSS Transform specification

  1. Start with the identity matrix.
  2. Translate by the puted X, Y and Z values of ‘transform-origin’.
  3. Multiply by each of the transform functions in ‘transform’ property in turn
  4. Translate by the negated puted X, Y and Z values of ‘transform-origin’

In other words, transform-origin: A; transform: B is the same as transform: translate(-A) B translate(A). (Transformations apply from right to left, so the first thing you want to happen goes at the end.)

So use the above rules to eliminate transform-origin and now you just have plain transforms you can concatenate.

Example:

  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)

bees

  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)

Now you can bine them since they all agree on the origin (i.e., no origin)

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)

Of course you can collapse the consecutive translations if you want

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

Or you can dig out your math textbook and pute the final transformation matrix.

Edit: Transforms apply right to left.

You'd have to deal with matrix transformations.

Every linear operation can be represented with a 3x3 matrix and a 3x1 vector that you can apply on the point of the plane. If p is a point, M the matrix and q the other vectory, every linear transformation can be represented as Mp + q.

If you have a 2d point, then its vector will be [x; y; 1] (a vertical vector), while the matrix can be of several form.

For translations, the matrix is just the identity matrix. The vector q is the translation vector.

For scaling, M is like

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

where a and b are scaling factor for x and y respectively. The vector q is null.

For rotations, say of an angle a, you'll get

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

and q is null again.

There are matrices for skewing, too. So, if you have to apply three consecutive transformations, you'll have to apply these kind of linear transformations. Your problem is that you have to deal with origins, too, so you'll have to subtract the vector o from p, than apply M, add q and then o again.

Let's say you have these transformation (M1, q1, o1) and (M2, q2, o2). When you apply the first one you get

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

Then you have to apply the second transformation:

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

In the end you'll get:

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

And so on with and eventual third (M3, q3, o3).

A mess? It looks like. But things can be simplyfied a bit if you know how the matrices look like.

Now, do the math, and apply it to transform: matrix(a, b, c, d, tx, ty).

发布评论

评论列表(0)

  1. 暂无评论