Yeniden çizim için tuval nasıl temizlenir


1012

Kompozit işlemleri denedikten ve tuval üzerine görüntü çizdikten sonra, şimdi görüntüleri kaldırmaya ve birleştirmeye çalışıyorum. Bunu nasıl yaparım?

Diğer görüntüleri yeniden çizmek için tuvali temizlemem gerekiyor; Bu bir süre devam edebilir, bu yüzden her seferinde yeni bir dikdörtgen çizmenin en verimli seçenek olacağını düşünmüyorum.

Yanıtlar:


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

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

42
clearRectDönüştürülmemiş bir içeriğe sahip olmanız veya gerçek sınırlarınızı takip etmeniz gerektiğini unutmayın .
Phrogz

7
Ayrıca, tuval genişliği ayarının a) değerinin farklı bir değere ayarlanması ve ardından Webkit uyumluluğu için yeniden ayarlanması gerektiğini ve b) bunun bağlam dönüşümünüzü sıfırlayacağını unutmayın .
Phrogz

45
Genişlik numarasını kullanmayın. Kirli bir hack. JavaScript gibi üst düzey bir dilde, istediğinizi en iyi şekilde belirtmek ve daha sonra alt düzey kodun bunları yerine getirmesine izin vermektir. Kendisine genişliğini ayarlama yok değil tuval temizlemektir gerçek niyeti, devlet.
andrewrk

22
Tamamen küçük bir düşündüren ama öneririm context.clearRect(0, 0, context.canvas.width, context.canvas.height). Etkili olarak aynı şey ama bir daha az bağımlılık (2 yerine 1 değişken)
gman

6
Bu yanıtı daha yeni okuyanlar için: bu cevabın değiştirildiğini ve yukarıdaki yorumlardan bazılarının artık geçerli olmadığını unutmayın .
daveslab

719

kullanın: context.clearRect(0, 0, canvas.width, canvas.height);

Bu, tüm tuvali temizlemenin en hızlı ve en açıklayıcı yoludur.

Kullanmayın: canvas.width = canvas.width;

Sıfırlama canvas.widthişlemi tüm tuval durumunu sıfırlar (örn. Dönüşümler, lineWidth, strokeStyle, vb.), Çok yavaştır (clearRect ile karşılaştırıldığında), tüm tarayıcılarda çalışmaz ve gerçekte ne yapmaya çalıştığınızı açıklamaz.

Dönüştürülmüş koordinatlarla başa çıkmak

Eğer dönüşüm matrisi değiştirilmiş olan (örneğin kullanılarak scale, rotateya da translatedaha sonra)context.clearRect(0,0,canvas.width,canvas.height) muhtemel tuvalin tamamını görünür kısmını temizlemez.

Çözüm? Tuvali temizlemeden önce dönüşüm matrisini sıfırlayın:

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

Düzenleme: Biraz profilleme yaptım ve (Chrome'da), dönüşümü sıfırlamadan 300x150'lik (varsayılan boyut) bir tuvali temizlemek yaklaşık% 10 daha hızlı. Tuvalinizin boyutu arttıkça bu fark düşer.

Bu zaten nispeten önemsiz, ancak çoğu durumda, temizlediğinizden çok daha fazla çizeceksiniz ve bu performans farkının önemsiz olduğuna inanıyorum.

100000 iterations averaged 10 times:
1885ms to clear
2112ms to reset and clear

4
@YumYumYum: clear () standart bir işlev midir? Öyle görünmüyor.
nobar

7
Bunun yerine canvaskullanarak yerel değişkene olan ihtiyacı kaldırabileceğinizi unutmayın ctx.canvas.
Drew Noakes

1
@DrewNoakes, iyi bir nokta, ama neredeyse her zaman hız amaçları için ayrı değişkenleri tercih ediyorum. Son derece küçüktür, ancak sık kullanılan özellikleri (özellikle bir animasyon döngüsünün içinde) yumuşatarak kayıttan çıkarma zamanından kaçınmaya çalışırım.
Prestaul

AlexanderN'in demosu artık bozuk görüntü bağlantısı nedeniyle çalışmadı, düzeltildi: jsfiddle.net/Ktqfs/50
Domino

Dönüşüm matrisi modifikasyonu durumunda tüm tuvali temizlemenin bir başka yolu, dönüşümleri takip etmek canvas.widthve bunları kendinize ve canvas.heighttemizlerken kendinize uygulamaktır . Dönüşümün sıfırlanmasıyla karşılaştırıldığında çalışma zamanı farkı üzerinde herhangi bir sayısal analiz yapmadım, ancak biraz daha iyi bir performans elde edeceğinden şüpheleniyorum.
NanoWizard

226

Çizgi çiziyorsanız, unutmadığınızdan emin olun:

context.beginPath();

Aksi takdirde çizgiler temizlenmez.


10
Bunun bir süre burada olmuştur ve bu kadar zamandan sonra yorumuna benim için aptal muhtemelen biliyorum, ama bu bir yıl boyunca beni rahatsız olmuştur ... Çağrı beginPathEğer yeni bir yol başladığınızda , düşünmeyin sadece sizin için mevcut yolunuzu da temizlemek istediğiniz tuvali temizliyoruz! Bu korkunç bir uygulamadır ve çizime bakmanın geriye dönük bir yoludur.
Prestaul

Ya sadece her şeyin tuvalini temizlemek istiyorsan. Bir oyun oluşturduğunuzu ve ekranı her saniyenin yüzde yüzünü yeniden çizmeniz gerektiğini söyleyelim.

1
@JoseQuinones, tuvalinizden beginPathhiçbir şeyi temizlemez, yolu sıfırlar, böylece çizmeden önce önceki yol girişleri kaldırılır. Muhtemelen buna ihtiyacın vardı, ama bir çizim işlemi olarak, bir temizleme işlemi değil. temizle, sonra başlaYol ve çiz, temizle ve başlaYol, sonra çiz. Fark mantıklı mı? Bir örnek için buraya bakın: w3schools.com/tags/canvas_beginpath.asp
Prestaul

1
Bu, zaman içinde yaşadığım animasyonumdaki yavaşlamayı çözdü. Her adımda ızgara çizgilerini yeniden çizdim, ancak önceki adımdaki satırları temizlemeden.
Georg Patscheider

118

Diğerleri zaten soruyu cevaplamak için mükemmel bir iş başardılar, ancak clear()bağlam nesnesindeki basit bir yöntem sizin için yararlı olursa (benim için), buradaki cevaplara dayanarak kullandığım uygulama:

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

Kullanımı:

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
Bu harika bir uygulama. Yerel prototiplerin geliştirilmesini tamamen destekliyorum, ancak atamadan önce "açık" ın tanımlanmadığından emin olmak isteyebilirsiniz - Bir gün hala yerel bir uygulama umuyorum. :) Tarayıcıların CanvasRenderingContext2D'yi nasıl geniş bir şekilde desteklediğini ve "yazılabilir" olarak bıraktığını biliyor musunuz?
Prestaul

@Prestaul geri bildirimi için teşekkürler - ayrıca, hiçbir tarayıcı javascript nesnelerini bu şekilde genişletmenizi engellememelidir.
JonathanK

@JonathanK, dönüşümü sıfırlayarak ve dönüştürmeden temizleme arasındaki performans farkının bazı profillerini görmek isterim. Küçük çizim yapıyorsanız farkın belirgin olacağını tahmin ediyorum ama çizdiğiniz şey önemsiz değilse, net adım ihmal edilebilir ... Daha fazla zamanım olduğunda bunu test etmem gerekebilir :)
Prestaul

Tamam, profili oluşturdum ve ayrıntıları yazıma ekleyeceğim.
Prestaul

35
  • Chrome iyi yanıt verir: context.clearRect ( x , y , w , h );@ Pentium10 tarafından önerildiği gibi, IE9 bu talimatı tamamen göz ardı ediyor gibi görünüyor.
  • IE9 yanıt veriyor gibi görünüyor: canvas.width = canvas.width;ancak @John Allsopp'in önce genişliği değiştirme çözümünü de kullanmadığınız sürece çizgileri, sadece şekilleri, resimleri ve diğer nesneleri temizlemez.

Yani böyle bir tuval ve bağlam oluşturduysanız:

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

Bunun gibi bir yöntem kullanabilirsiniz:

function clearCanvas(context, canvas) {
  context.clearRect(0, 0, canvas.width, canvas.height);
  var w = canvas.width;
  canvas.width = 1;
  canvas.width = w;
}

13
Yöntemin yalnızca bağlamı iletip kullanarak basitleştirilebileceğini unutmayın context.clearRect(0,0,context.canvas.width,context.canvas.height).
Phrogz

5
IE 9, bir clearRect çağrısına kesinlikle cevap vermelidir ... (Bkz: msdn.microsoft.com/en-us/library/ff975407(v=vs.85).aspx ) Canvas.width'i değiştirmek kadar yavaş, tek yol daha yavaş alabilirsiniz iki kez değiştirmek ve de clearRect çağırarak.
Prestaul

1
Maalesef daha net olmalıyım ... Bu yöntem işe yarayacak (bir dönüşüm uygulamadığınız sürece), ancak gerekli olmadığı bir [yavaş] kaba kuvvet tekniğidir. ClearRect'i en hızlı olduğu gibi kullanın ve bir tuval uygulamasıyla her tarayıcıda çalışmalıdır.
Prestaul

1
IE hala yol tamponu olma nedeniyle satırları yeniden çiziyor inanıyorum. Bu formatı kullanıyorum ve mükemmel çalışıyor. function clearCanvas(ctx) { ctx.beginPath(); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); }
DarrenMB

Bundan önce her yöntemi denedim ... ve işe yarayan tek yöntem buydu. Chrome'u çizgiler, dikdörtgenler ve metinlerle kullanıyorum ... yerleşik bir şey yapmanın çok zor olacağını düşünmemiştim! Teşekkürler!
Anthony Griggs

26

Bu 2018 ve yine de tuvali yeniden çizmek için tamamen temizlemek için yerel bir yöntem yok. clearRect() gelmez tamamen tuval temizleyin. Doldurulmayan tip çizimleri temizlenmez (örn.rect() )

1.To tamamen bağımsız çizmek nasıl anlaşılır tuval:

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

Artıları: Inme stilini korur, fillStyle vb .; Gecikme yok;

Eksileri: Herhangi bir şey çizmeden önce beginPath kullanıyorsanız gereksizdir

2. genişliği / yükseklik kesmek kullanarak:

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

VEYA

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

Artıları: IE Eksileri ile çalışır: StroStyle, fillStyle siyaha sıfırlar; laggy;

Neden yerel bir çözüm olmadığını merak ediyordum. Aslında, clearRect()çoğu kullanıcı beginPath()herhangi bir yeni yol çizmeden önce yaptığı için tek satırlı çözüm olarak kabul edilir . BeginPath yalnızca çizgi çizerken kullanılmalı ve kapalı yol gibi değilrect().

Kabul edilen cevabın sorunumu çözmemesinin nedeni budur ve farklı hack'leri denemek için saatler harcadım. Lanet seni mozilla


Bence bu, özellikle tuval çizmek için doğru cevap. BeginPath yardımcı olurken, clearRect'i nasıl çağırırsam yapayım, kalan bağlamdan muzdarip oldum!
Shao-Kui

20

X, y koordinatlarını ve tuvalin yüksekliğini ve genişliğini ileterek clearRect yöntemini kullanın. ClearRect tüm tuvali şu şekilde temizler:

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

Bunu sadece bir yönteme koyabilir ve ekranı her yenilemek istediğinizde çağırabilirsiniz, düzeltin.

@ XXX.xxx plz html'nizdeki tuval kimliğini kontrol edin ve ilk satır için aynısını kullanın (kimliğe göre öğe almak için)
Vishwas

14

Burada bir ton iyi cevap var. başka bir not, bazen tuvali kısmen temizlemek eğlenceli olabilir. yani, bir önceki görüntüyü tamamen silmek yerine "kaybolur". bu hoş yollar efektleri verebilir.

bu kolay. arka plan renginizin beyaz olduğunu varsayalım:

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

Bunun mümkün olduğunu biliyorum ve cevabınızla ilgili bir sorunum yok, merak ediyorum, eğer hareket eden 2 nesneniz varsa ve bunlardan sadece birini izlemek istiyorsanız, bunu nasıl yapardınız?
Süper

bu çok daha karmaşık. bu durumda, ekran dışı bir tuval oluşturmalısınız ve her çerçeve, burada açıklanan kısmi silme yöntemini kullanarak o tuval üzerine çizilmesini istediğiniz nesneleri çizmeli ve ayrıca her çerçeve ana tuvali% 100 temizler, iz bırakmayan çizer ve daha sonra drawImage () kullanarak ekran dışı tuvali ana tuval üzerine birleştirin. Ayrıca, globalCompositeOperation'ı görüntüler için uygun bir şeye ayarlamanız gerekir. örneğin "çarpma" açık bir arka plan üzerinde koyu renkli nesneler için iyi çalışır.
orion elenzil

12

Hızlı bir yol yapmak

canvas.width = canvas.width

Idk nasıl çalışır ama işe yarıyor!


Vay. Bu gerçekten işe yarıyor, Bunu nasıl buldunuz?
zipzit

@zipit Hızlı numara Normal takas oluşturmadan sonra medium.com'u buldum :)
Jacob Morris

1
Bunun neden işe yaradığını anlamaya çalışırken saçlarımı çekiyorum! Paylaşım için teşekkürler!
aabbccsmith

Herkes bunun neden işe yaradığını açıklayabilir ve hatta canvas.width + = 0 işi de yapar, bunun arkasındaki korkutucu bilim nedir?
PYK

8

Sınırları ve matris dönüşümlerini dikkate almadan kullandığım şey budur:

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

Temelde, bağlam mevcut durumunu kaydeder ve bir şeffaf piksel çizer copyolarak globalCompositeOperation. Ardından, önceki bağlam durumunu geri yükler.


benim için çalışıyor ...! Teşekkürler.
NomanJaved

6

Bu chart.js'deki pieChart'ım için çalıştı

<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

Test ettiğim tüm tarayıcılarda en hızlı yolun aslındaRect'i beyaz veya istediğiniz renkle doldurmak olduğunu gördüm. Çok büyük bir monitör var ve tam ekran modunda clearRect agonizingly yavaş, ancak fillRect makul.

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

Dezavantajı, tuvalin artık şeffaf olmamasıdır.


4

webkit'te genişliği farklı bir değere ayarlamanız gerekir, ardından başlangıç ​​değerine geri ayarlayabilirsiniz.


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

Bu, clearRect'ten daha yavaştır (0,0, canvas.width, canvas.height)
sEver

4

Basit, ancak çok okunaklı olmayan bir yol bunu yazmaktır:

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

// after doing some rendering

canvas.width = canvas.width;  // clear the whole canvas

2

Her zaman kullanırım

cxt.fillStyle = "rgb(255, 255, 255)";
cxt.fillRect(0, 0, canvas.width, canvas.height);

bu en kolay yol! En azından benim için.
Jacques Olivier

1
context.clearRect(0,0,w,h)   

verilen dikdörtgeni RGBA değerleri ile doldurun:
0 0 0 0: Chrome
0 0 0 255 ile: FF ve Safari ile

Fakat

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

tarayıcı ne olursa olsun
0 0 0 255 ile dolu dikdörtgen
olsun!


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

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



0

en hızlı yol:

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
vay ... Hangi tarayıcıda? Benimkinde (OS X'te Chrome 22 ve Firefox 14) yönteminiz açık ara en yavaş seçenektir. jsperf.com/canvas-clear-speed/9
Prestaul

1
Gelecekte> 5 yıl, bu hala çok büyük miktarda en yavaş yöntemdir, ~ 700x daha yavaştır clearRect.
mgthomas99

0

Yalnızca clearRect kullanıyorsanız, çiziminizi göndermek için bir formunuz varsa, bunun yerine temizleme yerine bir gönderim alırsınız veya belki de önce temizlenebilir ve daha sonra geçersiz bir çizim yükleyebilirsiniz. fonksiyonun başlangıcında varsayılan:

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

Umarım birine yardımcı olur.


0

Bunu her zaman kullanırım

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

NOT

clearRect ve requestAnimationFrame'i birleştirmek istediğiniz şeyse daha akıcı animasyon sağlar


-2

Bunların hepsi standart bir tuvali nasıl temizlediğinizin harika örnekleridir, ancak paperjs kullanıyorsanız, bu işe yarayacaktır:

JavaScript'te genel bir değişken tanımlayın:

var clearCanvas = false;

PaperScript'inizden şunları tanımlayın:

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

ClearCanvas'ı true olarak ayarladığınız her yerde, ekrandaki tüm öğeleri temizleyecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.