如何清除画布以进行重绘

ric*_*ard 945 javascript html5 canvas composite html5-canvas

在尝试复合操作和在画布上绘制图像后,我现在正在尝试删除图像和合成.我该怎么做呢?

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

Pen*_*m10 1202

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

context.clearRect(0, 0, canvas.width, canvas.height);
Run Code Online (Sandbox Code Playgroud)

  • 不要使用宽度技巧.这是一个肮脏的黑客.在JavaScript等高级语言中,您想要的是最好地表达您的意图,然后让较低级别的代码实现它们.将宽度设置为自身*不*表明您的真实意图,即清除画布. (45认同)
  • 请注意,对于`clearRect`,您需要具有未转换的上下文,或者跟踪您的实际边界. (39认同)
  • 一个完全不重要的建议,但我建议`context.clearRect(0,0,context.canvas.width,context.canvas.height)`.它实际上是相同的东西,但一个较少的依赖(1变量而不是2) (20认同)
  • 请注意,设置画布宽度a)需要将其设置为不同的值然后再返回[用于Webkit兼容性](http://stackoverflow.com/questions/2142535/how-to-clear-the-canvas-for -redrawing/3385076#3385076),和b)这将[重置你的上下文转换](http://stackoverflow.com/questions/5526486/clear-entire-transformed-html5-canvas-while-preserving-context-transform) . (7认同)
  • 实际上,宽度技巧会导致2D画布和WebGL中的FPS下降 - 更喜欢使用.clearRect,这是标准方法. (5认同)
  • 对于这个答案的最近读者:**请注意,此答案已被修改,并且上述某些评论不再适用**. (5认同)
  • 我想知道为什么没有可以与路径一起使用的“context.clear()”函数,例如“context.fill()”。 (3认同)
  • 宽度技巧非常好,只需要一个简单的补充就是`canvas.width + = 0`,当你通过`getElementById()`获取画布并且不存储它时,它非常有用 (3认同)
  • 要获取您的上下文:`var c = document.getElementById('canv1')` 和 `var context = c.getContext('2d')` (2认同)
  • 您要么需要在每次清除后重新绘制背景,要么在第一个未清除并包含背景的画布下方放置第二个画布。 (2认同)

Pre*_*aul 702

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

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

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

重置canvas.width重置所有画布状态(例如转换,lineWidth,strokeStyle等),它非常慢(与clearRect相比),它不适用于所有浏览器,并且它不描述您实际尝试做的事情.

处理变换后的坐标

如果您修改了转换矩阵(例如,使用scale,, rotatetranslate),则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();
Run Code Online (Sandbox Code Playgroud)

编辑: 我刚刚完成了一些分析,并且(在Chrome中)在不重置转换的情况下清除300x150(默认大小)画布的速度提高了约10%.随着画布的大小增加,这种差异会下降.

这已经相对微不足道了,但在大多数情况下,你的吸引力远远超过清理范围,我相信这种性能差异无关紧要.

100000 iterations averaged 10 times:
1885ms to clear
2112ms to reset and clear
Run Code Online (Sandbox Code Playgroud)

  • 请注意,您可以使用`ctx.canvas`来删除对本地`canvas`变量的需要. (7认同)
  • @YumYumYum:clear()是标准函数吗?它似乎不是. (4认同)
  • @DrewNoakes,好点,但我几乎总是为了速度目的选择单独的变量。它非常小,但我试图通过对常用属性(尤其是在动画循环内部)使用别名来避免取消引用时间。 (2认同)

tre*_*mbl 215

如果你画线,请确保你不要忘记:

context.beginPath();
Run Code Online (Sandbox Code Playgroud)

否则线路将不会被清除.

  • 我知道这已经存在了一段时间,所有这段时间后我都很难评论,但这一直困扰我一年......**当你开始一条新的道路时,请拨打`beginPath`**,不要以为只是因为你要清除画布而要清除你现有的路径!这将是一种可怕的做法,是一种看待绘画的倒退方式. (8认同)
  • @JoseQuinones,`beginPath` 不会清除画布上的任何内容,它会重置路径,以便在绘制之前删除先前的路径条目。您可能确实需要它,但作为绘图操作,而不是清除操作。清除,然后开始路径并绘制,不清除并开始路径,然后绘制。区别有意义吗?看这里的例子:http://www.w3schools.com/tags/canvas_beginpath.asp (2认同)
  • 这解决了我的动画随着时间的推移而变慢的问题。我在每一步都重新绘制了网格线,但没有清除上一步中的线。 (2认同)

Jon*_*anK 116

其他人已经很好地回答了这个问题但是如果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();
    }           
};
Run Code Online (Sandbox Code Playgroud)

用法:

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
};
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的实现.我完全支持增强原生原型,但你可能希望确保在分配之前没有定义"clear" - 我仍然希望有一天能够实现本机实现.:)你知道浏览器有多广泛支持CanvasRenderingContext2D并让它"可写"吗? (6认同)

gre*_*ade 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');
Run Code Online (Sandbox Code Playgroud)

你可以使用这样的方法:

function clearCanvas(context, canvas) {
  context.clearRect(0, 0, canvas.width, canvas.height);
  var w = canvas.width;
  canvas.width = 1;
  canvas.width = w;
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,通过仅传入上下文并使用`context.clearRect(0,0,context.canvas.width,context.canvas.height)`可以简化该方法. (12认同)
  • IE 9应该绝对响应clearRect调用...(参见:http://msdn.microsoft.com/en-us/library/ff975407(v = vs.85).aspx)和更改canvas.width一样慢,你可以变慢的唯一方法是改变它两次并调用clearRect. (5认同)

szi*_*qui 20

这是2018年,仍然没有完全清除画布重绘的本机方法.clearRect() 完全清除画布.非填充类型图纸未清除(例如rect())

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

context.clearRect(0, 0, context.canvas.width, context.canvas.height);
context.beginPath();
Run Code Online (Sandbox Code Playgroud)

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

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

2.使用宽度/高度黑客:

context.canvas.width = context.canvas.width;
Run Code Online (Sandbox Code Playgroud)

要么

context.canvas.height = context.canvas.height;
Run Code Online (Sandbox Code Playgroud)

优点:适用于IE Con​​s:将strokeStyle,fillStyle重置为黑色; Laggy;

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

这就是为什么接受的答案没有解决我的问题,我最终浪费时间尝试不同的黑客.诅咒你的mozilla


Vis*_*was 19

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

canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
Run Code Online (Sandbox Code Playgroud)


ori*_*zil 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);
Run Code Online (Sandbox Code Playgroud)


Jac*_*ris 10

一个快速的方法是做

canvas.width = canvas.width
Run Code Online (Sandbox Code Playgroud)

Idk它是如何工作的,但确实如此!

  • 我正在拔我的头发试图弄清楚为什么这会起作用!感谢分享! (2认同)

小智 5

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

context.fillStyle = "#ffffff";
context.fillRect(0,0,canvas.width, canvas.height);
Run Code Online (Sandbox Code Playgroud)

缺点是画布不再透明。


San*_*l S 5

这适用于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
Run Code Online (Sandbox Code Playgroud)


sup*_*afa 5

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

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();
}
Run Code Online (Sandbox Code Playgroud)

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


obj*_*ect 5

我总是用

cxt.fillStyle = "rgb(255, 255, 255)";
cxt.fillRect(0, 0, canvas.width, canvas.height);
Run Code Online (Sandbox Code Playgroud)

对于自定义颜色,以及

ctx.clearRect(0, 0, canvas.width, canvas.height);
Run Code Online (Sandbox Code Playgroud)

用于在清除时使画布透明


Yuk*_*élé 5

最短的方法:

canvas.width += 0
Run Code Online (Sandbox Code Playgroud)

  • 最短或最有效的方法不一定是最好的方法 (2认同)

dan*_*y74 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()
}
Run Code Online (Sandbox Code Playgroud)


Kai*_*ido 5

现在有一种.reset()方法不仅可以清除画布缓冲区,还可以完全重置上下文的所有属性(样式等),重置其转换矩阵,清除其当前子路径,清除其状态堆栈(由save()restore()),并删除所有剪切区域。

context.reset();
// now 'context' is clear as new
Run Code Online (Sandbox Code Playgroud)

基本上,它与 具有相同的效果canvas.width += 0,只是它更惯用。

然而,在当前的 Chromium 实现中,它似乎与 一样慢canvas.width += 0,它也会生成一个新的缓冲区,而不是简单地清除前一个缓冲区(导致更多的内存垃圾)。另一个需要注意的是,它目前仅在 Chromium 浏览器中受支持。不过要填充它,你可以采用 Chrome 方式

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

Run Code Online (Sandbox Code Playgroud)