Cómo limpiar el lienzo para volver a dibujar


1013

Después de experimentar con operaciones compuestas y dibujar imágenes en el lienzo, ahora estoy tratando de eliminar imágenes y componer. ¿Cómo hago esto?

Necesito limpiar el lienzo para volver a dibujar otras imágenes; esto puede continuar por un tiempo, así que no creo que dibujar un nuevo rectángulo cada vez sea la opción más eficiente.

Respuestas:


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

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

42
Tenga en cuenta que clearRectdebe tener un contexto no transformado o realizar un seguimiento de sus límites reales.
Phrogz

77
Tenga en cuenta además que establecer el ancho del lienzo a) necesita establecerlo en un valor diferente y luego volver a hacerlo por compatibilidad con Webkit , y b) esto restablecerá su transformación de contexto .
Phrogz

45
No uses el truco de ancho. Es un truco sucio. En un lenguaje de alto nivel como JavaScript, lo que desea es expresar mejor sus intenciones y luego dejar que el código de nivel inferior las cumpla. Establecer el ancho en sí mismo no indica su verdadera intención, que es limpiar el lienzo.
andrewrk

22
Una sugerencia totalmente menor pero sugeriría context.clearRect(0, 0, context.canvas.width, context.canvas.height). Efectivamente es lo mismo pero una dependencia menos (1 variable en lugar de 2)
gman

66
Para lectores más recientes de esta respuesta: tenga en cuenta que esta respuesta fue modificada y que algunos de los comentarios anteriores ya no se aplican .
daveslab

719

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

Esta es la forma más rápida y descriptiva de borrar todo el lienzo.

No utilice: canvas.width = canvas.width;

El restablecimiento canvas.widthrestablece todos los estados del lienzo (por ejemplo, transformaciones, ancho de línea, estilo de trazo, etc.), es muy lento (en comparación con clearRect), no funciona en todos los navegadores y no describe lo que realmente está intentando hacer.

Manejo de coordenadas transformadas

Si ha modificado la matriz de transformación (por ejemplo scale, usando , rotateo translate), entonces context.clearRect(0,0,canvas.width,canvas.height)probablemente no borrará toda la parte visible del lienzo.

¿La solución? Restablezca la matriz de transformación antes de limpiar el lienzo:

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

Editar: Acabo de hacer algunos perfiles y (en Chrome) es aproximadamente un 10% más rápido borrar un lienzo de 300x150 (tamaño predeterminado) sin restablecer la transformación. A medida que aumenta el tamaño de su lienzo, esta diferencia disminuye.

Eso ya es relativamente insignificante, pero en la mayoría de los casos obtendrá mucho más de lo que está limpiando y creo que esta diferencia de rendimiento es irrelevante.

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

44
@YumYumYum: ¿Clear () es una función estándar? No parece ser
nobar

77
Tenga en cuenta que puede eliminar la necesidad de una canvasvariable local utilizando en su ctx.canvaslugar.
Drew Noakes

1
@DrewNoakes, buen punto, pero casi siempre opto por variables separadas para fines de velocidad. Es extremadamente menor, pero trato de evitar la desreferenciación del tiempo aliasing las propiedades de uso frecuente (especialmente dentro de un bucle de animación).
Prestaul

La demostración de AlexanderN ya no funcionó debido al enlace de imagen roto, corregido: jsfiddle.net/Ktqfs/50
Domino

Otra forma de borrar todo el lienzo en caso de modificación de la matriz de transformación es simplemente realizar un seguimiento de las transformaciones y aplicarlas usted mismo canvas.widthy canvas.heightal borrarlas. No he hecho ningún análisis numérico sobre la diferencia de tiempo de ejecución en comparación con el restablecimiento de la transformación, pero sospecho que obtendría un rendimiento un poco mejor.
NanoWizard

226

Si está dibujando líneas, asegúrese de no olvidar:

context.beginPath();

De lo contrario, las líneas no se despejarán.


10
Sé que esto ha estado aquí por un tiempo y probablemente sea una tontería para mí comentar después de todo este tiempo, pero esto me ha estado molestando durante un año ... Llama beginPathcuando comiences un nuevo camino , no asumas eso solo porque están limpiando el lienzo que desea borrar su ruta existente también! Esta sería una práctica horrible y es una forma inversa de mirar el dibujo.
Prestaul

¿Qué pasa si solo quieres limpiar el lienzo de todo? Digamos que está creando un juego y que necesita volver a dibujar la pantalla cada tantas centésimas de segundo.

1
@JoseQuinones, beginPathno borra nada de su lienzo, restablece la ruta para que las entradas de ruta anteriores se eliminen antes de dibujar. Probablemente lo necesitaba, pero como operación de dibujo, no como una operación de limpieza. borrar, luego comenzar Ruta y dibujar, no borrar y comenzar Ruta, luego dibujar. ¿Tiene sentido la diferencia? Mire aquí para ver un ejemplo: w3schools.com/tags/canvas_beginpath.asp
Prestaul

1
Esto resolvió la desaceleración de mi animación que experimenté con el tiempo. Redibujé líneas de cuadrícula en cada paso, pero sin borrar las líneas del paso anterior.
Georg Patscheider

118

Otros ya han hecho un excelente trabajo respondiendo la pregunta, pero si un clear()método simple en el objeto de contexto fuera útil para usted (lo fue para mí), esta es la implementación que uso en base a las respuestas aquí:

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

66
Esta es una gran implementación. Apoyo totalmente la mejora de los prototipos nativos, pero es posible que desee asegurarse de que "clear" no esté definido antes de asignarlo; todavía espero una implementación nativa algún día. :) ¿Sabes en qué medida los navegadores son compatibles con CanvasRenderingContext2D y lo dejan "grabable"?
Prestaul

Gracias por los comentarios de @Prestaul; además, ningún navegador debe evitar que extienda objetos JavaScript de esta manera.
JonathanK

@ Jonathan Jonathan, me encantaría ver un perfil de la diferencia de rendimiento entre borrar con y sin restablecer la transformación. Supongo que la diferencia será evidente si estás dibujando poco, pero si lo que estás dibujando no es trivial, entonces el paso claro es insignificante ... Puede que tenga que probarlo más tarde cuando tenga más tiempo :)
Prestaul

Ok, hice el perfil y voy a agregar los detalles a mi publicación.
Prestaul

35
  • Chrome responde bien a: context.clearRect ( x , y , w , h );como lo sugiere @ Pentium10, pero IE9 parece ignorar por completo esta instrucción.
  • Parece que IE9 responde: canvas.width = canvas.width;pero no borra líneas, solo formas, imágenes y otros objetos a menos que también use la solución de @John Allsopp de cambiar primero el ancho.

Entonces, si tiene un lienzo y un contexto creados así:

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

Puedes usar un 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;
}

13
Tenga en cuenta que el método puede simplificarse pasando solo el contexto y utilizando context.clearRect(0,0,context.canvas.width,context.canvas.height).
Phrogz

55
IE 9 debería responder absolutamente a una llamada clearRect ... (Ver: msdn.microsoft.com/en-us/library/ff975407(v=vs.85).aspx ) Tan lento como cambiar canvas.width es, la única forma podría disminuir su velocidad cambiando dos veces y llamando a clearRect también.
Prestaul

1
Lo siento, debería ser más claro ... Este método funcionará (siempre que no haya aplicado una transformación), pero es una técnica de fuerza bruta [lenta] donde no es necesaria. Simplemente use clearRect, ya que es más rápido y debería funcionar en todos los navegadores con una implementación de lienzo.
Prestaul

1
Creo que IE está redibujando las líneas debido a que todavía están en el búfer de ruta. Yo uso este formato y funciona perfecto. function clearCanvas(ctx) { ctx.beginPath(); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); }
DarrenMB

Probé todos y cada uno de los métodos antes de esto ... y este fue el único que funcionó. Estoy usando Chrome con líneas, rectángulos y texto ... ¡no habría pensado que sería tan difícil hacer algo que debería integrarse! ¡Gracias!
Anthony Griggs

27

Esto es 2018 y aún no existe un método nativo para borrar completamente el lienzo para volver a dibujar. clearRect() No borra el lienzo por completo. Los dibujos de tipo sin relleno no se borran (p. Ej. rect())

1.Para limpiar completamente el lienzo, independientemente de cómo dibuje:

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

Pros: conserva el estilo de trazo, el estilo de relleno, etc .; Sin retraso;

Contras: innecesario si ya está utilizando beginPath antes de dibujar cualquier cosa

2.Utilizando el ancho / alto hack:

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

O

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

Pros: Funciona con IE Contras: Restablece strokeStyle, fillStyle a negro; Laggy;

Me preguntaba por qué no existe una solución nativa. En realidad, clearRect()se considera como la solución de línea única porque la mayoría de los usuarios lo hacen beginPath()antes de dibujar cualquier ruta nueva. Aunque beginPath solo se debe usar al dibujar líneas y no en rutas cerradas comorect().

Esta es la razón por la cual la respuesta aceptada no resolvió mi problema y terminé perdiendo horas probando diferentes hacks. Te maldigo mozilla


Creo que esta es la respuesta correcta, especialmente para dibujar lienzos. Sufrí de context.stroke restante sin importar cómo llame a clearRect, ¡mientras beginPath ayudó!
Shao-Kui

20

Use el método clearRect pasando coordenadas x, y, altura y ancho del lienzo. ClearRect borrará todo el lienzo como:

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

Simplemente puede poner esto en un método y llamarlo cada vez que desee actualizar la pantalla, correcto.

@ XXX.xxx por favor verifique la identificación del lienzo en su html y use la misma para la primera línea (para obtener el elemento por identificación)
Vishwas

14

Hay un montón de buenas respuestas aquí. Una nota adicional es que a veces es divertido borrar solo parcialmente el lienzo. es decir, "desvanece" la imagen anterior en lugar de borrarla por completo. Esto puede dar buenos efectos de senderos.

es fácil. suponiendo que el color de fondo sea blanco:

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

Sé que es posible y no tengo ningún problema con tu respuesta, solo me pregunto, si tienes 2 objetos que se mueven y solo quieres rastrear uno de ellos, ¿cómo harías eso?
súper

Eso es mucho más complejo. en ese caso, debe crear un lienzo fuera de la pantalla, y cada cuadro dibuja los objetos que desea seguir en ese lienzo utilizando el método de borrado parcial que se describe aquí, y también cada cuadro borra el lienzo principal al 100%, dibuja el no arrastrado objetos, y luego componga el lienzo fuera de la pantalla en el principal usando drawImage (). También deberá establecer globalCompositeOperation en algo apropiado para las imágenes. por ejemplo, "multiplicar" funcionaría bien para objetos oscuros sobre un fondo claro.
orion elenzil

12

Una forma rápida es hacer

canvas.width = canvas.width

¡No sé cómo funciona, pero lo hace!


Guau. Esto realmente funciona. ¿Cómo encontraste esto?
zipzit

@zipit Truco rápido que encontré en medium.com después de que el borrado normal no se mostraba :)
Jacob Morris

1
Me estoy sacando el pelo tratando de entender por qué esto funciona. ¡Gracias por compartir!
aabbccsmith

¿Alguien puede explicar por qué eso funciona e incluso canvas.width + = 0 también hace el trabajo, cuál es la maldita ciencia detrás de esto?
PYK

8

Esto es lo que uso, independientemente de los límites y las transformaciones matriciales:

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

Básicamente, guarda el estado actual del contexto y dibuja un píxel transparente con copyas globalCompositeOperation. Luego, restaura el estado del contexto anterior.


esto funciona para mi...! Gracias.
NomanJaved

6

Esto funcionó para mi pieChart en 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

He descubierto que en todos los navegadores que pruebo, la forma más rápida es llenar Rect con blanco o con el color que desee. Tengo un monitor muy grande y en modo de pantalla completa clearRect es extremadamente lento, pero fillRect es razonable.

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

El inconveniente es que el lienzo ya no es transparente.


4

en webkit necesita establecer el ancho en un valor diferente, luego puede volver a establecerlo en el valor inicial


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

Esto es más lento que clearRect (0,0, canvas.width, canvas.height)
sEver

4

Una manera simple, pero no muy legible es escribir esto:

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

// after doing some rendering

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

2

Yo siempre uso

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

¡Esta es la manera más fácil! Bueno, al menos para mí.
Jacques Olivier

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

rellena el rectángulo dado con valores RGBA:
0 0 0 0: con Chrome
0 0 0 255: con FF y Safari

Pero

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

deje que el rectángulo se llene con
0 0 0 255
sin importar el navegador!


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

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



0

la manera más 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

12
wow ... ¿En qué navegador? En el mío (Chrome 22 y Firefox 14 en OS X) su método es, con mucho, la opción más lenta. jsperf.com/canvas-clear-speed/9
Prestaul

1
> 5 años en el futuro, este sigue siendo el método más lento en una cantidad muy grande, ~ 700 veces más lento que clearRect.
mgthomas99

0

Si usa clearRect solo, si lo tiene en un formulario para enviar su dibujo, recibirá un envío en lugar del borrado, o tal vez pueda borrarse primero y luego cargar un dibujo vacío, por lo que deberá agregar un preventDefault al comienzo de la función:

   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 ayude a alguien.


0

Siempre uso esto

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

NOTA

la combinación de clearRect y requestAnimationFrame permite una animación más fluida si eso es lo que está buscando


-2

Todos estos son excelentes ejemplos de cómo limpiar un lienzo estándar, pero si está utilizando paperjs, entonces esto funcionará:

Defina una variable global en JavaScript:

var clearCanvas = false;

De su PaperScript defina:

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

Ahora, donde establezca clearCanvas en true, borrará todos los elementos de la pantalla.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.