HTML5 Canvas Flickers in Firefox 4

I am working on proof of concept on HTML5 canvas. I was able to make it work like a charm in Chrome and IE9, but in Firefox 4 I constantly get flickering when it redraws the canvas. I tried several methods mentioned on this site like double buffering, but I still get a lot of flicker. Any insight into this would be appreciated!

<!DOCTYPE HTML> <html> <head> <style type="text/css"> body { margin:0px; padding:0px; text-align:center; } canvas { outline:0; border:1px solid #000; margin-top: 10px; margin-left: auto; margin-right: auto; } </style> <script type="text/javascript"> var canvasWidth = 640; var thisXPos = 0; var canvasHeight = 820; var thisYPos = 0; var canvas = null; var context = null; var gLoop = null; var rain = []; var rainImg = "images/raindrop.gif"; var bgImg = null; var i; for (i = 0; i < howManyLetters; i++) { rain.push([Math.floor(Math.random() * canvasWidth), Math.floor(Math.random() * canvasHeight),rainImg]); } var DrawRain = function() { for (i = 0; i < 10; i++) { thisXPos = rain[i][0]; thisYPos = rain[i][1]; imgSrc = rain[i][2]; letterImg = new Image(); letterImg.setAtX = thisXPos; letterImg.setAtY = thisYPos; letterImg.onload = function() { context.drawImage(this, this.setAtX, this.setAtY); } letterImg.src = imgSrc; } }; var MoveRain = function(e) { for (i = 0; i < 10; i++) { if ((rain[i][1] - 5) > canvasHeight) { randomnumber = Math.floor(Math.random()*26); rain[i][0] = Math.random() * canvasWidth; rain[i][1] = 0; rain[i][2] = rainImg; } else { rain[i][1] += e; } } }; var clear = function() { context.beginPath(); context.rect(0, 0, canvasWidth, canvasHeight); context.closePath(); bgImg = new Image(); bgImg.src = "images/bg.png"; bgImg.onload = function() { context.drawImage(bgImg,0,0); } } var GameLoop = function() { context.save(); clear(); MoveRain(1); DrawRain(); context.restore(); gLoop = setTimeout(GameLoop, 10); } function loadGame() { canvas = document.getElementById("gameCanvas"); context = canvas.getContext("2d"); canvas.width = canvasWidth; canvas.height = canvasHeight; GameLoop(); } </script> </head> <body onload="loadGame();"> <canvas id="gameCanvas"></canvas> </body> </html> 
+4
source share
2 answers

I compared your example with this:

http://jsfiddle.net/sPm3b/6/

And it works very fast in Firefox and Chrome.

So we know that the problem is with the images.

You need to optimize how they are created and loaded. Right now, every clear() creating a new image and waiting for it to load! This image should only be created once, in your loadGame() , and then reused over and over again.

Same thing with letterImg in DrawRain() . Move its creation to loadGame()

This will probably fix the problem.

EDIT:

like this:

At the top add:

 var letterImg = new Image(); var bgImg = new Image(); 

Then

 function loadGame() { canvas = document.getElementById("gameCanvas"); context = canvas.getContext("2d"); canvas.width = canvasWidth; canvas.height = canvasHeight; bgImg.src = "images/bg.png"; letterImg.src = "images/raindrop.gif"; // optional: wait for them to load here GameLoop(); } 

Then drawRain, for example, would look like this:

 var DrawRain = function() { for (i = 0; i < 10; i++) { thisXPos = rain[i][0]; thisYPos = rain[i][1]; context.drawImage(letterImg, thisXPosX, thisYPos); // letterImg was already constructed, no need to make it again } }; 
+5
source

In addition to the answer of Simon Sarris. I used the "double canvas" method to avoid curling the screen with a heavy canvas.

How it works, there are always 2 versions of the canvas, one in the DOM, one on the outside and always draws one that is not in the DOM . I use it with a redraw queue.

here is part of the working code

 (...) clear: function() { //rotating on 2 canvas, one for draw (outside DOM) one for show var self = this; if (null == self.canvasbackup) { var tmpcanvas = self.canvas.clone(true); self.canvasbackup = self.canvas; self.canvas=tmpcanvas; } else { var tmpcanvas = self.canvasbackup; self.canvasbackup = self.canvas; self.canvas=tmpcanvas; } self.ctx = self.canvas[0].getContext('2d'); self.ctx.clearRect( 0, 0, self.options.width, self.options.height ); jQuery.each(self.elements,function(idx,elt){ // custom function: my elements need to know which canvas they depends on elt.reconnectCanvas(self.canvas,self.ctx); }); }, inDOM: function() { var self = this; if(null==self.canvasbackup) { //1st time need to get all things in DOM self.canvas.appendTo(self.div); self.div.appendTo(self.container); } else { // remove current shown canvas self.connectHuman(); self.canvasbackup.remove(); // loosing some events here... self.canvas.appendTo(self.div); // div is already in DOM, we are in redraw } }, redraw: function() { var self = this; self.clear(); jQuery.each(self.elements,function(idx,elt){ elt.draw(); elt.enddraw(); }); self.inDOM(); } (...) 
+1
source

All Articles