Question

I'm doing an animated transform in Raphael (and Snap.svg, which does the same).

If I apply a rotation to a basic element, it rotates normally as I would expect. However, if I already have a previous transform applied (even if its t0,0 or r0), the element seems to scale down and back up, as though it always has to fit in its previous bounding box or something.

Here is an example fiddle

var r1 = s.rect(0,0,100,100,20,20).attr({ fill: "red", opacity: "0.8", stroke: "black", strokeWidth: "2" }); 
r1.transform('t0,0'); // any transform leads to shrink on rotate...
r1.animate({ transform: 'r90,50,50' }, 2000);


var r2 = s.rect(150,0,100,100,20,20).attr({ fill: "blue", opacity: "0.8", stroke: "black", strokeWidth: "2" });
r2.animate({ transform: 'r90,200,50' }, 2000);

Is there something obvious I'm missing on animated transforms as to what is happening ?

Was it helpful?

Solution

There are a couple different things you need to understand to figure out what's going on here.

The first is that your animating transform is replacing your original transform, not adding on to it. If you include the original transform instruction in the animation, you avoid the shrinking effect:

var r1 = s.rect(0,0,100,100,20,20)
        .attr({ fill: "red", opacity: "0.8", stroke: "black", strokeWidth: "2" }); 
r1.transform('t0,0'); 
    // any transform leads to shrink on rotate...
r1.animate({ transform: 't0,0r90,50,50' }, 5000); 
    //unless you repeat that transform in the animation instructions

http://jsfiddle.net/96D8t/3/

You can also avoid the shrinking effect if your original transformation is a rotation around the same center:

var r1 = s.rect(0,0,100,100,20,20)
        .attr({ fill: "red", opacity: "0.8", stroke: "black", strokeWidth: "2" }); 
r1.transform('r0,50,50'); // no shrinking this time...
r1.animate({ transform: 'r90,50,50' }, 2000);

http://jsfiddle.net/96D8t/4/

But why should it make a difference, seeing as a translation of 0,0 or a rotation of 0 doesn't actually change the graphic? It's a side effect of the way the program calculates in-between values when you ask it to convert between two different types of transformations.

Snap/Raphael are converting your two different transformations into matrix transformations, and then interpolating (calculating intermediate values) between each value in the matrix.

A 2D graphical transformation can be represented by a matrix of the form

a   c   e
b   d   f

(that's the standard lettering)

You can think of the two rows of the matrix as two algebra formulas for determining the final x and y value, where the first number in the row is multiplied by the original x value, the second number is multiplied by the original y value, and the third number is multiplied by a constant 1:

newX = a*oldX + c*oldY + e;
newY = b*oldX + d*oldY + f;

The matrix for a do-nothing transformation like t0,0 is

1   0   0
0   1   0

Which is actually represented internally as an object with named values, like

{a:1,  c:0,  e:0,
 b:0,  d:1,  f:0}

Either way, it just says that the newX is 1 times the oldX, and the newY is 1 times the oldY.

The matrix for your r90,50,50 command is:

0   -1   100
1    0   0

I.e., if your old point is (50,100), the formulas are

newX = 0*50 -1*100 + 100*1 = 0
newY = 1*50 + 0*100 + 0    = 50

The point (50,100) gets rotated 90degrees around the point (50,50) to become (0,50), just as expected.

Where it starts getting unexpected is when you try to transform

1   0   0
0   1   0

to

0   -1   100
1    0   0

If you transform each number in the matrix from the start value to the end value, the half-way point would be

0.5   -0.5   50
0.5    0.5   0

Which works out as the matrix for scaling the rectangle down by half and rotating it 45degrees around (50,50).

All of that might be more math than you needed to know, but I hope it helps make sense of what's going on.

Regardless, the easy solution is to make sure that you always match up the types of transforms before and after the animation, so that the program can interpolate the original values, instead of the matrix values.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top