Commande de lecture des animations Web dans Chrome 39

Plus tôt cette année, Chrome 36 a lancé la méthode element.animate dans le cadre de la spécification Web Animations plus large. Cela permet d'écrire des animations natives efficaces de manière impérative, ce qui donne aux développeurs le choix de créer leurs animations et transitions avec l'approche la plus adaptée.

Pour vous rafraîchir la mémoire, voici comment vous pouvez animer un nuage à l'écran, avec un rappel une fois l'opération terminée:

var player = cloud.animate([
    {transform: 'translateX(' + start + 'px)'},
    {transform: 'translateX(' + end + 'px)'}
], 5000);
player.onfinish = function() {
    console.info('Cloud moved across the screen!');
    startRaining(cloud);
};

Cette méthode est incroyablement simple et mérite d'être intégrée à votre boîte à outils lorsque vous créez des animations ou des transitions de manière impérative. Toutefois, dans Chrome 39, des fonctionnalités de commande de lecture ont été ajoutées à l'objet AnimationPlayer renvoyé par element.animate. Auparavant, une fois une animation créée, vous ne pouviez appeler que cancel() ou écouter l'événement de fin.

Ces ajouts de lecture élargissent les possibilités des animations Web, en les transformant en outil polyvalent plutôt que de prescrire des transitions, c'est-à-dire : des animations "fixes" ou prédéfinies.

Mettre en pause, revenir en arrière ou modifier la vitesse de lecture

Commençons par modifier l'exemple ci-dessus pour mettre en pause l'animation si l'utilisateur clique sur le nuage:

cloud.addEventListener('mousedown', function() {
    player.pause();
});

Vous pouvez également modifier la propriété playbackRate:

function changeWindSpeed() {
    player.playbackRate *= (Math.random() * 2.0);
}

Vous pouvez également appeler la méthode reverse(), ce qui revient normalement à inverser la valeur playbackRate actuelle (multipliée par -1). Toutefois, il existe quelques cas particuliers:

  • Si le changement causé par la méthode reverse() entraîne la fin effective de l'animation en cours d'exécution, currentTime est également inversé.Par exemple, si une toute nouvelle animation est inversée, l'ensemble de l'animation sera lu à l'envers.

  • Si le lecteur est en pause, la lecture de l'animation commence.

Utiliser la barre de lecture

Un AnimationPlayer permet désormais de modifier son currentTime pendant l'exécution d'une animation. Normalement, cette valeur augmente au fil du temps (ou diminue, si la valeur playbackRate est négative). Cela peut permettre de contrôler la position d'une animation de manière externe, par exemple via une interaction de l'utilisateur. On parle couramment de nettoyage.

Par exemple, si votre page HTML représente le ciel et que vous souhaitez que le geste de glisser-déposer modifie la position d'un nuage en cours de lecture, vous pouvez ajouter des gestionnaires au document:

var startEvent, startEventTime;
document.addEventListener('touchstart', function(event) {
    startEvent = event;
    startEventTime = players.currentTime;
    player.pause();
});
document.addEventListener('touchmove', function(event) {
    if (!startEvent) return;
    var delta = startEvent.touches[0].screenX -
        event.changedTouches[0].screenX;
    player.currentTime = startEventTime + delta;
});

Lorsque vous faites glisser le pointeur sur le document, currentTime est modifié pour refléter la distance par rapport à votre événement d'origine. Vous pouvez également reprendre la lecture de l'animation à la fin du geste:

document.addEventListener('touchend', function(event) {
    startEvent = null;
    player.play();
});

Ce comportement peut même être combiné à un comportement de rétrogradation, en fonction de l'endroit où la souris a été retirée de la page (démo combinée).

Au lieu de nettoyer un AnimationPlayer en réponse à une interaction utilisateur, son currentTime peut également être utilisé pour afficher la progression ou l'état, par exemple pour afficher l'état d'un téléchargement.

L'utilité d'un AnimationPlayer est qu'il permet de définir une valeur et de laisser l'implémentation native sous-jacente s'occuper de la visualisation de sa progression. Dans le cas d'un téléchargement, la durée d'une animation peut être définie sur la taille de téléchargement totale, et currentTime sur la taille actuellement téléchargée (démo).

Transitions et gestes de l'UI

Les plates-formes mobiles sont depuis longtemps le domaine des gestes courants: glisser, balayer, lancer, etc. Ces gestes ont tendance à avoir un thème commun: un composant d'interface utilisateur déplaçable, tel que le « tirer pour actualiser » dans une liste ou une barre latérale ouverte à partir du côté gauche de l'écran.

Avec les animations Web, un effet similaire est très facile à reproduire sur le Web, que ce soit sur ordinateur ou sur mobile. Par exemple, lorsqu'un geste de contrôle de currentTime est terminé:

var steps = [ /* animation steps */ ];
var duration = 1000;
var player = target.animate(steps, duration);
player.pause();
configureStartMoveListeners(player);

var setpoints = [0, 500, 1000];
document.addEventListener('touchend', function(event) {
    var srcTime = player.currentTime;
    var dstTime = findNearest(setpoints, srcTime);
    var driftDuration = dstTime - srcTime;

    if (!driftDuration) {
    runCallback(dstTime);
    return;
    }

    var driftPlayer = target.animate(steps, {
    duration: duration,
    iterationStart: Math.min(srcTime, dstTime) / duration,
    iterations: Math.abs(driftDuration) / duration,
    playbackRate: Math.sign(driftDuration)
    });
    driftPlayer.onfinish = function() { runCallback(dstTime); };
    player.currentTime = dstTime;
});

Cela crée une animation supplémentaire qui effectue une "dérive". Cela va de l'endroit où le geste a été effectué jusqu'à notre cible correcte connue.

Cela fonctionne, car les animations ont une priorité en fonction de leur ordre de création: dans ce cas, driftPlayer aura la priorité sur player. Une fois driftPlayer terminée, elle et ses effets disparaissent. Toutefois, son heure finale correspondra à la valeur currentTime du lecteur sous-jacent, de sorte que votre UI restera cohérente.

Enfin, si vous aimez les chatons, vous pouvez utiliser l'application Web de démonstration pour montrer ces gestes. Il est adapté aux mobiles et utilise le polyfill pour assurer la rétrocompatibilité. Essayez donc de le charger sur votre appareil mobile.

Allez-y et utilisez element.animate.

La méthode element.animate est très efficace, que vous l'utilisiez pour des animations simples ou que vous exploitiez le AnimationPlayer renvoyé de différentes manières.

Ces deux fonctionnalités sont également entièrement compatibles avec les autres navigateurs modernes via un polyfill léger. Ce polyfill effectue également la détection de fonctionnalités. Par conséquent, à mesure que les fournisseurs de navigateurs implémenteront la spécification, cette fonctionnalité ne fera que s'améliorer et s'accélérer au fil du temps.

La spécification Web Animations continuera également d'évoluer. Si vous souhaitez tester les fonctionnalités à venir, elles sont également disponibles dans un polyfill plus détaillé: web-animations-next.