Bagaimana menghapus kanvas untuk digambar ulang

1013

Setelah bereksperimen dengan operasi komposit dan menggambar gambar pada kanvas saya sekarang mencoba untuk menghapus gambar dan pengomposisian. Bagaimana saya melakukan ini?

Saya perlu membersihkan kanvas untuk menggambar ulang gambar lain; ini bisa berlangsung sebentar jadi saya tidak berpikir menggambar persegi panjang baru setiap kali akan menjadi pilihan yang paling efisien.

richard
sumber

Jawaban:

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

context.clearRect(0, 0, canvas.width, canvas.height);
Pentium10
sumber
42
Perhatikan bahwa untuk clearRectAnda harus memiliki konteks yang tidak diubah, atau melacak batasan Anda yang sebenarnya.
Phrogz
7
Perhatikan lebih lanjut bahwa mengatur lebar kanvas a) perlu mengaturnya ke nilai yang berbeda dan kemudian kembali lagi untuk kompatibilitas Webkit , dan b) ini akan mengatur ulang transformasi konteks Anda .
Phrogz
45
Jangan gunakan trik lebar. Ini hack kotor. Dalam bahasa tingkat tinggi seperti JavaScript yang Anda inginkan adalah menyatakan maksud Anda, dan kemudian biarkan kode tingkat yang lebih rendah memenuhinya. Mengatur lebar untuk dirinya sendiri tidak menyatakan niat Anda yang sebenarnya, yaitu membersihkan kanvas.
andrewrk
22
Saran yang sangat kecil tapi saya sarankan context.clearRect(0, 0, context.canvas.width, context.canvas.height). Secara efektif hal yang sama tetapi satu ketergantungan kurang (1 variabel, bukan 2)
gman
6
Untuk pembaca yang lebih baru dari jawaban ini: menyadari bahwa jawaban ini dimodifikasi dan bahwa beberapa komentar di atas tidak berlaku lagi .
daveslab
719

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

Ini adalah cara tercepat dan paling deskriptif untuk menghapus seluruh kanvas.

Jangan gunakan: canvas.width = canvas.width;

Menyetel canvas.widthulang semua keadaan kanvas (mis. Transformasi, lineWidth, strokeStyle, dll.), Ini sangat lambat (dibandingkan dengan clearRect), itu tidak berfungsi di semua browser, dan itu tidak menggambarkan apa yang sebenarnya Anda coba lakukan.

Berurusan dengan koordinat yang diubah

Jika Anda telah memodifikasi matriks transformasi (misalnya menggunakan scale, rotateatau translate) maka context.clearRect(0,0,canvas.width,canvas.height)kemungkinan besar tidak akan menghapus seluruh bagian terlihat dari kanvas.

Solusinya? Setel ulang matriks transformasi sebelum membersihkan kanvas:

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

Sunting: Saya baru saja melakukan beberapa profil dan (di Chrome) sekitar 10% lebih cepat untuk menghapus kanvas 300x150 (ukuran standar) tanpa mengatur ulang transformasi. Ketika ukuran kanvas Anda meningkat, perbedaan ini menurun.

Itu sudah relatif tidak signifikan, tetapi dalam banyak kasus Anda akan menggambar jauh lebih banyak daripada yang Anda kliring dan saya percaya perbedaan kinerja ini tidak relevan.

100000 iterations averaged 10 times:
1885ms to clear
2112ms to reset and clear
Prestaul
sumber
4
@YumYumYum: Jelas () fungsi standar? Sepertinya tidak.
Nobar
7
Perhatikan bahwa Anda dapat menghapus kebutuhan untuk canvasvariabel lokal dengan menggunakan ctx.canvassebagai gantinya.
Drew Noakes
1
@DrewNoakes, bagus, tapi saya hampir selalu memilih variabel yang terpisah untuk keperluan kecepatan. Ini sangat kecil, tetapi saya mencoba untuk menghindari waktu dereferencing dengan aliasing properti yang sering digunakan (terutama di dalam loop animasi).
Prestaul
Demo AlexanderN tidak berfungsi lagi karena tautan gambar rusak, diperbaiki: jsfiddle.net/Ktqfs/50
Domino
Cara lain untuk menghapus seluruh kanvas dalam hal modifikasi matriks transformasi adalah hanya melacak transformasi dan menerapkannya sendiri canvas.widthdan canvas.heightketika membersihkan. Saya belum melakukan analisis numerik pada perbedaan runtime dibandingkan dengan mengatur ulang transformasi, tapi saya menduga itu akan menghasilkan kinerja yang sedikit lebih baik.
NanoWizard
226

Jika Anda menggambar garis, pastikan Anda tidak lupa:

context.beginPath();

Kalau tidak, garis tidak akan dihapus.

gemetar
sumber
10
Saya tahu ini telah ada di sini untuk sementara waktu dan mungkin konyol bagi saya untuk berkomentar setelah sekian lama, tetapi ini telah mengganggu saya selama setahun ... Hubungi beginPathketika Anda memulai jalan baru , jangan menganggap itu hanya karena Anda sedang membersihkan kanvas yang ingin Anda hapus jalur yang ada juga! Ini akan menjadi praktik yang mengerikan dan merupakan cara mundur untuk melihat gambar.
Prestaul
Bagaimana jika Anda hanya ingin membersihkan kanvas dari segalanya. Katakanlah bahwa Anda membuat game dan Anda perlu menggambar ulang layar setiap ratusan detik.
1
@ JoseQuinones, beginPathtidak menghapus apa pun dari kanvas Anda, itu me-reset path sehingga entri path sebelumnya dihapus sebelum Anda menggambar. Anda mungkin memang membutuhkannya, tetapi sebagai operasi menggambar, bukan operasi kliring. jelas, lalu beginPath dan gambar, tidak jelas dan beginPath, lalu gambar. Apakah perbedaan itu masuk akal? Lihat di sini untuk contoh: w3schools.com/tags/canvas_beginpath.asp
Prestaul
1
Ini menyelesaikan perlambatan animasi yang saya alami seiring waktu. Saya menggambar ulang garis kisi pada setiap langkah, tetapi tanpa menghapus garis dari langkah sebelumnya.
Georg Patscheider
118

Orang lain telah melakukan pekerjaan yang sangat baik untuk menjawab pertanyaan, tetapi jika clear()metode sederhana pada objek konteks akan berguna bagi Anda (bagi saya), ini adalah implementasi yang saya gunakan berdasarkan jawaban di sini:

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

Pemakaian:

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
sumber
6
Ini implementasi yang bagus. Saya sepenuhnya mendukung peningkatan prototipe asli, tetapi Anda mungkin ingin memastikan bahwa "clear" tidak didefinisikan sebelum menetapkannya - saya masih berharap untuk implementasi asli suatu hari nanti. :) Apakah Anda tahu bagaimana browser secara luas mendukung CanvasRenderingContext2D dan membiarkannya "dapat ditulis"?
Prestaul
Terima kasih atas umpan balik @Prestaul - juga, tidak ada browser yang mencegah Anda memperluas objek javascript dengan cara ini.
JonathanK
@ JonathanK, saya ingin melihat beberapa profil dari perbedaan kinerja antara kliring dengan dan tanpa mengatur ulang transformasi. Saya menduga perbedaannya akan jelas jika Anda melakukan sedikit menggambar tetapi jika apa yang Anda gambar tidak sepele maka langkah yang jelas diabaikan ... Saya mungkin harus menguji nanti ketika saya punya lebih banyak waktu :)
Prestaul
Ok, saya membuat profil dan saya akan menambahkan detail ke posting saya.
Prestaul
35
  • Chrome merespons dengan baik: context.clearRect ( x , y , w , h );seperti yang disarankan oleh @ Pentium10 tetapi IE9 tampaknya sepenuhnya mengabaikan instruksi ini.
  • IE9 tampaknya merespons: canvas.width = canvas.width;tetapi tidak menghapus garis, hanya bentuk, gambar, dan objek lain kecuali Anda juga menggunakan solusi @John Allsopp untuk pertama-tama mengubah lebar.

Jadi jika Anda memiliki kanvas dan konteks yang dibuat seperti ini:

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

Anda dapat menggunakan metode seperti ini:

function clearCanvas(context, canvas) {
  context.clearRect(0, 0, canvas.width, canvas.height);
  var w = canvas.width;
  canvas.width = 1;
  canvas.width = w;
}
granat
sumber
13
Perhatikan bahwa metode ini dapat disederhanakan dengan hanya memasukkan konteks dan menggunakan context.clearRect(0,0,context.canvas.width,context.canvas.height).
Phrogz
5
IE 9 harus benar-benar menanggapi panggilan clearRect ... (Lihat: msdn.microsoft.com/en-us/library/ff975407(v=vs.85).aspx ) Selambat mengubah canvas.width adalah, satu-satunya cara Anda bisa menjadi lebih lambat dengan mengubahnya dua kali dan memanggil clearRect juga.
Prestaul
1
Maaf, saya harus lebih jelas ... Metode ini akan berhasil (selama Anda belum menerapkan transformasi), tetapi merupakan teknik brute force [lambat] yang tidak diperlukan. Cukup gunakan clearRect karena ini tercepat dan harus bekerja di setiap browser dengan implementasi kanvas.
Prestaul
1
Saya percaya IE sedang menggambar ulang garis karena mereka masih di buffer path. Saya menggunakan format ini dan bekerja dengan sempurna. function clearCanvas(ctx) { ctx.beginPath(); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); }
DarrenMB
Saya mencoba setiap metode sebelum ini ... dan ini adalah satu-satunya metode yang berhasil. Saya menggunakan Chrome dengan garis, persegi panjang dan teks ... tidak akan menyangka akan sangat sulit untuk melakukan sesuatu yang seharusnya ada di dalamnya! Terima kasih!
Anthony Griggs
27

Ini adalah 2018 dan masih belum ada metode asli untuk menghapus kanvas sepenuhnya untuk menggambar ulang. clearRect() tidak membersihkan kanvas sepenuhnya. Gambar jenis non-isi tidak dihapus (mis. rect())

1. Untuk menghapus kanvas sepenuhnya terlepas dari cara Anda menggambar:

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

Pro: Mempertahankan strokeStyle, fillStyle dll; Tidak ketinggalan;

Cons: Tidak perlu jika Anda sudah menggunakan beginPath sebelum menggambar apa pun

2.Menggunakan hack lebar / tinggi:

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

ATAU

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

Pro: Bekerja dengan IE Cons: Mereset strokeStyle, fillStyle menjadi hitam; Laggy;

Saya bertanya-tanya mengapa solusi asli tidak ada. Sebenarnya, clearRect()dianggap sebagai solusi garis tunggal karena sebagian besar pengguna lakukan beginPath()sebelum menggambar jalur baru. Padahal beginPath hanya digunakan saat menggambar garis dan bukan jalan tertutup sepertirect().

Ini adalah alasan mengapa jawaban yang diterima tidak menyelesaikan masalah saya dan saya akhirnya menghabiskan waktu berjam-jam untuk mencoba hack yang berbeda. Terkutuklah kamu mozilla

sziraqui
sumber
Saya pikir ini adalah jawaban yang tepat, terutama untuk menggambar kanvas. Saya menderita dari konteks yang tersisa. Stroke tidak peduli bagaimana saya memanggil clearRect, sementara beginPath membantu!
Shao-Kui
20

Gunakan metode clearRect dengan melewatkan koordinat x, y dan tinggi serta lebar kanvas. ClearRect akan menghapus seluruh kanvas sebagai:

canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
Wisnu
sumber
Anda bisa menempatkan ini dalam metode dan menyebutnya setiap kali Anda ingin menyegarkan layar, benar.
@ XXX.xxx silakan periksa id kanvas di html Anda dan gunakan yang sama untuk baris pertama (untuk mendapatkan elemen dengan id)
Vishwas
14

ada banyak jawaban bagus di sini. satu catatan lebih lanjut adalah bahwa kadang-kadang menyenangkan hanya membersihkan sebagian kanvas. yaitu, "fade out" gambar sebelumnya alih-alih menghapusnya seluruhnya. ini dapat memberikan efek jejak yang bagus.

mudah. seandainya warna latar belakang Anda putih:

// 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);
orion elenzil
sumber
Saya tahu itu mungkin dan saya tidak punya masalah dengan jawaban Anda, saya hanya ingin tahu, jika Anda memiliki 2 objek yang bergerak, dan Anda hanya ingin menelusuri salah satu dari mereka, bagaimana Anda akan melakukannya?
super
itu jauh lebih kompleks. dalam hal ini, Anda harus membuat kanvas di luar layar, dan setiap frame menggambar objek yang ingin Anda lacak ke kanvas itu menggunakan metode parsial-hapus yang dijelaskan di sini, dan juga setiap frame menghapus kanvas utama 100%, menggambar non-trailing objek, dan kemudian komposit kanvas off-layar ke yang utama menggunakan drawImage (). Anda juga perlu mengatur globalCompositeOperation ke sesuatu yang sesuai untuk gambar. mis. "multiply" akan bekerja dengan baik untuk objek gelap pada latar belakang yang terang.
orion elenzil
12

Cara cepat adalah melakukan

canvas.width = canvas.width

Idk cara kerjanya tetapi itu!

Jacob Morris
sumber
Wow. Ini benar-benar bekerja, Bagaimana Anda menemukan ini?
zipzit
@zipit Trik cepat yang saya temukan dari medium.com setelah pembukaan normal tidak menghasilkan :)
Jacob Morris
1
Saya mencabut rambut saya mencoba mencari tahu mengapa ini berhasil! Terima kasih telah berbagi!
aabbccsmith
Adakah yang bisa menjelaskan mengapa itu bekerja dan bahkan canvas.width + = 0 melakukan pekerjaan itu juga, apa yang dibalik ilmu ini?
PYK
8

Inilah yang saya gunakan, terlepas dari batasan dan transformasi matriks:

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

Pada dasarnya, ini menyimpan keadaan konteks saat ini, dan menggambar piksel transparan dengan copyas globalCompositeOperation. Kemudian, pulihkan keadaan konteks sebelumnya.

superruzafa
sumber
ini bekerja untuk saya ...! Terima kasih.
Noman Diambil
6

Ini berfungsi untuk pieChart saya di chart.js

<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
Sanal S
sumber
5

Saya telah menemukan bahwa di semua browser yang saya uji, cara tercepat adalah dengan benar-benar mengisiRect dengan warna putih, atau warna apa pun yang Anda inginkan. Saya memiliki monitor yang sangat besar dan dalam mode layar penuh clearRect sangat lambat, tetapi fillRect masuk akal.

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

Kekurangannya adalah bahwa kanvas tidak lagi transparan.

John Page
sumber
4

di webkit Anda perlu mengatur lebar ke nilai yang berbeda, maka Anda dapat mengaturnya kembali ke nilai awal

John Allsopp
sumber
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;
}
Imagine Breaker
sumber
Ini lebih lambat daripada clearRect (0,0, canvas.width, canvas.height)
sEver
4

Cara sederhana, tetapi tidak terlalu mudah dibaca adalah menulis ini:

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

// after doing some rendering

canvas.width = canvas.width;  // clear the whole canvas
Chang
sumber
2

Saya selalu menggunakan

cxt.fillStyle = "rgb(255, 255, 255)";
cxt.fillRect(0, 0, canvas.width, canvas.height);
GameMaster1928
sumber
ini cara termudah! Setidaknya untuk saya.
Jacques Olivier
1
context.clearRect(0,0,w,h)   

isi kotak yang diberikan dengan nilai RGBA:
0 0 0 0: dengan Chrome
0 0 0 255: dengan FF & Safari

Tapi

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

biarkan persegi panjang diisi dengan
0 0 0 255
tidak masalah browser!

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

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

Gavin T
sumber
1

cara terpendek:

canvas.width += 0
Yukulélé
sumber
0

jalan tercepat:

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
elser
sumber
12
wow ... Di browser mana? Di tambang (Chrome 22 dan Firefox 14 di OS X) metode Anda, sejauh ini, merupakan opsi paling lambat. jsperf.com/canvas-clear-speed/9
Prestaul
1
> 5 tahun ke depan, ini masih merupakan metode paling lambat dengan jumlah yang sangat besar, ~ 700x lebih lambat dari clearRect.
mgthomas99
0

Jika Anda menggunakan clearRect saja, jika Anda memilikinya dalam bentuk untuk mengirimkan gambar Anda, Anda akan mendapatkan kiriman sebagai gantinya, atau mungkin itu dapat dihapus terlebih dahulu dan kemudian mengunggah gambar batal, jadi Anda harus menambahkan preventDefault pada awal fungsi:

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

Semoga ini bisa membantu seseorang.

JoelBonetR
sumber
0

Saya selalu menggunakan ini

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

CATATAN

menggabungkan clearRect dan requestAnimationFrame memungkinkan animasi yang lebih lancar jika Anda menginginkannya

Anthony Gedeon
sumber
-2

Ini semua adalah contoh yang bagus tentang bagaimana Anda menghapus kanvas standar, tetapi jika Anda menggunakan paperjs, maka ini akan berhasil:

Tentukan variabel global dalam JavaScript:

var clearCanvas = false;

Dari PaperScript Anda tentukan:

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

Sekarang di mana pun Anda mengatur clearCanvas menjadi true, itu akan menghapus semua item dari layar.

Robert Ogle
sumber