
La siguiente es una publicación invitada de Petr Tichy. Petr escribe mucho sobre animación, interacción y SVG, así que estoy emocionado de tenerlo aquí para compartir algo de esa experiencia con una demostración tan divertida. Es una animación que apuesto a que muchos de ustedes han visto antes, pero se siente un poco mágica quizás más allá de lo que parece que podemos hacer en la web. Like fue creado por artistas de video / software de edición de video. Pero no, SVG-puede-hacer-eso.
Hace poco, Google reveló su marca actualizada e introdujo la nueva identidad en una página con animaciones creativas.
Intenté recrear algunas de estas animaciones usando SVG y GreenSock. En este artículo, lo guiaré a través de mi proceso paso a paso. Ojalá puedas aprender algo en el camino.
Aquí está la animación final:
Vea el logotipo de Pen Google SVG – GreenSock Animation por Petr TIchy (@ihatetomatoes) en CodePen.
Configurar SVG en Illustrator
El primer paso fue crear un SVG con todas las partes necesarias que estarán animadas. Tracé una captura de pantalla `.png` en Illustrator y creé un contorno simple del círculo.
Para ayudarme a alinear las cosas correctamente, dividí este círculo en 4 partes pares. Luego, creé 4 círculos uno encima del otro y 4 puntos, tratando de ser lo más preciso posible.
Sabía que usaría GreenSock para la animación, y sabía que los círculos deberían ser fáciles de animar usando DrawSVGPlugin.
Para crear el espacio entre la línea recta de la “G” y la parte superior del círculo, creé un elemento blanco invisible #gMask
(N. ° 1 y n. ° 2 en la siguiente ilustración). Bastante feo para ser honesto, pero hizo el trabajo de crear la forma final de “G”.
La animación en línea recta se crea utilizando 3 partes (n. ° 3 y n. ° 4 en la ilustración siguiente).
- A – línea recta con borde redondeado – utilizada al comienzo de la animación de línea
- B – máscara clipPath – área de recorte
- C – línea recta – se muestra al final de la animación
Mientras todavía estaba en Illustrator, agrupé y nombré todas las capas con algo lógico. Esto me ahorró tiempo más tarde en el editor de código. Agrupar y renombrar elementos de un SVG puede ser un proceso bastante lento en HTML. Es mucho más fácil hacerlo directamente en Illustrator.
Luego, exporté el SVG y lo ejecuté a través del Editor en línea SVG de Peter Collingridge para reducir algunos kilobytes.
Toda la secuencia de animación se puede dividir en 3 partes:
- Animación de onda de los puntos.
- Puntos en la letra “G”
- De “G” a los puntos
Analicemos las partes individuales con más detalle.
1. Animación ondulada de los puntos
Esta es la primera parte de la animación y fue la más fácil de crear.
Vea el logotipo de Pen Google SVG – GreenSock Animation por Petr TIchy (@ihatetomatoes) en CodePen.
Simplemente estamos animando los puntos hacia arriba y hacia abajo usando el GreenSock .to()
método.
Cada punto tiene su propia línea de tiempo, dotWaveTl
que lo mueve a y: -7, y: 7
y luego de vuelta a y: 0
.
Luego, las cuatro líneas de tiempo se insertan en una línea de tiempo principal, dotsWaveTl
, con un ligero retraso.
Esto crea los efectos de onda de los cuatro puntos.
function getDotsWaveTl(){
var dotsWaveTl = new TimelineMax();
$dots.each(function(index, element){
var dotWaveTl = new TimelineMax(),
delay = 0.15;
dotWaveTl
.to(element, 0.4, {y: -7, ease:Power1.easeOut})
.to(element, 0.8, {y: 7, ease:Power1.easeInOut})
.to(element, 0.4, {y: 0, ease:Power1.easeIn})
.to(element, 0.4, {y: -7, ease:Power1.easeOut})
.to(element, 0.8, {y: 7, ease:Power1.easeInOut})
.to(element, 0.4, {y: 0, ease:Power1.easeIn});
dotsWaveTl.add(dotWaveTl, delay*index);
});
return dotsWaveTl;
}
En esto getDotsWaveTl
Función recorremos todos los puntos, creando una línea de tiempo para cada uno de ellos, luego insertamos estas líneas de tiempo en un dotsWaveTl
que es devuelto por esta función.
Los preadolescentes individuales tienen una relajación diferente para hacer que esta onda se sienta más natural.
Luego, simplemente agregamos esta línea de tiempo a la línea de tiempo maestra tl
.
/* Main timeline */
tl.add(getDotsWaveTl());
Agregaremos las otras partes de la secuencia de animación a la misma línea de tiempo maestra.
Si desea obtener más información sobre cómo funcionan las líneas de tiempo de GreenSock, consulte mi Tutorial de GreenSock TimelineLite.
2. Puntos en la letra “G”
Esta fue, con mucho, la parte más difícil de la animación.
Vea el logotipo de Pen Google SVG – GreenSock Animation por Petr TIchy (@ihatetomatoes) en CodePen.
¿Qué lo hizo tan difícil? Unas pocas cosas. Tuve que:
- traza un camino para cada uno de los puntos
- calcular un tiempo preciso para cada uno de los puntos
- calcula el tiempo y la animación de la línea recta azul
- sincronizar puntos y animación de líneas
Cuando miramos el código, verá que esta parte de la animación se crea utilizando dos líneas de tiempo.
/* Dots rotation */
function getDotsRotateTl(){
var dotsRotateTl = new TimelineMax();
dotsRotateTl
.to($dotRed, 0.9, {bezier:{curviness: 1.5, values: pathRed, ease:Power2.easeInOut}}, 0)
.to($dotYellow, 1.2, {bezier:{curviness: 1, values: pathYellow, ease:Power2.easeInOut}}, 0)
.to($dotGreen, 1.5, {bezier:{curviness: 1, values: pathGreen, ease:Power2.easeInOut}}, 0);
return dotsRotateTl;
}
dotsRotateTl
es una línea de tiempo en la que estoy animando puntos rojos, amarillos y verdes a lo largo de un camino Bézier. Sabía cuál era el punto de partida y dónde quería que terminaran los puntos, y solo necesitaba resolver los puntos intermedios.
pathRed
es una matriz de puntos que definen la ruta de la animación de puntos rojos.
Se utiliza la misma técnica para los puntos amarillos y verdes. He definido 4 puntos para cada uno y he calculado la duración correcta (1,2 segundos para el amarillo y 1,5 segundos para el punto verde).
La segunda línea de tiempo es un poco más compleja.
/* Draw G */
function getDrawGTl(){
var drawGTl = new TimelineMax();
drawGTl
.to($dotBlue, 0.6, {x: 47, ease:Power2.easeIn})
.set($gLineAnim, {autoAlpha: 1, immediateRender: false})
.set($dotBlue, {autoAlpha: 0, immediateRender: false}, '+=0.1')
.from($gLineAnim, 0.8, {x: -120, ease:Power2.easeOut}, '-=0.2')
/* draw red part */
.add('startDrawingG', 1)
.set($gRed, {autoAlpha: 1, immediateRender: false}, 'startDrawingG')
.fromTo($gRed, 0.5, {drawSVG:"71% 88%"}, {drawSVG:"0% 26%", ease:Power1.easeOut}, '-=0.2')
.set($dotRed, {autoAlpha: 0, immediateRender: false}, 'startDrawingG')
/* draw yellow part */
.set($gYellow, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.1')
.fromTo($gYellow, 0.6, {drawSVG:"71% 88%"}, {drawSVG:"17% 36%", ease:Power2.easeOut}, '-=0.45')
.set($dotYellow, {autoAlpha: 0, immediateRender: false}, 'startDrawingG+=0.1')
/* draw green part */
.set($gGreen, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.1')
.fromTo($gGreen, 0.55, {drawSVG:"71% 88%"}, {drawSVG:"36% 61%", ease:Power2.easeOut}, '-=0.6')
.set($dotGreen, {autoAlpha: 0, immediateRender: false}, 'startDrawingG+=0.4')
/* draw blue part */
.set($gLineAnim, {autoAlpha: 0, immediateRender: false}, 'startDrawingG+=0.3')
.set($gLine, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.3')
.set($gBlue, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.3')
.fromTo($gBlue, 0.55, {drawSVG:"71% 88%"}, {drawSVG:"61% 78%", ease:Power2.easeOut}, '-=0.55')
/* draw ending red part */
.set($gRedb, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.25')
.fromTo($gRedb, 0.7, {rotation: '-10', drawSVG:"100% 100%"}, {rotation: '0',drawSVG:"80% 100%", ease:Power2.easeOut}, '-=0.22');
return drawGTl;
}
El drawGTl
La línea de tiempo controla el movimiento del punto azul. Cuando se mueve 47 píxeles hacia la derecha, lo ocultamos y mostramos la línea con el borde derecho redondeado (A) como se muestra en la segunda imagen del desglose de SVG.
Un segundo en el drawGTl
reproducción de la línea de tiempo, agrego el startDrawingG
etiqueta. Esto me permite agregar otras interpolaciones en el momento adecuado y controlarlas con precisión ajustando su compensación, p. Ej. startDrawingG+=0.3
.
Una vez que el punto rojo llega al punto de intersección, lo ocultamos y mostramos el círculo rojo, que luego se anima usando GreenSock DrawSVGPlugin.
.fromTo($gRed, 0.5, {drawSVG:"71% 88%"}, {drawSVG:"0% 26%", ease:Power1.easeOut}, '-=0.2')
En este momento, y durante todo el desarrollo de esta demostración, he utilizado mucho el control deslizante de la interfaz de usuario de jQuery para determinar con precisión los valores y tiempos correctos.
Una vez que el segmento rojo se dibuja lo suficientemente largo, haremos lo mismo con los siguientes segmentos.
El punto de partida es el mismo para todos 71% 88%
segmentos, pero el punto final es diferente para cada uno de ellos.
Para completar el dibujo de toda la letra “G” usando el DrawSVGPlugin, tuve que duplicar el círculo rojo y animar el nuevo $gRedb
en el momento adecuado.
Hice esta actualización directamente en el HTML; no volver a Illustrator.
.fromTo($gRedb, 0.7, {rotation: '-10', drawSVG:"100% 100%"}, {rotation: '0', drawSVG:"80% 100%", ease:Power2.easeOut}, '-=0.22');
Una combinación de rotación, drawSVG
Los valores, el tiempo y el desplazamiento correcto me permitieron crear la animación perfecta del segmento rojo.
3. De “G” a los puntos
La animación de regreso a los puntos fue mucho más fácil de crear. Usé las mismas técnicas que en la línea de tiempo anterior, solo que en orden inverso.
Vea el logotipo de Pen Google SVG – GreenSock Animation por Petr TIchy (@ihatetomatoes) en CodePen.
Utilicé por primera vez el DrawSVGPlugin
para hacer los segmentos de colores más cortos, luego miró fijamente para rotarlos.
Cuando el segmento de color es lo suficientemente pequeño, lo oculto, muestro el punto relevante y lo animo a la posición inicial.
Aquí hay una ilustración de lo que está sucediendo en la línea de tiempo:
Y aquí está toda la función que devuelve esta línea de tiempo:
/* Back to dots */
function getBackToDotsTl(){
var backToDotsTl = new TimelineMax();
backToDotsTl
/* blue straight line out */
.to($gLineMask, 0.3, {attr: {x: 365}, transformOrigin: 'right center', ease:Power0.easeNone})
.set([$gLineMask, $gLine], {autoAlpha: 0})
/* start moving colored segments (circles) */
.add('rotateG')
.to($gBlue, 0.3, {drawSVG:"56% 78%", ease:Power0.easeNone}, 'rotateG-=0.3')
.to($gGreen, 0.3, {drawSVG:"31% 56%", ease:Power0.easeNone}, 'rotateG-=0.3')
.to($gYellow, 0.3, {drawSVG:"12% 31%", ease:Power0.easeNone}, 'rotateG-=0.3')
.to($gRed, 0.3, {drawSVG:"0% 21%", ease:Power0.easeNone}, 'rotateG-=0.3')
/* start rotating colored segments (circles) */
.add('rotateCircles')
.to([$gBlue, $gRed, $gGreen], 0.4, {rotation:"+=50", transformOrigin: 'center center', ease:Power0.easeNone}, 'rotateCircles')
.to($gGreen, 0.4, {drawSVG:"10% 20%", ease:Power0.easeNone}, 'rotateCircles')
.to($gYellow, 0.4, {rotation:"+=40", transformOrigin: 'center center', drawSVG:"0% 10%", ease:Power0.easeNone}, 'rotateCircles')
.to($gBlue, 0.4, {drawSVG:"50% 60%", ease:Power0.easeNone}, 'rotateCircles')
.to($gRed, 0.1, {drawSVG:"0% 0%", ease:Power0.easeNone}, 'rotateCircles')
.to($gRedb, 0.3, {rotation:"+=50", drawSVG:"80% 90%", ease:Power2.easeInOut}, 'rotateCircles')
/* show red dot */
.set($dotRed, {autoAlpha: 1, x: 60, y: -37}, 'rotateCircles+=0.1')
.set($gRedb, {autoAlpha: 0}, 'rotateCircles+=0.1')
.to($dotRed, 0.9, {bezier:{curviness: 1.5, values: pathRedBack, ease:Power2.easeOut}}, 'rotateCircles+=0.1')
/* show blue dot */
.set($dotBlue, {autoAlpha: 1, x: 51, y: 53}, 'rotateCircles+=0.3')
.set($gBlue, {autoAlpha: 0}, 'rotateCircles+=0.3')
.to($dotBlue, 0.6, {bezier:{curviness: 1.5, values: pathBlueBack, ease:Power2.easeOut}}, 'rotateCircles+=0.3')
/* show yellow dot */
.set($dotYellow, {autoAlpha: 1, x: -5, y: -44}, 'rotateCircles+=0.4')
.set($gYellow, {autoAlpha: 0}, 'rotateCircles+=0.4')
.to($dotYellow, 0.7, {bezier:{curviness: 1.5, values: pathYellowBack, ease:Power2.easeOut}}, 'rotateCircles+=0.4')
/* show green dot */
.set($dotGreen, {autoAlpha: 1, x: -108, y: -56}, 'rotateCircles+=0.4')
.set($gGreen, {autoAlpha: 0}, 'rotateCircles+=0.4')
.to($dotGreen, 0.6, {bezier:{curviness: 1.5, values: pathGreenBack, ease:Power2.easeOut}}, 'rotateCircles+=0.4')
.to($gMask, 0.3, {rotation:"+=60", transformOrigin: '-9 58', ease:Power2.easeInOut}, 'rotateCircles');
return backToDotsTl;
}
He usado el rotateG
y rotateCircles
etiquetas para colocar a la mayoría de los preadolescentes en esta línea de tiempo exactamente donde yo quería.
Luego, incluí esta función en la línea de tiempo principal y ajusté la hora exacta donde insertarla.
/* Main timeline */
tl.add(getDotsWaveTl())
.add(getDotsRotateTl(), '-=0.35')
.add(getDrawGTl(), '-=1.6')
.add(getBackToDotsTl(), '+=2');
tl.timeScale(1.8);
getBackToDotsTl
se inserta con un retraso de 2 segundos, ('+=2')
, lo que hace que la “G” permanezca completamente completa durante 2 segundos antes de volver a animar a los puntos.
También modifiqué la velocidad final de la animación estableciendo el timeScale
a 1.8
en lugar del predeterminado 1
. Siéntase libre de cambiar el valor para ver la animación a una velocidad diferente.
La última función a mencionar es init()
.
/* Init */
function init(){
TweenLite.set([$gLine,$circles], {autoAlpha: 0});
TweenLite.set($gBlue, {drawSVG:"61% 78%"}); /* start at 71% 78% */
TweenLite.set($gGreen, {drawSVG:"36% 61%"});
TweenLite.set($gYellow, {drawSVG:"17% 36%"});
TweenLite.set($gRed, {drawSVG:"0% 26%"});
TweenLite.set($gRedb, {drawSVG:"78% 100%", transformOrigin: 'center center'});
TweenLite.set($gLineAnim, {autoAlpha: 0});
}
init();
Esta es una función en la que estoy configurando todo, por ejemplo, ocultando algunos elementos, haciendo que los segmentos tengan la longitud correcta, etc.
Utilizo esta función en animaciones GSAP más complejas, como este SVG GreenSock Lab, para obtener el punto de partida correcto que necesito, porque la mayoría de las veces estoy exportando el diseño final o el marco que contiene todos los activos de Illustrator.
En otras palabras, esta función configura el lienzo adecuado para el principio.
¿Por qué utilicé GreenSock?
Ya hay algunos artículos sobre GreenSock en CSS-Tricks, así que supongo que ya conoces sus puntos fuertes. Pero, aquí hay algunas razones por las que elegí esta biblioteca de animación para el trabajo:
- GSAP le brinda un control preciso sobre el tiempo y la duración de interpolaciones y líneas de tiempo individuales
- La API de GSAP ofrece un anidamiento de líneas de tiempo increíblemente flexible
- GSAP corrige muchas inconsistencias entre navegadores cuando se trabaja con SVG
- El control deslizante de jQuery UI le permite desplazarse por la línea de tiempo de GSAP y acelerar el desarrollo
- GSAP le permite concentrarse en la parte creativa de sus proyectos interactivos
- El uso de etiquetas es ideal para líneas de tiempo más complejas.
Conclusión
Sé que algunos de los fragmentos de código y las líneas de tiempo de mi animación pueden parecer abrumadores, así que no dudes en hacer cualquier pregunta en los comentarios a continuación o en Twitter. @ihatetomatoes.