Erik Putz
Erik Putz

Reputation: 359

Canvas animation keeps redrawing previous frames

I am figuring this one out an unhealthy amount of time for now and I did not found any note for this bug. I started to build a simple HTML Canvas animation in JavaScript. For now I expect the small squares to move. Here is the code (I am also using babeljs):

class Pod {
  constructor(x,y) {        
    this.posX = x;
    this.posY = y;
    this.velX = getRandomNumber(-5,5);
    this.velY = getRandomNumber(-5,5);    
  }

  getPos() {
    return ([this.posX,this.posY]);
  }

  move() {
    this.posX += this.velX;
    this.posY += this.velY;
  }

  render() {    
    ctx.save();   
    ctx.rect(this.posX,this.posY,3,3);
    ctx.fillStyle = "#ffffff";
    ctx.fill();
    ctx.restore();
  }
}
/*the classes end here*/

var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d');

var elementsNum = 10;

const stack = new Array(elementsNum);

for(var i = 0; i < elementsNum; i++) {
  stack[i] = new Pod(getRandomNumber(0,500),getRandomNumber(0,500));
}


function run() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = "#000000";
  ctx.fillRect(0,0,canvas.width,canvas.height);
  ctx = canvas.getContext('2d');
  for(var i = 0; i < elementsNum; i++) {
    stack[i].move();
    stack[i].render();
  }
  //window.requestAnimationFrame(run);
}


/*helper functions*/
function getRandomNumber(min, max) {
  return Math.random() * (max - min) + min;
}

After running a cycle of the function run(), the small squares (I called them Pods) are rendered. Next cycle starts with clearing the canvas with ctx.clearRect... I am resetting the context and start moving and then drawing the Pods from the stack. When I draw the first Pod, it will draw all of them and also the previous frame.

Here is the codepen for this particular script: http://codepen.io/erikputz/pen/YNNXqX

(I knowingly commented the requestAnimationFrame, so you need to use the console to call the run() function)

Thank you forward for your help.

Upvotes: 1

Views: 860

Answers (1)

zfrisch
zfrisch

Reputation: 8660

http://codepen.io/zfrisch/pen/bgazyO

This should solve your issue:

render() {    

ctx.beginPath();
ctx.rect(this.posX,this.posY,3,3);
ctx.fillStyle = "#ffffff";
ctx.fill();
ctx.closePath();

}

With canvas you need to identify individual shapes through code by using the beginPath and closePath methods. In certain methods this is innate, like in fillRect. Hence the above code could be simplified even more to:

render() {    
ctx.fillStyle = "#ffffff";
ctx.fillRect(this.posX,this.posY,3,3);  
}

When you're just declaring a shape (rect) you need to specify when the path begins and when it is closed, otherwise it will most likely cause issues like the shape-bleeding you had in your original code.

Also, as a tip, you don't need to save state.save() / .restore() unless you're translating/scaling/rotating/or moving on the canvas element. Filling shapes doesn't apply.

Upvotes: 2

Related Questions