How to clear the canvas for redrawing
Asked Answered
I

25

1288

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.

Indigenous answered 26/1, 2010 at 20:50 Comment(2)
No answer mentions this, but the clear color is this one: canvas.style.backgroundColor = "lime";Janise
Benchmarks for all mentioned methods here: measurethat.net/Benchmarks/Show/14723/2/…Bricklaying
T
1708

Given that canvas is a canvas element or an OffscreenCanvas object, use clearRect:

const context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
Teaser answered 26/1, 2010 at 20:52 Comment(8)
Note that for clearRect you need to either have an untransformed context, or keep track of your actual boundaries.Pooka
I wonder why there isn't a context.clear() function that can be used with a path, like context.fill().Emery
@B1KMusic : This is easy to simulate using destination-out compositing. JsFiddle.Instalment
@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.Emery
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)Presumption
To get your context: var c = document.getElementById('canv1') and var context = c.getContext('2d')Pokpoke
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.Province
I think in begging this used for context.rect, but realized it clear part of canvas or full not direct the rect created, thoght it like give the context.rect but I was mistaken thanks for helpSelfcommand
W
803

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
Wixted answered 17/7, 2011 at 5:6 Comment(8)
Note that you can remove the need for a local canvas variable by using ctx.canvas instead.Daunt
@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).Wixted
AlexanderN's demo didn't work anymore due to broken image link, fixed: jsfiddle.net/Ktqfs/50Theotheobald
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.Interweave
@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!Wixted
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.... :PUnpeg
Usectx.resetTransform(); ctx.clearRect(0, 0, canvas.width, canvas.height); Dermatitis
This answer works for me as I was using ctx.scale() in my project.Zolner
S
257

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

context.beginPath();

Otherwise the lines won't get cleared.

Survive answered 13/1, 2011 at 7:12 Comment(4)
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.Wixted
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.Denunciate
@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: w3schools.com/tags/canvas_beginpath.aspWixted
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.Cachalot
C
131

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
};
Constituency answered 15/3, 2012 at 15:5 Comment(5)
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"?Wixted
Thanks for the feedback @Wixted - also, no browser should prevent you from extending javascript objects in this manner.Constituency
@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 :)Wixted
Ok, I did the profiling and I'm going to add the details to my post.Wixted
@Wixted 2022 and still no native implementation of context.clear()... Yet, in the prototype enhancement, I wouldn't check whether clear() is available or not. Imagine one day the method is available, it then silently "overwrites" your custom method and might introduce hard-to-find bugs due to a different possible implementation.Heiner
F
42

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

Forbes answered 8/5, 2018 at 12:29 Comment(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!Maryleemarylin
R
38
  • 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;
}
Raki answered 3/11, 2010 at 9:48 Comment(5)
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).Pooka
IE 9 should absolutely respond to a clearRect call... (See: 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.Wixted
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.Wixted
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); }Cornflakes
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!Soubrette
O
23

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);
Opprobrious answered 13/11, 2013 at 6:8 Comment(2)
You could just put this in a method and call it every time that you want to refresh the screen, correct.Denunciate
@ XXX.xxx plz check id of canvas in your html and use same for first line (to get element by id)Opprobrious
O
17

A quick way is to do

canvas.width = canvas.width

Idk how it works but it does!

Overmatter answered 8/5, 2018 at 16:56 Comment(5)
Wow. This really does work, How did you ever find this?Unruffled
@zipit Quick trick I found off of medium.com after normal clearing wasn't rendering :)Overmatter
I am pulling my hair out trying to figure out why this works! Thanks for sharing!Cooncan
Can anyone explain why that does work and even canvas.width+=0 does the job too, whats the freaking science behind of this?Myrtlemyrvyn
Canvases are being reset when any dimension is set. To be more specific, they become transparent black.Cibis
C
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);
Crouse answered 4/5, 2012 at 4:36 Comment(2)
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?Motta
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.Crouse
P
11

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.

Pour answered 28/5, 2018 at 15:14 Comment(0)
I
10

I always use

ctx.fillStyle = "rgb(255, 255, 255)";
ctx.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

Irresolute answered 11/1, 2019 at 20:45 Comment(4)
this is the easiest way! Well, for me at least.Ladybug
No, it does not do the job. <canvas> 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 <body>) has a white background. On the other hand ctx.clearRect(0, 0, canvas.width, canvas.height) does the job correctly.Himmler
You are correct, I will edit the answer. Completely forgot about that method!Irresolute
I find the mix of cxt and ctx in your example a bit frustrating.Candler
J
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
Jasisa answered 26/2, 2016 at 12:36 Comment(0)
G
7

the shortest way:

canvas.width += 0
Gilmour answered 22/1, 2020 at 18:6 Comment(3)
sure its short but also a bit confusing, if im reading that line of code i wouldnt think of it clearing the canvasNope
the shortest or most efficient way doesnt have to be the best wayNope
I see this in the W3C example above this line and I think this way will be more efficient than the clear rect. it will be similar to canvas.width = canvas.widthKalinda
I
6

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.

Inhumane answered 25/3, 2013 at 22:29 Comment(0)
C
5

There is now a .reset() method which will not only clear the canvas buffer but also completely reset all the properties of the context (styles etc.), reset its transformation matrix, clear its current sub-path, clear its states stack (the one controlled by save() and restore()), and remove all the clipping regions.

context.reset();
// now 'context' is clear as new

Basically, it has the same effects as canvas.width += 0, except that it's more idiomatic.

However it seems that in current Chromium's implementation it's as slow as canvas.width += 0, it also does generate a new buffer instead of simply clearing the previous one (resulting in more memory garbage). Another caveat is that it's currently only supported in Chromium browsers. Though to polyfill it you can go the Chrome way

if (!CanvasRenderingContext2D.prototype.reset) {
  CanvasRenderingContext2D.prototype.reset = function() {
    this.canvas.width += 0;
  };
}
if (!OffscreenCanvasRenderingContext2D.prototype.reset) {
  OffscreenCanvasRenderingContext2D.prototype.reset = function() {
    this.canvas.width += 0;
  };
}

Cooperstein answered 26/1, 2010 at 20:50 Comment(2)
context.reset() is not available in Firefox yet (version 106, november 2022)Doncaster
@Doncaster " Another caveat is that it's currently only supported in Chromium browsers"Cooperstein
L
5
private clearCanvas() {
  const canvas: HTMLCanvasElement = this.ctx.canvas
  this.ctx.save()
  this.ctx.setTransform(1, 0, 0, 1, 0, 0)
  this.ctx.clearRect(0, 0, canvas.width, canvas.height)
  this.ctx.restore()
}
Lavaliere answered 8/12, 2021 at 11:30 Comment(0)
T
4

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

Throb answered 2/8, 2010 at 4:50 Comment(0)
F
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;
}
Ferocity answered 11/4, 2014 at 11:39 Comment(1)
This is slower than clearRect(0,0,canvas.width,canvas.height)Borrow
C
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
Conversion answered 24/8, 2017 at 21:34 Comment(0)
F
2
Context.clearRect(starting width, starting height, ending width, ending height);

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

Fluorescence answered 30/9, 2017 at 15:38 Comment(0)
R
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

Rameriz answered 27/3, 2020 at 19:48 Comment(0)
C
1

This is a Free hand drawing Canvas with a Clear Canvas Button.
See this live example of a canvas which you can draw on and also when required clear it for redrawing clearRect() is used to delete the prersent canvas and fillRect() is used to again draw the initial canvas which was clean and had no drawings on it.

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    painting = false,
    lastX = 0,
    lastY = 0,
    lineThickness = 1;

canvas.width=canvas.height = 250;
ctx.fillRect(0, 0, 250, 250);

canvas.onmousedown = function(e) {
    painting = true;
    ctx.fillStyle = "#ffffff";
    lastX = e.pageX - this.offsetLeft;
    lastY = e.pageY - this.offsetTop;
};

canvas.onmouseup = function(e){
    painting = false;
}

canvas.onmousemove = function(e) {
    if (painting) {
        mouseX = e.pageX - this.offsetLeft;
        mouseY = e.pageY - this.offsetTop;

        // find all points between        
        var x1 = mouseX,
            x2 = lastX,
            y1 = mouseY,
            y2 = lastY;


        var steep = (Math.abs(y2 - y1) > Math.abs(x2 - x1));
        if (steep){
            var x = x1;
            x1 = y1;
            y1 = x;

            var y = y2;
            y2 = x2;
            x2 = y;
        }
        if (x1 > x2) {
            var x = x1;
            x1 = x2;
            x2 = x;

            var y = y1;
            y1 = y2;
            y2 = y;
        }

        var dx = x2 - x1,
            dy = Math.abs(y2 - y1),
            error = 0,
            de = dy / dx,
            yStep = -1,
            y = y1;

        if (y1 < y2) {
            yStep = 1;
        }

        lineThickness = 4;

        for (var x = x1; x < x2; x++) {
            if (steep) {
                ctx.fillRect(y, x, lineThickness , lineThickness );
            } else {
                ctx.fillRect(x, y, lineThickness , lineThickness );
            }

            error += de;
            if (error >= 0.5) {
                y += yStep;
                error -= 1.0;
            }
        }



        lastX = mouseX;
        lastY = mouseY;

    }
}
var button=document.getElementById("clear");
button.onclick=function clearcanvas(){
  canvas=document.getElementById("canvas"),
  ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, 250, 250);
canvas.width=canvas.height = 250;
ctx.fillRect(0, 0, 250, 250);}
#clear{border-radius:10px;
font-size:8px !important;
position:absolute;
top:1px;}
#canvas{border-radius:10px}
<link href="https://www.w3schools.com/w3css/4/w3.css" rel="stylesheet"/>
<button id="clear" class="w3-padding w3-xxlarge w3-pink" type="button">Clear Canvas</button>
<canvas id="canvas"></canvas>
Canossa answered 26/1, 2010 at 20:50 Comment(0)
P
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.

Proliferous answered 10/1, 2017 at 18:14 Comment(0)
Q
0

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.

Quaff answered 12/4, 2012 at 15:58 Comment(0)
C
0

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
Carbamidine answered 13/8, 2012 at 18:32 Comment(2)
wow... In which browser? In mine (Chrome 22 and Firefox 14 on OS X) your method is, by far, the slowest option. jsperf.com/canvas-clear-speed/9Wixted
>5 years in the future, this is still the slowest method by a very large amount, ~700x slower than clearRect.Barde

© 2022 - 2024 — McMap. All rights reserved.