Controllo della riproduzione di animazioni web in Chrome 39

All'inizio di quest'anno, Chrome 36 ha introdotto il metodo element.animate nell'ambito delle più ampie specifiche delle 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 alle loro esigenze.

Per un breve ripasso, ecco come puoi animare una nuvola sullo schermo, con un callback al termine:

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 da solo è incredibilmente facile e vale la pena di essere considerato come parte della cassetta degli attrezzi 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 solo cancel() o ascoltare l'evento di completamento.

Queste aggiunte al playback ampliano le possibilità di ciò che le animazioni web possono fare: trasformano le animazioni in uno strumento per uso generale, anziché essere prescrittive per le transizioni, ad esempio Animazioni "fisse" o predefinite.

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

Iniziamo aggiornando l'esempio riportato sopra per mettere in pausa l'animazione se si 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 in genere equivale a invertire l'attuale playbackRate (moltiplica per -1). Esistono però un paio di casi speciali:

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

  • Se il player è in pausa, l'animazione inizierà a essere riprodotta.

Scrub del player

Ora un AnimationPlayer consente di modificare il relativo currentTime durante l'esecuzione di un'animazione. In genere, questo valore aumenta nel tempo (o diminuisce, se playbackRate è negativo). In questo modo, la posizione di un'animazione potrebbe essere controllata dall'esterno, ad esempio tramite l'interazione dell'utente. Questo processo è comunemente noto come scrubbing.

Ad esempio, se la tua pagina HTML rappresenta il cielo e vuoi che un gesto di trascinamento modifichi la posizione di una nuvola attualmente in riproduzione, puoi 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 simbolo currentTime viene modificato in base alla 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 può essere combinato anche con il comportamento di inversione, a seconda di dove il mouse è stato sollevato dalla pagina (demo combinata).

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

L'utilità di AnimationPlayer è che consente di impostare un valore e di lasciare che l'implementazione nativa di base si occupi della visualizzazione dei progressi. Nel caso del download, la durata di un'animazione potrebbe essere impostata sulle dimensioni totali del download e currentTime impostato sulle dimensioni attualmente scaricate (demo).

Transizioni e gesti dell'interfaccia utente

Le piattaforme mobile sono da tempo il regno dei gesti comuni: trascinamento, scorrimento, lancio e simili. Questi gesti tendono ad avere un tema comune: un componente dell'interfaccia utente trascinabile, ad esempio "Tira per aggiornare" di una visualizzazione elenco o una barra laterale che viene creata dal lato sinistro dello schermo.

Con le animazioni web, è molto facile replicare un effetto simile qui sul web, su computer o dispositivo mobile. Ad esempio, quando viene completato un gesto di controllo di 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;
});

Viene creata un'animazione aggiuntiva che esegue una "deviazione". Il video viene riprodotto dal punto in cui è stato completato il gesto fino al nostro target noto buono.

Questo funziona perché le animazioni hanno una priorità in base all'ordine di creazione: in questo caso, driftPlayer avrà la precedenza sul player. Al termine di driftPlayer, l'effetto e l'effetto stesso scompaiono. Tuttavia, la sua ora finale corrisponderà a currentTime del player sottostante, quindi l'interfaccia utente rimarrà coerente.

Infine, se ti piacciono i gattini, esiste una applicazione web di dimostrazione che mostra questi gesti. È ottimizzato per il mobile e utilizza il polyfill per la compatibilità con le versioni precedenti, quindi prova a caricarlo sul tuo dispositivo mobile.

Vai avanti e usa element.animate

Il metodo element.animate è fantastico in questo momento, che tu lo utilizzi per animazioni semplici o per sfruttare il AnimationPlayer restituito in altri modi.

Queste due funzionalità sono supportate completamente 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 la specifica, questa funzionalità diventerà sempre più veloce e migliorerà nel tempo.

Anche le specifiche di Web Animations continueranno a evolversi. Se vuoi provare le funzionalità in arrivo, sono ora disponibili anche in un polyfill più dettagliato: web-animations-next.