requestAnimationFrame

facebook-svg gplus-svg twitter-svg

Qué es requestAnimationFrame()

Para animar objetos en JavaScript, hasta hace muy poco se utilizaba ( y todavía se utiliza mucho ) el método setInterval(). Por ejemplo el código para una animación de 60 fotogramas/segundo tiene este aspecto:

window.setInterval( function(){
  // código que genera una fotograma
},1000/60);

Vea una animación básica con setInterval()

Paul Irish introdujo hace unos años un método mejor: requestAnimationFrame(), un método que genera animaciones fluidas, que paran en pestañas ( tabs ) inactivas, y es mucho más eficiente en los navegadores. Además el soporte para requestAnimationFrame es muy bueno.

¿Cómo utilizar requestAnimationFrame()?

1. Creamos una función que genera una nueva fotograma.
2. Llamamos esta función utilizando requestAnimationFrame una vez para iniciar la animación.
3. Ulteriormente la función volverá a llamarse a si misma de manera recurrente.  ( En programación una función recursiva o recurrente es una función que se llama a si misma desde dentro. )

function nuevaFotograma(){
  // código que genera una fotograma
  window.requestAnimationFrame(nuevaFotograma);
}

window.requestAnimationFrame(nuevaFotograma);

Vea una animación básica con requestAnimationFrame().

¿Cómo controlar la frecuencia de las fotogramas?

El problema es esto: ¿cómo controlar la frecuencia de las fotogramas, ya que no hay ningún parámetro que pueda controlar la temporización? Por ahora podemos utilizar esta técnica:

var fotogramasPorSegundo = 15;
function Animacion() {
    setTimeout(function() {
        window.requestAnimationFrame(Animacion);
        // código que genera una fotograma
    }, 1000 / fotogramasPorSegundo);
}

El reloj interno ( timestamp )

La función de retrollamada ( o callback function ) de requestAnimationFrame, o sea la función Animacion(), tiene como único argumento un reloj interno DOMHighResTimeStamp.

Veamos un ejemplo muy sencillo en el cual utilizamos el reloj interno para parar la animación después de un segundo ( 1000 milisegundos ).

var start;
  function Animacion(relojInterno) {
    if (!start) start = relojInterno;
    var progreso = relojInterno - start;
    if (progreso < 1000) {
      console.log(progreso);
      window.requestAnimationFrame(Animacion);
    }
  }
window.requestAnimationFrame(Animacion);

Vea este ejemplo en Codepen.io

Actualmente el reloj interno utilizado es de tipo Date.now(), pero en el próximo futuro cambiará a un reloj interno de alta resolución ( que utiliza performance.now() ).

Lea más acerca del reloj interno de requestAnimationFrame.

El Polyfill

Para quien no lo sepa, en programación un polyfill es un grupo de funciones, normalmente escritas en JavaScript, que permiten que los usuarios de navegadores antiguos tengan la misma experiencia ( o casi ) que los demás usuarios. Probablemente el mejor polyfill para requestAnimationFrame lo puede encontrar en GitHub

Vea el polyfill.

Parar y reiniciar la animación

Exactamente como setInterval(), el método requestAnimationFrame() devuelve un id, que podemos utilizar para parar la animación. Para esto utilizamos el método cancelAnimationFrame() asi:

1. Primero guardamos el id de la animación en una variable.
2. Cancelamos la animación utilizando el id guardado.

var elId = window.requestAnimationFrame(nuevaFotograma);
  . . .
if (elId) { window.cancelAnimationFrame(elId); }

Para reiniciar la animación podemos utilizar un evento, como por ejemplo click:

elemento.addEventListener("click", reiniciarAnimacion ,false);

Donde reiniciarAnimacion es la función (la tenemos que escribir) que reinicia la animación.

Un ejemplo muy sencillo

A continuación queremos hacer que un cuadrado gire alrededor de su centro. En el JavaScript empezamos con el polyfill que hemos visto anteriormente.

La función girar() crea una a una las fotogramas de la animación: con cada reiteración el cuadrado gira 5 grados. Finalmente  la función start() inicia la animación, y la función stopAnimacion() la para. Veamos el código.

Ejemplo de animación con requestAnimationFrame()

Haz clic en el canvas para parar o reiniciar la animación

Su navegador no soporta canvas :(

var c = document.getElementById("c");
var ctx = c.getContext("2d");
var cw = c.width;
var ch = c.height;

var rad = Math.PI/180;

var angulo = 5;
var parado = true;
var elId;

ctx.strokeStyle = "#d16";
ctx.fillStyle = "rgba(255,255,255,.1)";
ctx.translate(cw/2,ch/2);
ctx.strokeRect(-75,-75,150,150);
 
function girar(){
	ctx.strokeRect(-75,-75,150,150)
	ctx.rotate(rad * angulo);
	ctx.fillRect(-cw/2,-ch/2, cw,ch);
	elId = window.requestAnimationFrame(girar);
}
 
function start() {
     elId = window.requestAnimationFrame(girar);
     parado = false;
}
function stopAnimacion() {
     if (elId) {
     window.cancelAnimationFrame(elId);
     }
     parado = true;
     }

c.addEventListener("click", function(){(parado == true) ? start() : stopAnimacion();} ,false)

Ejemplo de animación con requestAnimationFrame()

Haz clic en el canvas para parar o reiniciar la animación

Su navegador no soporta canvas :(

Vea más ejemplos de animaciones con requestAnimationFrame en codepen.io