# Canvas Transformations by [kirupa](https://www.kirupa.com/me/index.htm) | filed under [Working with the Canvas](https://www.kirupa.com/canvas/index.htm) So far everything we've drawn on the `canvas` was done without thinking much about exactly what our pixels are drawn into. Saying that our pixels are drawn on the `canvas` is only one part of the full picture. Under the `canvas` is an invisible virtual grid: ![](https://www.kirupa.com/canvas/images/empty_grid_144.png) It is this invisible virtual grid that all of the various draw commands we've seen map their pixels into. By default, this grid isn't very interesting. It becomes a whole lot more interesting when you transform it. You can rotate this grid: ![](https://www.kirupa.com/canvas/images/empty_grid_rotate_144.png) You can shift the starting point of this grid: ![](https://www.kirupa.com/canvas/images/empty_translate_144.png) You can even scale each individual "cell" inside the grid to be larger or smaller: ![](https://www.kirupa.com/canvas/images/empty_grid_scale_144.png) Why is this interesting? It is interesting because your `canvas` and anything you draw inside it will get scaled, rotated, or translated as well. This sort of makes up for the lack of interesting things you can do with the draw methods we've seen. At most, you can specify the size and position. That's not a lot, so transforms provide you with a few more ways of customizing what you draw. In this tutorial, we are going to learn all about it. Onwards! ## Meet the Transformation Methods The three methods you have for transforming your `canvas` are `translate`, `scale`, and `rotate`. In the following sections, let's look at how to use these methods. ### Translating If you want to shift your `canvas` and everything that gets drawn, you have the the `translate` method: ```js context.translate(x, y); ``` The x and y arguments specify the number of pixels to shift your canvas horizontally and vertically by. Below is a simple example of what this looks like: ```js // Transform context.translate(50, 50); // Circle context.beginPath(); context.arc(200, 200, 93, 0, 2 * Math.PI, true); context.fillStyle = "#FF6A6A"; context.fill(); // Square context.fillStyle = "#00CCFF"; context.fillRect(50, 50, 100, 100); ``` This code draws a circle and a square to our `canvas`. The call to the `translate` method at the top shifts both of the shapes over by 50 pixels. The following diagram shows the result of this translation: ![](https://www.kirupa.com/canvas/images/circle_square_translate_144.png) The entire `canvas` and the origin (0, 0) position is shifted, **so all future drawing operations will have their positions offset automatically**. Having a transform apply to all draw operations from here on out may be undesirable, and we'll look at how to address that in a little bit. Just ignore this minor annoyance for now. ### Rotating This is probably my favorite transform, for rotating the things you draw is really hard using the drawing commands we have available today. The way you rotate is by using the `rotate` method, and it looks as follows: ```js context.rotate(angle); ``` This method takes one argument that determines the angle (in the form of radians) you wish to rotate the `canvas` by. Here is an example of us rotating some text that we draw by 45 degrees: ```js // Transform context.rotate(45 * Math.PI / 180); // Text context.font = "bold 48px Helvetica, Arial, sans-serif"; context.fillStyle = "steelblue"; context.fillText("Wheeeee!", 150, 0); ``` Here is what this looks like: ![](https://www.kirupa.com/canvas/images/transform_text_144.png) I chose a text example to highlight the **rotate** transform because text is one of the things you draw that is nearly impossible to re-create using rotated angled lines and curves. Without the `rotate` method, you'd be spending a lot of time trying to get a single character to look right - much less an entire word or a series of words! By comparison, rotating geometric shapes is much easier. With that said, you should still use the `rotate` method whenever you can instead of rotating manually...like an animal. ### Scaling The last individual transform we will look at is the `scale` method that is responsible for scaling what you draw: ```js context.scale(x, y); ``` This method takes two arguments that specify the horizontal and vertical scale accordingly. You can specify the arguments in the form of decimal values with 1 representing the original scale. A number between 0 and 1 means that what you draw will be scaled down, and a number greater than 1 means that what you draw will be scaled up. The following code highlights an example where a poor square is stretched horizontally to twice its size: ```js // Transform context.scale(2, 1); // Square context.fillStyle = "#FFCC00"; context.fillRect(50, 100, 100, 100); ``` If we had to visualize this, this would look as follows: ![](https://www.kirupa.com/canvas/images/square_scale_144.png) You can even specify negative values to flip our canvas horizontally or vertically. In the following code, we flip some text horizontally and scale it down by 50%: ```js // Transform context.scale(-.5, 1); // Text context.font = "bold 96px Helvetica, Arial, sans-serif"; context.fillStyle = "#CC6699"; context.fillText("Confused", -700, 100); ``` This would look as follows: ![](https://www.kirupa.com/canvas/images/text_scale_squish_144.png) The negative value for the `scale` method's x argument flips our `canvas` horizontally. The value of .5 squishes things by 50%. #### Combining Transforms You aren't limited to using only a single transform to torture your `canvas` with. You can apply multiple transforms very easily: ```js context.scale(-.5, 1); context.rotate(45 * Math.PI / 180); context.translate(40, 10); ``` The reason this is possible has to do with how these transforms are implemented. There is a transform matrix that represents all of the transform values you can use: ![](https://www.kirupa.com/canvas/images/matrix_transform_144.png) These values aren't dependent on any other values, so you can independently set multiple transforms without stepping on any numerical toes. Don't worry if that doesn't make any sense. Just remember that all the `translate`, `rotate`, and `scale` methods end up affecting are the values stored by this matrix. You can set this matrix directly by using the `setTransform` method, but covering that goes beyond the scope of what you would use frequently in the real world. ## Undoing Transforms This may be the part you have been eagerly waiting for. As you probably realized by now, transforming the `canvas` isn't an operation that resets itself with each thing you draw. It's not like a `fillStyle` or `strokeStyle`. The transformation is always there for any draw operation you perform in the future. That isn't always desirable, right? To handle this, you need to explicitly turn the transforms off. There are several ways you can do with this. We'll look at two approaches in this section and focus on a slightly different (and heavy-handed) approach in a future tutorial where we look at how to save and restore state. ### Resetting the Transform...the Easy Way The easiest way to reset a transform is to call the `resetTransform` method: ```js // Transform context.translate(50, 50); context.scale(2, 2); // Circle context.beginPath(); context.arc(200, 200, 93, 0, 2 * Math.PI, true); context.fillStyle = '#FF6A6A'; context.fill(); // Reset the Transform context.resetTransform(); // Square context.fillStyle = '#00CCFF'; context.fillRect(50, 50, 100, 100); ``` The `resetTransform` method performs the magic needed to the transformation matrix you saw earlier to get everything back to how it was before a transform was even applied. In our example, the circle will be drawn on the transformed canvas. The square will be drawn on the untransformed canvas. Because of how drawing on the canvas works, untransforming the canvas with our circle already on it won't affect how the circle displays. Only ***future*** draw operations after `resetTransform` will be impacted. ### Manually Resetting the Transform TL;DR: Just use `resetTransform`. Skip this section. Tell your friends. Before we go on, I should mention this upfront: I don't recommend you reset the transform with using the approach I am about to show you. The only reason I am showing you this is to give you a better understanding of how transforms affect the `canvas`. Plus, it inflates the length of this article and helps make all of us look really smart by learning about this. The more tedious way to reset your `canvas` to its untransformed state involves setting new transforms to undo what your earlier transforms did. That seems straightforward, but as you will see in a few seconds, there are some complications here that you'll need to deal with. Here is an example of what this madness looks like: ```js // Transform context.translate(50, 50); context.scale(2, 2); // Circle context.beginPath(); context.arc(200, 200, 93, 0, 2 * Math.PI, true); context.fillStyle = '#FF6A6A'; context.fill(); // Reset the Transform context.scale(.5, .5); context.translate(-50, -50); // Square context.fillStyle = '#00CCFF'; context.fillRect(50, 50, 100, 100); ``` Pay attention to the highlighted lines where we set the transform first and then reset the transform next. Resetting a transform in this approach isn't as simple as specifying the default transform values for `translate` and `scale`: ```js context.scale(1, 1); context.translate(0, 0); ``` That seems like the logical thing to do, but that only works in a world where the `canvas` can intelligently access its previous state. The moment our canvas gets transformed, it only sees the world through its transformed lenses. Setting a `scale` value of 1 or a `translate` value of 0 means that you just stay at the current transformed state. The fix is where the tediousness comes in: ***You have to account for the earlier transform that has been applied and negate it.*** If the original transform called for everything to be scaled by 200%, you need to reset the scale by scaling everything by 50% instead. If your `translate` transform shifted everything by 50 pixels horizontally and vertically, you undo this by translating back by 50 pixels in the horizontal and vertical directions. That's what our code highlights: ```js context.scale(.5, .5); context.translate(-50, -50); ``` There is one more wrinkle. The order you perform this reset is important. Notice that we first undo the scale before resetting the position. If you didn't do this, you will have changed the position of an element that will then be repositioned again as a result of the scale operation. Getting the position right at this point will require more calculations, and that isn't particularly fun. This whole section isn't fun! ## Conclusion The most difficult thing about learning how to transform the `canvas` is how bizarre it is. If you are familiar with transforms in CSS, you know that you only affect the element or elements you are targeting. In the wacky world of the `canvas`, there is no concept of an element. Everything is either the `canvas` itself or raw pixels. If you wish to draw something rotated (or scaled or translated), you transform the `canvas` first and then draw whatever you were planning on drawing. The strangeness of this all goes away with practice...and a lot of therapy.