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 rappel, voici comment animer un nuage à l'écran, avec un rappel à la fin:

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 contrôle de la 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(), qui équivaut normalement à inverser le playbackRate actuel (multiplier 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 mis en pause, l'animation commence à être lue.

Utiliser la barre de lecture

Un AnimationPlayer permet désormais de modifier son currentTime pendant l'exécution d'une animation. En règle générale, cette valeur augmente avec le temps (ou diminue, si playbackRate est négatif). 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, la valeur currentTime change 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 du téléchargement, la durée d'une animation peut être définie sur la taille totale du téléchargement, 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, comme la fonctionnalité "Tirer pour actualiser" d'une vue Liste ou une barre latérale qui s'ouvre à 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 se joue entre l'endroit où le geste a été effectué et notre cible 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 currentTime du lecteur sous-jacent, de sorte que votre UI restera cohérente.

Enfin, si vous aimez les chatons, une application Web de démonstration présente ces gestes. Il est adapté aux mobiles et utilise le polyfill pour la rétrocompatibilité. Essayez 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.