如何清除画布以重新绘制

IT技术 javascript html canvas html5-canvas composite
2021-01-24 03:49:05

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

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

6个回答

鉴于这canvas是一个画布元素或OffscreenCanvas对象

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

context.clearRect(0, 0, canvas.width, canvas.height);
请注意,clearRect您需要有一个未转换的上下文,或者跟踪您的实际边界。
2021-03-14 03:49:05
进一步注意,设置画布宽度 a) 需要将其设置为不同的值,然后再次返回以实现 Webkit 兼容性,并且 b) 这将重置您的上下文转换
2021-03-19 03:49:05
不要使用宽度技巧。这是一个肮脏的黑客。在像 JavaScript 这样的高级语言中,你想要的是最好地陈述你的意图,然后让低级代码实现它们。将宽度设置为自身并不能说明您的真实意图,即清除画布。
2021-03-20 03:49:05
一个完全次要的建议,但我建议context.clearRect(0, 0, context.canvas.width, context.canvas.height)它实际上是同一件事,但依赖项少了一个(1 个变量而不是 2 个)
2021-03-21 03:49:05
对于此答案的最近读者:请注意,此答案已修改,并且上述某些评论不再适用
2021-03-31 03:49:05

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

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

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

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

处理变换坐标

如果您修改了转换矩阵(例如使用scalerotate、 或translate),则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
@YumYumYum:clear() 是标准函数吗?似乎不是。
2021-03-22 03:49:05
在变换矩阵修改的情况下清除整个画布的另一种方法是简单地跟踪变换canvas.widthcanvas.height在清除时自己应用它们与重置变换相比,我没有对运行时差异进行任何数值分析,但我怀疑它会获得更好的性能。
2021-03-24 03:49:05
@DrewNoakes,好点,但我几乎总是为了速度目的选择单独的变量。它非常小,但我试图通过对常用属性(尤其是在动画循环内部)使用别名来避免取消引用时间。
2021-03-25 03:49:05
请注意,您可以canvas通过使用ctx.canvas消除对局部变量的需要
2021-03-26 03:49:05
由于图像链接损坏,AlexanderN 的演示不再工作,已修复:jsfiddle.net/Ktqfs/50
2021-03-28 03:49:05

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

context.beginPath();

否则线条不会被清除。

@JoseQuinones,beginPath不会清除画布上的任何内容,它会重置路径,以便在绘制之前删除先前的路径条目。您可能确实需要它,但作为绘图操作,而不是清除操作。清除,然后开始路径并绘制,不清除并开始路径,然后绘制。区别有意义吗?在此处查看示例:w3schools.com/tags/canvas_beginpath.asp
2021-03-18 03:49:05
这解决了我的动画随着时间的推移而变慢的问题。我在每一步都重新绘制了网格线,但没有清除上一步中的线。
2021-03-19 03:49:05
如果您只想清除画布上的所有内容怎么办。假设您正在创建一个游戏,并且您需要每隔百分之一秒重新绘制屏幕。
2021-03-21 03:49:05
我知道这已经有一段时间了,这么长时间之后我发表评论可能很愚蠢,但这已经困扰了我一年......当你开始一条新路时打电话beginPath,不要以为只是因为你正在清除您想要清除现有路径的画布!这将是一种可怕的做法,是一种倒退的看待绘画的方式。
2021-03-27 03:49:05

其他人已经很好地回答了这个问题,但是如果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
};
@JonathanK,我很想看到一些关于在重置转换和不重置转换的情况下清除之间的性能差异的分析。我猜如果你画的很少,差异会很明显,但如果你画的不是微不足道的,那么清晰的步骤可以忽略不计......我可能需要稍后有更多时间来测试:)
2021-03-11 03:49:05
感谢@Prestaul 的反馈——此外,任何浏览器都不应该阻止您以这种方式扩展 javascript 对象。
2021-03-19 03:49:05
好的,我进行了分析,并将在我的帖子中添加详细信息。
2021-04-01 03:49:05
这是一个很好的实现。我完全支持增强本机原型,但您可能希望确保在分配之前没有定义“clear”——我仍然希望有一天能够实现本机实现。:) 您知道浏览器支持 CanvasRenderingContext2D 并使其“可写”的范围有多广吗?
2021-04-07 03:49:05

这是 2018 年,仍然没有本地方法可以完全清除画布以进行重绘。clearRect() 不会完全清除画布。非填充类型的图纸不会被清除(例如rect()

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

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

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

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

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

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

或者

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

优点:适用于 IE 缺点:将strokeStyle、fillStyle 重置为黑色;迟钝;

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

这就是为什么接受的答案没有解决我的问题并且我最终浪费了几个小时尝试不同的黑客的原因。诅咒你 mozilla

我认为这是正确的答案,尤其是对于画布。无论我如何调用 clearRect,我都会遇到剩余的 context.stroke,而 beginPath 有所帮助!
2021-03-31 03:49:05