简体   繁体   English

如何清除画布以进行重绘

[英]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.这可能会持续一段时间,所以我不认为每次都绘制一个新矩形是最有效的选择。

Given that canvas is a canvas element or an OffscreenCanvas object ,鉴于canvas是画布元素或OffscreenCanvas对象

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

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

Use: context.clearRect(0, 0, canvas.width, canvas.height);使用: 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;不要使用: canvas.width = canvas.width;

Resetting canvas.width resets all canvas state (eg 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.重置canvas.width重置所有画布状态(例如转换、lineWidth、strokeStyle 等),它非常慢(与 clearRect 相比),它不适用于所有浏览器,并且它没有描述您实际尝试的内容去做。

Dealing with transformed coordinates处理变换的坐标

If you have modified the transformation matrix (eg 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.如果您修改了转换矩阵(例如使用scalerotatetranslate ),则context.clearRect(0,0,canvas.width,canvas.height)可能不会清除画布的整个可见部分。

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.编辑:我刚刚做了一些分析,并且(在 Chrome 中)在不重置转换的情况下清除 300x150(默认大小)画布的速度大约快 10%。 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

If you are drawing lines, make sure you don't forget:如果您正在绘制线条,请确保不要忘记:

context.beginPath();

Otherwise the lines won't get cleared.否则线条不会被清除。

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:其他人已经很好地回答了这个问题,但是如果上下文对象上的一个简单的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();
    }           
};

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

This is 2018 and still there is no native method to completely clear canvas for redrawing.这是 2018 年,仍然没有本地方法可以完全清除画布以进行重绘。 clearRect() does not clear the canvas completely. clearRect()不会完全清除画布。 Non-fill type drawings are not cleared out (eg. rect() )非填充类型的图纸不会被清除(例如rect()

1.To completely clear canvas irrespective of how you draw: 1.无论您如何绘制,都要完全清除画布:

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

Pros: Preserves strokeStyle, fillStyle etc.;优点:保留strokeStyle、fillStyle等; No lag;没有滞后;

Cons: Unnecessary if you are already using beginPath before drawing anything缺点:如果您在绘制任何内容之前已经使用了 beginPath,则不需要

2.Using the width/height hack: 2.使用宽度/高度黑客:

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

OR或者

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

Pros: Works with IE Cons: Resets strokeStyle, fillStyle to black;优点:适用于 IE 缺点:将strokeStyle、fillStyle 重置为黑色; 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.实际上, clearRect()被认为是单行解决方案,因为大多数用户在绘制任何新路径之前都会执行beginPath() Though beginPath is only to be used while drawing lines and not closed path like rect().虽然 beginPath 只在绘制线条时使用,而不是像rect().这样的封闭路径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诅咒你 mozilla

  • Chrome responds well to: context.clearRect ( x , y , w , h ); Chrome 响应良好: context.clearRect ( x , y , w , h ); as suggested by @Pentium10 but IE9 seems to completely ignore this instruction.正如@Pentium10 所建议的那样,但 IE9 似乎完全忽略了这条指令。
  • IE9 seems to respond to: canvas.width = canvas.width; IE9 似乎响应: 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.但它不会清除线条,只会清除形状、图片和其他对象,除非您还使用 @John Allsopp 的首先更改宽度的解决方案。

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

Use clearRect method by passing x,y co-ordinates and height and width of canvas.通过传递 x,y 坐标以及画布的高度和宽度来使用 clearRect 方法。 ClearRect will clear whole canvas as : ClearRect 将清除整个画布为:

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

A quick way is to do一个快速的方法是做

canvas.width = canvas.width

Idk how it works but it does!不知道它是如何工作的,但确实如此!

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

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 .基本上,它保存上下文的当前状态,并绘制一个透明像素, copyglobalCompositeOperation Then, restores the previous context state.然后,恢复之前的上下文状态。

This worked for my pieChart in chart.js这适用于我在 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

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.我有一个非常大的显示器,在全屏模式下,clearRect 非常慢,但 fillRect 是合理的。

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

The drawback is that the canvas is no longer transparent.缺点是画布不再透明。

I always use我总是用

cxt.fillStyle = "rgb(255, 255, 255)";
cxt.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用于在清除时使画布透明

最短的方法:

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

在webkit中你需要将宽度设置为不同的值,然后你可以将其设置回初始值

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
context.clearRect(0,0,w,h)   

fill the given rectangle with RGBA values :用 RGBA 值填充给定的矩形:
0 0 0 0 : with Chrome 0 0 0 0 : 使用铬
0 0 0 255 : with FF & Safari 0 0 0 255:使用 FF 和 Safari

But

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

let the rectangle filled with让矩形充满
0 0 0 255 0 0 0 255
no matter the browser !无论浏览器!

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

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

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如果这就是你想要的,结合 clearRect 和 requestAnimationFrame 允许更流畅的动画

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

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:如果您只使用 clearRect,如果您在表单中使用它来提交您的绘图,您将获得一个提交而不是清除,或者可以先清除它然后上传一个无效的绘图,因此您需要添加一个在函数开始时防止默认:

   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.希望它可以帮助某人。

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.现在有一个.reset()方法,它不仅会清除画布缓冲区,还会完全重置上下文的所有属性(样式等),重置其转换矩阵,清除其当前子路径,清除其状态堆栈(由save()restore()控制的那个),并删除所有剪辑区域。

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

Basically, it has the same effects as canvas.width += 0 , except that it's more idiomatic.基本上,它与canvas.width += 0具有相同的效果,只是它更惯用。

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).然而,在当前 Chromium 的实现中,它似乎和canvas.width += 0一样慢,它也会生成一个新的缓冲区,而不是简单地清除前一个缓冲区(导致更多的内存垃圾)。 Another caveat is that it's currently only supported in Chromium browsers.另一个警告是它目前仅在 Chromium 浏览器中受支持。 Though to polyfill it you can go the Chrome way虽然要填充它,你可以使用 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;
  };
}

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.请参阅此画布的现场示例,您可以在该画布上进行绘制,并在需要时清除它以重新绘制clearRect()用于删除当前画布,而fillRect()用于再次绘制干净且没有绘图的初始画布它。

 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>

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

These are all great examples of how you clear a standard canvas, but if you are using paperjs, then this will work:这些都是你如何清除标准画布的很好的例子,但如果你使用的是 paperjs,那么这将起作用:

Define a global variable in JavaScript:在 JavaScript 中定义一个全局变量:

var clearCanvas = false;

From your PaperScript define:从您的 PaperScript 定义:

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.现在,无论您将 clearCanvas 设置为 true,它都会清除屏幕上的所有项目。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM