Como limpar a tela para redesenhar

1013

Depois de experimentar operações compostas e desenhar imagens na tela, agora estou tentando remover imagens e composição. Como eu faço isso?

Preciso limpar a tela para redesenhar outras imagens; isso pode continuar por um tempo, então não acho que desenhar um novo retângulo toda vez seja a opção mais eficiente.

Richard
fonte

Respostas:

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

context.clearRect(0, 0, canvas.width, canvas.height);
Pentium10
fonte
42
Observe que clearRectvocê precisa ter um contexto não transformado ou acompanhar seus limites reais.
Phrogz
7
Observe ainda que a configuração da largura da tela a) precisa configurá-la com um valor diferente e, em seguida, novamente para compatibilidade com o Webkit eb) isso redefinirá sua transformação de contexto .
Phrogz
45
Não use o truque de largura. É um truque sujo. Em uma linguagem de alto nível, como JavaScript, o que você deseja é declarar melhor suas intenções e deixar que o código de nível inferior as cumpra. Definir a largura para si mesmo não indica sua verdadeira intenção, que é limpar a tela.
precisa saber é o seguinte
22
Uma sugestão totalmente menor, mas eu sugiro context.clearRect(0, 0, context.canvas.width, context.canvas.height). É efetivamente a mesma coisa, mas uma menor dependência (1 variável em vez de 2)
gman
6
Para leitores mais recentes desta resposta: saiba que essa resposta foi modificada e que alguns dos comentários acima não se aplicam mais .
Davelab
719

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

Essa é a maneira mais rápida e descritiva de limpar a tela inteira.

Não use: canvas.width = canvas.width;

A redefinição canvas.widthredefine todo o estado da tela (por exemplo, transformações, lineWidth, strokeStyle etc.), é muito lento (comparado ao clearRect), não funciona em todos os navegadores e não descreve o que você está realmente tentando fazer.

Lidando com coordenadas transformadas

Se você modificou a matriz de transformação (por exemplo scale, usando,, rotateou translate), context.clearRect(0,0,canvas.width,canvas.height)provavelmente não limpará toda a parte visível da tela.

A solução? Redefina a matriz de transformação antes de limpar a tela:

// 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: Acabei de fazer alguns perfis e (no Chrome) é 10% mais rápido para limpar uma tela de 300 x 150 (tamanho padrão) sem redefinir a transformação. À medida que o tamanho da sua tela aumenta, essa diferença diminui.

Isso já é relativamente insignificante, mas na maioria dos casos você estará atraindo consideravelmente mais do que está limpando e acredito que essa diferença de desempenho seja irrelevante.

100000 iterations averaged 10 times:
1885ms to clear
2112ms to reset and clear
Prestaul
fonte
4
@YumYumYum: Clear () é uma função padrão? Não parece ser.
Nobar
7
Observe que você pode remover a necessidade de uma canvasvariável local usando ctx.canvas.
Drew Noakes
1
@DrewNoakes, bom ponto, mas quase sempre opto por variáveis ​​separadas para fins de velocidade. É extremamente pequeno, mas tento evitar o tempo de desreferenciamento, alternando as propriedades usadas com freqüência (especialmente dentro de um loop de animação).
Prestaul 25/10/12
A demo de AlexanderN não funcionou mais devido a um link quebrado da imagem, corrigido: jsfiddle.net/Ktqfs/50
Domino
Outra maneira de limpar a tela inteira no caso de modificação da matriz de transformação é simplesmente acompanhar as transformações e aplicá-las a você canvas.widthe canvas.heightao limpar. Eu não fiz nenhuma análise numérica sobre a diferença de tempo de execução em comparação com a redefinição da transformação, mas suspeito que isso proporcionaria um desempenho um pouco melhor.
NanoWizard 01/09/2015
226

Se você estiver desenhando linhas, não se esqueça:

context.beginPath();

Caso contrário, as linhas não serão limpas.

tremer
fonte
10
Eu sei que isso está aqui há um tempo e provavelmente é bobagem para mim comentar depois de todo esse tempo, mas isso está me incomodando há um ano ... Ligue beginPathquando você começar um novo caminho , não assuma isso apenas porque você estão limpando a tela que você deseja limpar também o caminho existente! Isso seria uma prática horrível e é uma maneira de olhar para trás ao desenhar.
Prestaul
E se você quiser apenas limpar a tela de tudo. Digamos que você está criando um jogo e que precisa redesenhar a tela a cada centésimo de segundo.
1
@JoseQuinones, beginPathnão limpa nada da tela, redefine o caminho para que as entradas anteriores sejam removidas antes de você desenhar. Você provavelmente precisou, mas como uma operação de desenho, não como uma operação de limpeza. clear e, em seguida, beginPath e draw, não clear e beginPath e, em seguida, draw. A diferença faz sentido? Veja aqui um exemplo: w3schools.com/tags/canvas_beginpath.asp
Prestaul
1
Isso resolveu a desaceleração da minha animação que experimentei ao longo do tempo. Redesenhei as linhas de grade em cada etapa, mas sem limpar as linhas da etapa anterior.
Georg Patscheider
118

Outros já fizeram um excelente trabalho respondendo à pergunta, mas se um clear()método simples no objeto de contexto seria útil para você (era para mim), esta é a implementação que utilizo com base nas respostas aqui:

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
};
JonathanK
fonte
6
Esta é uma ótima implementação. Eu apoio totalmente o aprimoramento de protótipos nativos, mas convém garantir que "clear" não seja definido antes de atribuí-lo - ainda estou esperando uma implementação nativa algum dia. :) Você sabe como os navegadores suportam o CanvasRenderingContext2D e o deixa "gravável"?
Prestaul
Obrigado pelo feedback @Prestaul - também, nenhum navegador deve impedir que você estenda objetos javascript dessa maneira.
JonathanK
@ JonathanK, eu adoraria ver alguns perfis da diferença de desempenho entre limpar com e sem redefinir a transformação. Suponho que a diferença será aparente se você estiver fazendo pouco desenho, mas que se o que você está desenhando não for trivial, o passo claro será insignificante ... Talvez eu precise testá-lo mais tarde, quando tiver mais tempo :)
Prestaul 11/04/12
Ok, eu fiz o perfil e vou adicionar os detalhes ao meu post.
Prestaul
35
  • O Chrome responde bem a: context.clearRect ( x , y , w , h );como sugerido por @ Pentium10, mas o IE9 parece ignorar completamente esta instrução.
  • O IE9 parece responder: canvas.width = canvas.width;mas não apaga linhas, apenas formas, figuras e outros objetos, a menos que você também use a solução de @John Allsopp para alterar primeiro a largura.

Portanto, se você tiver uma tela e um contexto criados assim:

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

Você pode usar um método como este:

function clearCanvas(context, canvas) {
  context.clearRect(0, 0, canvas.width, canvas.height);
  var w = canvas.width;
  canvas.width = 1;
  canvas.width = w;
}
Grenade
fonte
13
Observe que o método pode ser simplificado passando apenas o contexto e usando context.clearRect(0,0,context.canvas.width,context.canvas.height).
Phrtz #
5
O IE 9 deve responder absolutamente a uma chamada clearRect ... (Consulte: msdn.microsoft.com/en-us/library/ff975407(v=vs.85).aspx ) Por mais lento que seja possível alterar o canvas.width, a única maneira você pode ficar mais lento alterando-o duas vezes e chamando clearRect também.
Prestaul
1
Desculpe, devo ficar mais claro ... Esse método funcionará (desde que você não tenha aplicado uma transformação), mas é uma técnica de força bruta [lenta] onde não é necessária. Basta usar o clearRect, pois é o mais rápido e deve funcionar em todos os navegadores com uma implementação de tela.
Prestaul
1
Acredito que o IE está redesenhando as linhas devido a elas ainda estarem no buffer do caminho. Eu uso esse formato e funciona perfeitamente. function clearCanvas(ctx) { ctx.beginPath(); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); }
precisa saber é o seguinte
Eu tentei cada método antes disso ... e este foi o único que funcionou. Estou usando o Chrome com linhas, retângulos e texto ... não teria pensado que seria tão difícil fazer algo que deveria ser incorporado! Obrigado!
Anthony Griggs
26

Estamos em 2018 e ainda não existe um método nativo para limpar completamente a tela para redesenho. clearRect() não limpa a tela completamente. Desenhos do tipo sem preenchimento não são limpos (por exemplo, rect())

1.Para limpar completamente a tela, independentemente de como você desenha:

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

Prós: preserva strokeStyle, fillStyle etc .; Sem atraso;

Contras: desnecessário se você já estiver usando beginPath antes de desenhar qualquer coisa

2. Usando o corte de largura / altura:

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

OU

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

Prós: Funciona com o IE Contras: Redefine strokeStyle, fillStyle para preto; Laggy;

Fiquei me perguntando por que uma solução nativa não existe. Na verdade, clearRect()é considerada a solução de linha única porque a maioria dos usuáriosbeginPath() antes de desenhar qualquer novo caminho. Embora o beginPath seja usado apenas ao desenhar linhas e não como caminho fechado,rect().

Essa é a razão pela qual a resposta aceita não resolveu meu problema e acabei perdendo horas tentando diferentes hacks. Maldito mozilla

sziraqui
fonte
Eu acho que esta é a resposta certa, especialmente para desenhar telas. Sofri com o restante do contexto. Toque, não importa como chamo clearRect, enquanto o beginPath ajudou!
Shao-Kui
20

Use o método clearRect passando coordenadas x, y e altura e largura da tela. O ClearRect limpará toda a tela como:

canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
Vishwas
fonte
Você pode simplesmente colocar isso em um método e chamá-lo sempre que desejar atualizar a tela, correto.
@ XXX.xxx plz verificar id de tela em seu html e use mesmo para primeira linha (para obter elemento por id)
Vishwas
14

Há uma tonelada de boas respostas aqui. Outra observação é que às vezes é divertido limpar apenas parcialmente a tela. isto é, "desbota" a imagem anterior em vez de apagá-la completamente. isso pode dar bons efeitos de trilhas.

é fácil. supondo que a cor de fundo seja branca:

// 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
fonte
Sei que é possível e não tenho nenhum problema com sua resposta, pergunto-me, se você tem 2 objetos em movimento e deseja apenas rastrear um deles, como você faria isso?
Super
isso é muito mais complexo. nesse caso, você deve criar uma tela fora da tela, e cada quadro desenha os objetos que deseja arrastar para a tela usando o método de eliminação parcial descrito aqui, e também cada quadro limpa a tela principal 100%, desenha a tela não arrastada objetos e, em seguida, componha a tela fora da tela na tela principal usando drawImage (). Você também precisará definir o globalCompositeOperation como algo apropriado para as imagens. por exemplo, "multiplicar" funcionaria bem para objetos escuros sobre um fundo claro.
Orion elenzil
12

Uma maneira rápida é fazer

canvas.width = canvas.width

Idk como funciona, mas funciona!

Jacob Morris
fonte
Uau. Isso realmente funciona. Como você encontrou isso?
zipzit 27/01/19
@zipit rápida truque que eu encontrei fora de medium.com após compensação normal não foi tornando :)
Jacob Morris
1
Estou arrancando meus cabelos tentando descobrir por que isso funciona! Obrigado por compartilhar!
aabbccsmith
Alguém pode explicar por que isso funciona e até mesmo canvas.width + = 0 também funciona, qual é a ciência por trás disso?
PYK 5/04
8

É isso que eu uso, independentemente dos limites e das transformações matriciais:

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

Basicamente, ele salva o estado atual do contexto e desenha um pixel transparente com copyas globalCompositeOperation. Em seguida, restaura o estado de contexto anterior.

superruzafa
fonte
funciona para mim...! Obrigado.
NomanJaved
6

Isso funcionou para o meu pieChart no 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
fonte
5

Descobri que em todos os navegadores que testo, a maneira mais rápida é realmente preencher o Rect com branco ou com a cor que você desejar. Eu tenho um monitor muito grande e, no modo de tela cheia, o clearRect é extremamente lento, mas o fillRect é razoável.

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

A desvantagem é que a tela não é mais transparente.

John Page
fonte
4

no webkit, você precisa definir a largura para um valor diferente e, em seguida, configurá-lo novamente para o valor inicial

John Allsopp
fonte
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;
}
Destruidor de sonhos
fonte
Esta é mais lento do que clearRect (0,0, canvas.width, canvas.height)
cortar
4

Uma maneira simples, mas não muito legível, é escrever o seguinte:

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

// after doing some rendering

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

Eu sempre uso

cxt.fillStyle = "rgb(255, 255, 255)";
cxt.fillRect(0, 0, canvas.width, canvas.height);
GameMaster1928
fonte
Esta é a maneira mais fácil! Bem, pelo menos para mim.
Jacques Olivier
1
context.clearRect(0,0,w,h)   

preencha o retângulo fornecido com os valores RGBA:
0 0 0 0: com Chrome
0 0 0 255: com FF e Safari

Mas

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

deixe o retângulo preenchido com
0 0 0 255,
não importa o navegador!

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

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

Gavin T
fonte
1

o caminho mais curto:

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

maneira mais rápida:

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
fonte
12
uau ... Em qual navegador? No meu (Chrome 22 e Firefox 14 no OS X), seu método é, de longe, a opção mais lenta. jsperf.com/canvas-clear-speed/9
Prestaul 5/12
1
> 5 anos no futuro, este ainda é o método mais lento em uma quantidade muito grande, ~ 700x mais lento que clearRect.
mgthomas99
0

Se você usar apenas o clearRect, se o tiver em um formulário para enviar seu desenho, você receberá um envio em vez da limpeza, ou talvez ele possa ser limpo primeiro e depois fazer o upload de um desenho nulo, portanto, você precisará adicionar um preventDefault no início da função:

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

Espero que ajude alguém.

JoelBonetR
fonte
0

Eu sempre uso isso

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

NOTA

combinar clearRect e requestAnimationFrame permite uma animação mais fluida, se é isso que você procura

Anthony Gedeon
fonte
-2

Estes são ótimos exemplos de como você limpa uma tela padrão, mas se você estiver usando o paperjs, isso funcionará:

Defina uma variável global em JavaScript:

var clearCanvas = false;

No PaperScript, defina:

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

Agora, onde quer que você defina clearCanvas como true, ele limpará todos os itens da tela.

Robert Ogle
fonte