如何清除画布以重画


1012

在尝试了复合操作并在画布上绘制图像之后,我现在尝试删除图像并进行合成。我该怎么做呢?

我需要清除画布才能重画其他图像;这可能会持续一段时间,所以我认为每次绘制一个新矩形都不是最有效的选择。

Answers:


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

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

42
请注意,因为clearRect您需要具有未转换的上下文,或者需要跟踪您的实际边界。
Phrogz

7
还要注意,设置画布宽度a)需要将其设置为其他值,然后再次返回以确保Webkit兼容,并且b)这将重置上下文转换
Phrogz

45
不要使用宽度技巧。这是一个肮脏的hack。在诸如JavaScript之类的高级语言中,您想要的是最好地陈述您的意图,然后让较低级别的代码实现它们。将宽度设置为自身并不能说明您的真实意图,即清除画布。
andrewrk

22
一个很小的建议,但我建议context.clearRect(0, 0, context.canvas.width, context.canvas.height)。实际上,这是同一件事,但是依赖性更少(1个变量而不是2个变量)
gman

6
对于此答案的最新读者:请注意,此答案已修改,并且上述某些注释不再适用
daveslab

719

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

这是清除整个画布的最快,最具描述性的方法。

不使用: canvas.width = canvas.width;

重置会canvas.width重置所有画布状态(例如,转换,lineWidth,strokeStyle等),它非常慢(与clearRect相比),在所有浏览器中均不起作用,并且无法描述您实际要执行的操作。

处理变换的坐标

如果您修改了转换矩阵(例如使用scalerotatetranslate),则context.clearRect(0,0,canvas.width,canvas.height)可能无法清除画布的整个可见部分。

解决方案?在清除画布之前,请重置转换矩阵:

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

编辑: 我刚刚进行了一些分析,并且(在Chrome中)清除300x150(默认大小)画布而不重置变换的速度大约快10%。随着画布大小的增加,这种差异也会降低。

这已经相对无关紧要了,但是在大多数情况下,您将获得比清算还多的钱,而且我认为这种性能差异无关紧要。

100000 iterations averaged 10 times:
1885ms to clear
2112ms to reset and clear

4
@YumYumYum:clear()是标准函数吗?似乎并非如此。
nobar 2012年

7
请注意,您可以改用来消除对局部canvas变量的需要ctx.canvas
德鲁·诺阿克斯

1
@DrewNoakes,很好,但出于速度目的,我几乎总是选择单独的变量。这是非常微小的,但我尝试通过为常用属性(尤其是在动画循环内部)进行别名来避免取消引用时间。
Prestaul,2012年

由于图像链接断开,AlexanderN的演示不再起作用,已修复:jsfiddle.net/Ktqfs/50
Domino

在进行转换矩阵修改时清除整个画布的另一种方法是简单地跟踪转换,canvas.widthcanvas.height在清除时将其自己应用。与重置转换相比,我没有对运行时差异进行任何数值分析,但我怀疑这样做会获得更好的性能。
NanoWizard's

226

如果要绘制线条,请确保不要忘记:

context.beginPath();

否则,行将无法清除。


10
我知道这已经存在了一段时间了,在这段时间里我一直对此发表评论可能很愚蠢,但这已经困扰了我一年…… 当您开始新的尝试时,请致电beginPath,不要仅仅因为您也在清除您要清除现有路径的画布!这将是一种可怕的做法,并且是一种向后看图纸的方式。
Prestaul

如果您只想清除所有内容,该怎么办。假设您正在创建游戏,并且需要每隔百分之一秒重新绘制屏幕。

1
@JoseQuinones beginPath不会清除画布上的任何内容,它会重置路径,以便在绘制之前删除先前的路径条目。您可能确实需要它,但是作为绘制操作,而不是清除操作。先清除,然后beginPath并绘制,而不清除并开始beginPath,然后绘制。区别有意义吗?请看此处的示例:w3schools.com/tags/canvas_beginpath.asp
Prestaul 2014年

1
随着时间的流逝,这解决了我的动画放慢的问题。我确实在每个步骤上都绘制了网格线,但是没有清除上一步中的线。
Georg Patscheider

118

其他人已经很好地回答了这个问题,但是如果clear()上下文对象上的简单方法对您有用(对我而言),这就是我根据以下答案使用的实现:

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

用法:

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

6
这是一个很好的实现。我完全支持增强本机原型,但是您可能要确保在分配“清除”之前未定义“清除”-我仍然希望有一天能实现本机实现。:)您知道浏览器广泛支持CanvasRenderingContext2D并将其保持为“可写”状态吗?
Prestaul

感谢@Prestaul的反馈-同样,没有浏览器应阻止您以这种方式扩展javascript对象。
JonathanK

@JonathanK,我很乐意看到在清除和不重置转换之间性能差异的一些分析。我猜想,如果您不做任何绘图,则差异会很明显,但是如果您绘图的内容不重要,那么清晰的步骤就可以忽略不计了……我可能会在以后有更多时间的时候进行测试:)
Prestaul

好的,我进行了分析,并将细节添加到我的帖子中。
Prestaul

35
  • Chrome响应良好:context.clearRect ( x , y , w , h );@ Pentium10建议,但IE9似乎完全忽略了此指令。
  • IE9似乎对此做出了响应:canvas.width = canvas.width;但是除非您也使用@John Allsopp的先更改宽度的解决方案,否则它不会清除线条,形状,图片和其他对象。

因此,如果您具有这样创建的画布和上下文:

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

您可以使用如下方法:

function clearCanvas(context, canvas) {
  context.clearRect(0, 0, canvas.width, canvas.height);
  var w = canvas.width;
  canvas.width = 1;
  canvas.width = w;
}

13
请注意,可以通过仅传入上下文并使用来简化该方法context.clearRect(0,0,context.canvas.width,context.canvas.height)
Phrogz

5
IE 9应该绝对响应clearRect调用...(请参阅:msdn.microsoft.com/en-us/library/ff975407 (v=vs.85 ).aspx)更改canvas.width的速度是一样慢的唯一方法通过更改两次并调用clearRect可以使速度变慢。
2011年

1
抱歉,我应该更加清楚...该方法可以工作(只要您尚未应用转换),但是它是一种[慢]蛮力技术,不需要使用。只需使用clearRect,因为它是最快的,并且可以在使用画布实现的所有浏览器中使用。
2011年

1
我相信IE正在重绘线路,因为它们仍在路径缓冲区中。我使用这种格式,并且效果很好。function clearCanvas(ctx) { ctx.beginPath(); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); }
DarrenMB '18年

在此之前,我尝试了每种方法……这是唯一可行的方法。我使用的是带有线条,矩形和文本的Chrome浏览器...以为做内置的事情会如此困难!谢谢!
安东尼·格里格斯

26

这是2018年,仍然没有原生方法可以完全清除画布以进行重画。clearRect() 不能完全清除画布。非填充类型的图形未清除(例如rect()

1. 无论您如何绘画,都要完全清除画布:

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

优点:保留strokeStyle,fillStyle等;没有滞后;

缺点:如果在绘制任何内容之前已经在使用beginPath,则不需要

2.使用width / height hack:

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

要么

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

优点:与IE搭配使用缺点:将strokeStyle,fillStyle重置为黑色;ggy

我想知道为什么不存在本机解决方案。实际上,这clearRect()被视为单行解决方案,因为大多数用户beginPath()在绘制任何新路径之前都会这样做。虽然beginPath仅在绘制线条而不是闭合路径时使用rect().

这就是为什么被接受的答案不能解决我的问题,而导致我浪费大量时间尝试其他黑客的原因。诅咒你mozilla


我认为这是正确的答案,尤其是在绘制画布时。无论如何调用clearRect,我都将剩下余下的context.stroke,而beginPath可以帮助您!
邵奎

20

通过传递x,y坐标以及画布的高度和宽度来使用clearRect方法。ClearRect会将整个画布清除为:

canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);

您可以将其放在一个方法中,并在每次要刷新屏幕时进行调用,更正。

@ XXX.xxx plz检查HTML中的画布ID,并将其用于第一行(通过ID获取元素)
Vishwas 2015年

14

这里有很多好的答案。还有一点要注意的是,有时只将画布部分清除是很有趣的。也就是说,“淡出”先前的图像,而不是完全擦除它。这可以给人留下深刻的印象。

这简单。假设您的背景色是白色:

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

我知道这是可能的,我的答案没有问题,我只是想知道,如果您有2个正在移动的对象,而您只想拖尾其中一个,那么您将如何做呢?
超级

这要复杂得多。在这种情况下,您应该创建一个屏幕外的画布,并且每个框架都使用此处所述的partial-erase方法将要拖尾的对象绘制到该画布上,并且每个框架都将主画布清除了100%,绘制了未拖曳的画布对象,然后使用drawImage()将屏幕外画布组合到主画布上。您还需要将globalCompositeOperation设置为适合图像的内容。例如“乘”会很好地适合浅色背景上的深色物体。
Orion elenzil 2014年

12

一种快速的方法是

canvas.width = canvas.width

知道它是如何工作的,但是确实可以!


哇。这确实有效,您是怎么找到这个的?
zipzit19年

@zipit我没有在正常清除后从medium.com找到的快速技巧:)
Jacob Morris

1
我正在拔头发,试图弄清楚为什么这样做!感谢分享!
aabbccsmith

谁能解释为什么这样行得通,甚至canvas.width + = 0也行得通,这背后的怪诞科学是什么?
PYK

8

这是我使用的,无论边界和矩阵转换如何:

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

基本上,它将保存上下文的当前状态,并使用copyas 绘制一个透明像素globalCompositeOperation。然后,还原以前的上下文状态。


这个对我有用...!谢谢。
NomanJaved

6

这适用于chart.js中的pieChart

<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

5

我发现在我测试过的所有浏览器中,最快的方法是用白色或任何您想要的颜色实际填充。我有一个非常大的监视器,在全屏模式下,clearRect非常慢,但是fillRect是合理的。

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

缺点是画布不再透明。



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

这比clearRect(0,0,canvas.width,canvas.height)慢
sEver 2015年

4

一种简单但不太易读的方法是编写以下代码:

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

// after doing some rendering

canvas.width = canvas.width;  // clear the whole canvas


1
context.clearRect(0,0,w,h)   

用RGBA值填充给定的矩形:
0 0 0 0:使用Chrome
0 0 0 255:使用FF和Safari

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

无论浏览器如何,让矩形填充
0 0 0 255


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

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



0

最快的方法:

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

12
哇...在哪个浏览器中?在我的系统中(OS X上的Chrome 22和Firefox 14),您的方法是迄今为止最慢的选项。jsperf.com/canvas-clear-speed/9
Prestaul 2012年

1
> 5年后,这仍然是最慢的方法,数量巨大,比慢约700倍clearRect
mgthomas99

0

如果仅使用clearRect,并且在表单中提交了图形,则会得到一个提交,而不是清除,或者可以先清除它,然后再上传一个无效的图形,所以您需要添加一个函数开始时的preventDefault:

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

希望它可以帮助某人。


0

我总是用这个

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

注意

如果您要这样做,则将clearRect和requestAnimationFrame结合使用可实现更流畅的动画


-2

这些都是清除标准画布的绝佳示例,但是如果您使用paperjs,则可以使用:

在JavaScript中定义全局变量:

var clearCanvas = false;

从PaperScript中定义:

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

现在,无论将clearCanvas设置为true哪里,它都将清除屏幕上的所有项目。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.