Come cancellare la tela per ridisegnare


1013

Dopo aver sperimentato operazioni composite e disegnando immagini sulla tela, ora sto provando a rimuovere immagini e compositing. Come faccio a fare questo?

Devo cancellare la tela per ridisegnare altre immagini; questo può andare avanti per un po ', quindi non credo che disegnare un nuovo rettangolo ogni volta sarà l'opzione più efficiente.

Risposte:


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

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

42
Si noti che clearRectè necessario disporre di un contesto non trasformato o tenere traccia dei limiti effettivi.
Phrogz,

7
Si noti inoltre che l'impostazione della larghezza della tela a) deve impostarla su un valore diverso e quindi di nuovo indietro per la compatibilità di Webkit , e b) questo ripristinerà la trasformazione del contesto .
Phrogz,

45
Non usare il trucco della larghezza. È un trucco sporco. In un linguaggio di alto livello come JavaScript, ciò che si desidera è esprimere al meglio le proprie intenzioni, quindi lasciare che il codice di livello inferiore le soddisfi. Impostare la larghezza a sé non dichiarare la vostra vera intenzione, che è quello di cancellare la tela.
Andrew

22
Un suggerimento del tutto secondario ma suggerirei context.clearRect(0, 0, context.canvas.width, context.canvas.height). È effettivamente la stessa cosa ma una dipendenza in meno (1 variabile invece di 2)
gman,

6
Per i lettori più recenti di questa risposta: tenere presente che questa risposta è stata modificata e che alcuni dei commenti di cui sopra non si applicano più .
daveslab,

719

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

Questo è il modo più rapido e descrittivo per cancellare l'intera tela.

Non usare: canvas.width = canvas.width;

Il ripristino canvas.widthripristina tutto lo stato della tela (ad es. Trasformazioni, lineWidth, strokeStyle, ecc.), È molto lento (rispetto a clearRect), non funziona in tutti i browser e non descrive ciò che stai effettivamente cercando di fare.

Gestire le coordinate trasformate

Se è stato modificato la matrice di trasformazione (ad esempio utilizzando scale, rotateo translate) quindi context.clearRect(0,0,canvas.width,canvas.height)probabilmente non cancellare l'intera porzione visibile della tela.

La soluzione? Ripristina la matrice di trasformazione prima di cancellare l'area di disegno:

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

Modifica: ho appena fatto un po 'di profilazione e (in Chrome) è circa il 10% più veloce per cancellare una tela 300x150 (dimensione predefinita) senza ripristinare la trasformazione. Man mano che la dimensione della tela aumenta, questa differenza diminuisce.

Questo è già relativamente insignificante, ma nella maggior parte dei casi disegnerai molto più di quello che stai cancellando e credo che questa differenza di prestazioni sia irrilevante.

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

4
@YumYumYum: clear () è una funzione standard? Non sembra essere.
nobar,

7
Si noti che è possibile rimuovere la necessità di una canvasvariabile locale utilizzando ctx.canvasinvece.
Drew Noakes,

1
@DrewNoakes, buon punto, ma quasi sempre opto per variabili separate ai fini della velocità. È estremamente minore, ma cerco di evitare il tempo di dereferenziazione aliasando le proprietà usate di frequente (specialmente all'interno di un loop di animazione).
Prestaul,

La demo di AlexanderN non funzionava più a causa di un link non funzionante, risolto: jsfiddle.net/Ktqfs/50
Domino

Un altro modo per cancellare l'intera tela in caso di modifica della matrice di trasformazione è semplicemente tenere traccia delle trasformazioni e applicarle a te stesso canvas.widthe canvas.heightdurante la cancellazione. Non ho fatto alcuna analisi numerica sulla differenza di runtime rispetto al ripristino della trasformazione, ma sospetto che migliorerebbe le prestazioni.
NanoWizard,

226

Se stai disegnando linee, assicurati di non dimenticare:

context.beginPath();

Altrimenti le linee non verranno cancellate.


10
So che questo è qui da un po 'ed è probabilmente sciocco per me commentare dopo tutto questo tempo, ma questo mi ha infastidito per un anno ... Chiama beginPathquando inizi una nuova strada , non dare per scontato solo perché tu stanno cancellando la tela che vuoi cancellare anche il tuo percorso esistente! Questa sarebbe una pratica orribile ed è un modo all'indietro di guardare al disegno.
Prestaul,

E se vuoi solo cancellare la tela da tutto. Diciamo che stai creando un gioco e che devi ridisegnare lo schermo ogni centesimi di secondo.

1
@JoseQuinones, beginPathnon cancella nulla dalla tela, reimposta il percorso in modo che le voci del percorso precedente vengano rimosse prima di disegnare. Probabilmente ne avevi bisogno, ma come un'operazione di disegno, non un'operazione di cancellazione. cancella, quindi iniziaPath e disegna, non cancella e iniziaPath, quindi disegna. La differenza ha senso? Guarda qui un esempio: w3schools.com/tags/canvas_beginpath.asp
Prestaul

1
Questo ha risolto il rallentamento della mia animazione che ho sperimentato nel tempo. Ho ridisegnato le linee della griglia su ogni passaggio, ma senza cancellare le linee dal passaggio precedente.
Georg Patscheider,

118

Altri hanno già fatto un ottimo lavoro nel rispondere alla domanda, ma se un semplice clear()metodo sull'oggetto contestuale ti fosse utile (lo era per me), questa è l'implementazione che utilizzo in base alle risposte qui:

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

Uso:

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
Questa è una grande implementazione. Sostengo pienamente il potenziamento dei prototipi nativi, ma potresti voler assicurarti che "clear" non sia definito prima di assegnarlo - spero ancora per un'implementazione nativa un giorno. :) Sai in che misura i browser supportano CanvasRenderingContext2D e lo lasciano "scrivibile"?
Prestaul,

Grazie per il feedback @Prestaul - inoltre, nessun browser dovrebbe impedirti di estendere gli oggetti javascript in questo modo.
JonathanK,

@JonathanK, mi piacerebbe vedere un po 'di profiling della differenza di prestazioni tra compensazione con e senza ripristinare la trasformazione. Immagino che la differenza sarà evidente se stai facendo poco disegno ma che se ciò che stai disegnando non è banale, allora il passo chiaro è trascurabile ... Potrei doverlo testare più tardi quando avrò più tempo :)
Prestaul,

Ok, ho fatto la profilazione e aggiungerò i dettagli al mio post.
Prestaul,

35
  • Chrome risponde bene a: context.clearRect ( x , y , w , h );come suggerito da @ Pentium10 ma IE9 sembra ignorare completamente questa istruzione.
  • Sembra che IE9 risponda: canvas.width = canvas.width;ma non cancella le linee, solo forme, immagini e altri oggetti a meno che non usi anche la soluzione di @John Allsopp per cambiare prima la larghezza.

Quindi se hai una tela e un contesto creati in questo modo:

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

Puoi usare un metodo come questo:

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

13
Si noti che il metodo può essere semplificato passando solo nel contesto e usando context.clearRect(0,0,context.canvas.width,context.canvas.height).
Phrogz,

5
Internet Explorer 9 dovrebbe assolutamente rispondere a una chiamata clearRect ... (Vedi: msdn.microsoft.com/en-us/library/ff975407(v=vs.85).aspx ) Lento come cambiare canvas.width è, l'unico modo potresti rallentare cambiandolo due volte e chiamando pure clearRect.
Prestaul,

1
Scusa, dovrei essere più chiaro ... Questo metodo funzionerà (purché tu non abbia applicato una trasformazione), ma è una tecnica [lenta] di forza bruta dove non è necessaria. Usa clearRect in quanto è più veloce e dovrebbe funzionare su tutti i browser con un'implementazione canvas.
Prestaul,

1
Credo che IE stia ridisegnando le linee perché sono ancora nel buffer di percorso. Uso questo formato e funziona perfettamente. function clearCanvas(ctx) { ctx.beginPath(); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); }
DarrenMB,

Ho provato tutti i metodi prima di questo ... e questo era l'unico che ha funzionato. Sto usando Chrome con linee, rettangoli e testo ... non avrei pensato che sarebbe stato così difficile fare qualcosa che dovrebbe essere integrato! Grazie!
Anthony Griggs,

27

Questo è il 2018 e non esiste ancora un metodo nativo per cancellare completamente la tela per il ridisegno. clearRect() non cancella completamente la tela. I disegni di tipo non di riempimento non vengono cancellati (ad es. rect())

1.Per cancellare completamente la tela indipendentemente da come si disegna:

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

Pro: preserva trattoStyle, fillStyle ecc .; Nessun ritardo;

Contro: non necessario se si sta già usando beginPath prima di disegnare qualcosa

2.Utilizzando l'hack larghezza / altezza:

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

O

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

Pro: Funziona con IE Contro: Reimposta strokeStyle, fillStyle su nero; lag;

Mi chiedevo perché non esistesse una soluzione nativa. In realtà, clearRect()è considerata la soluzione a linea singola perché la maggior parte degli utenti lo fa beginPath()prima di tracciare qualsiasi nuovo percorso. Anche se beginPath deve essere utilizzato solo durante il disegno di linee e non come percorsi chiusirect().

Questo è il motivo per cui la risposta accettata non ha risolto il mio problema e ho finito per perdere ore a provare diversi hack. Ti maledico Mozilla


Penso che questa sia la risposta giusta, soprattutto per il disegno su tela. Ho sofferto di rimanente context.stroke non importa come chiamo clearRect, mentre beginPath mi ha aiutato!
Shao-Kui,

20

Usa il metodo clearRect passando le coordinate x, y e l'altezza e la larghezza della tela. ClearRect cancella l'intera tela come:

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

Potresti semplicemente inserire questo in un metodo e chiamarlo ogni volta che vuoi aggiornare lo schermo, corretto.

@ XXX.xxx per favore controlla l'id della tela nel tuo html e usa lo stesso per la prima riga (per ottenere l'elemento per id)
Vishwas

14

ci sono un sacco di buone risposte qui. un'ulteriore nota è che a volte è divertente cancellare solo parzialmente la tela. cioè "sfumare" l'immagine precedente invece di cancellarla del tutto. questo può dare dei bei effetti trail.

è facile. supponendo che il colore di sfondo sia bianco:

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

So che è possibile e non ho alcun problema con la tua risposta, mi chiedo solo se hai 2 oggetti che si stanno muovendo e vuoi solo seguirne uno, come faresti?
super

è molto più complesso. in tal caso, dovresti creare una tela fuori schermo e ogni cornice disegna gli oggetti che vuoi trascinare su quella tela usando il metodo di cancellazione parziale qui descritto, e anche ogni cornice cancella la tela principale al 100%, disegna la non trascinata oggetti, quindi comporre la tela fuori schermo su quella principale usando drawImage (). Dovrai anche impostare globalCompositeOperation su qualcosa di appropriato per le immagini. es. "moltiplicare" funzionerebbe bene per oggetti scuri su uno sfondo chiaro.
Orion Elenzil,

12

Un modo rapido è quello di fare

canvas.width = canvas.width

Idk come funziona ma funziona!


Wow. Funziona davvero, come l'hai mai trovato?
zipzit,

@zipit Trucco rapido che ho trovato su medium.com dopo che il normale clearing non veniva visualizzato :)
Jacob Morris,

1
Mi sto strappando i capelli cercando di capire perché funziona! Grazie per la condivisione!
aabbccsmith il

Qualcuno può spiegare perché questo funziona e anche canvas.width + = 0 fa anche il lavoro, qual è la scienza eccentrica alla base di questo?
PYK,

8

Questo è quello che uso, indipendentemente dai confini e dalle trasformazioni della matrice:

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

Fondamentalmente, salva lo stato corrente del contesto e disegna un pixel trasparente con copyas globalCompositeOperation. Quindi ripristina lo stato di contesto precedente.


per me funziona...! Grazie.
NomanJaved il

6

Questo ha funzionato per il mio grafico a torta in 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

5

Ho scoperto che in tutti i browser che collaudo, il modo più veloce è in realtà riempireRect con il bianco o il colore che desideri. Ho un monitor molto grande e in modalità schermo intero clearRect è stranamente lento, ma fillRect è ragionevole.

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

Lo svantaggio è che la tela non è più trasparente.


4

nel webkit è necessario impostare la larghezza su un valore diverso, quindi è possibile ripristinarla sul valore iniziale


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

Questo è più lento di clearRect (0,0, canvas.width, canvas.height)
ogni

4

Un modo semplice, ma non molto leggibile è scrivere questo:

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

// after doing some rendering

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

2

Lo uso sempre

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

questo è il modo più semplice! Beh, almeno per me.
Jacques Olivier,

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

riempi il rettangolo dato con i valori RGBA:
0 0 0 0: con Chrome
0 0 0 255: con FF e Safari

Ma

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

lascia che il rettangolo si riempia di
0 0 0 255,
indipendentemente dal browser!


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

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



0

modo più veloce:

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
wow ... In quale browser? Nel mio (Chrome 22 e Firefox 14 su OS X) il tuo metodo è di gran lunga l'opzione più lenta. jsperf.com/canvas-clear-speed/9
Prestaul

1
> 5 anni in futuro, questo è ancora il metodo più lento di una quantità molto grande, ~ 700x più lento di clearRect.
mgthomas99,

0

Se usi solo clearRect, se lo hai in un modulo per inviare il tuo disegno, otterrai un invio invece della cancellazione, o forse può essere prima cancellato e quindi caricare un disegno vuoto, quindi dovrai aggiungere un preventDefault all'inizio della funzione:

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

Spero che aiuti qualcuno.


0

Lo uso sempre

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

NOTA

la combinazione di clearRect e requestAnimationFrame consente un'animazione più fluida se è quello che stai cercando


-2

Questi sono tutti ottimi esempi di come si cancella un'area di disegno standard, ma se si utilizzano paperjs, allora funzionerà:

Definire una variabile globale in JavaScript:

var clearCanvas = false;

Dal tuo PaperScript definisci:

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

Ora, ovunque imposti clearCanvas su true, cancellerà tutti gli elementi dallo schermo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.