Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Svg matrix decomposition

In svg we have method element.getCTM() which returns a SVGMatrix as:

[a c e][b d f][0 0 1] 

I want to calculate sx , sy and angle of rotation from this matrix.

like image 754
rsk Avatar asked Jan 02 '12 06:01

rsk


1 Answers

There is a lot to read and learn on this subject. I'll give a basic answer, but be aware, if you are trying to do a game or animations this is NOT the way to do it.

a == sx and d == sy, so you'll access these like this:

var r, ctm, sx, sy, rotation;

r   = document.querySelector('rect'); // access the first rect element
ctm = r.getCTM();
sx  = ctm.a;
sy  = ctm.d;

Now for the rotation a == cos(angle) and b == sin(angle). Asin and acos can't alone give you the complete angle, but together they can. You want to use atan since tan = sin/cos and for just this kind of problem you actually want to use atan2:

RAD2DEG = 180 / Math.PI;
rotation = Math.atan2( ctm.b, ctm.a ) * RAD2DEG;

If you study the inverse trigonometric functions and the unit circle you'll understand why this works.

Here is W3C's indespensible resource on SVG transformations: http://www.w3.org/TR/SVG/coords.html. Scroll down a bit and you can read a lot more about what I've mentioned above.

UPDATE, example usage how to programmatically do animations. Keep the transformations stored separately and when these are updated, overwrite/update the SVG element transform.

var SVG, domElement, ...

// setup
SVG        = document.querySelector( 'svg' );
domElement = SVG.querySelector( 'rect' );
transform  = SVG.createSVGTransform();
matrix     = SVG.createSVGMatrix();
position   = SVG.createSVGPoint();
rotation   = 0;
scale      = 1;

// do every update, continuous use
matrix.a = scale;
matrix.d = scale;
matrix.e = position.x;
matrix.f = position.y;

transform.setMatrix( matrix.rotate( rotation ) );
domElement.transform.baseVal.initialize( transform ); // clear then put
like image 72
bennedich Avatar answered Nov 05 '22 23:11

bennedich