DÍA 3

Animando SVG con VelocityJS

A la hora de animar SVG nos encontramos con el poco éxito de SMIL y las limitaciones de CSS3, pero nos queda toda la potencia de JavaScript. En este artículo vamos a ver VelocityJS, una de las librerías más potentes para animar SVG.


Antes de entrar en materia vamos a enumerar y explicar un poco las diferentes opciones que tenemos a la hora de animar SVG.

SMIL

A nuestra disposición tenemos el método nativo para animar SVG, que es SMIL. Por desgracia ninguna de las últimas versiones de Internet Explorer han dado soporte a SMIL. Aunque esto no siempre fue así y versiones inferiores dieron soporte a SMIL 2.0. En el futuro Chrome dejara de dar soporte a SMIL, así que por desgracia y contra mi voluntad mi opinión es que no invirtáis vuestro tiempo en aprenderlo. Aún así, si todavía tenéis interés, en su día hablamos sobre SMIL en un Hangout de DesarrolloWeb. Y aquí unos cuantos ejemplos de lo que podemos hacer con SMIL SVG animation with SMIL.

CSS3

También podemos animar SVG con CSS3. El soporte en Internet Explorer es a partir de IE10, hay que tener en cuenta que no las transformaciones no tienen soporte en Internet Explorer, tampoco en Edge. Otro método que tampoco recomiendo por todas las contras que nos encontramos. También estuvimos hablando sobre animaciones CSS3 sobre SVG en otro Hangout de DesarrolloWeb.

JavaScript

Tenemos varias librerías para animar SVG con JavaScript. Lo primero que vamos a ver es lo que está preparando la W3C para el futuro sobre el tema de las animaciones. Su idea es juntar lo mejor de SMIL con CSS3 en una nueva especificación de animaciones llamado WebAnimations, la cosa todavía esta muy verde. Y solamente Chrome/Opera y Firefox soportan alguna propiedad en sus versiones experimentales como Chrome Canary y FirefoxDeveloper. Aquí tenéis unos cuantos ejemplos de WebAnimations.

Ahora vamos a ver SNAP.SVG, predecesora de la famosa librería RaphaëlJS, y desarrollada en gran parte por Dmitry Baranovskiy y Adobe. También estuvimos hablando sobre ella en un Hangout de DesarrolloWeb.

Otra librería para animar SVG con JS es SVG.JS. Unos buenos ejemplos de lo que podemos hacer con SVG.JS Hulk SVG Animation Draggable Polygon SVG. Más demos en CodePen.

Por último una librería que últimamente se esta usando mucho es GSAP. Aquí unos cuantos ejemplos de lo que podemos hacer con GSAP GSAP SVG Animations.

VelocityJS

VelocityJS es una librería creada por Julian Shapiro con la que podemos crear animaciones de color, transformaciones, loops, easings, scroll y lo que nos importa en este artículo, animar SVG. Como habéis podido leer tenemos varias posibilidades además de animar SVG, lo cual hace que en mi modesta opinión sea mi librería favorita para animar después de dejar de usar SMIL.

Antes de nada y si nunca antes había oído hablar de VelocityJS te recomiendo que le eches un ojo a la amplia y bien explicada documentación, sobre todo a la lista de propiedades de SVG que podemos animar con VelocityJS, y que es lo que vamos a ver a continuación. Y también que le eches un vistazo a la colección de demos que hay en CodePen Velocity.js: The Official Collection.

SVG

Vamos a crear una animación con simplemente cuatro líneas creadas con SVG y con el logo de Octuweb.

Lo primero que vamos a hacer es crear nuestro documento SVG con un width de 1200px y un height de 600.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 600">
//Aquí ira el código del SVG
</svg>

Ahora vamos a crear cuatro líneas que son las que más adelante vamos a animar. Para crear una línea en SVG tenemos cuatro coordenadas. La primera de ellas x1 pertenece a la coordenada horizontal y determina el punto desde el que comenzará la línea a lo largo de la coordenada horizontal. La segunda de ellas y1 pertenece a la coordenada vertical y determina el punto desde el que comenzará la línea a lo largo de la coordenada vertical. La tercera de ellas es x2 pertenece a la coordenada horizontal y determina el punto en el que terminará la línea. La última de ellas es y2 pertenece a la coordenada vertical y determina el punto en el que terminará la línea. Vamos a jugar con el stroke-width de las líneas, que corresponde al grosor de la línea, vamos a darle a todas 1px de grosor. Con el stroke-linecap=”round” le decimos que tanto el principio como el final de las líneas sea redondeado.

<line id="primera" x1="600" y1="0" x2="600" y2="0" stroke="#EB6060" stroke-width="1" stroke-linecap="round"/>

A la primera línea le damos un id=”primera”, para así luego poder jugar con ella con VelocityJS. Vamos con las medidas, le indicamos a través de x1 y x2 que empiece y termine en 600px en su coordenada horizontal y en 0px en su coordenada vertical. Así que la línea estará situada en la mitad de la parte superior del SVG.

<line id="segunda" x1="1200" y1="300" x2="1200" y2="300" stroke="#4C6B8E" stroke-width="1" stroke-linecap="round"/>

A la segunda línea le damos un id=”segunda”. Y la vamos a posicionar en su coordenada horizontal en 1200px. En su coordenada vertical la situamos en 300px. Así que la línea estará situada en la mitad de la parte derecha del documento.

<line id="tercera" x1="0" y1="0" x2="0" y2="0" stroke="#109DA9" stroke-width="1" stroke-linecap="round"/>

A la tercera línea le damos un id=”tercera”. Y la vamos a posicionar en su coordenada horizontal en 0px. En su coordenada vertical la situamos en 0px. Así que la línea estará situada al principio de la parte superior del documento.

<line id="cuarta" x1="0" y1="600" x2="0" y2="600" stroke="#F0E6BE" stroke-width="1" stroke-linecap="round"/>

A la cuarta línea le damos un id=”cuarta”. Y la vamos a posicionar en su coordenada horizontal en 0px. En su coordenada vertical la situamos en 600px. Así que la línea estará situada al principio de la parte inferior del documento.

Ahora vamos a incluir el logo de Octuweb. También añadimos un botón con la clase class=”logo-boton” y lo vamos a meter todo dentro de un div que tendrá un id=”contenedor-logo”. Lo vamos a ocultar con un display: none;.

<div id="contenedor-logo">
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="175.2" height="200" viewBox="0 0 175.2 200">
    <g id="letras" transform="translate(0, 20)">
        <path id="OCTUWEB" fill="#EC6160" d="M27,124.9c0-16.5-24.5-16.5-24.5,0S27,141.4,27,124.9L27,124.9z M8.8,124.9c0-8.6,11.9-8.6,11.9,0C20.7,133.5,8.8,133.5,8.8,124.9L8.8,124.9z M30.1,124.8c0,8.1,6.2,12.2,12.3,12.2 c5.1,0,10.4-2.7,11.3-9.4h-6c-0.6,2.5-2.7,3.8-5.3,3.8c-3.6,0-5.9-3.1-5.9-6.6c0-3.9,2.3-6.6,5.9-6.6c2.5,0,4.4,1.1,5.2,3.5h6
            c-0.9-6.4-6.3-9.1-11.2-9.1C36.3,112.6,30.2,116.7,30.1,124.8L30.1,124.8z M61.9,118.4v18.3h6v-18.3h5.8v-5.5H56v5.5H61.9z M86.8,131.6c-1.8,0-3.7-1-3.7-2.9l0-15.8h-5.8v15.9c0,5.2,4.6,8.3,9.5,8.3c4.9,0,9.4-3.1,9.4-8.3l0-15.9h-5.8v15.8 C90.4,130.6,88.6,131.6,86.8,131.6L86.8,131.6z M114,113.3l-4,12.6h-0.1l-1.1-4l-3.1-9h-6.2v0.9L108,137h3.4l3.8-11.5h0.1l3.8,11.5 h3.5l8.3-23.2v-0.9h-6.1l-3,9l-1.1,4h-0.1l-4.1-12.6H114z M149.4,112.9h-14.9v23.8h15.2v-5.4h-9.1v-4.2h8.1v-5.4h-8.1v-3.3h8.8 V112.9z M172.6,120.2c0-4.1-3.3-7.3-7.4-7.3H155v23.8h11.2c4.9,0,7.4-3.3,7.5-7.5c0-2.1-0.9-3.9-2.9-4.9 C171.9,123.4,172.6,121.7,172.6,120.2L172.6,120.2z M165.7,127.3c2.5,0,2.5,4,0,4h-4.8v-4H165.7z M164.7,118.4c2.5,0,2.4,3.8,0,3.8 h-3.8v-3.8H164.7z"
/>
    </g>
    <g id="logo">
        <g id="icono" transform="translate(45, 20)">
            <g id="octogono">
                <polygon id="Polygon-1" fill="none" stroke="#EC6160" stroke-width="2" points="43,2.5 71.6,14.4 83.5,43 71.6,71.6 43,83.5 14.4,71.6 2.5,43 14.4,14.4"/>
                <polygon id="Polygon-2" fill="#EC6160" stroke="#fff" stroke-width="0.9" points="43.1,6.6 68.9,17.3 79.6,43.1 68.9,68.9 43.1,79.6 17.3,68.9 6.6,43.1 17.3,17.3"/>
            </g>
            <path id="O" fill="#fff" d="M62.6,43.2c0-26.5-39.3-26.5-39.3,0C23.3,69.7,62.6,69.7,62.6,43.2L62.6,43.2z M28.1,43.2 c0-20.6,29.7-20.6,29.7,0C57.8,63.7,28.1,63.7,28.1,43.2L28.1,43.2z M57.3,43.2c0-19.6-28.6-20-28.6,0 C28.7,63.2,57.3,62.8,57.3,43.2L57.3,43.2z M33.4,43.2c0-13.8,19.2-13.8,19.2,0C52.6,57.1,33.4,57.1,33.4,43.2L33.4,43.2z"/>
        </g>
    </g>
    </svg>
    <button class="logo-boton">
        <span class="logo-boton-texto">23 DIAS | 23 AUTORES</span>
    </button>
</div>

Ahora que ya tenemos toda la estructura montada, vamos a comenzar a animar.

Antes de nada vamos a añadir VelocityJS y jQuery en el HTML y también vamos a crear un archivo que llamaremos animacion.js donde vamos a ir incluyendo el código de la animación. A continuación el orden.

<script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="js/velocity.min.js"></script>
<script src="js/animacion.js"></script>

Lo primero vamos a crear variables con los selectores de las líneas y con los divs que vamos a animar.

var primera = $("#primera");
var segunda = $("#segunda");
var tercera = $("#tercera");
var cuarta = $("#cuarta");

var grupoLineas = primera.add(segunda).add(tercera).add(cuarta);

var contenedor = $("#contenedor-logo");
var botonLogo = $(".logo-boton");

A continuación vamos a crear la primera function que vamos a llamar animacionLineas.

function animacionLineas(){
//Código de la función
}

Vamos a animar la primera línea:

$(primera)
    // Primero vamos a retrasar el comienzo de la animación 200ms
    .delay(200)
    // Llamamos a la librería
    .velocity({
        // Aquí le indicamos la propiedad que queremos animar, en este caso y2, la cúal llevara el final de la línea hasta los 600px, recordad que esta línea le hemos dicho que comience en la coordenada 0px
        y2: 600
    }, {
        //Aquí le indicamos la duración, en este caso 1000ms
        duration: 1000,
        //El tipo de easing que vamos a darle a la animación
        easing: "spring"
    })
    //Una vez completada la primera parte, vamos a volver a darle un delay de 150ms
    .delay(150)
    .velocity({
        // Aquí vamos a animar la propiedad strokeWidth, le habiamos indicado que tuviera 1px de grosor, ahora vamos a decirle que lo amplie hasta 1500px
        strokeWidth: 1500

Ya tenemos la primera animación, la línea va desde la parte superior hasta la inferior, y cuando completa el camino se expande a lo ancho del documento. Podéis ver el resultado en CodePen.

Aquí podéis ver los diferentes easings que podemos utilizar con VelocityJS.

Vamos con la segunda línea:

$(segunda)
    .delay(200)
    .velocity({
        // Ahora vamos a animar la coordenada x2, recordad que le indicamos que comenzara en 1200
        x2: 0
    }, {
        duration: 1000,
        easing: "swing"
    })
    .delay(50)
    .velocity({
        strokeWidth: 1500,

Ya tenemos la segunda animación, la línea va desde la mitad del final del documento hasta el comienzo, y cuando completa el camino se expande a lo alto del documento. Podéis ver el resultado en CodePen.

Vamos a por la tercera línea:

$(tercera)
    .delay(200)
    .velocity({
        //Ahora vamos a animar dos coordenadas, a esta línea le indicamos que todas sus coordenadas estuvieran posicionadas en 0, es decir en la esquina superior izquierda.
        x2: 1200,
        y2: 600
    }, {
        duration: 1000,
        easing: "spring"
    })
    .delay(50)
    .velocity({
        strokeWidth: 1500,

Ya tenemos la tercera animación, la línea va desde la esquina superior izquierda hasta la esquina inferior derecha y cuando completa el camino se expande a lo largo y ancho del documento. Podéis ver el resultado en CodePen.

Vamos a por la cuarta animación:

$(cuarta)
    .delay(200)
    .velocity({
    //Vamos a volver a animar dos coordenadas para obtener un resultado parecido al anterior. Esta línea esta ubicada en la parte superior derecha del documento.
        x2: 1200,
        y2: 0
    }, {
        duration: 1000,
        easing: "swing"
    })
    .delay(50)
    .velocity({
        strokeWidth: 1500,
        complete: function() {
            $("#contenedor-logo")
                .show(300)
        }
    });

Ya tenemos la última animación de las líneas, en esta ocasión la línea va desde la esquina superior derecha hasta la esquina inferior izquierda y cuando completa el camino se expande a lo largo y ancho del documento. Podéis ver el resultado en CodePen.

Cuando acabe esta animación vamos a mostrar con .show() el contenedor que ocultamos con CSS.

$(contenedor)
    .show(300)

Ya hemos terminado la primera y la más larga de las funciones. En el código que podéis ver en GitHub he concatenado las animaciones de las líneas a través de la propiedad complete. En el artículo las he ido troceando para que se entienda de la mejor forma posible.

Ahora vamos a darle un poco de vida al logo de Octuweb. Para ello primero vamos a crear la function botonHover. Cuando el usuario haga hover en el botón el logo de Octuweb girará sobre si mismo y se ampliará de tamaño.

Tip: Cuando vayamos a utilizar transformaciones hay que recordar que en SVG estas se aplican sobre el eje (0,0), es decir en la esquina izquierda, y no desde el centro, lo que genera unas cuantas horas de diversión. Para aplicar la transformación y que el objeto rote sobre si mismo vamos a utilizar la propiedad de CSS transform-origin: 50% 50%; pero Firefox no se lleva bien con ella, así que le tenemos que pasar el valor en px.
function botonHover() {
    $(botonLogo).hover(function() {
        $(logo).velocity({
            //rotamos el logo 360grados
            rotateZ: 360,
            //Aumentamos su tamaño 1.5
            scale: 1.5
        }, {
            duration: 500,
            //Con el loop hacemos que el logo gire 360 grados y vuelva a su posición original. Lo mismo con scale, va a 1.5 y luego vuelve a su escala original. Mucho ojo y no abuséis del loop!
            loop: 1
        })
    });
}

Aquí podéis ver el resultado en CodePen.

Ahora vamos con el toque final. Cuando el usuario haga click vamos a mandar a las líneas a su estado original, haremos desaparecer el logo y el botón, y por último mandaremos al usuario a la web de Octuweb.

Vamos a crear la function botonClick.

function botonClick() {
    $(botonLogo).click(function() {
        //Vamos a actuar sobre todas las líneas
        $(grupoLineas).velocity({
                //Vamos a reducir el grosor de las líneas de 1500px a 1px
                strokeWidth: 1,
                //Mandamos todas las coordenadas x2 de las líneas a la coordenada 0. Esto como vais a ver a continuación no afectará a todas las líneas
                x2: 0
            }, {
                duration: 750
            })
            .delay(25)
            .velocity({
                //Ahora vamos a actuar sobre las dos líneas que todavía se han quedado a la vista
                y2: 0,
                x1: 0
            }, {
                duration: 500
            });
        $(contenedor).delay(1500)
            .velocity({
                //Y ya por último vamos a reducir la escala del contenedor a 0 y mandamos al usuario a la web original :)
                scale: 0
            }, {
                duration: 500,
                easing: "spring"
            });
    });
}

Y aquí el resultado final.

La colección con todas las demos en CodePen y el código para trastear en GitHub.