Pregunta

Lo que me gustaría hacer es dibujar mis gráficos en una memoria intermedia y luego ser capaz de copiar tal cual a la lona para que pueda hacer la animación y el parpadeo evitar. Pero no pude encontrar esta opción. Alguien sabe cómo puedo hacerlo?

¿Fue útil?

Solución

En el siguiente enlace útil, además de mostrar ejemplos y ventajas de utilizar el doble buffer, espectáculos varios otros consejos de rendimiento para utilizar el elemento canvas de HTML5. Incluye enlaces a las pruebas, que jsPerf resultados de las pruebas agregadas a través de los navegadores en una base de datos Browserscope. Esto asegura que las puntas de rendimiento se verifican.

http://www.html5rocks.com/en/tutorials/canvas/performance/

Para su comodidad, he incluido un ejemplo mínima de doble buffer efectiva como se describe en el artículo.

// canvas element in DOM
var canvas1 = document.getElementById('canvas1');
var context1 = canvas1.getContext('2d');

// buffer canvas
var canvas2 = document.createElement('canvas');
canvas2.width = 150;
canvas2.height = 150;
var context2 = canvas2.getContext('2d');

// create something on the canvas
context2.beginPath();
context2.moveTo(10,10);
context2.lineTo(10,30);
context2.stroke();

//render the buffered canvas onto the original canvas element
context1.drawImage(canvas2, 0, 0);

Otros consejos

Un método muy simple es tener dos elementos de lona en la misma ubicación de la pantalla y la visibilidad de ajuste para el búfer que tiene que mostrar. Dibuje en el escondido y voltear cuando haya terminado.

Algunos código:

CSS:

canvas { border: 2px solid #000; position:absolute; top:0;left:0; 
visibility: hidden; }

mover de un tirón en JS:

Buffers[1-DrawingBuffer].style.visibility='hidden';
Buffers[DrawingBuffer].style.visibility='visible';

DrawingBuffer=1-DrawingBuffer;

En este código el array 'Buffers []' sostiene ambas lienzo-objetos. Así que cuando se quiere empezar a dibujar usted todavía tiene que obtener el contexto:

var context = Buffers[DrawingBuffer].getContext('2d');

Los navegadores que he probado todas manejar este búfer para usted por no volver a pintar el lienzo hasta que el código que dibuja su marco se ha completado. Ver también la lista de correo WHATWG: http: //www.mail- archive.com/whatwg@lists.whatwg.org/msg19969.html

Siempre se podía hacer var canvas2 = document.createElement("canvas"); y no lo añadirá a la DOM en absoluto.

Simplemente decir ya que ustedes parecen tan obsesionado con display:none; apenas se parece más limpio para mí y imita la idea de la forma en doble buffer con mayor precisión que sólo tener un lienzo con torpeza invisible.

Más de dos años después:

No hay necesidad de 'manualmente' implementar el doble buffer. El Sr. Geary escribió sobre esto en su libro "HTML5 Canvas" .

Para reducir de manera efectiva el uso de parpadeo requestAnimationFrame() !

Josh preguntó (una copia de tiempo) sobre cómo el navegador sabe "cuando el dibujo que termine el proceso" para evitar el parpadeo. Me he comentado directamente a su puesto, pero mi representante no es lo suficientemente alta. También esto es sólo mi opinión. No tengo hechos que lo respalden, pero me siento bastante seguro de ello y puede ser útil para otros leyendo esto en el futuro.

Estoy adivinando el navegador no "sabe" cuando estás dibujo hecho. Pero al igual que la mayoría de JavaScript, siempre y cuando se ejecuta su código sin pérdida de control al navegador, el navegador se bloquea en esencia y no / no puede actualizar / responden a su interfaz de usuario. Supongo que si se borra el lienzo y dibuja todo su marco sin ceder el control al navegador, será en realidad no llamar su lienzo hasta que haya terminado.

Si se configura una situación en la que su representación se extiende por varias llamadas setTimeout / setInterval / requestAnimationFrame, en las que clara la lona en una llamada y dibujar elementos en el lienzo en los próximos llamadas, repitiendo el ciclo (por ejemplo) cada 5 llamadas, estaría dispuesto a apostar que vería el parpadeo ya que la tela se actualiza después de cada llamada.

Dicho esto, no estoy seguro de que había que confiar. Ya estamos en el punto de que Javascript está compilado a código máquina nativo antes de la ejecución (por lo menos eso es lo que el motor V8 de Chrome lo hace por lo que entiendo). No me sorprendería si no fuera demasiado tiempo antes de navegadores empezaron a correr su javascript en un hilo separado de la interfaz de usuario y la sincronización de cualquier acceso a los elementos de la interfaz que permite la interfaz de usuario para la actualización / responder durante la ejecución de Javascript que no se accede a la interfaz de usuario. Cuando / si eso sucede (y entiendo que hay muchos obstáculos que habría que superar, tales como controladores de eventos dando inicio mientras que todavía se está ejecutando otro código), que probablemente veremos el parpadeo en la animación de la lona que no están usando una especie de doble búfer.

Personalmente, Me encanta la idea de dos elementos de lona posicionado sobre la parte superior de la otra y alterna que se muestra / dibujado en cada trama. Bastante discreto y probablemente añadida muy fácilmente de una aplicación existente con unas pocas líneas de código.

Para los incrédulos, aquí hay un código de parpadeo. Tenga en cuenta que estoy limpiando de forma explícita para borrar el círculo anterior.

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

function draw_ball(ball) {
    ctx.clearRect(0, 0, 400, 400);
    ctx.fillStyle = "#FF0000";
    ctx.beginPath();
    ctx.arc(ball.x, ball.y, 30, 0, Math.PI * 2, true);
    ctx.closePath();
    ctx.fill();
}

var deltat = 1;
var ball = {};
ball.y = 0;
ball.x = 200;
ball.vy = 0;
ball.vx = 10;
ball.ay = 9.8;
ball.ax = 0.1;

function compute_position() {
    if (ball.y > 370 && ball.vy > 0) {
        ball.vy = -ball.vy * 84 / 86;
    }
    if (ball.x < 30) {
        ball.vx = -ball.vx;
        ball.ax = -ball.ax;
    } else if (ball.x > 370) {
        ball.vx = -ball.vx;
        ball.ax = -ball.ax;
    }
    ball.ax = ball.ax / 2;
    ball.vx = ball.vx * 185 / 186;
    ball.y = ball.y + ball.vy * deltat + ball.ay * deltat * deltat / 2
    ball.x = ball.x + ball.vx * deltat + ball.ax * deltat * deltat / 2
    ball.vy = ball.vy + ball.ay * deltat
    ball.vx = ball.vx + ball.ax * deltat
    draw_ball(ball);
}

setInterval(compute_position, 40);
<!DOCTYPE html>
<html>
<head><title>Basketball</title></head>
<body>
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
</body></html>

No hay parpadeo en los navegadores web! Ya utilizan búfer dbl para su prestación. js motor hará toda su prestación antes de mostrarlo. Además, el contexto guardar y restaurar única pila de datos de la matriz de transformación y tal, no el propio contenido de la lona. Por lo tanto, usted no necesita o desea búfer DBL!

En lugar de rodar su propia, es probable que va a conseguir el mejor kilometraje mediante el uso de una biblioteca existente para crear animaciones JavaScript limpio y libre de parpadeo:

Aquí hay una popular: http://processingjs.org

se necesitan 2 lienzo: (note el css z-index y posición: absoluta)

<canvas id="layer1" width="760" height="600" style=" position:absolute; top:0;left:0; 
visibility: visible;  z-index: 0; solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<canvas id="layer2" width="760" height="600" style="position:absolute; top:0;left:0; 
visibility: visible;  z-index: 1; solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>

Se puede notar que la primera tela es visible y el segundo está oculta la idea es aprovechar la ocultado después de eso vamos a ocultar el visible y hacer que el lienzo ocultas visibles. cuando está oculta 'borrar tela oculta

<script type="text/javascript">
var buff=new Array(2);
buff[0]=document.getElementById("layer1");
buff[1]=document.getElementById("layer2");

ctx[0]=buff[0].getContext("2d");
ctx[1]=buff[1].getContext("2d");
var current=0;
// draw the canvas (ctx[ current ]);
buff[1- current ].style.visibility='hidden';
buff[ current ].style.visibility='visible';
ctx[1-current].clearRect(0,0,760,600);
current =1-current;

9.10 Opera es muy lento y muestra el proceso de elaboración. Si desea ver un navegador no utiliza el doble buffer, tratar Opera 9.10 cabo.

Algunas personas sugirieron que los navegadores son de alguna manera determinar el momento en que termine el proceso de dibujo, pero se pueden explicar como que el trabajo puede? No he notado ningún parpadeo obvia en Firefox, Chrome, IE9 o incluso cuando el dibujo es lento por lo que parece que es lo que están haciendo, pero la forma en que se lleva a cabo es un misterio para mí. ¿Cómo sería el navegador cada vez saber que es refrescante la pantalla justo antes de que el dibujo más instrucciones son para ser ejecutado? ¿Cree que el tiempo justo, así que si un intervalo de más de 5 ms o menos que pase sin que la ejecución de una instrucción de lienzo de dibujo, se supone que con seguridad puede buffers de intercambio?

En la mayoría de las situaciones, no es necesario hacer esto, los implementos navegador esto para usted. Pero no siempre es útil!

Usted todavía tiene que aplicar esto cuando el dibujo es muy complicado. La mayor parte de la tasa de actualización de la pantalla es de aproximadamente 60 Hz, significa que las actualizaciones de pantalla por 16 ms. velocidad de actualización del navegador de mayo cerca de este número. Si su necesidad de forma 100ms para ser completado, verá una forma incompleta. Así que se puede implementar el doble buffer en esta situación.

Me han hecho una prueba: Clear a rect, wait for some time, then fill with some color. Si fijo el tiempo de 10 ms, no voy a ver el parpadeo. Pero si lo fijo a 20 ms, el parpadeo sucede.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top