Pular para o conteúdo principal

Animações de Carregamento: Janeiro

· Leitura de 11 minutos

Primeira das doze animações.


Animações de Carregamento (série de 10 partes)
  1. Introdução
  2. Janeiro
  3. Fevereiro
  4. Março
  5. Abril
  6. Maio
  7. Junho
  8. Julho
  9. Agosto
  10. Setembro

Animação

Resultado final:

Introdução

Criei essa animação com SVG, seguindo essa estrutura:

<!-- definições de tamanho --><svg>  <defs>    <!-- caminho que o círculo percorre -->    <path />  </defs>  <!-- plano de fundo -->  <rect />  <!-- desenho do caminho que o círculo percorre, para debug -->  <path />  <!-- círculo -->  <ellipse>    <!-- animação que faz o círculo percorrer o caminho -->    <animateMotion>      <mpath />    </animateMotion>    <!-- animação que estica o círculo horizontalmente -->    <animate />    <!-- animação que estica o círculo verticalmente -->    <animate />    <!-- animação que rotaciona o círculo -->    <animateTransform />  </ellipse></svg>

Como funciona

info

Omiti alguns elementos e atributos nos blocos a seguir para manter a explicação concisa.

Tamanho

Aqui defini que a animação tem 200 pixels de largura e altura no elemento svg.

Com um elemento rect, defini o plano de fundo branco com borda cinza e cantos arredondados. O stroke é desenhado centralizado na borda do rect, ou seja, metade dentro e metade fora. Como defini strokeWidth de 1 pixel, para que metade do stroke não ficasse cortada, subtraí 1 pixel de width (0,5 pixels da esquerda e da direita) e height (0,5 pixels de cima e de baixo) e movi 0,5 pixels nos eixos x e y. Dessa forma, a borda não é cortada pelos limites de altura e largura definidos no elemento svg.

Resultado



Código

<svg  xmlns="http://www.w3.org/2000/svg"  viewBox="0 0 200 200"  width="200"  height="200">  <rect    width="199"    height="199"    x="0.5"    y="0.5"    fill="white"    stroke="lightgray"    strokeWidth="1"    rx="6"  /></svg>

Caminho

Dentro de defs, defini o path que será o caminho que o círculo percorre. Ele será referenciado pelo seu id, motion-path. O caminho é uma curva quadrática definida usando o comando Q.

Depois do rect, que é o plano de fundo, defini outro path para visualizar o caminho, visto que o que é definido dentro de defs não é renderizado. Esse path é removido na conclusão da animação.

Resultado



Código

<svg>  <defs>    <path id="motion-path" d="M50,150 Q100,0 150,150" />  </defs>  <rect></rect>  <path    d="M50,150 Q100,0 150,150"    fill="none"    stroke="lightgray"    strokeWidth="1"  /></svg>

Círculo e suas animações

info

A duração final da animação é de um segundo e meio. Nesta seção as animações têm duração de 10 segundos para ficarem mais evidentes.

Animação que percorre o caminho

Inicialmente, criei a animação que define o ciclo de ida e volta do círculo.

Defini o círculo com um elemento ellipse, pois ele permite definir o raio nos eixos x e y separadamente. Usei os raios diferentes para deformar o círculo durante a animação. O elemento mpath referencia o path#motion-path, enquanto o elemento animateMotion define a animação.

No elemento animateMotion, defini os atributos da seguinte forma:

  • repeatCount="indefinite": a animação repete indefinidamente.
  • dur="10000ms": a duração é de 10 segundos para os exemplos.
  • calcMode="spline": para poder usar curvas de Bézier no atributo keySplines.
  • keyTimes: Define em quais momentos específicos durante a duração da animação os keyPoints ocorrerão, varia de 0 a 1. Nesse caso, defini três momentos: 0, que é o início; 0.5; que é o meio; 1, que é o fim.
  • keyPoints: Define onde o círculo deve estar ao longo do caminho, varia de 0 a 1. Defini três posições para cada momento do keyTimes: 0, que é o início do caminho, 1 que é o final do caminho; 0, que volta ao início do caminho. Ou seja, no primeiro momento a posição é o início do caminho, no segundo é o final, e no terceiro é o início novamente, completando o ciclo de animação.
  • keySplines: Define curvas de Bézier para suavizar a progressão entre keyPoints. Defini a mesma curva na ida e na volta: x1 = 0.2, y1 = 0.6, x2 = 0.7 e y2 = 0.4 (visualização em cubic-bezier.com). É uma curva ligeiramente mais rápida no início, mais lenta no meio, e que acelera novamento no final. Dessa forma, o círculo se move rapidamente nos pontos de impacto, enquanto se move mais lentamente quando está no ar.

Resultado



Código

<svg>  <defs></defs>  <rect />  <path />  <ellipse rx="8" ry="8" fill="black">    <animateMotion      repeatCount="indefinite"      dur="10000ms"      calcMode="spline"      keyTimes="0; 0.5; 1"      keyPoints="0; 1; 0"      keySplines="0.2,0.6,0.7,0.4; 0.2,0.6,0.7,0.4"    >      <mpath href="#motion-path" />    </animateMotion>  </ellipse></svg>

Animações que esticam

Em seguida, fiz as animações que distorcem o círculo de alguma forma.

Animando rx

Para transmitir a ideia de impacto, criei uma animação que estica o círculo horizontalmente quando ele atinge o chão.

No elemento animate, defini os atributos da seguinte forma:

  • attributeName="rx": representa o raio no eixo x.
  • repeatCount="indefinite": a animação repete indefinidamente.
  • dur="10000ms": a duração é de 10 segundos para os exemplos.
  • calcMode="spline": para poder usar curvas de Bézier no atributo keySplines.
  • keyTimes: Define em quais momentos específicos durante a duração da animação os values serão assumidos pelo atributo attributeName, varia de 0 a 1. Nesse caso, defini cinco momentos: 0, que é o início do arco; 0.25, que é o topo do arco; 0.5, que é o fim do arco; 0.75, que é o topo do arco novamente; 1, que é o início do arco novamente.
  • values: Define os valores que o atributo attributeName assumirá. Defini cinco valores para cada momento do keyTimes: 10 no início do arco; 8 no topo do arco; 10 no fim do arco; 8 no topo do arco novamente; 10 no início do arco novamente. Ou seja, o raio aumenta para 10 no início e fim do arco, e volta para 8 nos outros momentos.
  • keySplines: Define curvas de Bézier para suavizar a progressão entre values. Defini as mesmas duas curvas na ida e na volta:
    • x1 = 0, y1 = 1, x2 = 1 e y2 = 1 (visualização em cubic-bezier.com). É uma curva veloz no início e que desacelera na metade para o final. Dessa forma, o valor vai de 10 a 8 de forma rápida na primeira metade da curva.
    • x1 = 1, y1 = 0, x2 = 1 e y2 = 0 (visualização em cubic-bezier.com). É uma curva vagarosa no início e que acelera bastante no final. Dessa forma, o valor vai de 8 a 10 de forma rápida apenas no fim da curva.
    • Dessa forma, o círculo se deforma rapidamente nos pontos de impacto, enquanto volta ao normal quando está no ar.

Apenas rx animado



Animando ry

Para transmitir a ideia de velocidade, criei uma animação que estica o círculo verticalmente quando ele está em movimento no ar. Porém, essa animação não leva em conta a trajetório do círculo, isso é resolvido na próxima seção.

No elemento animate, defini os atributos da seguinte forma:

  • attributeName="ry": representa o raio no eixo y.
  • repeatCount="indefinite": a animação repete indefinidamente.
  • dur="10000ms": a duração é de 10 segundos para os exemplos.
  • calcMode="spline": para poder usar curvas de Bézier no atributo keySplines.
  • keyTimes: Define em quais momentos específicos durante a duração da animação os values serão assumidos pelo atributo attributeName, varia de 0 a 1. Nesse caso, defini cinco momentos: 0, que é o início do arco; 0.25, que é o topo do arco; 0.5, que é fim do arco; 0.75, que é o topo do arco novamente; 1, que é o início do arco novamente.
  • values: Define os valores que o atributo attributeName assumirá. Defini cinco valores para cada da momento do keyTimes: 8 no início do arco; 8.6 no topo do arco; 8 no fim do arco; 8.6 no topo do arco novamente; 8 no início do arco novamente. Ou seja, o raio aumenta para 8.6 enquanto o círculo está no topo do arco, e volta para 8 nos outros momentos.
  • keySplines: Define curvas de Bézier para suavizar a progressão entre values. Defini as mesmas duas curvas na ida e na volta:
    • x1 = 0, y1 = 1, x2 = 0.5 e y2 = 1 (visualização em cubic-bezier.com). É uma curva veloz no início e que desacelera mais para o final. Dessa forma, o valor vai de 8 a 8.6 de forma rápida.
    • x1 = 1, y1 = 0, x2 = 1 e y2 = 0 (visualização em cubic-bezier.com). É uma curva vagarosa no início e que acelera bastante no final. Dessa forma, o valor vai de 8.6 a 8 de forma rápida apenas no fim da curva.
    • Dessa forma, o círculo se deforma ligeiramente enquanto está no ar.

Apenas ry animado



Resultado



Código

<svg>  <defs></defs>  <rect />  <path />  <ellipse>    <animateMotion></animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="10000ms"      calcMode="spline"      values="10; 8; 10; 8; 10"      keyTimes="0; 0.25; 0.5; 0.75; 1"      keySplines="0,1,1,1; 1,0,1,0; 0,1,1,1; 1,0,1,0"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="10000ms"      calcMode="spline"      values="8; 8.6; 8; 8.6; 8"      keyTimes="0; 0.25; 0.5; 0.75; 1"      keySplines="0,1,0.5,1; 1,0,1,0; 0,1,0.5,1; 1,0,1,0"    />  </ellipse></svg>

Animação que rotaciona

Em seguida, fiz a animação que rotaciona o círculo para que a animação do atributo ry siga a trajetória correta.

No elemento animateTransform, defini os atributos da seguinte forma:

  • attributeName="transform": atributo de transformação.
  • repeatCount="indefinite": a animação repete indefinidamente.
  • dur="10000ms": a duração é de 10 segundos para os exemplos.
  • type="rotate": tipo rotação.
  • keyTimes: Define em quais momentos específicos durante a duração da animação os values serão assumidos pelo atribute attributeName, varia de 0 a 1. Nesse caso, defini três momentos: 0, que é o início; 0.5, que é o meio; 1, que é o fim.
  • values: Define os valores que o atributo attributeName assumirá. Defini três valores para cada da momento do keyTimes: 0, sem rotação; 180, meia volta; 0, sem rotação novamente. Ou seja, no intervalo em que o círculo se movimenta entre um extremo e outro do arco, o círculo completa meia volta.
  • Não é necessário definir calcMode e keySplines, visto que a animação é linear.

Resultado



Código

<svg>  <defs></defs>  <rect />  <path />  <ellipse>    <animateMotion></animateMotion>    <animate />    <animate />    <animateTransform      attributeName="transform"      repeatCount="indefinite"      dur="10000ms"      type="rotate"      values="0; 180; 0"      keyTimes="0; 0.5; 1"    />  </ellipse></svg>

Conclusão

Foi uma animação divertida de criar, pois me permitiu explorar novas técnicas com SVG. Ainda não tinha tido a oportunidade de usar os elementos animateMotion, animateTransform e mpath, que são fundamentais para criar movimentos mais fluidos e dinâmicos. O elemento animateMotion, por exemplo, foi essencial para fazer com que o círculo seguisse uma trajetória de maneira simples.

Durante o processo, aprendi mais sobre o funcionamento das curvas de Bézier no atributo keySplines, o que me proporcionou um controle mais preciso sobre a aceleração e desaceleração das animações, permitindo criar transições mais naturais. Um dos desafios foi ajustar esses valores para obter um movimento orgânico, e a experimentação com diferentes curvas foi essencial para alcançar a animação que eu tinha em mente.

Além disso, estudar essas técnicas ampliou minha compreensão do SVG como um todo, o que certamente será útil para as próximas postagens.

Resultado



Código

<svg  xmlns="http://www.w3.org/2000/svg"  viewBox="0 0 200 200"  width="200"  height="200">  <defs>    <path id="motion-path" d="M50,150 Q100,0 150,150" />  </defs>  <rect    width="199"    height="199"    x="0.5"    y="0.5"    fill="white"    stroke="lightgray"    strokeWidth="1"    rx="6"  />  <ellipse rx="8" ry="8" fill="black">    <animateMotion      repeatCount="indefinite"      dur="1500ms"      calcMode="spline"      keyTimes="0; 0.5; 1"      keyPoints="0; 1; 0"      keySplines="0.2,0.6,0.7,0.4; 0.2,0.6,0.7,0.4"    >      <mpath href="#motion-path" />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="1500ms"      calcMode="spline"      values="10; 8; 10; 8; 10"      keyTimes="0; 0.25; 0.5; 0.75; 1"      keySplines="0,1,1,1; 1,0,1,0; 0,1,1,1; 1,0,1,0"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="1500ms"      calcMode="spline"      values="8; 8.6; 8; 8.6; 8"      keyTimes="0; 0.25; 0.5; 0.75; 1"      keySplines="0,1,0.5,1; 1,0,1,0; 0,1,0.5,1; 1,0,1,0"    />    <animateTransform      attributeName="transform"      repeatCount="indefinite"      dur="1500ms"      type="rotate"      values="0; 180; 0"      keyTimes="0; 0.5; 1"    />  </ellipse></svg>

Leitura recomendada