Justin Hathaway Justin Hathaway - 2 months ago 11
Javascript Question

Why doesn't context.clearRect() work inside requestAnimationFrame loop?

I have a canvas element on the page that is having a circle drawn and moved on it. The circle is being moved by one pixel in every iteration of the loop. Here is the code.



function clearPage() {
context.clearRect(0,0,300, 150);
};

var canvasEl = document.getElementById("main");
var context = canvasEl.getContext('2d');

context.fillStyle = 'red';
context.strokeStyle = 'red';

var x = 0;
function moveCircle() {
clearPage();
context.arc(x, 75, 20, 0, 2* Math.PI);
context.stroke();
x++;
window.requestAnimationFrame(moveCircle);
}
moveCircle();

canvas {
border: 1px solid black;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
<title>Canvas Practice</title>
</head>
<body>
<canvas id='main'></canvas>
<script src="main.js"></script>
</body>
</html>





As is evident, my function clears the page before drawing the new circle. Though when run, you can see that it leaves the previously drawn circles on the page. If you were to call the clearPage() function after it finished animating, the whole page would get cleared like expected.

More than anything, I just want to know why this is happening. It doesn't seem to be completely intuitive but my best guess is that it has to do with the behavior of requestAnimationFrame();

Answer

You should use the context.beginPath(); before drawing the arc.

The reason is that the arcs are added to to the same path so each command redraws the whole path (see https://www.w3.org/TR/2dcontext/#dom-context-2d-arc). Using the beginPath starts a new path for each arc and thus does not redraw the previous ones.

function clearPage() {
    context.clearRect(0,0,300, 150);
  };

  var canvasEl = document.getElementById("main");
  var context = canvasEl.getContext('2d');
  
  context.fillStyle = 'red';
  context.strokeStyle = 'red';
 
  var x = 0;
  function moveCircle() {
    clearPage();
    context.beginPath();
    context.arc(x, 75, 20, 0, 2* Math.PI);
    context.stroke();
    x++;
    window.requestAnimationFrame(moveCircle);
  }
  moveCircle();
canvas {
  border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
  <head>
    <title>Canvas Practice</title>
  </head>
  <body>
    <canvas id='main'></canvas>
    <script src="main.js"></script>
  </body>
</html>