Skip to content

Animating between complex transforms

jaukia edited this page Nov 25, 2010 · 3 revisions

It is enough to do the calculation (affine transform) for the matrix only when starting the animation. From there on, you can just animate between the initial affine transform values and the final values.

For example, if you have:

matrix(0.000000, 0.707107, -1.414213, 0.707107, 0.000000, 0.000000)

This can be normalized with:

function affineTransform(m) {
    var a=m[0],b=m[1],c=m[2],d=m[3],e=m[4],f=m[5];
    
    if(Math.abs(a*d-b*c)<0.01) {
        console.log("fail!");
        return;
    }
    
    var tx = e, ty = f;
    
    var sx = Math.sqrt(a*a+b*b);
    a = a/sx;
    b = b/sx;

    var k = a*c+b*d;
    c -= a*k;
    d -= b*k;
    
    var sy = Math.sqrt(c*c+d*d);
    c = c/sy;
    d = d/sy;
    k = k/sy;
    
    if((a*d-b*c)<0.0) {
        a = -a;
        b = -b;
        c = -c;
        d = -d;
        sx = -sx;
        sy = -sy;
    }

    var r = Math.atan2(b,a);
    return {"tx":tx, "ty":ty, "r":r, "k":Math.atan(k), "sx":sx, "sy":sy};
}

You may use it like this:

m = [0.000000, 0.707107, -1.414213, 0.707107, 0.000000, 0.000000];
var aff = affineTransform(m);

As output, in var aff, you get:

{ k: 0.46364789184359106,
  r: 1.5707963267948966,
  sx: 0.707107,
  sy: 1.414213,
  tx: 0,
  ty: 0}

These params correspond directly to css transform statements and can be converted back with:

function matrixCompose(ia) {
    var ret = "translate("+roundNumber(ia.tx,6)+"px,"+roundNumber(ia.ty,6)+"px) ";
    ret += "rotate("+roundNumber(ia.r,6)+"rad) skewX("+roundNumber(ia.k,6)+"rad) ";
    ret += "scale("+roundNumber(ia.sx,6)+","+roundNumber(ia.sy,6)+")";
    return ret;
}

function roundNumber(number, precision) {
    precision = Math.abs(parseInt(precision,10)) || 0;
    var coefficient = Math.pow(10, precision);
    return Math.round(number*coefficient)/coefficient;
}

Example with aff:

matrixCompose(aff);

The output of this is:

"translate(0px,0px) rotate(1.570796rad) skewX(0.463648rad) scale(0.707107,1.414213)"

So basically, this is a way to transform any simple or complex set of transforms into a combination of translate, rotate, skewX and scale. And when you do this conversion to both the animation start and end states, then you can be quite sure that the animation is reasonable and there are no weirdnesses (at least when the corresponding angles are less than PI apart from each other).

Clone this wiki locally