HTML5 Canvas: You don’t always have to clear the entire thing

April 3rd, 2011

When I first started working with the HTML5 canvas element, the one thing I found a bit frustrating was the fact that you had to clear the canvas and then redraw it. Coming from Flash, I wasn’t used to this because it’s one of the many things Flash does for you. With canvas, if you’re doing something like moving a space ship around in a game and you don’t clear it before you draw the ship’s new position, eventually you’ll just end up with canvas full of ships. So, we call clearRect and clear the canvas before we draw the ship’s new position and then it looks like the ship is moving around, when it’s really just being redrawn in it’s new position.

But the thing I didn’t realize at first, and I’m sure many other newbies at working with canvas don’t realize either, but you don’t have to clear the entire canvas, you can just simulate what Flash does and just redraw the area that’s changed. Why would you want to do this? Well, think about a graphically heavy game but there’s only one or two objects moving around, you could cut down on CPU use if you just redraw the areas affected by the moving objects.

This is actually a lot simpler than you would think. Instead of something like this:

1
ctx.clearRect(0,0,canvasWidth,canvasHeight);

we can do something like this:

1
ctx.clearRect(square.x,square.y,square.w,square.h);

In the first example, we’re clearing the entire canvas, in the second, we’re just clearing the area of a square. So now we’re just redrawing a 20 by 20 pixel area instead of say, a 500 by 500 pixel area, a lot less work for our broswer and CPU!

Plus, we can call clearRect more than once. So, here’s the code for an example that has two moving squares, one we can control with the arrow keys and one that moves down on it’s own. And instead of clearing the entire canvas, we just clear two square sized areas.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>ClearRect Test</title>
<style>
body {
  margin:0;
  padding:0;
  background:#000;
}
canvas {
  display:block;
  margin:20px auto;
  border:1px dashed #0f0;
}
</style>
<script>
var canvas, ctx, loop, square, square2, rightKey = false, leftKey = false, upKey = false, downKey = false;

function init() {
  canvas = document.getElementById('canvas');
  ctx = canvas.getContext('2d');
  square = {x:10,y:10,w:20,h:20};
  square2 = {x:400,y:10,w:20,h:20};
  draw();
  document.addEventListener('keydown',keyDown,false);
  document.addEventListener('keyup',keyUp,false);
}
function clearRect() {
  ctx.clearRect(square2.x,square2.y,square2.w,square2.h);
  ctx.clearRect(square.x,square.y,square.w,square.h);
}
function drawSquare() {
  if (rightKey) square.x += 5;
  else if (leftKey) square.x -= 5;
  if (upKey) square.y -= 5;
  else if (downKey) square.y += 5;
  ctx.fillStyle = '#0f0';
  ctx.fillRect(square.x,square.y,square.w,square.h);
  square2.y += 1;
  ctx.fillRect(square2.x,square2.y,square2.w,square2.h);
}
function keyDown(e) {
  if (e.keyCode == 39) rightKey = true;
  else if (e.keyCode == 37) leftKey = true;
  if (e.keyCode == 38) upKey = true;
  else if (e.keyCode == 40) downKey = true;
}

function keyUp(e) {
  if (e.keyCode == 39) rightKey = false;
  else if (e.keyCode == 37) leftKey = false;
  if (e.keyCode == 38) upKey = false;
  else if (e.keyCode == 40) downKey = false;
}
function draw() {
  clearRect();
  drawSquare();
  loop = setTimeout(draw, 1000/30);
}
window.onload = init;
</script>
</head>

<body>
<canvas id="canvas" width="500" height="500"></canvas>
</body>
</html>

I’ve just started experimenting with this technique, but I can really see it’s potential. There will still be plenty of times when it’s better to use clearRect to clear the entire canvas, but having this in your arsenal will help you become a better JavaScript developer.

One Response to HTML5 Canvas: You don’t always have to clear the entire thing

  1. imbusy says:

    You would also have to redraw whatever background objects intersect the square you are redrawing. It’s not hard, but it does require you to think about square vs. square collision checks for objects.

Leave a Reply

Your email address will not be published. Required fields are marked *