再描画のためにキャンバスをクリアする方法


1012

合成操作を試し、キャンバスに画像を描画した後、画像を削除して合成しようとしています。どうすればよいですか?

他の画像を再描画するためにキャンバスをクリアする必要があります。これはしばらく続くので、毎回新しい長方形を描くことが最も効率的なオプションになるとは思いません。

回答:


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

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

42
clearRect変換されていないコンテキストがあるか、実際の境界を追跡する必要があることに注意してください。
Phrogz

7
さらに、キャンバスの幅を設定するには、a)幅を別の値に設定してから、Webkitの互換性のために再度設定する必要があります。b)これにより、コンテキスト変換リセットされます
Phrogz

45
幅のトリックを使用しないでください。それは汚いハックです。JavaScriptなどの高水準言語では、意図を最もよく表し、低レベルのコードがそれらを実行できるようにすることが目的です。幅をそれ自体に設定しても、キャンバスをクリアするという本当の意図は示されませ
andrewrk 2013

22
まったくマイナーな提案ですが、私は提案しcontext.clearRect(0, 0, context.canvas.width, context.canvas.height)ます。実質的に同じですが、依存関係が1つ少なくなります(2ではなく1変数)
gman

6
この回答の最近の読者の方へ:この回答は変更されており、上記のコメントの一部は適用されなくなったことに注意してください。
daveslab 2017年

719

使用する: 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

4
@YumYumYum:clear()は標準関数ですか?それはそうではないようです。
nobar

7
代わりにcanvasを使用して、ローカル変数の必要性を削除できることに注意してくださいctx.canvas
Drew Noakes

1
@DrewNoakes、良い点ですが、ほとんどの場合、速度を上げるために個別の変数を選びます。非常にマイナーですが、頻繁に使用されるプロパティ(特にアニメーションループ内)のエイリアスを作成することで、時間の逆参照を回避しようとしています。
Prestaul

画像リンクが壊れていたため、AlexanderNのデモが機能しなくなりました。修正:jsfiddle.net/Ktqfs/50
Domino

変換行列の変更の際にキャンバス全体をクリアするもう一つの方法は、単純な変換を追跡し、それらに自分を適用することですcanvas.widthし、canvas.heightクリア時に。変換をリセットする場合と比較して、実行時の違いについて数値分析を行っていませんが、少し優れたパフォーマンスが得られると思います。
NanoWizard、2015

226

線を描く場合は、次のことを忘れないでください。

context.beginPath();

そうしないと、行がクリアされません。


10
私はこれがしばらくここにあることを知っており、おそらくこれまでにコメントするのはおそらくばかげていますが、これは1年間私を悩ませてきました... 新しい道を始めるときに電話beginPathしてください。既存のパスをクリアしたいキャンバスもクリアしています!これは恐ろしい習慣であり、描画を逆向きに見る方法です。
Prestaul

すべてのキャンバスをクリアしたい場合はどうでしょう。ゲームを作成していて、100分の1秒ごとに画面を再描画する必要があるとしましょう。

1
@JoseQuinones beginPathは、キャンバスから何も消去せず、パスをリセットして、描画する前に以前のパスエントリを削除します。あなたはおそらくそれを必要としましたが、描画操作として、クリア操作ではありません。クリアしてからbeginPathと描画し、クリアしてからbeginPathして描画しないでください。違いは理にかなっていますか?例についてはこちらをご覧ください:w3schools.com/tags/canvas_beginpath.asp
Prestaul

1
これにより、時間の経過とともに経験した私のアニメーションのスローダウンが解決されました。すべてのステップでグリッド線を再描画しましたが、前のステップの線をクリアしませんでした。
Georg Patscheider 16

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
これは素晴らしい実装です。私はネイティブプロトタイプの拡張を完全にサポートしていますが、割り当てる前に "clear"が定義されていないことを確認する必要があるかもしれません-私はまだネイティブ実装をいつか望んでいます。:)ブラウザがどのように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を変更するのと同じくらい遅いのが唯一の方法です遅くなる可能性は、2回変更してclearRectを呼び出すことです。
Prestaul

1
申し訳ありませんが、もっと明確にする必要があります...この方法は(変換を適用していない限り)機能しますが、必要のない場合は[遅い]総当たりの手法です。clearRectを使用するのは、それが最も速く、キャンバスの実装を備えたすべてのブラウザーで機能するはずだからです。
Prestaul

1
それらがまだパスバッファーにあるため、IEがラインを再描画していると思います。私はこのフォーマットを使用しており、完璧に動作します。function clearCanvas(ctx) { ctx.beginPath(); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); }
DarrenMB 2018年

私はこれの前にあらゆる方法を試しました...そしてこれがうまくいった唯一の方法でした。私は線、四角形、テキストでChromeを使用しています...組み込みが必要なことを行うのはそれほど難しいとは思わなかったでしょう!ありがとう!
Anthony Griggs、2018

26

これは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の呪い


これは正解だと思います。特にキャンバスを描く場合はそうです。beginPathの助けを借りながら、clearRectをどのように呼び出しても、私は残りのcontext.strokeに苦しみました!
Shao-Kui、

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

14

ここにはたくさんの良い答えがあります。もう1つの注意点は、キャンバスを部分的にのみクリアすることが楽しい場合があることです。つまり、前のイメージを完全に消去するのではなく、「フェードアウト」します。これは素晴らしいトレイル効果を与えます。

それは簡単です。背景色が白だとすると:

// 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つのオブジェクトがあり、そのうちの1つだけを追跡したい場合、どうやってそれを実行しますか?
スーパー

それはかなり複雑です。その場合は、画面外のキャンバスを作成し、各フレームで、ここで説明する部分消去メソッドを使用して、そのキャンバス上に追跡するオブジェクトを描画します。また、各フレームでメインキャンバスを100%クリアし、非追跡を描画しますオブジェクトを作成し、drawImage()を使用してオフスクリーンキャンバスをメインキャンバスに合成します。また、globalCompositeOperationを画像に適したものに設定する必要があります。たとえば、「乗算」は、明るい背景の暗いオブジェクトに適しています。
orion elenzil 2014年

12

簡単な方法は

canvas.width = canvas.width

Idkそれがどのように機能するかですが、それは機能します!


ワオ。これは実際に機能します。これをどのようにして見つけましたか?
zipzit

@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

私がテストしたすべてのブラウザーで、最速の方法は実際に白または希望の色でfillRectを塗りつぶすことです。非常に大きなモニターを使用していますが、フルスクリーンモードでは、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

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
うわー...どのブラウザで?私の場合(Chrome 22およびOS X上のFirefox 14)、あなたの方法は断然、最も遅いオプションです。jsperf.com/canvas-clear-speed/9
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に設定すると、画面からすべてのアイテムがクリアされます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.