简体   繁体   中英

Simple Html5 Canvas operation slows down browser

I've been playind with canvas lately and started today to work on using setInterval to refresh / animate it regularly. I was surprised to see how this is heavy for the cpu and slows down eveyrthing. Looking at example online I m sure there is something wrong with my way of doing. I then simplified what I wanted to do at the maximum (not playing with image but rectangles, not using too many objects, etc) but still got the same problem.

I was trying to get a white flash (at 12fps) on top of two rectangles...So nothing complicate at all...

Here is my code.

function Canvas(name){
this.ctx=document.getElementById(name).getContext('2d');
this.canvas=this.ctx.canvas;
this.width=this.canvas.width;
this.height=this.canvas.height;
this.layers=new Array();

this.draw = function() {
this.canvas.width = this.canvas.width;
    this.ctx.beginPath();
    this.ctx.rect(0,0,this.width,this.height);
    this.ctx.closePath();
    this.ctx.fillStyle="#eaeaea";
    this.ctx.fill();
    this.ctx.beginPath();
    this.ctx.rect(250,50,300,250);
    this.ctx.closePath();
    this.ctx.fillStyle="#ff0000";
    this.ctx.fill();

    intensity=Math.random();
    this.flash(intensity);
 };

this.flash = function(intensity) {
    this.ctx.globalAlpha = intensity;
    this.ctx.beginPath();
    this.ctx.rect(0,0,this.width,this.height);
    this.ctx.closePath();
    this.ctx.fillStyle="#fff";
    this.ctx.fill();
    this.ctx.globalAlpha = 1;
    setInterval(this.draw.bind(this),1000);
};

function initCanvas(){
mycanvas=new Canvas('myCanvas');
mycanvas.draw();
}

$(document).ready(function() {
    initCanvas();
});

Solution found:

Use setTimeout instead of setInterval .

Close all the paths, which you open:

this.draw = function() {
    this.canvas.width = this.canvas.width;
    this.ctx.beginPath();
    this.ctx.rect(0,0,this.width,this.height);
    this.ctx.closePath();    //Closing
    this.ctx.fillStyle="#eaeaea";
    this.ctx.fill();
    this.ctx.beginPath();
    this.ctx.rect(250,50,300,250);
    this.ctx.closePath();    //Closing
    this.ctx.fillStyle="#ff0000";
    this.ctx.fill();

    this.flash(40);
};

this.flash = function(intensity) {
    this.ctx.globalAlpha = intensity;
    this.ctx.beginPath();
    this.ctx.rect(0,0,this.width,this.height);
    this.ctx.closePath();    //Closing
    this.ctx.fillStyle="#fff";
    this.ctx.fill();
    this.ctx.globalAlpha = 1;
    setInterval(this.draw.bind(this),1000);
};

You've got a massive memory leak because you keep using setInterval in the flash function. Let's look at the sequence of events

  • mycanvas object created
  • draw()
  • draw calls flash
  • flash sets an interval to call draw every second
  • draw calls flash and sets another interval
  • Process repeats till you've got a lot of intervals calling draw

To solve it, use setTimeout in flash . So it calls draw after a second, which calls flash and then calls draw again in a second. Also, 1000ms won't give you 12fps. 1000/12 will.

Also, use ctx.closePath(); to close the paths you opened with beginPath()

You also never closed the Canvas function with a } .

Here's a demo

I don't know if this is relevant anymore, but I found myself in a similar situation and wanted to give an even better answer. Use requestAnimationFrame(yourLoop) , especially for games since it is faster and has better performance. http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM