Reputation: 43673
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 combine (dx1, dy1, zoom1, angle1, cx1, cy1) with (dx2, dy2, zoom2, angle2, cx2, cy2) to get final values that can be combine 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 combine tranformations with different transform-origin points?
Upvotes: 4
Views: 2360
Reputation: 45173
You don't have to learn matrix math. According to the CSS Transform specification
- Start with the identity matrix.
- Translate by the computed X, Y and Z values of ‘transform-origin’.
- Multiply by each of the transform functions in ‘transform’ property in turn
- Translate by the negated computed 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:
transform-origin: 5px 5px; transform: translate(10px, 40px)
transform-origin: 25px 30px; transform: scale(2)
transform-origin: 10px 10px; transform: rotate(30deg)
becomes
transform: translate(-5px, -5px) translate(10px, 40px) translate(5px, 5px)
transform: translate(-25px, -30px) scale(2) translate(25px, 30px)
transform: translate(-10px, -10px) rotate(30deg) translate(10px, 10px)
Now you can combine 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 compute the final transformation matrix.
Edit: Transforms apply right to left.
Upvotes: 9
Reputation: 22617
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)
.
Upvotes: 1