Controllo della riproduzione di animazioni web in Chrome 39

[Nome di persona]
Sam Thorogood

All'inizio di quest'anno, Chrome 36 ha introdotto il metodo element.animate nell'ambito della più ampia specifica delle animazioni web. In questo modo è possibile creare animazioni native efficaci scritte in modo imperativo, offrendo agli sviluppatori la possibilità di creare le animazioni e le transizioni più adatte.

Per un rapido ripasso, ecco come puoi animare una nuvola sullo schermo, richiamando una volta terminato:

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);
};

Questo aspetto da solo è incredibilmente facile e vale la pena considerarlo come parte degli strumenti quando si creano in modo imperativo animazioni o transizioni. Tuttavia, in Chrome 39 sono state aggiunte funzionalità di controllo della riproduzione all'oggetto AnimationPlayer restituito da element.animate. In precedenza, dopo la creazione di un'animazione, potevi chiamare solo cancel() o ascoltare l'evento finale.

Queste aggiunte alla riproduzione aprono le possibilità di ciò che possono fare le animazioni web: trasformare le animazioni in uno strumento generico, invece di prescrivere le transizioni, ovvero animazioni "fisse" o predefinite.

Mettere in pausa, tornare indietro o modificare la velocità di riproduzione

Iniziamo aggiornando l'esempio precedente per mettere in pausa l'animazione se l'utente fa clic sul cloud:

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

Puoi anche modificare la proprietà playbackRate:

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

Puoi anche chiamare il metodo reverse(), che solitamente equivale a invertire l'attuale playbackRate (moltiplica per -1). Tuttavia, esistono un paio di casi speciali:

  • Se la modifica causata dal metodo reverse() determina la fine efficace dell'animazione in esecuzione, viene invertita anche la metrica currentTime; ad esempio, se viene invertita una nuova animazione, l'intera animazione verrà riprodotta all'indietro.

  • Se il player è in pausa, viene avviata la riproduzione dell'animazione.

Eseguire lo scrubbing del player

Un elemento AnimationPlayer ora consente di modificare currentTime mentre è in esecuzione un'animazione. Normalmente, questo valore aumenta nel tempo (o diminuisce, se playbackRate è negativo). In questo modo la posizione di un'animazione potrebbe essere controllata dall'esterno, magari tramite l'interazione dell'utente. In genere, ciò è definito scrubbing.

Ad esempio, se la tua pagina HTML rappresenta il cielo e vuoi utilizzare un gesto di trascinamento per cambiare la posizione di una nuvola attualmente in riproduzione, potresti aggiungere alcuni gestori al documento:

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;
});

Mentre trascini il documento, il valore currentTime viene modificato in modo da riflettere la distanza dall'evento originale. Potrebbe anche essere opportuno riprendere la riproduzione dell'animazione al termine del gesto:

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

Questo potrebbe anche essere combinato con l'inversione, a seconda di dove è stato sollevato il mouse dalla pagina (demo combinata).

Anziché eseguire lo scrubbing di un AnimationPlayer in risposta a un'interazione da parte di un utente, puoi utilizzare currentTime anche per mostrare l'avanzamento o lo stato, ad esempio per mostrare lo stato di un download.

L'utilità è che AnimationPlayer consente l'impostazione di un valore e l'implementazione nativa sottostante si occupa della visualizzazione dell'avanzamento. Nel caso di download, la durata di un'animazione potrebbe essere impostata sulle dimensioni totali di download e currentTime sulle dimensioni attualmente scaricate (demo).

Transizioni dell'interfaccia utente e gesti

Le piattaforme per dispositivi mobili sono da tempo il regno dei gesti comuni: trascinamento, scorrimento, scorrimento e così via. Questi gesti tendono ad avere un tema comune: un componente dell'interfaccia utente trascinabile, ad esempio il pulsante "Tira per aggiornare" di una visualizzazione elenco o l'esecuzione di una barra laterale dal lato sinistro dello schermo.

Con le animazioni web, un effetto simile è molto facile da replicare qui sul web, da computer o dispositivo mobile. Ad esempio, quando un gesto che controlla currentTime viene completato:

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;
});

In questo modo viene creata un'animazione aggiuntiva che esegue una "deriva". Viene riprodotto tra il punto in cui è stato completato il gesto e il nostro obiettivo noto.

Funziona perché le animazioni hanno una priorità in base al loro ordine di creazione: in questo caso, driftPlayer ha la precedenza sul player. Al termine, driftPlayer e i suoi effetti scompaiono. Tuttavia, l'ora finale corrisponderà all'attuale ora del player sottostante, quindi l'interfaccia utente rimarrà coerente.

Infine, se ti piacciono i gattini, puoi trovare un'applicazione web demo che mostra questi gesti. È ottimizzato per dispositivi mobili e utilizza il polyfill per garantire la compatibilità con le versioni precedenti, quindi prova a caricarlo sul tuo dispositivo mobile.

Vai avanti e element.animate

Il metodo element.animate è estremamente popolare al momento, sia che lo si stia utilizzando per animazioni semplici sia che lo si stia sfruttando in altri modi (AnimationPlayer).

Queste due funzionalità sono pienamente supportate anche in altri browser moderni tramite un polyfill leggero. Questo polyfill esegue anche il rilevamento delle funzionalità, in modo che man mano che i fornitori di browser implementano le specifiche, questa funzionalità migliora con il passare del tempo.

Anche le specifiche relative alle animazioni web continueranno a evolversi. Se ti interessa scoprire le funzionalità in arrivo, ora sono disponibili anche in un polyfill più dettagliato: web-animations-next.