HTML5 Canvas - How to apply transformation

In previous post How to do animation in canvas, I talked about some basic techniques used for animation in HTML5. In this post I will discuss a very important and very powerful mechanics of animation, transformations. Transformations play a very important part in animation and graphic world. Therefore it is very important to grasp some fundamental concepts behind transformations in HTML5 canvas. If you do not understand some of these fundamentals then transformations can be very frustrating and confusing to apply to get the desired effect. Therefore I will strongly recommend that you should spend some time on this topic.

Canvas Transformation Functions

Lets first look at the functions provided in HTML5 canvas API.

• context.scale(x, y)
• context.rotate(angle)
• context.translate(x, y)
• context.transform
• context.setTransform(a, b, c, d, e, f)

In this post I am going to mainly concentrate on translate and rotate functions. These two functions are easiest to use and apply to get some basic transformations applied to graphics object.

Axis and Origin Of Canvas

Transformations is all about axis and origin of your drawing surface. Therefore it is very important to understand this concept about HTML5 canvas. Following image shows you origin and direction of axis for canvas. As you can see that by default, top left corner is origin (0,0) of the axis of canvas. Values of x-coordinate increase moving towards right and values of y-coordinates increase moving downwards. If you have been doing computer graphics then this is something fundamental. But I thought I will just put it down for sake of completeness of discussion.

Importance of origin

In graphics everything is defined by coordinates. For example you define location of a point by saying that start point of my line is (2,2). These coordinate values are with reference to origin of axis. This example of point means that point is 2 units in x-direction and 2 units in y-direction. Following image shows how this point could be plotted. Apply Translation

Now lets see why origin is important. For example above, lets say that we translate axis origin by 1 unit in x-axis and 1 unit in y-axis. This means that (0,0) location of original canvas has moved by (1,1). Following image shows what this translation means. Now you can see where the origin is. Now if I want to plot the same point (2,2) on canvas, its location is going to be calculated 2 units in x-axis and 2 units in y-axis. But this location is in reference to the origin of axis. So based on this, the point is going to be drawn as shown below. As you can see that this point is located at (2,2) from translated origin but it is at (3,3) from the original location of origin. Now you can see effect of translation.

Apply Rotation

Now lets say that after translating the axis origin by (2,2), you decide to rotate the axis by 45 degree. And then plot the same Point (2,2). As you can see from the image below that point has been plotted at (2,2) but it is 2 units from x-axis and 2 units from y-axis with respect to translated and rotated axis. How does canvas transformation work?

From two examples you have got some idea of effect of the transformation. Let me put it down in some simple terms how transformations work in HTML5 canvas. When you start with a canvas, there is a transformation matrix applied to whole canvas. At the begining this matrix is identity matrix. What this means is that there origin of canvas is at top left corner of your canvas HTML element. All the objects you draw have this identity matrix applied to it. Since it is identity matrix which means no translation and no rotation. When you call methods, translate, rotate, scale etc., you change this canvas matrix to apply the effects that you asked for. Any objects that you will draw after calling these transformation methods will have those transformations applied to it. And any objects that you draw before calling transformation functions will have only identity matrix applied. What this means is that it is very important when you call the transform functions.

Transformation In Action

Lets look at effect of HTML5 canvas transformation functions on some real graphics action. Following image shows a default canvas that has grid drawn on the surface and a rectangle at the center. This has no transformation applied to it. Now I am going to call rotate method on canvas as shown in code snippet below.

NetFour.Graphics.prototype.applyRotation = function (deg) {
var rad = deg * Math.PI / 180;
};

Following image shows effect of apply rotation of 30 degree. As you can see that whole grid along with the rectangle has been rotated by 30 degree. And you can see in top left corner that blue lines showing axis have rotated by 30 degree. Now I am going to call translate method on canvas with (20, 20) as shown in code snippet below.

NetFour.Graphics.prototype.applyTranslation = function (x, y) {
this.drawingCtx.translate(x, y);
};

Following image shows effect of this translation. As you can see the whole grid along with rectangle at the center got translated by (20,20). You can see in top left corner of grid that blue lines showing axis translated by (20,20).

Apply Transformation To Individual Objects

So far I have talked about fundamental working of transformations. If you look at the examples discussed so far, they do not seem to be very useful in real graphic applications. You must be thinking why would I want to rotate the whole canvas and all objects in it. You are right, I am more interested in application transformations to individual object. For example if I have an image on the canvas, I want to rotate the image along its center or at top left corner of image. To accomplish this, you just need to understand the basic concepts that I talked about earlier. Let me enforce these concepts one more time.

Coordinates are in reference to origin

Based on this very simple fact, if you can compensate for translations and rotations when drawing an object, you can accomplish what you intend to do. Lets look at this with an example. I will use the demo canvas.

Dimensions

Canvas:
height=400, width = 400
Rectangle In Center:
width=60, height=40

Transformation Objective

I want to draw the rectangle at the center of canvas but rotate it by 45 degree.

How to do it?

In simple terms what we need is a function call as follows.

context.rotate(45*Math.PI/180);

This is not going to work because transformation matrix is applied to whole canvas. This would mean that the rectangle will move along a 45 degree arc that has center at (0,0). Now you can see where I am getting to when I talked about origin and its importance. If somehow I can move my origin at center of the canvas, draw the rectangle at center of canvas and then apply rotation of 45 degree that would do the trick. Here are canvas function calls without any transformations.

graphics.drawingCtx.fillRect(170, 180, 60, 40);

Now if I apply rotation of 45 degree and call above function then rectangle will get drawn somewhere outside the canvas. As I described above, we will have to apply some compensation. Lets first move the origin to center of canvas. That would mean a translation like below.

graphics.drawingCtx.translate(200, 200);

Now that origin has moved, drawing rectangle at (170,180) will make it render very close to edge of canvas. This would mean that we will have to apply compensation to top left corner of rectangle. Since origin moved by 200 in x and y direction, we will have to subtract that much translation from original left top location of rectangle. So now the rectangle will drawn as below.

graphics.drawingCtx.fillRect(170-200, 180-200, 60, 40);

Now that we have compensated for translation, only thing left is to apply rotation of 45 degree.

graphics.drawingCtx.rotate(45 * Math.PI/180); Remember to reset transformation

This is very important you reset the matrix after you are done drawing with your required transformations. Remember that the transformation matrix is applied to all drawing after transformation has been applied.

Demo Application

You can play with demo application at the following link.

In the demo, you can play with Move Origin check box to see how applying compensation to origin affects drawing of objects. Attached javascript files contain NetFourXFormDemo.js file that has complete implementation of demo site.

Weather

7.5 °C / 45.5 °F Clouds