richard
richard

Reputation: 14540

How to clear the canvas for redrawing

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.

Upvotes: 1316

Views: 1295003

Answers (26)

Zibx
Zibx

Reputation: 94

If you do not use transformations this would do the thing:

context.clearRect(0, 0, width, height)

I usually fill the full canvas with a rect of background color

If transformations are applied — you can getTransform and do some school math to clear the canvas in the applied transform space. It is not so complicated, but I spent some time yesterday with paper when I needed to transform the mouse position to the local space of each drawn element (for collision check):

a, b, c, d, e, f — is the canvas matrix data, X, Y — mouse position, and x, y — position in local space

Math:
ax + cy + e = X
bx + dy + f = Y

x = (X - cy - e) / a
y = (Y - bx - f ) / d

x = (X - c*(Y - bx - f) / d - e ) / a

adx = dX - cY + bcx + cf - ed
x(ad - bc) = dX - cY + cf - ed

Answer:
x = (dX - cY + cf - ed)/(ad - bc)
y = (Y - bx - f) / d

You would need to do it for all 4 corners (0,0), (w,0), (w,h), (0,h), then get min/max of all results x, and y, then fillRect or clearRect for rect with arguments: (minX, minY, maxX-minX, maxY-minY)

I do not think it would be optimal in the performance term way. Actually, I thought that the most performant way would be to getImageData of an empty canvas and put it back by the putImageData method, but performance tests show that this is not the case. An optimal way to clear if transformations are applied is:

context.save();
context.setTransform(1,0,0,1,0,0);
context.clearRect(0,0,800, 600);
context.restore();

Here is a jsperf link with all options that I've tried.

Upvotes: 0

Pentium10
Pentium10

Reputation: 208012

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);

Upvotes: 1743

Kaiido
Kaiido

Reputation: 137084

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;
  };
}

Upvotes: 6

danday74
danday74

Reputation: 57195

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()
}

Upvotes: 7

object-Object
object-Object

Reputation: 1691

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

Upvotes: 10

Souradip Mandal
Souradip Mandal

Reputation: 35

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>

Upvotes: 1

Anthony Gedeon
Anthony Gedeon

Reputation: 383

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

Upvotes: 2

Yukul&#233;l&#233;
Yukul&#233;l&#233;

Reputation: 17102

the shortest way:

canvas.width += 0

Upvotes: 7

sziraqui
sziraqui

Reputation: 6112

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

Upvotes: 42

superruzafa
superruzafa

Reputation: 761

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.

Upvotes: 11

Jacob Morris
Jacob Morris

Reputation: 554

A quick way is to do

canvas.width = canvas.width

Idk how it works but it does!

Upvotes: 17

Gavin T
Gavin T

Reputation: 61

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

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

Upvotes: 2

Chang
Chang

Reputation: 1716

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

Upvotes: 5

JoelBonetR
JoelBonetR

Reputation: 1572

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.

Upvotes: 1

Sanal S
Sanal S

Reputation: 1152

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

Upvotes: 7

Prestaul
Prestaul

Reputation: 85204

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

Upvotes: 812

user3355403
user3355403

Reputation:

function clear(context, color)
{
    var tmp = context.fillStyle;
    context.fillStyle = color;
    context.fillRect(0, 0, context.canvas.width, context.canvas.height);
    context.fillStyle = tmp;
}

Upvotes: 4

Vishwas
Vishwas

Reputation: 7067

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);

Upvotes: 23

JonathanK
JonathanK

Reputation: 3040

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
};

Upvotes: 131

John Page
John Page

Reputation: 363

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.

Upvotes: 7

elser
elser

Reputation: 159

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

Upvotes: 0

Robert Ogle
Robert Ogle

Reputation: 59

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.

Upvotes: 0

orion elenzil
orion elenzil

Reputation: 5443

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);

Upvotes: 14

trembl
trembl

Reputation: 3971

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

context.beginPath();

Otherwise the lines won't get cleared.

Upvotes: 260

grenade
grenade

Reputation: 32169

  • 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;
}

Upvotes: 38

John Allsopp
John Allsopp

Reputation: 69

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

Upvotes: 4

Related Questions