1. Code
  2. JavaScript

Animaciones basadas en JavaScript con Anime.js, Parte 3: Valores, línea de tiempo y reproducción

En el tutorial anterior de la serie Anime.js, aprendiste sobre diferentes tipos de parámetros que controlan cómo se deben animar los diferentes elementos de destino. También aprendiste a usar los parámetros de función para cambiar gradualmente el retraso o la duración de los elementos.
Scroll to top
10 min read
This post is part of a series called JavaScript-Based Animations Using Anime.js.
JavaScript-Based Animations Using Anime.js, Part 2: Parameters
JavaScript-Based Animations Using Anime.js, Part 4: Callbacks, Easings, and SVG

Spanish (Español) translation by Steven (you can also view the original English article)

En el tutorial anterior de la serie Anime.js, aprendiste sobre diferentes tipos de parámetros que controlan cómo se deben animar los diferentes elementos de destino. También aprendiste a usar los parámetros de función para cambiar gradualmente el retraso o la duración de los elementos.

En este tutorial, daremos un paso más y aprenderemos cómo especificar los valores de propiedad ellos mismos usando números regulares, valores basados en funciones y fotogramas clave. También aprenderás a reproducir animaciones en secuencia utilizando líneas de tiempo.

Especificar valores de propiedad

Anime.js te permite especificar los valores finales o el final para las propiedades animables de los elementos de destino. El valor inicial o de arranque de la animación es el valor predeterminado de esa propiedad. Cualquier valor especificado en el CSS también puede actuar como valor inicial. Hay varias formas de especificar un valor final.

También puede ser un número sin unidades. En este caso, las unidades originales o predeterminadas de la propiedad se utilizan al calcular los valores de la propiedad. También puedes especificar el valor como una cadena, pero la cadena debe contener al menos un valor numérico. Ejemplos de valores de cadena serían 10vh, 80% y 9.125turn.

En lugar de especificar un valor absoluto, también puedes especificar valores de propiedad en relación con su valor actual. Por ejemplo, puedes establecer que el valor de translateY final sea 150px mayor que el valor actual usando +=150px como valor. Ten en cuenta que solo puedes usar la suma, la multiplicación y la resta mientras especificas valores relativos.

Al animar colores, no puedes usar nombres de colores como rojo, negro y azul para establecer un valor de color final para la animación. En tales casos, la animación de color no se producirá en absoluto y el cambio será instantáneo. La única forma de animar colores es especificar los valores como dígitos hexadecimales o en términos de valores RGB y HSL.

Como habrás notado, no hemos estado especificando un valor inicial para nuestros elementos de destino para animarlos. Anime.js determina automáticamente el valor inicial basado en nuestro CSS y los valores predeterminados de esas propiedades. Sin embargo, puedes especificar un valor inicial que no sea el valor predeterminado para una propiedad mediante matrices. El primer elemento de la matriz significa el valor inicial y el segundo elemento significa el valor final.

En lugar de usar el mismo valor final para todos tus elementos de destino, puedes usar funciones para establecer diferentes valores para diferentes parámetros. El proceso es similar a especificar parámetros de propiedad basados en funciones.

1
var uniqueTranslation = anime({
2
  targets: '.square',
3
  translateY: function(el, i) {
4
    return 50 * (i + 1);
5
  },
6
  autoplay: false
7
});
8
9
var randomScaling = anime({
10
  targets: '.square',
11
  scale: function(el, i) {
12
    return Math.random()*1.5 + i/10;
13
  },
14
  autoplay: false
15
});
16
17
var randomRotation = anime({
18
  targets: '.square',
19
  rotate: function() {
20
    return anime.random(-180, 180);
21
  },
22
  autoplay: false
23
});
24
25
var randomRadius = anime({
26
  targets: '.square',
27
  borderRadius: function(el) {
28
    return 20 + Math.random()*el.offsetWidth/4;
29
  },
30
  autoplay: false
31
});
32
33
var randomAll = anime({
34
  targets: '.square',
35
  translateY: function(el, i) {
36
    return 50 + 50 * i;
37
  },
38
  scale: function(el, i) {
39
    return Math.random()*1.5 + i/10;
40
  },
41
  rotate: function() {
42
    return anime.random(-180, 180);
43
  },
44
  borderRadius: function(el) {
45
    return Math.random()*el.offsetWidth/2;
46
  },
47
  duration: function() { return anime.random(1500, 2400); },
48
  delay: function() { return anime.random(0, 1000); },
49
  autoplay: false
50
});

Para la propiedad translateY, estamos usando el índice del elemento para establecer un valor de traducción. El uso de 50 * (i + 1) aumenta el valor de translateY para cada elemento en 50 píxeles.

La animación de escala también usa el índice del elemento junto con la función Math.random() incorporada para devolver un número pseudoaleatorio de punto flotante menor que 1. De esta manera, los elementos escalan aleatoriamente, pero la parte i/10 de la propiedad aumenta ligeramente la posibilidad de que los elementos que se produzcan al final tengan un tamaño mayor.

Dentro del código para la animación de rotación, estamos usando la función auxiliar anime.random(a, b) para obtener enteros aleatorios entre -180 y 180. Esta función es útil para asignar valores integrales aleatorios a propiedades como translateY y rotate. El uso de esta función para asignar valores de escala aleatorios producirá resultados extremos.

El valor del radio del borde para diferentes elementos se determina calculando el ancho de los elementos de destino usando el parámetro de función el. Finalmente, la última parte del código también asigna valores aleatorios a los parámetros duration y delay.

Puedes ver que la animación lograda por la última parte es muy aleatoria. No existe relación entre los valores de las diferentes propiedades de los elementos o sus valores de retardo y duración. En la vida real, es más sensato usar valores que pueden agregar algún sentido de dirección a la animación.

Please accept marketing cookies to load this content.

También es posible animar diferentes propiedades de sus elementos de destino utilizando fotogramas clave. Cada fotograma clave consta de una matriz del objeto de propiedad. Puedes utilizar el objeto para especificar el valor de la propiedad, la duración, el retraso y la relajación (durationdelay y easing) para esa parte de la animación. El siguiente código crea una animación de traducción basada en fotogramas clave.

1
var keyframeTranslation = anime({
2
  targets: '.square',
3
  translateY: [
4
    { value: 100, duration: 500},
5
    { value: 300, duration: 1000, delay: 1000},
6
    { value: 40, duration: 500, delay: 1000}
7
  ],
8
  autoplay: false
9
});
10
11
var keyframeAll = anime({
12
  targets: '.square',
13
  translateY: [
14
    { value: 100, duration: 500},
15
    { value: 300, duration: 1000, delay: 1000},
16
    { value: 40, duration: 500, delay: 1000}
17
  ],
18
  scale: [
19
    { value: 1.1, duration: 500},
20
    { value: 0.5, duration: 1000, delay: 1000},
21
    { value: 1, duration: 500, delay: 1000}
22
  ],
23
  rotate: [
24
    { value: 60, duration: 500},
25
    { value: -60, duration: 1000, delay: 1000},
26
    { value: 75, duration: 500, delay: 1000}
27
  ],
28
  borderRadius: [
29
    { value: 10, duration: 500},
30
    { value: 50, duration: 1000, delay: 1000},
31
    { value: 25, duration: 500, delay: 1000}
32
  ],
33
  delay: function(el, i) { return 100*(i+1) },
34
  autoplay: false
35
});

También puedes animar varias propiedades a la vez especificando valores diferentes o iguales para todos los parámetros. En el segundo caso, el parámetro de retardo (delay) global aplica un retardo inicial a todos los elementos en función de su índice. Este retraso es independiente del retraso aplicado a cada propiedad dentro de los fotogramas clave.

Please accept marketing cookies to load this content.

Crear y manipular líneas de tiempo

Hasta ahora en la serie, hemos estado usando el parámetro delay para reproducir diferentes animaciones en una secuencia específica. Para usar la demora con este propósito, también necesitamos saber la duración de la animación anterior.

Con la creciente complejidad de la secuencia de animación, mantener el valor de retardo correcto se vuelve muy tedioso. Cualquier cambio en la duración de una de las animaciones nos obligará a recalcular todos los valores de retardo para mantener las animaciones en la secuencia original.

Una mejor solución a este problema es usar líneas de tiempo para controlar la secuencia de animación. Tienes que usar la función anime.timeline() para crear una línea de tiempo en Anime.js. También puedes pasar diferentes parámetros a esta función como un objeto. Estos parámetros pueden especificar la dirección en la que se reproduce la línea de tiempo, el número de bucles y un parámetro de reproducción automática (autoplay) para determinar si la animación debe reproducirse automáticamente. Todos estos parámetros se han discutido en detalle en el tutorial de parámetros de esta serie.

Puedes agregar diferentes animaciones a una línea de tiempo usando el método add(). Todas las animaciones agregadas a la línea de tiempo se reproducirán en el orden en que se agregaron. Es posible especificar valores de compensación absolutos o relativos para controlar el orden en que se reproducen las animaciones.

Cuando se utilizan valores de desplazamiento relativo, el tiempo de inicio de la animación actual se determina en relación con el tiempo de la animación anterior. Las compensaciones relativas pueden ser de tres tipos:

  • +=offset: En este caso, la animación actual comienza a reproducirse después de que hayan pasado milisegundos de compensación desde el final de la animación anterior.
  • -=offset: En este caso, la animación actual comienza a reproducirse un número de desplazamiento de milisegundos antes del final de la animación anterior.
  • *=offset: En este caso, la animación actual comienza a reproducirse después de milisegundos iguales a los tiempos de compensación que ha pasado la duración de la animación de la animación anterior.

El siguiente código muestra cómo crear una línea de tiempo básica y una línea de tiempo con valores de desplazamiento relativo.

1
var basicTimeline = anime.timeline({
2
  direction: "alternate",
3
  loop: 2,
4
  autoplay: false
5
});
6
7
basicTimeline.add({
8
    targets: '.square',
9
    translateY: 200
10
 }).add({
11
    targets: '.red',
12
    translateY: 100
13
 }).add({
14
    targets: '.blue',
15
    translateY: 0
16
 });
17
18
var offsetTimeline = anime.timeline({
19
  direction: "alternate",
20
  loop: 2,
21
  autoplay: false
22
});
23
24
offsetTimeline.add({
25
    targets: '.square',
26
    translateY: 200
27
 }).add({
28
    targets: '.red',
29
    offset: '+=1000',
30
    translateY: 100
31
 }).add({
32
    targets: '.blue',
33
    offset: '*=2',
34
    translateY: 0
35
 });

Please accept marketing cookies to load this content.

Intenta hacer clic en el botón Offset Timeline en la demostración anterior. Verás que hay un retraso de 2 segundos entre el final de la animación de los cuadrados rojos y el comienzo de la animación de los cuadrados azules.

No hemos especificado una duración (duration) para la animación del cuadrado rojo. Por lo tanto, se utiliza como duración un valor predeterminado de 1000ms o 1s. El desplazamiento del multiplicador de la animación del cuadrado azul duplica ese valor, y esto da como resultado un retraso de dos segundos en la animación.

Cuando se utilizan valores de compensación absolutos, la hora de inicio de la línea de tiempo se utiliza como punto de referencia. Es posible invertir la secuencia en la que se reproducen las animaciones utilizando valores de desplazamiento grandes para las animaciones que ocurren al comienzo de la línea de tiempo.

Opciones de reproducción

Anime.js tiene una variedad de opciones para reproducir, pausar, reiniciar o buscar animaciones o líneas de tiempo en cualquier momento.

La función play() nos permite iniciar la animación desde su progreso actual. La función pause() congelará la animación en el momento en que se llamó a la función. La función restart() inicia la animación desde el principio, independientemente de su progreso actual. La función seek(value) se puede utilizar para avanzar la animación por número de valor (value) de milisegundos.

Debes tener en cuenta que la función play() solo reanuda la animación desde el momento en que se pausó. Si la animación ya ha llegado a su fin, no puedes volver a reproducir la animación con play(). Para reproducir la animación, deberás utilizar la función restart().

1
var slowAnimation = anime({
2
  targets: '.square',
3
  translateY: 250,
4
  borderRadius: 50,
5
  duration: 4000,
6
  easing: 'linear',
7
  autoplay: false
8
});
9
10
document.querySelector('.play').onclick = slowAnimation.play;
11
document.querySelector('.pause').onclick = slowAnimation.pause;
12
document.querySelector('.restart').onclick = slowAnimation.restart;
13
14
var seekInput = document.querySelector('.seek');
15
16
seekInput.oninput = function() {
17
  slowAnimation.seek(slowAnimation.duration * (seekInput.value / 100));
18
};

Ten en cuenta que no estamos usando seekInput.value para establecer un valor para la función de búsqueda. Esto se debe a que el valor máximo para la entrada de rango se ha establecido en 100 en el marcado. Usar directamente el valor para el rango de entrada nos permitirá buscar solo hasta 100ms. Multiplicar el valor de entrada del rango con la duración de la animación asegura que podamos buscar la animación desde el principio hasta el final en nuestro control deslizante de rango.

Please accept marketing cookies to load this content.

Reflexiones finales

En este tutorial, aprendiste a animar diferentes valores de propiedad como números, funciones o fotogramas clave. También aprendiste a controlar y manipular las líneas de tiempo en Anime.js para controlar el orden en que se reproduce una secuencia de animación.

Si estás buscando recursos adicionales para estudiar o usar en tu trabajo, consulta lo que tenemos disponible en el mercado de Envato.

Si tienes alguna pregunta relacionada con este tutorial, dímelo en los comentarios.