2011-09-09 18 views
12

Para jugar con el lienzo HTML5, decidí crear una aplicación que dibujara una esfera analógica. Todo está bien, excepto que las líneas antiguas no se borran de la manera que yo esperaría. He incluido parte del código de abajo - DrawHands() es llamado una vez por segundo:Borrado de líneas previamente dibujadas en un lienzo HTML5

var hoursPoint = new Object(); 
var minutesPoint = new Object(); 
var secondsPoint = new Object(); 

function drawHands() 
{ 
    var now = new Date(); 

    drawLine(centerX, centerY, secondsPoint.X, secondsPoint.Y, "white", 1); 
    var seconds = now.getSeconds(); 
    secondsPoint = getOtherEndOfLine(centerX, centerY, 2 * Math.PI/60 * seconds, 0.75 * radius); 
    drawLine(centerX, centerY, secondsPoint.X, secondsPoint.Y, "black", 1); 

    drawLine(centerX, centerY, minutesPoint.X, minutesPoint.Y, "white", 3); 
    var minutes = now.getMinutes(); 
    minutesPoint = getOtherEndOfLine(centerX, centerY, 2 * Math.PI/60 * minutes, 0.75 * radius); 
    drawLine(centerX, centerY, minutesPoint.X, minutesPoint.Y, "black", 3); 

    drawLine(centerX, centerY, hoursPoint.X, hoursPoint.Y, "white", 3); 
    var hours = now.getHours(); 
    if (hours >= 12) { hours -= 12; } // Hours are 0-11 
    hoursPoint = getOtherEndOfLine(centerX, centerY, (2 * Math.PI/12 * hours) + (2 * Math.PI/12/60 * minutes), 0.6 * radius); 
    drawLine(centerX, centerY, hoursPoint.X, hoursPoint.Y, "black", 3); 
} 

para dar sentido a lo anterior, hay dos funciones auxiliares:

  • drawLine (x1, y1 , x2, y2, color, grosor)
  • getOtherEndOfLine (x, y, ángulo, longitud)

El problema es que mientras todas las manos se ven inmersos como se esperaba en negro, que nunca se borran. Yo esperaría que, dado que la misma línea se dibuja en blanco (el color de fondo) borraría efectivamente lo que se dibujó previamente en ese punto. Pero este no parece ser el caso.

¿Algo que me falta?

Respuesta

13

Por razones que podría ampliar, debería considerar borrar su lienzo y volver a dibujarlo por completo a menos que existan razones de rendimiento o composición para no hacerlo.

¿Quieres clearRect, algo como esto:

//clear the canvas so we can draw a fresh clock 
ctx.clearRect(0, 0, canvasWidth, canvasHeight); 

//redraw your clock here 
/* ... */ 
+3

Si hubiera que desea borrar una línea o una forma específica (como yo), en lugar de despejar una zona rectangular, estableciendo 'ctx.globalCompositeOperation =" destination-out "' - como se menciona en la solución de andrewmu a una [pregunta similar] (http://stackoverflow.com/questions/3328906/erasing-in-html5-canvas) - will pretty hace que sus operaciones de relleno/trazo actúen como una herramienta de borrador. Recuerde cambiar el modo de composición cuando haya terminado. Consulte la [composición y recorte de Mozilla] (https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Compositing) para obtener detalles completos. – TheMadDeveloper

+0

No es necesario borrar siempre el lienzo por completo.Vea la respuesta de Simon Sarris usando getImageData/putImageData, que le permite restaurar el dibujo a cualquier fase anterior del dibujo. – Allasso

+0

Corrección del comentario anterior: debería leer la respuesta de mrmcgreg. – Allasso

4

La razón por la que no se puede simplemente volver a dibujar la línea en blanco y esperanza para que pueda borrar la antigua línea es porque puede haber cierto grado de suavizado/sangría. También notará que una línea horizontal recta dibujada en un píxel frente a un medio píxel se ve muy diferente debido a esto.

Cuando haga sus líneas blancas de "borrado", intente dibujarlas con un lineWidth más grande por aproximadamente 3 o 4. Eso debería funcionar para su caso.

También debe dibujar todas las líneas blancas primero, luego todas las líneas negras, en caso de que se crucen.

4

Una forma rápida y fácil de limpiar es un lienzo para establecer el ancho:

context.canvas.width = context.canvas.width; 
+1

Huele como dependiendo de una implementación particular en un navegador en particular, que es una manera fácil de comportamiento indefinido en otros navegadores. – BarbaraKwarc

10

En lugar de borrar las cosas que no desea, puede guardar el estado de la tela en el momento antes de que dibujó las cosas que no desea y luego restaurar el lienzo en ese estado para 'borrarlas'.

Esto se puede lograr con bastante facilidad utilizando ImageData:

var canvas = document.querySelector('canvas'), 
 
    context = canvas.getContext('2d'); 
 

 
context.fillStyle = 'blue'; 
 
context.fillRect(0,0,10,10); 
 

 
// save the state of the canvas here 
 
var imageData = context.getImageData(0,0,canvas.width,canvas.height); 
 

 
// draw a red rectangle that we'll get rid of in a second 
 
context.strokeStyle = 'red'; 
 
context.strokeRect(70,70,20,20); 
 

 
setTimeout(function() { 
 
    // return the canvas to the state right after we drew the blue rect 
 
    context.putImageData(imageData, 0, 0); 
 
}, 1000);
<canvas width=100 height=100>

+1

Este método tiene una ventaja sobre el uso de clearRectangle, ya que puede obtener ImageData en cualquier fase del dibujo y restaurar a ese nivel, mientras que clearRectangle siempre lo llevará de vuelta a un lienzo en blanco. Por esta razón, he votado a favor. – Allasso

+1

... Incluso podría tomar instantáneas en varios puntos del proceso de dibujo si fuera necesario restaurarlo. – Allasso

+0

Esto también puede evitar tener que volver a cargar una imagen si está utilizando una como fondo. – Allasso