Orquestación y animación de SVGs en React con Framer Motion

María Simó
Secuoyas Experience
7 min readAug 5, 2020
Ilustrar.io — made by Gema Hoang @Secuoyas

En el artículo anterior de esta serie sobre animaciones con Framer Motion, animamos la entrada de elementos en el viewport. Entonces mencionábamos brevemente el modo en que podemos lograr un ligero efecto de stagger — escalonado, en la animación de elementos.

En esta ocasión, vamos a aprender en detalle cómo crear ese efecto de stagger y en general, cómo podemos hacer que las animaciones de distintos elementos “cooperen” para formar una animación secuenciada u orquestación.

Además vamos a aprovechar para trabajar con svgs, otra de las posibilidades que nos ofrece Framer Motion.

Lo que vamos a hacer

Infografía animada en https://coronavirus.secuoyas.com/contexto
Infografía animada en https://coronavirus.secuoyas.com/contexto

Para la página de Contexto de COVID·19-ES, nuestro compañero Rubi creó una ilustración vectorial para mostrar el proceso de infección de la célula humana por la covid. A la hora de llevarla a desarrollo, creamos un efecto de orquestación con sus elementos, que es el que vamos a reproducir en este artículo mediante el uso de variants de Framer Motion.

Estos mismos conceptos son aplicables a cualquier situación en la que necesitéis animar secuencialmente elementos –en la documentación de Framer Motion, por ejemplo, podéis encontrar un caso de aplicación a la animación de un side menu.

Manos a la obra

Sandbox: https://codesandbox.io/s/secuoyas-covid-orchestration-2i06t?file=/src/App.js:0-5553

Como se aprecia en el ejemplo, vamos a animar la aparición de los comentarios que informan la ilustración (formados por un texto y un path), y el puñado de virus réplica que aparecen en la esquina inferior derecha. También vamos a animar el path que recorre la ilustración. Usaremos este sandbox con una versión simplificada del código como referencia. ¡Vamos a ello!

Para empezar, y una vez hayamos exportado desde nuestra aplicación de diseño la ilustración como svg, la envolveremos en un componente de React.

Para crear un efecto de orquestación con Framer Motion necesitamos definir una animación en el elemento padre de nuestro componente, a través de la cual se coordina el resto. Añadimos el prefijo “motion” a las etiquetas de apertura y cierre del svg, para declarar que vamos a animar este elemento.

Después de eso, si únicamente quisiéramos animar el svg, nos bastaría con declarar la propiedad animate (y, de manera opcional, la propiedad initial) directamente en el elemento. De la siguiente manera (línea 4):

Esto crea una animación de fade in que afecta a todo el svg. Si además queremos orquestar distintas animaciones de sus elementos internos, aquí es donde entra el uso de variants.

Variants requiere que declaremos la animación como un objeto independiente (línea 2), en el que una de sus propiedades define el estado inicial y otra cómo se va a animar el elemento — en este ejemplo, hemos llamado a estas propiedades “hidden” y “visible”, pero podemos darles el nombre que queramos.

Este objeto lo pasamos al elemento svg a través de la prop variants. También tenemos que conectar los nombres de las propiedades del objeto, “hidden” y “visible”, con las props del elemento initial y animate (línea 19).

Vamos a examinar este snippet. En la transición de nuestra animación vemos que declaramos la propiedad staggerChildren con un valor de 1. Esto va a hacer que los hijos del svg se animen con un delay de 1 segundo entre ellos, de manera secuencial. También usamos la propiedad when, con el valor beforeChildren. Así indicamos que queremos empezar a animar los hijos del svg una vez que la animación de fade in haya concluido.

Cómo funciona variants

Gracias a que variants tiene la capacidad de propagarse a través del DOM, todos los hijos del svg a los que queramos aplicar una animación van a reconocer las propiedades initial y animate del padre. Lo más interesante es que podemos aplicar diferentes animaciones a los elementos hijos mediante la prop variants, y mientras las propiedades de estos objetos se llamen igual que las del elemento padre (hidden y visible, recordamos), no tendremos que volver a declararlas en los elementos hijos.

Puede sonar algo confuso, pero es muy sencillo si lo vemos a través de un ejemplo:

Sandbox: https://codesandbox.io/s/secuoyas-simple-orquestation-f0rdy

Vemos cómo en el elemento padre de la animación, declaramos las props variants, initial y animate (línea 35), mientras que en los elementos hijos (líneas 45 y 52), a los que hemos aplicado una animación distinta, sólo necesitamos declarar variants, porque gracias a la propagación el elemento entiende que debe usar la propiedad hidden del objeto como valor inicial y la propiedad visible como valor de la animación.

Organizando nuestro componente

Volviendo al sandbox de nuestra infografía, para poner el foco sobre la animación, hemos organizado nuestro componente de la siguiente manera:

  • Los elementos internos del svg que dibujan la ilustración se han externalizado a un componente puramente presentacional (Illustration.js) al que luego llamamos dentro del svg.
  • Hemos creado el componente Flag, para presentar y animar los textos que informan a la ilustración. En este componente se define una animación para animar el path y otra para animar el texto. Vamos a reusar este componente para cada uno de nuestros textos, para lo cual es necesario indicarle cada vez que lo usemos las siguientes props: contents (el texto), d (el recorrido del path) y las coordenadas de posición x e y. El texto, debido a las especificaciones de svg, debe ser un array de strings que mapeamos para posicionarlas con espacio entre sí de 18px (indicado por el atributo dy).
  • Todos los objetos donde definimos las animaciones están juntos en un mismo archivo (animations.js) y los importamos donde sea necesario.

Algunas consideraciones:

  • Hay que tener en cuenta que cada uno de estos componentes dentro del svg principal se van a animar en el orden en que estén presentados en el DOM.
Un ejemplo de orquestación
  • La propagación de variants afecta a todos los hijos de la animación principal, no sólo a los directos. Esto significa que no sólo todas las instancias del component Flag van a aparecer en orden, si no que también los elementos dentro de este componente aparecen uno después de otro. Porque se ven afectadas por la propiedad staggerChildren del padre. Por eso se animará primero el elemento path y luego el text.

Con esto ya tendríamos el efecto principal, con los textos animándose uno a uno. ¿Qué nos queda? Animar el largo path que recorre la ilustración y las réplicas de los virus que aparecen al final del todo.

Animar svg paths

Animar paths es ridículamente fácil con Framer Motion, y de hecho, ya lo hemos hecho en el path del componente Flag. En esencia, lo único que tenemos que hacer es, cuando definamos nuestras variants, llevar la propiedad pathLength de 0 a 1. Luego la aplicamos variants a nuestro path.

Lo único que debemos tener en cuenta, y esto es del interés de nuestros amigos en la parte del diseño, es que el path se va a animar en el orden en que esté dibujado. Si lo dibujamos de izquierda a derecha, aparecerá de izquierda a derecha, y viceversa. En Illustrator creo que el sentido del path es configurable en la exportación del svg, pero en Figma no (¿quizás mediante algún plugin?).

Dynamic Variants

Para animar las réplicas del virus usamos dynamic variants, para que en lugar de que todas las réplicas aparecieran con de forma regular, pudiéramos jugar con las propiedades de la animación para crear un efecto un poco más interesante visualmente.

Para eso, lo primero que tenemos que hacer es crear un componente con la ilustración, que reutilizaremos una y otra vez. En el archivo CovidSvg.js, tenemos ese componente, que recibe las props de posición, x e y, además de width, el tamaño de que vamos a dar a cada instancia. También tenemos un array de posiciones y tamaños para cada instancia. Importamos todo en nuestro componente principal.

Al final del svg (porque, como hemos apuntado antes, es el elemento que queremos animar en último lugar), vamos a mapear el array de posiciones y tamaño, y crear las instancias del componente, suministrándole la información de cada posición del array como props.

Lo que tenemos que notar aquí es que además creamos la prop custom, con el valor del índice (línea 32). Mediante custom, podemos pasar un argumento a variants y usarlo en una pequeña función. En este caso, hacemos que el delay sea un valor dinámico, de modo que la aparición de las réplicas tenga un pequeño efecto de aceleración.

Eso es todo, por ahora 😃

Espero que este artículo os pueda servir como puerta de entrada a Framer Motion, para conocer nuevos detalles sobre esta librería o simplemente sumar conocimiento a vuestra experiencia con animaciones en React.

En el primer artículo de la serie podéis aprender cómo disparar vuestra animación en el momento adecuado del scroll, con Intersection Observer.

Atentos, porque en las próximas semanas, seguiremos compartiendo otras técnicas de animación + scroll que hemos empleado en COVID·19-ES: Parallax y Scroll-driven Animations.

¡Gracias por leer!

--

--

María Simó
Secuoyas Experience

Front end developer at Secuoyas. I studied Arts and then I realized art was anywhere else, so I became a designer, and after some years, a developer.