1114

After experimenting with composite operations and drawing images on the canvas I'm now trying to remove images and compositing. How do I do this?

I need to clear the canvas for redrawing other images; this can go on for a while so I don't think drawing a new rectangle every time will be the most efficient option.

smalinux
  • 1,059
  • 2
  • 11
  • 25
richard
  • 12,450
  • 7
  • 33
  • 38

23 Answers23

1452

Given that canvas is a canvas element or an OffscreenCanvas object,

const context = canvas.getContext('2d');

context.clearRect(0, 0, canvas.width, canvas.height);
D. Pardal
  • 4,876
  • 1
  • 13
  • 32
Pentium10
  • 190,605
  • 114
  • 394
  • 474
  • 1
    Setting the width works for me on Chrome 9.0.597.107, but not on Safari 5.0.3 (Windows) – Amir Mar 03 '11 at 02:33
  • 47
    Note that for `clearRect` you need to either have an untransformed context, or keep track of your actual boundaries. – Phrogz Apr 02 '11 at 22:56
  • 7
    Note further that setting the canvas width a) needs to set it to a different value and then back again [for Webkit compatibility](http://stackoverflow.com/questions/2142535/how-to-clear-the-canvas-for-redrawing/3385076#3385076), and b) this will [reset your context transformation](http://stackoverflow.com/questions/5526486/clear-entire-transformed-html5-canvas-while-preserving-context-transform). – Phrogz Apr 02 '11 at 23:27
  • 5
    Indeed the width trick causes a drop in FPS both in 2D canvas and in WebGL — prefer to use .clearRect, which is the standard method. – dionyziz Aug 17 '11 at 20:51
  • 1
    @bplus: `context.canvas.width = context.canvas.width` clears the context. Works in Chrome as well. –  Nov 02 '12 at 04:52
  • @kadaj, it may work but it is substantially slower than alternatives and destroys the state of your canvas. Why use a slow hack when you can use the method designed for clearing a canvas (and doing it fast)? – Prestaul Dec 06 '12 at 21:44
  • 1
    I wonder why there isn't a `context.clear()` function that can be used with a path, like `context.fill()`. – Braden Best Jan 28 '13 at 22:09
  • 3
    The width trick is really nice, just one more addition to make it simplier is `canvas.width+=0` which is useful when you are getting canvas by `getElementById()` and not storing it – Kyborek Feb 17 '13 at 11:55
  • 1
    @B1KMusic : This is easy to simulate using destination-out compositing. [JsFiddle](http://jsfiddle.net/wYA9y/). – Brian McCutchon Jul 31 '13 at 21:59
  • 1
    @Sortofabeginner Ugh, global composites, still need to learn how to use those. Anyways, `CanvasRenderingContext2D.prototype.clear()` seems like a function that should be in the standard library. – Braden Best Aug 01 '13 at 05:07
  • 52
    Don't use the width trick. It's a dirty hack. In a high level language such as JavaScript what you want is to best state your intentions, and then let the lower level code fulfill them. Setting the width to itself does *not* state your true intention, which is to clear the canvas. – andrewrk Aug 09 '13 at 18:24
  • I noticed changing the width introduces an issue in Firefox where the next draw of the canvas is delayed. This becomes increasingly annoying if you use multiple canvases with different animations on both that need to be fairly aligned. Long story short: use clearRect (especially if you plan on using multiple canvases for performance). – Martijn Hols Feb 02 '14 at 20:06
  • 31
    A totally minor suggesting but I'd suggest `context.clearRect(0, 0, context.canvas.width, context.canvas.height)`. It's effectively the same thing but one less dependency (1 variable instead of 2) – gman Aug 18 '16 at 08:19
  • 1
    re: stating intentions in high level languages - In just about any real context, a programmer needs to do whatever currently works well, regardless of what language they're working in. They can't wait around for however long for the underlying tech to change. You can make your intention clear by naming your function "clearCanvas" or calling an external library function named as clearly. (To be clear - I'm not advocating the hack. I'm just saying that if you do use it, you can make your intention clear enough by simply wrapping it in a function called "clearCanvas.") – Shavais Sep 18 '16 at 22:55
  • 19
    For more recent readers of this answer: **be aware that this answer was modified and that some of the above comments no longer apply**. – daveslab Jan 12 '17 at 11:26
  • 2
    To get your context: `var c = document.getElementById('canv1')` and `var context = c.getContext('2d')` – herve May 31 '17 at 14:34
  • 2
    You either need to redraw the background after each clear or have a second canvas below the first one that doesn't get cleared and contains the background. – Badrush May 09 '19 at 02:02
753

Use: context.clearRect(0, 0, canvas.width, canvas.height);

This is the fastest and most descriptive way to clear the entire canvas.

Do not use: canvas.width = canvas.width;

Resetting canvas.width resets all canvas state (e.g. transformations, lineWidth, strokeStyle, etc.), it is very slow (compared to clearRect), it doesn't work in all browsers, and it doesn't describe what you are actually trying to do.

Dealing with transformed coordinates

If you have modified the transformation matrix (e.g. using scale, rotate, or translate) then context.clearRect(0,0,canvas.width,canvas.height) will likely not clear the entire visible portion of the canvas.

The solution? Reset the transformation matrix prior to clearing the canvas:

// Store the current transformation matrix
context.save();

// Use the identity matrix while clearing the canvas
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvas.width, canvas.height);

// Restore the transform
context.restore();

Edit: I've just done some profiling and (in Chrome) it is about 10% faster to clear a 300x150 (default size) canvas without resetting the transform. As the size of your canvas increases this difference drops.

That is already relatively insignificant, but in most cases you will be drawing considerably more than you are clearing and I believe this performance difference be irrelevant.

100000 iterations averaged 10 times:
1885ms to clear
2112ms to reset and clear
Prestaul
  • 76,622
  • 10
  • 80
  • 84
  • 4
    @YumYumYum: Is clear() a standard function? It doesn't seem to be. – Brent Bradburn Jun 24 '12 at 19:15
  • 9
    Note that you can remove the need for a local `canvas` variable by using `ctx.canvas` instead. – Drew Noakes Oct 12 '12 at 21:30
  • 2
    @DrewNoakes, good point, but I almost always opt for separate variables for speed purposes. It is extremely minor, but I try to avoid dereferencing time by aliasing frequently used properties (especially inside of an animation loop). – Prestaul Oct 25 '12 at 18:05
  • AlexanderN's demo didn't work anymore due to broken image link, fixed: http://jsfiddle.net/Ktqfs/50/ – Domino Mar 16 '15 at 15:07
  • Another way to clear the entire canvas in the event of transformation matrix modification is to simply keep track of the transformations and apply them yourself to `canvas.width` and `canvas.height` when clearing. I haven't done any numerical analysis on the runtime difference compared to resetting the transform, but I suspect it would eek out a little better performance. – NanoWizard Sep 01 '15 at 20:50
  • @NanoWizard, I haven't tested clearing specifically, but I have done similar things in the past in canvas wrapper libs I've written (e.g. to calculate hit-boxes after transformations). In my experience, setting the transform is extremely efficient and highly optimized (as is saving/restoring state). If you have the option of using those built in optimizations, choose them every time! – Prestaul Sep 02 '15 at 16:20
  • This seems like a gaping hole in the API in my opinion.There should be a standardized clear() call that does not require arguments to be passed. But I guess I'm not part of the standards board.... :P – dudewad Oct 13 '15 at 23:53
  • how about garbage collection? do both methods have the same behavior wrt GC? also worth noting is that according to http://simonsarris.com/blog/346-how-you-clear-your-canvas-matters the `width` method is faster on Safari. – Erik Kaplun Dec 04 '15 at 13:33
  • @ErikAllik, you referenced a blog from 2011 that only mentions Safari on Windows; probably not a key portion of the market. WRT garbage collection, I haven't done any tests but `clearRect` is a drawing command and should have no more impact on memory than calling `fillRect` or any other drawing method. Profiling changes of your canvas `width` might be more interesting, but there are too many other reasons not to use it to make it worth the effort. – Prestaul Dec 07 '15 at 19:43
237

If you are drawing lines, make sure you don't forget:

context.beginPath();

Otherwise the lines won't get cleared.

trembl
  • 3,415
  • 2
  • 18
  • 13
  • 14
    I know this has been here for a while and it is probably silly for me to comment after all this time, but this has been bothering me for a year... **Call `beginPath` when you begin a new path**, do not assume that just because you are clearing the canvas you want to clear your existing path as well! This would be a horrible practice and is a backwards way of looking at drawing. – Prestaul Feb 01 '12 at 21:57
  • What if you just want to clear the canvas of everything. Lets say that you are creating a game and that you need to redraw the screen every so many hundredths of a second. –  Apr 02 '14 at 17:59
  • 1
    @JoseQuinones, `beginPath` does not clear anything off of your canvas, it resets the path so that previous path entries are removed before you draw. You probably did need it, but as a drawing operation, not a clearing operation. clear, then beginPath and draw, not clear and beginPath, then draw. Does the difference make sense? Look here for an example: http://www.w3schools.com/tags/canvas_beginpath.asp – Prestaul Jul 01 '14 at 19:03
  • 2
    This solved the slowdown of my animation I experienced over time. I did redraw grid lines on every step, but without clearing the lines from the previous step. – Georg Patscheider Dec 05 '16 at 12:20
122

Others have already done an excellent job answering the question but if a simple clear() method on the context object would be useful to you (it was to me), this is the implementation I use based on answers here:

CanvasRenderingContext2D.prototype.clear = 
  CanvasRenderingContext2D.prototype.clear || function (preserveTransform) {
    if (preserveTransform) {
      this.save();
      this.setTransform(1, 0, 0, 1, 0, 0);
    }

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

    if (preserveTransform) {
      this.restore();
    }           
};

Usage:

window.onload = function () {
  var canvas = document.getElementById('canvasId');
  var context = canvas.getContext('2d');

  // do some drawing
  context.clear();

  // do some more drawing
  context.setTransform(-1, 0, 0, 1, 200, 200);
  // do some drawing with the new transform
  context.clear(true);
  // draw more, still using the preserved transform
};
JonathanK
  • 2,830
  • 1
  • 18
  • 20
  • 7
    This is a great implementation. I fully support enhancing native prototypes, but you might want to ensure that "clear" is not defined before assigning it - I'm still hoping for a native implementation some day. :) Do you know how broadly browsers support CanvasRenderingContext2D and leave it "writable"? – Prestaul Apr 09 '12 at 17:26
  • Thanks for the feedback @Prestaul - also, no browser should prevent you from extending javascript objects in this manner. – JonathanK Apr 11 '12 at 02:53
  • @JonathanK, I'd love to see some profiling of the performance difference between clearing with and without resetting the transformation. I'm guessing that the difference will be apparent if you are doing little drawing but that if what you are drawing is not trivial then the clear step is negligible... I may have to test that later when I have more time :) – Prestaul Apr 11 '12 at 14:01
  • Ok, I did the profiling and I'm going to add the details to my post. – Prestaul Apr 11 '12 at 14:28
36
  • Chrome responds well to: context.clearRect ( x , y , w , h ); as suggested by @Pentium10 but IE9 seems to completely ignore this instruction.
  • IE9 seems to respond to: canvas.width = canvas.width; but it doesn't clear lines, just shapes, pictures and other objects unless you also use @John Allsopp's solution of first changing the width.

So if you have a canvas and context created like this:

var canvas = document.getElementById('my-canvas');
var context = canvas.getContext('2d');

You can use a method like this:

function clearCanvas(context, canvas) {
  context.clearRect(0, 0, canvas.width, canvas.height);
  var w = canvas.width;
  canvas.width = 1;
  canvas.width = w;
}
grenade
  • 28,964
  • 22
  • 90
  • 125
  • 14
    Note that the method can be simplified by passing in only the context and using `context.clearRect(0,0,context.canvas.width,context.canvas.height)`. – Phrogz Apr 02 '11 at 23:29
  • 5
    IE 9 should absolutely respond to a clearRect call... (See: http://msdn.microsoft.com/en-us/library/ff975407(v=vs.85).aspx) As slow as changing canvas.width is, the only way you could get slower is by changing it twice and calling clearRect as well. – Prestaul Aug 22 '11 at 20:46
  • 1
    Sorry, I should be more clear... This method will work (as long as you haven't applied a transform), but is a [slow] brute force technique where it isn't necessary. Just use clearRect as it is fastest and should work across every browser with a canvas implementation. – Prestaul Aug 22 '11 at 20:51
  • 1
    I believe IE is redrawing the lines due to them being in the path buffer still. I use this format and it works perfect. `function clearCanvas(ctx) { ctx.beginPath(); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); }` – DarrenMB Jan 24 '18 at 15:51
  • I tried each and every method before this... and this was the only one that worked. I am using Chrome with lines, rectangles and text... wouldn't had thought it would be so hard to do something that should be built in! Thanks! – Anthony Griggs Feb 05 '18 at 05:23
34

This is 2018 and still there is no native method to completely clear canvas for redrawing. clearRect() does not clear the canvas completely. Non-fill type drawings are not cleared out (eg. rect())

1.To completely clear canvas irrespective of how you draw:

context.clearRect(0, 0, context.canvas.width, context.canvas.height);
context.beginPath();

Pros: Preserves strokeStyle, fillStyle etc.; No lag;

Cons: Unnecessary if you are already using beginPath before drawing anything

2.Using the width/height hack:

context.canvas.width = context.canvas.width;

OR

context.canvas.height = context.canvas.height;

Pros: Works with IE Cons: Resets strokeStyle, fillStyle to black; Laggy;

I was wondering why a native solution does not exist. Actually, clearRect() is considered as the single line solution because most users do beginPath() before drawing any new path. Though beginPath is only to be used while drawing lines and not closed path like rect().

This is the reason why the accepted answer did not solve my problem and I ended up wasting hours trying different hacks. Curse you mozilla

sziraqui
  • 4,315
  • 3
  • 22
  • 36
  • 1
    I think this is the right answer, especially for drawing canvas. I suffered from remaining context.stroke no matter how I call clearRect, while beginPath helped! – Shao-Kui Oct 26 '19 at 08:21
21

Use clearRect method by passing x,y co-ordinates and height and width of canvas. ClearRect will clear whole canvas as :

canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
Vishwas
  • 6,219
  • 5
  • 34
  • 64
  • You could just put this in a method and call it every time that you want to refresh the screen, correct. –  Apr 02 '14 at 18:04
  • @ XXX.xxx plz check id of canvas in your html and use same for first line (to get element by id) – Vishwas Mar 25 '15 at 04:45
15

A quick way is to do

canvas.width = canvas.width

Idk how it works but it does!

Jacob Morris
  • 438
  • 3
  • 17
14

there are a ton of good answers here. one further note is that sometimes it's fun to only partially clear the canvas. that is, "fade out" the previous image instead of erasing it entirely. this can give nice trails effects.

it's easy. supposing your background color is white:

// assuming background color = white and "eraseAlpha" is a value from 0 to 1.
myContext.fillStyle = "rgba(255, 255, 255, " + eraseAlpha + ")";
myContext.fillRect(0, 0, w, h);
orion elenzil
  • 2,926
  • 2
  • 26
  • 40
  • I know it's possible and I have no problem with your answer, I just wonder, if you have 2 objects that are moving, and you only want to trail one of them, how would you go about doing that? –  Jun 21 '14 at 17:57
  • 1
    that's a good deal more complex. in that case, you should create an off-screen canvas, and each frame draw the objects you want trailed onto that canvas using the partial-erase method described here, and also each frame clear the main canvas 100%, draw the non-trailed objects, and then composite the off-screen canvas onto the main one using drawImage(). You'll also need to set the globalCompositeOperation to something appropriate for the images. eg "multiply" would work well for dark objects on a light background. – orion elenzil Jun 22 '14 at 06:04
9

This is what I use, regardless boundaries and matrix transformations:

function clearCanvas(canvas) {
  const ctx = canvas.getContext('2d');
  ctx.save();
  ctx.globalCompositeOperation = 'copy';
  ctx.strokeStyle = 'transparent';
  ctx.beginPath();
  ctx.lineTo(0, 0);
  ctx.stroke();
  ctx.restore();
}

Basically, it saves the current state of the context, and draws a transparent pixel with copy as globalCompositeOperation. Then, restores the previous context state.

superruzafa
  • 593
  • 1
  • 6
  • 9
7

This worked for my pieChart in chart.js

<div class="pie_nut" id="pieChartContainer">
    <canvas id="pieChart" height="5" width="6"></canvas> 
</div>

$('#pieChartContainer').html(''); //remove canvas from container
$('#pieChartContainer').html('<canvas id="pieChart" height="5" width="6"></canvas>'); //add it back to the container
Sanal S
  • 919
  • 10
  • 22
5

I have found that in all browsers I test, the fastest way is to actually fillRect with white, or whataever color you would like. I have a very large monitor and in full screen mode the clearRect is agonizingly slow, but the fillRect is reasonable.

context.fillStyle = "#ffffff";
context.fillRect(0,0,canvas.width, canvas.height);

The drawback is that the canvas is no longer transparent.

John Page
  • 307
  • 3
  • 5
5

I always use

cxt.fillStyle = "rgb(255, 255, 255)";
cxt.fillRect(0, 0, canvas.width, canvas.height);

For a custom color, and

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

For making the canvas transparent when clearing

object-Object
  • 1,077
  • 6
  • 13
  • this is the easiest way! Well, for me at least. – Jacques Olivier Mar 25 '20 at 11:15
  • No, it does not do the job. `` is transparent by default. It should show the underlying content in case it overlaps with other HTML elements. With your code above, you assumed the parent of the canvas (most likely ``) has a white background. On the other hand `ctx.clearRect(0, 0, canvas.width, canvas.height)` does the job correctly. – Siu Ching Pong -Asuka Kenji- Sep 07 '20 at 02:29
  • You are correct, I will edit the answer. Completely forgot about that method! – object-Object Sep 08 '20 at 16:55
4
function clear(context, color)
{
    var tmp = context.fillStyle;
    context.fillStyle = color;
    context.fillRect(0, 0, context.canvas.width, context.canvas.height);
    context.fillStyle = tmp;
}
Imagine Breaker
  • 1,884
  • 1
  • 10
  • 8
4

in webkit you need to set the width to a different value, then you can set it back to the initial value

4

A simple, but not very readable way is to write this:

var canvas = document.getElementId('canvas');

// after doing some rendering

canvas.width = canvas.width;  // clear the whole canvas
Chang
  • 1,425
  • 1
  • 13
  • 22
4

the shortest way:

canvas.width += 0
Yukulélé
  • 11,464
  • 8
  • 52
  • 76
  • sure its short but also a bit confusing, if im reading that line of code i wouldnt think of it clearing the canvas – Luke_ Sep 09 '20 at 14:44
  • the shortest or most efficient way doesnt have to be the best way – Luke_ Sep 29 '20 at 09:09
2
context.clearRect(0,0,w,h)   

fill the given rectangle with RGBA values :
0 0 0 0 : with Chrome
0 0 0 255 : with FF & Safari

But

context.clearRect(0,0,w,h);    
context.fillStyle = 'rgba(0,0,0,1)';  
context.fillRect(0,0,w,h);  

let the rectangle filled with
0 0 0 255
no matter the browser !

2
Context.clearRect(starting width, starting height, ending width, ending height);

Example: context.clearRect(0, 0, canvas.width, canvas.height);

FelixSFD
  • 5,456
  • 10
  • 40
  • 106
Gavin T
  • 51
  • 7
2

I always use this

ctx.clearRect(0, 0, canvas.width, canvas.height)
window.requestAnimationFrame(functionToBeCalled)

NOTE

combining clearRect and requestAnimationFrame allows for more fluid animation if that is what you're going for

Anthony Gedeon
  • 304
  • 3
  • 10
1

fastest way:

canvas = document.getElementById("canvas");
c = canvas.getContext("2d");

//... some drawing here

i = c.createImageData(canvas.width, canvas.height);
c.putImageData(i, 0, 0); // clear context by putting empty image data
elser
  • 121
  • 1
  • 6
  • 12
    wow... In which browser? In mine (Chrome 22 and Firefox 14 on OS X) your method is, by far, the slowest option. http://jsperf.com/canvas-clear-speed/9 – Prestaul Sep 05 '12 at 01:50
  • 1
    >5 years in the future, this is still the slowest method by a very large amount, ~700x slower than `clearRect`. – mgthomas99 Feb 20 '18 at 12:15
1

If you use clearRect only, if you have it in a form to submit your drawing, you'll get a submit instead the clearing, or maybe it can be cleared first and then upload a void drawing, so you'll need to add a preventDefault at the beggining of the function:

   function clearCanvas(canvas,ctx) {
        event.preventDefault();
        ctx.clearRect(0, 0, canvas.width, canvas.height);
    }


<input type="button" value="Clear Sketchpad" id="clearbutton" onclick="clearCanvas(canvas,ctx);">

Hope it helps someone.

JoelBonetR
  • 1,469
  • 1
  • 10
  • 18
-1

These are all great examples of how you clear a standard canvas, but if you are using paperjs, then this will work:

Define a global variable in JavaScript:

var clearCanvas = false;

From your PaperScript define:

function onFrame(event){
    if(clearCanvas && project.activeLayer.hasChildren()){
        project.activeLayer.removeChildren();
        clearCanvas = false;
    }
}

Now wherever you set clearCanvas to true, it will clear all the items from the screen.

rmtheis
  • 6,978
  • 9
  • 56
  • 74