I need help in deep understanding of matrix in SVG. I already know about matrix, I want to rotate and scale without using scale or rotate word. I want to use transform=’matrix(a,b,c,d,e,f)’. I know ‘a/d’ value determine the scale, ‘e/f’ determines the position. tan(b),tan(c) determines the skew. cos(a),sin(b),-sin(c),cos(d) determines the angle.But I want to know how this work, I need thoroughly help in understanding matrix in SVG.
Advertisement
Answer
Matrix operations are composed of individual, “local” transformations (i.e. translate, rotate, scale, skew) by matrix concatenation (i.e. multiplication).
For example, if you want to rotate an object by r
degrees around a point (x, y)
, you would translate to (x, y)
, rotate r
degrees, then translate back to the original position (-x, -y)
.
By what is often referred to as “chaining” (as described above) each successive “local” transformation is combined to produce a result. Therefore, at any location in a chain of transformations, the “local” transformation space (at that location) is composed of all operations that came before.
What this implies is that when transforming some parameter of an SVG element (i.e. translate) the transform is applied to it’s current transformation space. So, for example if the element is already rotated 30 degrees, then a translation of (8, 5)
would not go 8 to the right and 5 down, but it would go the rotation of (8, 5) by 30 degrees – relative to the current position.
So this is a bit of a gotcha.
One way to help deal with this complication is to decompose transformation matrices into their individual, total transformations (i.e. total translation, total rotation/skew, total scale), but decomposition says nothing about what individual basic transformations went into the combined totals, nor of the order in which they occurred. This is a problem because 2D transformations are not commutative, e.g. translate(x, y)->rotate(r)
is not the same as rotate(r)->translate(x, y)
.
The best way that I’ve found is to only compose transformations in a certain order and keep track of the totals in that order, then when a new transformation is introduced, used the totals that have been tracked, update the one that is being modified and recompose the entire transformation.
Like so: (pseudo-code)
// EDIT: initialize components (new SVGMatrix returns the identity matrix) var transX=0, transY=0, rot=0, scaX=0, scaY=0, skwX=0, skwY=0, matrix = new SVGmatrix(); // example rotate function rotate(svgEl, angle){ rot = rot + angle; updateTransform(); applyTransform(svgEl); }; function updateTransform(){ // the order that I've found most convenient // (others may do it differently) matrix.translate(transX, transY); matrix.rotate(rot); matrix.scale(scaX, scaY); matrix.skewX(skwX); matrix.skewY(skwY); }; function applyTransform(el){ el.transform = matrix; };
To be clear, this is not suggesting that matrices are not a good way of representing transformations, nor is it suggesting a better way – far from it.
Transformation matrices are a powerful tool, and when used appropriately, they are very effective at handling complex animations, but they are not trivial to use in all cases.
This may be a bit advanced, but for more information about animations using matrix transformations, this short code example provides a wealth of information and references to start from.
http://www.w3.org/TR/2011/WD-css3-2d-transforms-20111215/#matrix-decomposition
Update: Just a note about the decomposed skew factor proposed at the above link.
Only a single skew factor ( in x ) is computed because skewing in both x and y is equivalent to a skew in x and a combined ( offset ) rotation.
Combining x skew and y skew ( with or without a rotation or translation, as in my above preferred composition order ) will result in a different x skew, rotation ( e.g. non-zero rotation if none was originally composed ), and translation ( e.g. an offset by some amount relative to the decomposed rotation in lieu of the original y skew ), but no recoverable y skew – using the linked decomposition method.
This is a limitation of composed affine matrices. So producing a final result matrix should generally be considered a one-way computation.