albert.walickihire me
← all solutions
javascript

How to clear a canvas in JavaScript?

Clear an HTML canvas with clearRect, why old shapes come back without beginPath, and how to clear correctly after translate, scale or rotate.

Call clearRect() on the 2D context with the full size of the canvas. It makes every pixel transparent again.

const canvas = document.querySelector('.drawing');
const ctx = canvas.getContext('2d');

ctx.clearRect(0, 0, canvas.width, canvas.height);

Use canvas.width and canvas.height, the size of the drawing surface in pixels, not the size of the element on the page (clientWidth or getBoundingClientRect()). The two are often different, especially when you make the drawing surface bigger for sharp rendering on high-density screens.

Cleared shapes come back: call beginPath()

This is the most common surprise. You clear the canvas, draw a new line, and the old lines reappear with it.

ctx.clearRect(0, 0, canvas.width, canvas.height);

ctx.beginPath(); // without this, old lines are stroked again
ctx.moveTo(20, 20);
ctx.lineTo(200, 120);
ctx.stroke();

clearRect() only clears pixels. The current path, everything you added with moveTo(), lineTo(), arc() or rect(), is still stored in the context. The next stroke() or fill() draws the whole path again, old parts included. beginPath() throws the old path away.

In an animation loop, that means clearing and starting a new path every frame:

function draw(x) {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  ctx.beginPath();
  ctx.arc(x, 75, 20, 0, Math.PI * 2);
  ctx.fill();

  requestAnimationFrame(() => draw((x + 2) % canvas.width));
}

draw(0);

fillRect() and strokeRect() don't touch the path, so they don't have this problem.

Clearing after translate, scale or rotate

clearRect() uses the current transform. If you called ctx.translate(100, 0), the rectangle you clear moves 100 pixels to the right too, and a strip on the left stays dirty. Reset the transform to the identity matrix while you clear, then restore it:

ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();

ctx.resetTransform() does the same as that setTransform() call.

Resetting everything

Setting the canvas width, even to the same value, clears the canvas and resets the whole context:

canvas.width = canvas.width;

That includes the transform, fillStyle, strokeStyle, lineWidth, font, the clipping region and the current path. It's useful when you want a completely fresh start, but it's surprising if you set your styles once at the beginning, and it's heavier than clearRect(), so don't do it on every frame.

There's also ctx.reset(), which does the same without the width trick. It's a fairly recent addition, so check Can I Use before relying on it.

Canvas with a solid background

If the canvas should never be transparent, fill it with the background color instead of clearing it:

ctx.fillStyle = '#0f172a';
ctx.fillRect(0, 0, canvas.width, canvas.height);

Clearing would make it transparent, so the page behind it would show through. For a canvas that's always opaque, you can also create the context with canvas.getContext('2d', { alpha: false }), which tells the browser it doesn't have to handle transparency for it.

more solutions
work with me

Got something that needs building?

Frontend builds, full-stack features in Django, design-system work. Available for work.

See my workGet in touch