Controllo della riproduzione di animazioni web in Chrome 39

All'inizio di quest'anno, Chrome 36 ha introdotto il metodo element.animate nell'ambito della più ampia specifica sulle animazioni web. Ciò consente di creare animazioni native efficienti scritte in modo imperativo, offrendo agli sviluppatori la possibilità di creare animazioni e transizioni con l'approccio più adatto a loro.

Per un rapido ripasso, ecco come puoi animare una nuvola sullo schermo, con un callback al termine dell'operazione:

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

Questa soluzione è incredibilmente facile e vale la pena prenderla in considerazione come parte del tuo strumento quando crei animazioni o transizioni in modo imperativo. Tuttavia, in Chrome 39, le funzionalità di controllo della riproduzione sono state aggiunte all'oggetto AnimationPlayer restituito da element.animate. In precedenza, una volta creata un'animazione, potevi chiamare cancel() o ascoltare l'evento finale.

Queste aggiunte alla riproduzione aprono le possibilità delle animazioni web: trasformare le animazioni in uno strumento generico, invece di essere prescrittive per le transizioni, ovvero animazioni "fisse" o predefinite.

Mettere in pausa, riavvolgere o modificare la velocità di riproduzione

Inizia aggiornando l'esempio riportato sopra per mettere in pausa l'animazione quando 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 normalmente equivale all'inversione del valore playbackRate corrente (moltiplica per -1). Tuttavia, esistono un paio di casi speciali:

  • Se la modifica causata dal metodo reverse() comporta la fine effettiva dell'animazione in esecuzione, anche il currentTime viene invertito.Ad esempio, se una nuova animazione viene invertita, l'intera animazione verrà riprodotta a ritroso.

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

Eseguire lo scrubbing del player

Un AnimationPlayer ora consente la modifica del relativo currentTime mentre è in esecuzione un'animazione. Solitamente, questo valore aumenterà nel tempo (o diminuirà, se il valore playbackRate è negativo). Ciò potrebbe consentire di controllare esternamente la posizione di un'animazione, magari attraverso l'interazione dell'utente. Questa operazione è comunemente nota come scrubbing.

Ad esempio, se la tua pagina HTML rappresentava il cielo e vuoi usare un gesto di trascinamento per cambiare la posizione della nuvola in riproduzione, puoi aggiungere al documento alcuni gestori:

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 sul documento, l'elemento currentTime si modifica per riflettere la distanza dall'evento originale. Puoi anche 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 del comportamento, a seconda di dove il mouse è stato spostato dalla pagina (demo combinata).

Anziché eseguire lo scrubbing di un AnimationPlayer in risposta a un'interazione dell'utente, l'elemento currentTime potrebbe essere utilizzato anche per mostrare l'avanzamento o lo stato, ad esempio per mostrare lo stato di un download.

In questo caso, l'utilità è che un AnimationPlayer consente di impostare un valore e che l'implementazione nativa sottostante si occupi della sua visualizzazione dell'avanzamento. Nel caso del download, la durata di un'animazione potrebbe essere impostata sulla dimensione totale di download e currentTime sulla dimensione attualmente scaricata (demo).

Transizioni e gesti della UI

Le piattaforme per dispositivi mobili sono da tempo il regno dei gesti comuni: trascinare, far scorrere, scorrazzare e così via. Questi gesti tendono ad avere un tema comune: un componente dell'interfaccia utente trascinabile, ad esempio il pulsante "Esegui il pull per aggiornare" di una visualizzazione elenco o una barra laterale che viene eseguita dal lato sinistro dello schermo.

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

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

Verrà creata un'animazione aggiuntiva che esegue una "deviazione". Questo viene riprodotto dal punto in cui è stato completato il gesto fino al bersaglio noto.

Funziona perché le animazioni hanno una priorità basata sull'ordine di creazione: in questo caso, driftPlayer ha la precedenza sul player. Al termine di driftPlayer, i suoi effetti scompaiono. Tuttavia, il tempo finale corrisponderà all'ora corrente del player sottostante, quindi la tua UI rimarrà coerente.

Infine, se vi piacciono i gattini, c'è un'applicazione web demo che mette in mostra questi gesti. È ottimizzato per il mobile e utilizza il polyfill per essere compatibile con le versioni precedenti, quindi prova a caricarlo sul tuo dispositivo mobile.

Continua e element.animate

Il metodo element.animate è davvero ottimo al momento, sia che lo utilizzi per animazioni semplici o che utilizzi AnimationPlayer restituito in altri modi.

Queste due funzionalità sono pienamente supportate anche in altri browser moderni tramite un polyfill leggero. Questo polyfill esegue anche il rilevamento delle funzionalità, quindi man mano che i fornitori di browser implementano le specifiche, questa funzionalità diventerà sempre più veloce e migliore con il passare del tempo.

Anche la specifica delle animazioni web continuerà a evolversi. Se ti interessa sperimentare le funzionalità in arrivo, sono disponibili anche in un polyfill più dettagliato: web-animations-next.