
Hoje eu gostaria de compartilhar com os senhores a facilidade de animação em SVG com as ferramentas que temos disponíveis atualmente. O SVG ainda é um daqueles assuntos que podem assustar muitos desenvolvedores, mas estou aqui para mostrar aos senhores o quanto ele pode ser fácil.
Ao fazer minha pesquisa habitual na Internet em busca de inspiração, deparei-me com o seguinte ótima postagem no From Up North. Como o senhor pode ver, há algumas ilustrações lindas de Miguel Sousa aka Heymikel, Snack Studio, Martín Feijoó & Sara Enríquez. Assim que vi as animações, a primeira coisa que me veio à mente foi como elas poderiam ser transformadas em animações SVG para serem usadas livremente na Internet.
Vamos ao que interessa
Existem algumas implementações diferentes, algumas com foco mais no lado Snap.svg das coisas, e outras também combinando animações Snap.svg e CSS.
Preparação
A primeira parte de qualquer projeto de SVG deve ser dedicada à otimização dos SVGs. Esperamos que, no seu caso, o senhor os tenha criado sozinho ou tenha um bom SVG fornecido pela sua equipe de design. Agora, em vez de colocar o vasto assunto da otimização neste artigo específico, recomendamos que o senhor consulte a seção de otimização. Recomendamos que o senhor consulte este artigo por Sara Soueidan que tem algumas ferramentas excelentes para ajudar o senhor.
A principal coisa que facilitará o trabalho com SVG é ser muito organizado com suas camadas e agrupamentos. Remova todas as camadas não utilizadas e agrupe os elementos que o senhor acha que serão vinculados na animação.
Configurando o Snap.svg
A beleza do Snap.svg é que ele é simples de configurar e nos oferece uma enorme quantidade de funcionalidades prontas para manipular nossos SVGs. A primeira etapa é incluí-lo em nosso projeto; há muitas maneiras de fazer isso, que podem ser encontradas aqui
Inicialização do elemento Snap SVG
// HTML <svg class="hill-valley article"></svg> // JS var s = new Snap('.hill-valley');
Carregar nosso SVG externo
Snap.load('img/hill-valley.svg', function (response) { var hillValley = response; s.append(hillValley); });
Animação de Gotham City
A melhor coisa a fazer com todas as suas animações é primeiro dar um passo atrás e pensar exatamente como o senhor vai implementar a animação e o que precisa acontecer.
Portanto, nessa animação específica, há duas animações principais em andamento: uma é a animação da “luz de morcego” que, se o senhor observar com atenção, também aplica uma máscara de recorte ao texto. A outra é a animação da cena se iluminando em relação à “luz de morcego” que se acende e pisca.
Animação da iluminação da cena
Queríamos mostrar aos senhores como é fácil usar animações CSS ainda para manipular os elementos SVG, por isso decidimos que a iluminação dessa animação seria perfeita para mostrar isso.
Apenas adicionamos classes aos caminhos que desejamos manipular e, em seguida, basta criar animações de quadro-chave. No exemplo de código abaixo, farei isso apenas para o WebKit, mas o senhor deve certificar-se de que tem todos os prefixos de fornecedor corretos.
.gotham__background { -webkit-animation: background-anim 7s infinite linear; } @-webkit-keyframes background-anim { 0%, 10%, 21%, 23%, 25%, 27%, 37%, 55%, 57%, 61%, 63%, 80% { fill: #333738; } 11%, 20%, 22%, 24%, 28%, 36%, 38%, 54%, 56%, 58%, 62%, 64%, 79% { fill: #6D6C6D; } }
Animação de luz de morcego
O componente central da animação de fundo é que aproveitamos ao máximo as máscaras de recorte do SVG. Ou seja, podemos mostrar o texto do título assim que o caminho do clipe passar por cima dele. A animação em si é bastante simples; trata-se apenas de uma rotação e rolagem simultâneas. Aproveitamos os algoritmos de facilitação disponíveis incorporados ao snap.svg. Para obter mais informações sobre o que esses algoritmos fazem, dê uma olhada em CodePen que criei aqui.
Para criar uma máscara de recorte em SVG, precisamos nos certificar de que nosso caminho esteja definido no elemento SVG do caminho de recorte, com um ID anexado a ele. Em seguida, aplicamos o atributo “clip-path” ao elemento que desejamos mascarar e isso define o caminho de recorte. Este é o aspecto desse código:
<clipPath id="b"> <use xlink:href="#a" overflow="visible"/> </clipPath> <g clip-path="url(#b)"></g>
Agora, vamos organizar essa animação:
// rotateElems is the element we wish to rotate rotateElems = s.selectAll('.gotham__rotate') rotateElems.animate({ transform: 'r0,250,453 s1,1' }, 1500, mina.elastic);
Porto Real
A animação de Kings Landing tem alguns pequenos truques para fazer com que algumas das animações pareçam mais realistas. Vamos falar sobre isso mais adiante. Por enquanto, vamos ver como criamos a animação da nuvem e como usamos o snap.svg para adicionar elementos extras de forma dinâmica.
Animação de nuvens
A beleza do SVG é que ele nos permite reutilizar elementos rapidamente. Seja um grupo, um caminho ou uma forma, ele pode até mesmo permitir que o senhor faça referência a recursos externos (os recursos externos têm menor suporte no navegador). Para isso, usamos a função use
que simplesmente faz referência a outros objetos na página usando o elemento xlink:href
.
Um aspecto a ser observado é que, se o senhor tiver atributos de preenchimento ou traçado no caminho original, eles também estarão em todos os elementos, independentemente do que tiver definido no elemento de uso. Portanto, se o senhor quiser reutilizar partes e ter atributos individuais nelas, é melhor não aplicar nenhum ao elemento mestre e aplicar somente aos elementos individuais.
Como vamos animar as nuvens em vários tamanhos e posições, é melhor deixar que o snap.svg gerencie esse processo em vez de codificá-lo no SVG. Tudo o que fazemos no SVG é criar o caminho da nuvem a ser copiado usando o elemento ‘use’.
O seguinte cria uma quantidade definida de nuvens em um layout aleatório, com uma escala arbitrária:
var containerHeight = s.node.offsetHeight / 4, numberOfClouds = 10; // Gets the width of the container cloudWidth = s.select('#a').getBBox().w; // Creates a group element clouds = s.g(); // Loop to create clouds for (var i = numberOfClouds; i >= 0; i—) { /** x is a random number between 0 and the container width y is a random number between 0 and our container height newCloud creates a use element referencing our cloud path randomScale is a random number between 0.2 and 0.9 **/ var x = Math.floor(Math.random() * cloudWidth), y = -Math.floor(Math.random() * containerHeight), newCloud = cloud.use(), randomScale = Math.random() * (0.9 - 0.2) + 0.2; // Applies our new attributes to the use element newCloud.attr({ x: x, y: y, transform: 's' + randomScale }); // Adds the use element to our group clouds.add(newCloud); }
Animar ao longo de um caminho
Uma coisa que o snap.svg não faz de imediato é fornecer um método que permita ao senhor animar um determinado caminho. No entanto, isso não é um grande problema, pois podemos utilizar o método Snap.animate, que nos permite manipular a animação quadro a quadro.
Tudo o que precisamos fazer agora é obter o caminho que desejamos animar. Em seguida, com um pouco de código, obtenha seus pontos em cada quadro da animação e aplique-os ao elemento que está sendo animado. Aqui está a função:
/** path is the path we wish with to animate along element is the element we want to animate start is the frame we wish to start the animation on dur is the duration in milliseconds callback is a function we wish to call once the animation has finished **/ animateAlongPath = function (path, element, start, dur, callback) { // Get the path length, so we know how many frames we will animate over var len = Snap.path.getTotalLength(path); Snap.animate(start, len, function (value) { // movePoint gets the path attributes at a certain frame var movePoint = Snap.path.getPointAtLength(path, value); // applies the attributes to our element element.attr({ cx: movePoint.x, cy: movePoint.y }); }, dur, mina.easeinout, function () { callback(path); }); };
Hill Valley
A animação para o Hill Valley SVG tem quatro componentes principais; com essa animação específica, usaremos os algoritmos de facilitação fornecidos pelo Snap.svg.
Animação de carro
Essa animação é apenas uma simples translação combinada com uma rotação. A única coisa que a torna mais complexa é a facilidade, que pode fazer com que ela pareça difícil de ser realizada.
/** car is our SVG car element carStartMatrix and carMidMatrix initialises our Snap Matrix **/ var car = s.select('.car'), carStartMatrix = new Snap.Matrix(), carMidMatrix = new Snap.Matrix(); // Sets up the matrix transforms carStartMatrix.rotate(10); carStartMatrix.translate(0,-50); carMidMatrix.rotate(-15); carMidMatrix.translate(300,-20); car.animate({ transform: carStartMatrix }, 1250, mina.easeinout, function () { car.animate({ transform: carMidMatrix }, 250); });
Animação de árvores
A animação da árvore é uma animação de rotação em duas partes para obter uma curvatura mais realista durante a animação. Se as folhas fossem da mesma cor, poderíamos ter usado uma transformação de caminho para a animação, mas, no nosso caso, a animação em duas partes foi a melhor opção.
É um conceito bastante simples, tudo o que fazemos é animar a árvore inteira em uma pequena quantidade e, ao mesmo tempo, animar ainda mais as folhas da árvore. Também podemos tirar o máximo proveito dos excelentes algoritmos de facilitação incorporados ao snap.svg. Veja como fazer isso:
/** leaves are the leaves element we want to rotate leavesDim is the bounding box dimension of leaves tree is the tree element we want to rotate treeDim is the bounding box dimension of the tree **/ var leaves = s.select('leaves'), leavesDim = leaves.getBBox(); leaves.animate({ transform: 'r25,' + (leavesDim.x + (leavesDim.width / 2)) + ',' + (leavesDim.y + leavesDim.height) }, 20, mina.easeinout, function (){ // This animation triggers once the other has finished leaves.animate({ transform: 'r0,' + (leavesDim.x + (leavesDim.width / 2)) + ',' + (leavesDim.y + leavesDim.height) }, 1000, mina.elastic); }); tree.animate({ transform: 'r8,' + (treeDim.x + (treeDim.width / 2)) + ',' + (treeDim.y + treeDim.height) }, 20, function () { // This animation triggers once the other has finished tree.animate({ transform: 'r0,' + (treeDim.x + (treeDim.width / 2)) + ',' + (treeDim.y + treeDim.height) }, 1000, mina.elastic); });
Animação do relógio
A animação do relógio é uma operação relativamente simples. O único cuidado que o senhor deve ter com as rotações é que, se ele girar 360 graus ou mais e, em seguida, for aplicada uma nova rotação, a animação seguirá na direção errada.
O senhor pode ver isso em nossa rotina de animação a seguir; vamos supor que essa linha de código esteja sendo chamada em um loop. Como o senhor pode ver, redefinimos a transformação rotacionada, de modo que a animação continua sendo redefinida.
var s.select('.minute'); // Resets to 0 clockMinute.transform('r0,195.5,105.5'); // Animates 360 degrees around the point 195.5,105.5 over 1250 ms clockMinute.animate({ transform: 'r90,195.5,105.5' },1250)
Animação de texto
A estrutura para a animação de texto é relativamente simples; apenas criamos cinco elementos de “uso” que fazem referência ao texto principal. Em seguida, na fila, acionamos uma animação que traduz todos os elementos linearmente para o canto superior direito do elemento de texto inicial.
/** textiles selects all of the .text elements, this is stored as an array amount is the max translation value divided by text elements on the page **/ var textElems = s.selectAll('.text'), amount = 20/textElems.length; // Loops through each element for (var i = 1; i < textElems.length; i++) { // Initiates the animation to translate to the correct position textElems[i].animate({ 'transform': 't' + (amount * i) + ',-' + (amount * i) }, 200, mina.easeinout); };
Esperamos que isso tenha lhe dado uma ideia de como é fácil animar SVG e criar imagens impressionantes. Se tiver alguma dúvida, não hesite em entrar em contato por meio dos links abaixo. O bom da animação em SVG é que ela funciona em todos os navegadores modernos e no IE9 em diante. Como o senhor verá nas minhas animações acima, em que uso animação de quadro-chave do CSS, basta usar snap.svg para fazer o mesmo.