Control de tiempo en animaciones basadas en script ("requestAnimationFrame")

Internet Explorer 10 y las aplicaciones de la Tienda Windows con JavaScript admiten el método requestAnimationFrame, que permite crear páginas web con animación de forma más fluida y eficaz, al llamar al fotograma de animación cuando el sistema está preparado para dibujarlo. Antes de esta API, las animaciones dibujadas con setTimeout y setInterval no ofrecían a los desarrolladores web una forma eficaz de programar temporizadores de gráficos para las animaciones. El resultado eran animaciones excesivamente dibujadas, ciclos de CPU desperdiciados y uso de energía adicional. Además, con frecuencia la animación se realiza incluso cuando el sitio web no es visible, especialmente cuando el sitio web usa páginas en las pestañas en segundo plano o cuando se minimiza el explorador.

Cuando una animación usa la resolución de un temporizador de JavaScript de 10 ms para dibujar animaciones, obtienes un error de coincidencia tal y como se muestra aquí.

Un diagrama que muestra la diferencia de frecuencia entre una frecuencia de pantalla y una resolución del temporizador de JavaScript

La fila superior representa la frecuencia de visualización de 16,7 ms de la mayoría de los monitores, y la fila inferior representa un setTimeout típico de 10 ms. No es posible dibujar uno de cada tres dibujos (indicado por la flecha roja) porque se solicita otro dibujo antes del intervalo de actualización de la pantalla. Esta falta de recursos produce animaciones entrecortadas porque se pierde uno de cada tres fotogramas. Esta reducción de la resolución del temporizador también puede afectar negativamente a la duración de la batería y reducir el rendimiento de las demás aplicaciones.

El método requestAnimationFrame (definido en la especificación del control de tiempo para animaciones basadas en script del World Wide Web Consortium [W3C]) puede resolver el problema de pérdida de fotogramas, ya que permite que las aplicaciones reciban notificaciones solo cuando el explorador necesita actualizar la visualización de la página. Como resultado, las aplicaciones se ajustan perfectamente al intervalo de dibujo del explorador y solo se usa la cantidad adecuada de recursos. El cambio de setTimeout a requestAnimationFrame es sencillo, ya que ambos programan una sola devolución de llamada. Para que la animación continúe, llama a requestAnimationFrame de nuevo después de haber llamado a la función de animación.

Uso de requestAnimationFrame

Para usar esta nueva API, simplemente llama a requestAnimationFrameusando una función de devolución de llamada. El sistema se encarga de los intervalos de tiempo. Si actualmente utilizas setTimeout para controlar los intervalos de tiempo de la animación, como en este ejemplo:


var handle = setTimeout(renderLoop, PERIOD);

Puedes reemplazar setTimeout por requestAnimationFrame como se muestra a continuación:


var handle = requestAnimationFrame(renderLoop);

Esto se encarga de la primera operación de volver a dibujar Para que la animación continúe, llama a requestAnimationFrame de nuevo desde la función de devolución de llamada (aquí se muestra como renderLoop).


<!DOCTYPE html>
<html>
  <head>
    <title>Script-based animation using requestAnimationFrame</title>
    <style type="text/css">
     #animated { 
       position: absolute; top:100px; 
       padding: 50px; background: crimson; color: white; 
       }
    </style>

 
  </head>
  <body>
    <div>Click the box to stop and start it</div>
    <div id="animated">Hello there.</div>
   
    <script type="text/javascript">
      // global variables 
      var elm = document.getElementById("animated");
      var handle = 0;
      var lPos = 0;

      renderLoop();  // call animation frame to start

      function renderLoop() {
          elm.style.left = ((lPos += 3) % 600) + "px";
          handle = window.requestAnimationFrame(renderLoop);
      }

      // click the box to stop the animation 
      document.getElementById("animated").addEventListener("click", function () {
        if (handle) {
          window.cancelAnimationFrame(handle);
          handle = null;
        } else {
          renderLoop();
        }
      }, false);

      </script>

  </body>
</html>


Este ejemplo empieza por guardar el elemento <div> en una variable global usando getElementById. Se llama a la función renderLoop() para iniciar la animación. Tras cambiar la posición del elemento <div>, se vuelve a llamar a requestAnimationFrame para prepararse para el siguiente movimiento. Esto sigue hasta que cierres el explorador o hagas clic en el elemento <div>.

El método addEventListener controla el evento de clic en el elemento <div>. Cuando haces clic en el elemento, se llama a cancelAnimationFrame con el controlador actual.

Tiempo en una función de devolución de llamada

Puedes usar la función de devolución de llamada para animar prácticamente cualquier elemento, por ejemplo, SVG, Canvas o, como se muestra aquí, propiedades CSS. La función de devolución de llamada tiene un parámetro time entrante, que representa la hora a la que se llamó a la función de devolución de llamada. Es un DOMHighResTimeStamp, tiempo de alta resolución medido desde el inicio de la navegación de la página. DOMHighResTimeStamp se mide en milisegundos, con una precisión de una milésima de milisegundo. Este valor de tiempo no se puede comparar directamente con Date.now(), que mide el tiempo en milisegundos desde el 01 de enero de 1970. Si quieres comparar el parámetro time con la hora actual, usa window.performance.now para la hora actual. El cambio del valor de tiempo de DOMTimeStamp a DOMHighResTimeStamp fue una modificación de última hora en el borrador de los editores (Editors Draft) más reciente de la especificación del control de tiempo para animaciones basadas en script de W3C, y es posible que algunos proveedores todavía lo implementen como DOMTimeStamp. Las versiones anteriores de la especificación de W3C usaban DOMTimeStamp, que permitía usar Date.now para obtener la hora actual.

Compatibilidad del explorador

Como se ha mencionado anteriormente, es posible que algunos proveedores de exploradores todavía implementen el parámetro DOMTimeStamp o no hayan implementado todavía la función de intervalos de tiempo window.performance.now. Como la especificación de W3C todavía no es final, otros fabricantes de exploradores han creado sus propias implementaciones prefijadas de requestAnimationFrame y cancelAnimationFrame. Este ejemplo proporciona una versión de nuestro programa de animación que funciona en varios exploradores y usa time para mover el elemento <div>.


<!DOCTYPE html>
<html>
<head>
<title>Script-based animation using requestAnimationFrame</title>
<style type="text/css">
div { position: absolute; left: 10px; top:100px; padding: 50px;
  background: crimson; color: white; }
</style>
<script type="text/javascript">
    var requestId = 0;
    var startime = 0;
    var lpos = 0;
    var elm;

    function init() {
        elm = document.getElementById("animated");
    }
    
    function render() {
        elm.style.left = ((lpos += 3) % 600) + "px";
        requestId = window.requestAFrame(render);
    }

    function start() {
        if (window.performance.now) {
            startime = window.performance.now();
        } else {
            startime = Date.now();
        }
        requestId = window.requestAFrame(render);
    }
    function stop() {
        if (requestId)
            window.cancelAFrame(requestId);        
    }


    // handle multiple browsers for requestAnimationFrame()
    window.requestAFrame = (function () {
        return window.requestAnimationFrame ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame ||
                window.oRequestAnimationFrame ||
                // if all else fails, use setTimeout
                function (callback) {
                    return window.setTimeout(callback, 1000 / 60); // shoot for 60 fps
                };
    })();

    // handle multiple browsers for cancelAnimationFrame()
    window.cancelAFrame = (function () {
        return window.cancelAnimationFrame ||
                window.webkitCancelAnimationFrame ||
                window.mozCancelAnimationFrame ||
                window.oCancelAnimationFrame ||
                function (id) {
                    window.clearTimeout(id);
                };
    })();

   
</script>
</head>
<body onload="init();">

<div id="animated">Hello there.</div>
<button onclick="start()">Start</button>
<button onclick="stop()">Stop</button>
</body>
</html>


Este ejemplo es una ampliación de una muestra de la especificación de W3C, con elementos prefijados por proveedores agregados. Además, el ejemplo prueba window.performance.now y, si no es compatible, usa Date.now para obtener la hora actual.

Referencia de API

requestAnimationFrame

Ejemplos y tutoriales

Animaciones eficaces con la muestra requestAnimationFrame

Demostraciones de la versión de prueba de Internet Explorer

Bubbles
requestAnimationFrame API

Publicaciones de IEBlog

Rendimiento web de W3C: inversiones en rendimiento constantes
Las API de rendimiento web se convierten rápidamente en recomendaciones de candidato de W3C
Progreso hacia una web estable en IE10 Release Preview
Resumen del año: grupo de trabajo de rendimiento web de W3C
Usar hardware de PC de manera más eficaz en HTML5: nuevas API de rendimiento web, parte 1

Especificación

Control de tiempo en animaciones basadas en script

 

 

Mostrar:
© 2014 Microsoft