HTML5 Canvas

HTML5 Canvas: Save & restore

HTML5 Canvas: Save and restore

Here I am going to explain save and restore within a Canvas as best I can. Without a doubt, this was the hardest thing to get my head around, so it’ll certainly be useful to explain here what it could be used for, why it is useful, and how to implement it.

How save & restore works

Save and restore allows us to set up a state, which would usually be a group of styles (e.g. background colours, shadows, and stroke widths and colours), and save it down for later use.

When a state is saved, it is placed onto a stack. Multiple states can be saved, and they are ‘piled up’ in the stack, so the state that was saved first will appear at the bottom, and the most recent at the top.

Then, when you want to restore the saved items, they will be restored from the top of the stack first, which are the most recent item saved, and then as more restores are made, the stack will diminish state by state and the last item to be restored will be the first item saved.

Save & restore example using coloured rectangles

I will go ahead and show an example based on my explanation above; I have used coloured rectangles to make the example simple to understand. The following steps have been carried out:

  • A rectangle with a green background is drawn and its state is saved (the shape itself isn’t saved, just the style – in this case the background colour). This is the first item on the stack. If another rectangle is drawn afterwards (or any other shape for that matter) without specifying any styling information, it will appear with exactly the same styling information as the one just drawn.
  • A rectangle with a yellow background is drawn next (and moved to the right so we can see it) and saved. This is the second item on the stack.
  • Then lastly, a rectangle with a pink background is drawn and also moved to the right so we can see it. This is the third item on the stack.
  • If I start restoring the states, if I draw another rectangle on the Canvas now, it will have a pink background, as this was the last saved state.
  • If restore is used again and I draw another rectangle, it will have a yellow background, as the yellow background state was saved directly before the pink background state.
  • Then, if I restore one more time and draw one last rectangle, it will appear with a background colour of green, which was the very first state that was saved.
HTML5 Canvas save and restore example using coloured rectangles

View demo

The markup

To save a state, use ctx.save() after you have specified a style or set of styles; this will save the state to the stack. Then, when you want to restore a previously saved state, use ctx.restore(), and draw a shape which the restored state will be applied to (in my case, I used rectangles).

View markup
Javascript portion
function draw() {	
	var canvas = document.getElementById("rectangles");
	if (canvas.getContext){
        	var ctx = canvas.getContext("2d"); 

		// Draw a green rectangle and save it
		ctx.fillStyle = "#9c0";
		ctx.fillRect (5, 5, 120, 160); 
		ctx.save();
			
		// Draw a yellow rectangle and save it
		ctx.fillStyle = "#fc0";
		ctx.fillRect (140, 5, 120, 160); 
		ctx.save();
			
		// Draw a pink rectangle and save it
		ctx.fillStyle = "#f06";
		ctx.fillRect (275, 5, 120, 160); 
		ctx.save();
			
		// Restore the previous (third) saved state and apply it to a rectangle
		ctx.restore();
		ctx.fillRect (410, 5, 120, 160); 
			
		// Restore the second saved state and apply it to a rectangle
		ctx.restore();
		ctx.fillRect (545, 5, 120, 160);
			
		// Restore the first saved state and apply it to a rectangle
		ctx.restore();
		ctx.fillRect (680, 5, 120, 160);
	}
}
HTML portion
<body onLoad="draw();">
	<canvas id="rectangles" width="800" height="170"></canvas>
</body>

But what practical use does save & restore have?

I know what you’re thinking; I couldn’t really think of anything I could use it for either. Well apparently it comes to good use when you are using transforms.

When you use a transform (e.g. translating, scaling, rotating), you transform the whole Canvas, not just one shape you place upon it. So, what I could do is save the canvas as it is before I apply any transforms to it, apply whatever transforms I like (let’s say I use ctx.rotate) and add a shape (which will be rotated, due to the transform context applied before it), then use restore to restore the Canvas back to how it was before I applied the transform. This will ensure that any other shapes I wish to add to the Canvas will not be affected by the transform.

Stretched shapes examples

These examples below show what would happen to some outlined shapes if I don’t use save and restore to reset the Canvas, and what they would look like if I did. I have used both a rectangle and a circle to experiment with. What I have done with these two is:

  • The square is 100px x 100px and the circle has a radius of 50px
  • They have a blue fill colour
  • They have a black stroke with a width of 8
  • I have doubled the horizontal width using ctx.scale so they are stretched horizontally

Without using save & restore

HTML5 Canvas save and restore example using coloured rectangles

View demo

As you can see, the shapes have been transformed, and the outline strokes have been transformed along with them, so they appear to be wider on the left and right sides of the shapes and narrower at the top and bottom.

If you look at my examples, you may notice that I have added a transform before applying anything else – this is just to get the shape into a place where the whole outline is visible, and not hidden off the edge of the Canvas.

View markup (for the rectangle)
Javascript portion
function draw() {	
	// Rectangle with squashed outline - Not using save and restore
        canvas = document.getElementById("rectangleNoSaveRestore");
        if (canvas.getContext) {
		var ctx = canvas.getContext("2d");
		
		ctx.translate(8, 4);
		
		ctx.scale(2, 1);
		
		ctx.beginPath();
		ctx.lineTo(100, 0);
		ctx.lineTo(100, 100);
		ctx.lineTo(0, 100);
		ctx.lineTo(0, 0);
		ctx.closePath();
		
		ctx.fillStyle = "#6cf";
		ctx.fill();
		ctx.lineWidth = 8;
		ctx.strokeStyle = "#000";
		ctx.stroke();
	}
}
HTML portion
<body onLoad="draw();">
	<canvas id="rectangleNoSaveRestore" width="216" height="108"></canvas>
</body>

Using save & restore

HTML5 Canvas save and restore example using coloured rectangles

View demo

View markup (for the rectangle)
Javascript portion
function draw() {	
	// Rectangle with intact outline - Using save and restore
        canvas = document.getElementById("rectangleSaveRestore");
        if (canvas.getContext) {
		var ctx = canvas.getContext("2d");
		
		ctx.translate(4, 4);
		
		ctx.save();
		
		ctx.scale(2, 1);
		
		ctx.beginPath();
		ctx.lineTo(100, 0);
		ctx.lineTo(100, 100);
		ctx.lineTo(0, 100);
		ctx.lineTo(0, 0);
		ctx.closePath();
		
		ctx.restore();
		
		ctx.fillStyle = "#6cf";
		ctx.fill();
		ctx.lineWidth = 8;
		ctx.strokeStyle = "#000";
		ctx.stroke();
	}
}
HTML portion
<body onLoad="draw();">
	<canvas id="rectangleSaveRestore" width="208" height="108"></canvas>
</body>

This next example shows what the shapes would look like if I used save and transform effectively. As you can see, the outlines have retained their shape. So, what I have done is added ctx.save() before ctx.scale so that the original setup of the Canvas was preserved. Then I have drawn the shapes (they will appear transformed), and immediately afterwards added ctx.restore() so that anything I add now won’t be affected by the transform. I now add in the styles – it doesn’t matter about the fill as that would have looked the same regardless, but it ensures that the stroke isn’t transformed along with the shape, as it was added in after the Canvas was restored back to normal.

If I come across any other uses, I’ll certainly post them here in the future!