Last Updated: September 09, 2019
·
25.19K
· avgp

Easy double buffering on HTML5 canvas

There is a lot of cool stuff around HTML5 canvas, requestAnimationFrame and making animations with Javascript.

If you can, you should also check out CSS animations if you're after animating DOM elements.

For more advanced stuff, you may want to use a canvas, that is usually GPU-accelerated and allows pretty high and stable framerates using window.requestAnimationFrame.

If you need double buffering on the canvas, one of the popular ways is to create a second canvas element and draw to that one and then draw the completed image to the primary canvas using drawImage, resulting in something like this:

var primaryCtx = document.getElementById("canvas").getContext("2d");
var secondaryCanvas = document.createElement("canvas"),
      secondaryCtx = secondaryCanvas.getContext("2d");

(function drawFrame() {
    requestAnimationFrame(drawFrame);
    secondaryCtx.fillStyle = "#f00";
    secondaryCtx.fillRect(10,10,20,20);
    primaryCtx.drawImage(secondaryCanvas);
})();

which never felt quite right.

Enter ctx.save() and ctx.restore()
Today I discovered there's a way that feels cleaner and performs just as good as the method from above:

(function drawFrame() {
    requestAnimationFrame(drawFrame);
    primaryCtx.save(); //Freeze redraw
    primaryCtx.fillStyle = "#f00";
    primaryCtx.fillRect(10,10,20,20);
    primaryCtx.restore(); //And now do the redraw
})();

which, despite the weird names, just freezes the rendering of the context and then resumes rendering after we're finished drawing on it.

2 Responses
Add your response

Hi, nice try. But I fear that using save() and restore() does not have your described effect. save() does not save the canvas (or its content) but its state, like e.g transformation matrices and drawing colors. While save() pushes the current state on a stack, restore() pops it back. This has nothing to do with double buffering.

over 1 year ago ·

Well, if it really reduced the flickering then think pragmatic and let it like this. Regarding the "double buffering" it seems that nowadays most browsers implement some double buffering. Take a look here: http://goo.gl/Ue05s7

Another very nice post on general Canvas performances is here: http://www.html5rocks.com/en/tutorials/canvas/performance/

One of the tips is about off-screen rendering to gain runtime performance. This is similar to classic double buffering (the author called it displaylist) and I make broad use of it. Not only for performance a important technique.

To effectively reduce flickering it is important to use requestAnimationFrame() instead of setInterval(). Here is some more detailed description, why to use requestAnimationFrame(): http://devbutze.blogspot.com.br/2013/09/requestanimationframe-is-what-you-need.html

over 1 year ago ·