Transformation Matrix
Basic Math
Let's try to understand how transformation matrixes are working in 2D.
Here is the typical 2D transformation matrix, it is widely used in CSS, SVG, Figma API, and most 2D graphics engines.
First of all let's start from the beginning and write down the underlying matrix multiplication math.
Playground
Check out this interactive playground! Use scroll to adjust values with 0.1 precision:
With this matrix we can do any affine transformation: rotate, scale, translate, flip, skew. This is why it is so widely used.
How does it work
In the above example I am just using canvas context setTransform
method and pass a
, b
, c
, d
, dx
, dy
as arguments before drawing an image.
Most functions are just matrix multiplication of original matrix and the transformation one
Rotation
For building rotation matrix we need to use radians and build the rotation transformation matrix
Here is the code that just do this
var rotate = function(rotateAngle){
var rad = rotateAngle * Math.PI / 180;
// current matrix is stored as a,b, dx, c,d, dy in this example
var mat1 = [[a,b], [c,d]];
var mat2 = [[Math.cos(rad), -Math.sin(rad)], [Math.sin(rad), Math.cos(rad)]];
// we multiply only a,b,c,d (2x2 matrix) and keep the dx and dy
var mul = [
[
mat1[0][0]*mat2[0][0] + mat1[0][1]*mat2[1][0],
mat1[0][0]*mat2[0][1] + mat1[0][1]*mat2[1][1],
dx
],
[
mat1[1][0]*mat2[0][0] + mat1[1][1]*mat2[1][0],
mat1[1][0]*mat2[0][1] + mat1[1][1]*mat2[1][1],
dy
]
];
return mul;
};
Scaling
Scaling is one of the easiest — we can just multiply a,b,c,d by some number. If we want to separate the axis — a
, c
gives us the X
axis scaling, and b
, d
— Y
In terms of matrix it looks like this:
var scale = function(x, y){
var mat1 = [[a,b], [c,d]];
// if y is not specified — do a proportional scaling by x
var mat2 = y === void 0 ? [[x,0], [0,x]] : [[x,0], [0,y]];
var mul = [
[
mat1[0][0]*mat2[0][0] + mat1[0][1]*mat2[1][0],
mat1[0][0]*mat2[0][1] + mat1[0][1]*mat2[1][1],
dx
],
[
mat1[1][0]*mat2[0][0] + mat1[1][1]*mat2[1][0],
mat1[1][0]*mat2[0][1] + mat1[1][1]*mat2[1][1],
dy
]
];
return mul;
};
Translate\move
For moving the image adjusting dx, dy would do the trick (in the above example we are working in global coordinate system). If we want to move image in relative coordinates — multiply a
, b
, c
, d
by the translation vector and add the result to dx
, dy
var move = function(x, y){
return [[a, b, dx+x], [c, d, dy+y]]
};
Flip
Flipping is similar to scaling, but we are using negative number. So flipping by X look like this:
Just call scale(-1, 1)
and it would do the trick.
Shear\skew
Skew is done by this matrix:
How is the origin working?
For changing the origin — I just draw the image at different position:
- For top-left corner — I draw it at the position
0, 0
- For bottom-right — at
-width, -height
- For center — at
-width/2, -height/2
Related articles
Relative transformation matrix
Global, and local coordinates
Animating transformation matrix changes