Does HTML5 / Canvas support double buffering?

What I would like to do is draw my graphs on a buffer and then copy them as onto a canvas so that I can do the animation and avoid flickering. But I could not find this option. Does anyone know how I can do this?

+74
javascript html5 canvas double-buffering
May 08 '10 at 19:05
source share
12 answers

The following useful link, besides showing examples and advantages of using double buffering, shows some other performance tips for using the html5 canvas element. It includes links to jsPerf tests, which combine test results in browsers into a browser database. This ensures that performance recommendations are checked.

http://www.html5rocks.com/en/tutorials/canvas/performance/

For your convenience, I have included a minimal example of efficient double buffering, as described in the article.

// canvas element in DOM var canvas1 = document.getElementById('canvas1'); var context1 = canvas1.getContext('2d'); // buffer canvas var canvas2 = document.createElement('canvas'); canvas2.width = 150; canvas2.height = 150; var context2 = canvas2.getContext('2d'); // create something on the canvas context2.beginPath(); context2.moveTo(10,10); context2.lineTo(10,30); context2.stroke(); //render the buffered canvas onto the original canvas element context1.drawImage(canvas2, 0, 0); 
+28
Apr 27 '12 at 19:56
source share

A very simple method is to have two canvas elements in the same place on the screen and set the visibility for the buffer you need to show. Draw hidden and flip when done.

Some codes:

CSS

 canvas { border: 2px solid #000; position:absolute; top:0;left:0; visibility: hidden; } 

Switching to JS:

 Buffers[1-DrawingBuffer].style.visibility='hidden'; Buffers[DrawingBuffer].style.visibility='visible'; DrawingBuffer=1-DrawingBuffer; 

In this code, the Buffers [] array contains both canvas objects. Therefore, when you want to start drawing, you still need to get the context:

 var context = Buffers[DrawingBuffer].getContext('2d'); 
+82
May 19 '10 at 10:09
source share

The browsers I tested process this buffering for you without redrawing the canvas until the code that draws your frame completes. See also the WHATWG mailing list: http://www.mail-archive.com/whatwg@lists.whatwg.org/msg19969.html

+18
Feb 28 2018-11-11T00:
source share

You can always do var canvas2 = document.createElement("canvas"); and do not add it to the DOM at all.

Just saying, since you guys are so obsessed with display:none; it just seems cleaner and more accurately mimics the idea of ​​double buffering than just an uncomfortably invisible canvas.

+11
Jan 16 '16 at 12:22
source share

More than two years later:

There is no need to manually double-buffer. Mr. Geary wrote about this in his book "HTML5 Canvas . "

To effectively reduce the use of flicker requestAnimationFrame() !

+7
Oct 09 '13 at 16:46
source share

For unbelievers, here's some kind of flickering code. Note that I explicitly clear to erase the previous circle.

 var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); function draw_ball(ball) { ctx.clearRect(0, 0, 400, 400); ctx.fillStyle = "#FF0000"; ctx.beginPath(); ctx.arc(ball.x, ball.y, 30, 0, Math.PI * 2, true); ctx.closePath(); ctx.fill(); } var deltat = 1; var ball = {}; ball.y = 0; ball.x = 200; ball.vy = 0; ball.vx = 10; ball.ay = 9.8; ball.ax = 0.1; function compute_position() { if (ball.y > 370 && ball.vy > 0) { ball.vy = -ball.vy * 84 / 86; } if (ball.x < 30) { ball.vx = -ball.vx; ball.ax = -ball.ax; } else if (ball.x > 370) { ball.vx = -ball.vx; ball.ax = -ball.ax; } ball.ax = ball.ax / 2; ball.vx = ball.vx * 185 / 186; ball.y = ball.y + ball.vy * deltat + ball.ay * deltat * deltat / 2 ball.x = ball.x + ball.vx * deltat + ball.ax * deltat * deltat / 2 ball.vy = ball.vy + ball.ay * deltat ball.vx = ball.vx + ball.ax * deltat draw_ball(ball); } setInterval(compute_position, 40); 
 <!DOCTYPE html> <html> <head><title>Basketball</title></head> <body> <canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;"> Your browser does not support the canvas element. </canvas> </body></html> 
+6
Jun 05 '12 at 6:27
source share

Josh asked (some time ago) how the browser knows “when the drawing process is over” to avoid flickering. I would immediately comment on his post, but my representative is not high enough. And this is just my opinion. I have no facts to support this, but I feel pretty confident about it, and may be useful to others reading this in the future.

I assume that the browser does not “know” when you are finished drawing. But, like most javascript, as long as your code works without giving up managing the browser, the browser is essentially blocked and cannot / cannot update / respond to its user interface. I assume that if you clear the canvas and draw your entire frame without giving up on the browser, it will not draw your canvas until you finish.

If you set up a situation where your rendering spans multiple calls to setTimeout / setInterval / requestAnimationFrame, where you clear the canvas in one call and draw elements on your canvas in the next few calls, repeating a loop (for example) every 5 calls, I bet you You will see flickering, as the canvas will be updated after each call.

However, I'm not sure I will trust this. We are already at a point where javascript is compiled to native machine code before execution (at least what the Chrome V8 engine does from what I understand). I would not be surprised if there wasn’t too much time before browsers ran javascript in a separate thread from the user interface and synchronized any access to the user interface elements, allowing the user interface to update / respond during javascript execution that did not have access to the user interface to the interface. When / if this happens (and I understand that there are many obstacles to overcome, such as event handlers when you are still running other code), we will probably see flickering on canvas animations that do not use some double buffering.

Personally, I like the idea of ​​two canvas elements located on top of each other and alternating, which are shown / drawn on each frame. Pretty non-intrusive and probably pretty easy to add to an existing application with a few lines of code.

+6
Sep 25
source share

There is no flicker in web browsers! They already use dbl buffering to render them. Js engine will do all your rendering before showing it. In addition, the context saves and restores only the data of the transformation matrix of the stack and, therefore, not the content of the canvas itself. So you don't need or need dbl buffers!

+5
Mar 06 2018-11-11T00:
source share

Instead of skating on your own, you'll probably get better mileage using your existing library to create pure JavaScript animations without flicker:

Popular here: http://processingjs.org

+3
May 12 '10 at 20:39
source share

Opera 9.10 is very slow and shows the drawing process. If you want your browser not to use double buffering, try using Opera 9.10.

Some people have suggested that browsers somehow determine when the drawing process ends, but can you explain how this might work? I did not notice any obvious flicker in Firefox, Chrome or IE9, even when the drawing is slow, so it seems that this is what they do, but how it is done is a mystery to me. How will the browser ever know that it is updating the display before other drawing instructions are followed? Do you think that they just time it is so, if the interval is more than 5 ms or so goes without executing the canvas drawing instruction, does it assume that it can safely change the buffer?

+2
Jan 23 '12 at 4:25
source share

you need 2 canvases: (pay attention to css z-index and position: absolute)

 <canvas id="layer1" width="760" height="600" style=" position:absolute; top:0;left:0; visibility: visible; z-index: 0; solid #c3c3c3;"> Your browser does not support the canvas element. </canvas> <canvas id="layer2" width="760" height="600" style="position:absolute; top:0;left:0; visibility: visible; z-index: 1; solid #c3c3c3;"> Your browser does not support the canvas element. </canvas> 

you can notice that the first canvas is visible, and the second hides the idea of ​​drawing it on the hidden one, after which we hide the visibility and make the hidden canvas visible. when it is hidden "clear hidden canvas

 <script type="text/javascript"> var buff=new Array(2); buff[0]=document.getElementById("layer1"); buff[1]=document.getElementById("layer2"); ctx[0]=buff[0].getContext("2d"); ctx[1]=buff[1].getContext("2d"); var current=0; // draw the canvas (ctx[ current ]); buff[1- current ].style.visibility='hidden'; buff[ current ].style.visibility='visible'; ctx[1-current].clearRect(0,0,760,600); current =1-current; 
+2
Apr 14 '12 at 23:21
source share

In most situations, you do not need to do this; the browser implements this for you. But not always useful!

You still need to realize this when your drawing is very complex. Most of the screen refresh rate is around 60 Hz, which means a 16 ms screen refresh. Browser refresh rates may be close to this number. If you need a 100 ms form, you will see an incomplete form. This way you can implement double buffering in this situation.

I did a test: Clear a rect, wait for some time, then fill with some color. If I set the time to 10 ms, I will not see the flicker. But if I set it to 20 ms, a flicker will occur.

+2
Jun 16 '13 at 12:08
source share



All Articles