Contrôle du minutage pour les animations basées sur des scripts (« requestAnimationFrame »)

Internet Explorer 10 et les applications Windows Store en JavaScript prennent en charge la méthode requestAnimationFrame, qui fournit une façon plus efficace et fluide de créer des pages Web animées en appelant le cadre d’animation quand le système est prêt à peindre le cadre. Avant cette API, les animations dessinées avec setTimeout et setInterval ne proposaient aux développeurs Web aucun moyen efficace leur permettant de planifier des minuteurs graphiques pour les animations. Il en résultait des animations exagérées, des cycles processeur gaspillés et des surplus de consommation d’énergie. En outre, une animation survient fréquemment même lorsqu’un site Web n’est pas visible, notamment lorsqu’il utilise des pages d’onglets en arrière-plan ou lorsque le navigateur est réduit.

Lorsqu’une animation utilise une résolution de minuteur JavaScript de 10 ms pour représenter des animations, vous obtenez une non-correspondance de minutage, comme illustré ici.

Diagramme illustrant la différence de fréquence entre une fréquence d’affichage et une résolution de minuteur JavaScript

La ligne du haut représente la fréquence d’affichage de 16,7 ms affichée sur la plupart des moniteurs et la ligne du bas représente un setTimeout standard de 10 ms. Il est impossible de représenter chaque troisième dessin (indiqué par une flèche rouge), car une autre demande de dessin se produit avant l’intervalle d’actualisation de l’affichage. Cette exagération entraîne des animations instables, car chaque troisième image est perdue. Cette réduction de la résolution du minuteur peut également avoir des effets négatifs sur la durée de vie de la batterie et réduire les performances des autres applications.

La méthode requestAnimationFrame (définie dans la spécification du contrôle Timing pour les animations basées sur des scripts du WC3 (World Wide Web Consortium)) peut résoudre le problème relatif aux images perdues car elle permet aux applications d’être averties si (et uniquement si) le navigateur doit mettre à jour l’affichage de la page. Par conséquent, les applications sont parfaitement alignées sur l’intervalle de dessin du navigateur et n’utilisent que la quantité de ressources appropriée. Il est aisé de basculer de setTimeout vers requestAnimationFrame, car les deux méthodes planifient un rappel unique. Pour obtenir une animation continue, appelez requestAnimationFrame de nouveau après l’appel à la fonction d’animation.

Utilisation de requestAnimationFrame

Pour utiliser cette nouvelle API, vous appelez requestAnimationFrame à l’aide d’une fonction de rappel. Le minutage est géré par le système. Si vous utilisez actuellement setTimeout pour influencer le minutage de votre animation, comme suit :


var handle = setTimeout(renderLoop, PERIOD);

Vous pouvez remplacer setTimeout par requestAnimationFrame, comme illustré ci-dessous :


var handle = requestAnimationFrame(renderLoop);

Cela prend en charge la première fois que vous redessinez. Pour que l’animation se poursuive, appelez de nouveau requestAnimationFrame au sein de votre fonction de rappel (indiquée ici par 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>


Cet exemple commence par enregistrer l’élément <div> dans une variable globale avec getElementById. La fonction renderLoop() est appelée pour commencer l’animation. Une fois que l’élément <div> est repositionné, la méthode requestAnimationFrame est appelée de nouveau pour configurer le mouvement suivant. Cela continue jusqu’à ce que vous fermiez le navigateur ou cliquiez sur l’élément <div>.

La méthode addEventListener traite l’événement de clic sur l’élément <div>. Lorsque vous cliquez sur l’élément, la méthode cancelAnimationFrame est appelée avec le handle actuel.

Temps dans une fonction de rappel

La fonction de rappel peut être utilisée pour animer quasiment tout, par exemple des propriétés SVG, Canvas ou, comme illustré ici, CSS. La fonction de rappel a un seul paramètre time entrant, qui représente l’heure à laquelle la fonction de rappel est appelée. Il s’agit d’un paramètre DOMHighResTimeStamp, une heure haute résolution mesurée à partir du début de la navigation de la page. DOMHighResTimeStamp est mesuré en millisecondes précises à un millième de milliseconde. Cette valeur de temps n’est pas directement comparable à Date.now(), qui mesure le temps en millisecondes depuis le 1er janvier 1970. Si vous voulez comparer le paramètre time avec l’heure actuelle, utilisez window.performance.now pour l’heure actuelle. Le remplacement de la valeur temporelle DOMTimeStamp par DOMHighResTimeStamp constituait un changement de dernière minute dans la dernière ébauche d’éditeur de la spécification du contrôle Timing pour les animations basées sur des scripts du WC3, et certains fournisseurs peuvent encore l’implémenter en tant que DOMTimeStamp. Les versions antérieures de la spécification W3C utilisaient DOMTimeStamp, ce qui vous permettait d’utiliser Date.now pour l’heure actuelle.

Prise en charge du navigateur

Comme cela a été mentionné précédemment, certains éditeurs de navigateurs peuvent encore implémenter le paramètre DOMTimeStamp ou n’ont pas implémenté la fonction de minutage window.performance.now. Comme la spécification W3C n’est pas encore finale, d’autres fabricants de navigateurs ont créé leurs propres implémentations préfixées de requestAnimationFrame et cancelAnimationFrame. Cet exemple fournit une version de notre programme d’animation qui fonctionne sur plusieurs navigateurs et utilise l’heure pour déplacer l’élément <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>


Cet exemple est une extension d’un exemple issu de la spécification W3C, avec des éléments préfixés par des éditeurs ajoutés. Cet exemple teste également window.performance.now et, si cette fonction n’est pas prise en charge, utilise Date.now pour obtenir l’heure actuelle.

Informations de référence sur les API

requestAnimationFrame

Exemples et didacticiels

Animations efficaces à l’aide de l’exemple requestAnimationFrame

Démonstrations du site Internet Explorer Test Drive

Bubbles
requestAnimationFrame API

Billets IEBlog

Performances Web W3C : Poursuite des investissements dans les performances
Les API Web Performance accèdent rapidement au statut « Candidate Recommendation » du W3C
Un Web plus stable dans IE10 Release Preview
Revue de l’année : Groupe de travail W3C Web Performance
Utilisation plus efficace du matériel de PC dans HTML5 : nouvelles API de performance Web, Première partie

Spécification

Contrôle du minutage pour les animations basées sur des scripts

 

 

Afficher:
© 2014 Microsoft