A principios de este año, Chrome 36 lanzó el método element.animate como parte de la especificación de animaciones web más amplia. Esto permite animaciones nativas y eficientes escritas de manera imperativa, lo que les brinda a los desarrolladores la opción de compilar sus animaciones y transiciones con el enfoque más adecuado para ellos.
Para hacer un repaso rápido, aquí te mostramos cómo puedes animar una nube en la pantalla, con una devolución de llamada cuando termines:
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);
};
Esto es increíblemente fácil y vale la pena considerarlo como parte de tu caja de herramientas cuando crees animaciones o transiciones de manera imperativa. Sin embargo, en Chrome 39, se agregaron funciones de control de reproducción al objeto AnimationPlayer
que muestra element.animate
. Anteriormente, una vez que se creaba una animación, solo podías llamar a cancel()
o escuchar el evento de finalización.
Estas incorporaciones de reproducción amplían las posibilidades de lo que pueden hacer las animaciones web: convertirlas en una herramienta de uso general, en lugar de ser prescriptivas sobre las transiciones, es decir, animaciones "fijas" o predefinidas.
Pausar, retroceder o cambiar la velocidad de reproducción
Comencemos por actualizar el ejemplo anterior para pausar la animación si se hace clic en la nube:
cloud.addEventListener('mousedown', function() {
player.pause();
});
También puedes modificar la propiedad playbackRate
:
function changeWindSpeed() {
player.playbackRate *= (Math.random() * 2.0);
}
También puedes llamar al método reverse()
, que normalmente equivale a invertir el playbackRate
actual (multiplicar por -1). Sin embargo, hay algunos casos especiales:
Si el cambio causado por el método
reverse()
provocara que la animación en ejecución finalice de manera efectiva, elcurrentTime
también se invierte (p. ej., si se invierte una animación nueva, toda la animación se reproducirá al revés).Si el reproductor está en pausa, se comenzará a reproducir la animación.
Arrastrar el cursor del reproductor
Un AnimationPlayer
ahora permite que se modifique su currentTime
mientras se ejecuta una animación. Por lo general, este valor aumentará con el tiempo (o disminuirá, si playbackRate
es negativo). Esto podría permitir que la posición de una animación se controle de forma externa, tal vez a través de la interacción del usuario. Esto se conoce comúnmente como limpieza.
Por ejemplo, si tu página HTML representara el cielo y quisieras que un gesto de arrastre cambie la posición de una nube que se está reproduciendo, podrías agregar algunos controladores 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;
});
A medida que arrastres el documento, el currentTime
cambiará para reflejar la distancia del evento original. También puedes reanudar la reproducción de la animación cuando finalice el gesto:
document.addEventListener('touchend', function(event) {
startEvent = null;
player.play();
});
Esto incluso se puede combinar con el comportamiento de inversión, según el lugar desde el que se levantó el mouse de la página (demostración combinada).
En lugar de borrar un AnimationPlayer
en respuesta a una interacción del usuario, su currentTime
también se puede usar para mostrar el progreso o el estado, por ejemplo, para mostrar el estado de una descarga.
La utilidad aquí es que un AnimationPlayer
permite establecer un valor y que la implementación nativa subyacente se encargue de su visualización de progreso. En el caso de la descarga, la duración de una animación se puede establecer en el tamaño total de descarga y el currentTime
en el tamaño descargado actualmente (demo).
Transiciones y gestos de la IU
Las plataformas para dispositivos móviles han sido durante mucho tiempo el reino de los gestos comunes: arrastrar, deslizar, lanzar y similares. Estos gestos suelen tener un tema en común: un componente de IU que se puede arrastrar, como el "deslizar para actualizar" de una vista de lista o una barra lateral que se crea desde el lado izquierdo de la pantalla.
Con las animaciones web, es muy fácil replicar un efecto similar aquí en la Web, ya sea en computadoras de escritorio o en dispositivos móviles. Por ejemplo, cuando se completa un gesto que controla 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;
});
Esto crea una animación adicional que realiza un "desplazamiento". Esto se reproduce entre el lugar donde se completó el gesto y nuestro objetivo conocido.
Esto funciona porque las animaciones tienen una prioridad según el orden en que se crean: en este caso, driftPlayer
tendrá prioridad sobre el jugador. Cuando se complete driftPlayer
, desaparecerá junto con sus efectos. Sin embargo, su hora final coincidirá con el currentTime subyacente del jugador, por lo que tu IU seguirá siendo coherente.
Por último, si te gustan los gatitos, hay una aplicación web de demostración que muestra estos gestos. Es compatible con dispositivos móviles y usa el polyfill para la retrocompatibilidad, así que intenta cargarlo en tu dispositivo móvil.
Continúa con element.animate
El método element.animate
es lo mejor en este momento, ya sea que lo uses para animaciones simples o aproveches su AnimationPlayer
que se muestra de otras maneras.
Estas dos funciones también son totalmente compatibles con otros navegadores modernos a través de un polyfill ligero. Este polyfill también realiza la detección de funciones, por lo que, a medida que los proveedores de navegadores implementen la especificación, esta función solo se volverá más rápida y mejor con el tiempo.
La especificación de animaciones web también seguirá evolucionando. Si te interesa probar las próximas funciones, también están disponibles en un polyfill más detallado: web-animations-next.