Pular para o conteúdo principal

Animações de Carregamento: Dezembro

· Leitura de 11 minutos

Última das doze animações.


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

Animação

É a animação de uma bandeira tremulando.

Resultado final:

Introdução

Criei esta animação em SVG, seguindo uma estrutura semelhante às anteriores:

<!-- definições de tamanho --><svg>  <!-- plano de fundo -->  <rect></rect>  <!-- doze círculos que se movem -->  <circle>    <!-- animação que move o círculo -->    <animateMotion></animateMotion>  </circle></svg>

Como funciona

info

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

Tamanho

Mantive o mesmo tamanho usado nas animações anteriores.

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

A animação utiliza doze caminhos dispostos em 3 linhas e 4 colunas. Os calculei da seguinte forma:

const WIDTH = 200;const HEIGHT = 200;const MARGIN_X = WIDTH * 0.31;const MARGIN_Y = HEIGHT * 0.37;const ROW_COUNT = 3;const COL_COUNT = 4;const RADIUS_X = WIDTH * 0.04;const RADIUS_Y = HEIGHT * 0.04;const ROW_GAP = (HEIGHT - 2 * MARGIN_Y) / (ROW_COUNT - 1);const COL_GAP = (WIDTH - 2 * MARGIN_X) / (COL_COUNT - 1);const arcs = [];for (let row = 0; row < ROW_COUNT; row++) {  const cy = MARGIN_Y + row * ROW_GAP;  for (let col = 0; col < COL_COUNT; col++) {    const cx = MARGIN_X + col * COL_GAP;    const path =      `M ${cx} ${cy - RADIUS_Y} ` +      `A ${RADIUS_X} ${RADIUS_Y} 0 1 1 ${cx} ${cy + RADIUS_Y} ` +      `A ${RADIUS_X} ${RADIUS_Y} 0 1 1 ${cx} ${cy - RADIUS_Y}`;    arcs.push(path);  }}/*[  'M 62 66 A 8 8 0 1 1 62 82 A 8 8 0 1 1 62 66',  'M 87.33333333333333 66 A 8 8 0 1 1 87.33333333333333 82 A 8 8 0 1 1 87.33333333333333 66',  'M 112.66666666666666 66 A 8 8 0 1 1 112.66666666666666 82 A 8 8 0 1 1 112.66666666666666 66',  'M 138 66 A 8 8 0 1 1 138 82 A 8 8 0 1 1 138 66',  'M 62 92 A 8 8 0 1 1 62 108 A 8 8 0 1 1 62 92',  'M 87.33333333333333 92 A 8 8 0 1 1 87.33333333333333 108 A 8 8 0 1 1 87.33333333333333 92',  'M 112.66666666666666 92 A 8 8 0 1 1 112.66666666666666 108 A 8 8 0 1 1 112.66666666666666 92',  'M 138 92 A 8 8 0 1 1 138 108 A 8 8 0 1 1 138 92',  'M 62 118 A 8 8 0 1 1 62 134 A 8 8 0 1 1 62 118',  'M 87.33333333333333 118 A 8 8 0 1 1 87.33333333333333 134 A 8 8 0 1 1 87.33333333333333 118',  'M 112.66666666666666 118 A 8 8 0 1 1 112.66666666666666 134 A 8 8 0 1 1 112.66666666666666 118',  'M 138 118 A 8 8 0 1 1 138 134 A 8 8 0 1 1 138 118',]*/

Nas linhas 19 e 22 é definido o centro do arco. É a margem inicial mais o deslocamento baseado na linha e coluna atuais. Ficaram posicionados da seguinte forma:



Nas linhas 25 e 26 é definido o primeiro arco (primeira metade do círculo). Ficaram desenhados da seguinte forma:



Na linha 27 é definido o segundo arco (segunda metade do círculo). Ficaram desenhados da seguinte forma:



Resultado



Código

<svg>  <rect></rect>  <path    fill="none"    stroke="lightgray"    stroke-width="1"    d="M 62 66 A 8 8 0 1 1 62 82 A 8 8 0 1 1 62 66"  ></path>  <path    fill="none"    stroke="lightgray"    stroke-width="1"    d="M 87.33333333333333 66 A 8 8 0 1 1 87.33333333333333 82 A 8 8 0 1 1 87.33333333333333 66"  ></path>  <path    fill="none"    stroke="lightgray"    stroke-width="1"    d="M 112.66666666666666 66 A 8 8 0 1 1 112.66666666666666 82 A 8 8 0 1 1 112.66666666666666 66"  ></path>  <path    fill="none"    stroke="lightgray"    stroke-width="1"    d="M 138 66 A 8 8 0 1 1 138 82 A 8 8 0 1 1 138 66"  ></path>  <path    fill="none"    stroke="lightgray"    stroke-width="1"    d="M 62 92 A 8 8 0 1 1 62 108 A 8 8 0 1 1 62 92"  ></path>  <path    fill="none"    stroke="lightgray"    stroke-width="1"    d="M 87.33333333333333 92 A 8 8 0 1 1 87.33333333333333 108 A 8 8 0 1 1 87.33333333333333 92"  ></path>  <path    fill="none"    stroke="lightgray"    stroke-width="1"    d="M 112.66666666666666 92 A 8 8 0 1 1 112.66666666666666 108 A 8 8 0 1 1 112.66666666666666 92"  ></path>  <path    fill="none"    stroke="lightgray"    stroke-width="1"    d="M 138 92 A 8 8 0 1 1 138 108 A 8 8 0 1 1 138 92"  ></path>  <path    fill="none"    stroke="lightgray"    stroke-width="1"    d="M 62 118 A 8 8 0 1 1 62 134 A 8 8 0 1 1 62 118"  ></path>  <path    fill="none"    stroke="lightgray"    stroke-width="1"    d="M 87.33333333333333 118 A 8 8 0 1 1 87.33333333333333 134 A 8 8 0 1 1 87.33333333333333 118"  ></path>  <path    fill="none"    stroke="lightgray"    stroke-width="1"    d="M 112.66666666666666 118 A 8 8 0 1 1 112.66666666666666 134 A 8 8 0 1 1 112.66666666666666 118"  ></path>  <path    fill="none"    stroke="lightgray"    stroke-width="1"    d="M 138 118 A 8 8 0 1 1 138 134 A 8 8 0 1 1 138 118"  ></path></svg>

Círculos e suas animações

Animações que percorrem o caminho

Cada círculo utiliza um elemento animateMotion para percorrer o caminho definido. O único atributo que varia entre os círculos é o begin, que define um atraso para cada círculo iniciar sua animação.

Os elementos circle compartilham os seguintes atributos:

  • fill="black": cor de preenchimento do círculo
  • r="8": raio do círculo

Os elementos animateMotion compartilham os seguintes atributos:

  • dur="1100ms": duração total da animação
  • repeatCount="indefinite": a animação se repete indefinidamente

Calculei o atraso de início (begin) de cada círculo da seguinte forma:

const ROW_COUNT = 3;const COL_COUNT = 4;const DURATION = 1_100;const ROW_DELAY = DURATION * 0.08;const COL_DELAY = DURATION * 0.08;const begins = [];for (let row = 0; row < ROW_COUNT; row++) {  const yBegin = row * ROW_DELAY;  for (let col = 0; col < COL_COUNT; col++) {    const xBegin = yBegin + col * COL_DELAY;    const begin = `-${xBegin}ms`;    begins.push(begin);  }}/*[  '-0ms',  '-88ms',  '-176ms',  '-264ms',  '-88ms',  '-176ms',  '-264ms',  '-352ms',  '-176ms',  '-264ms',  '-352ms',  '-440ms',]*/

Nas linhas 11 e 14 são definidos os atrasos das linhas e colunas. Cada deslocamento para a direita e para baixo adiciona atraso. Como os atrasos são iguais, os círculos na antidiagonal (canto superior direito ao canto inferior esquerdo) têm o mesmo atraso. Por exemplo:



Resultado



Código

<svg>  <rect></rect>  <path></path>  <path></path>  <path></path>  <path></path>  <path></path>  <path></path>  <path></path>  <path></path>  <path></path>  <path></path>  <path></path>  <path></path>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      path="M 62 66 A 8 8 0 1 1 62 82 A 8 8 0 1 1 62 66 "      begin="-0ms"      repeatCount="indefinite"    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      path="M 87.33333333333333 66 A 8 8 0 1 1 87.33333333333333 82 A 8 8 0 1 1 87.33333333333333 66 "      begin="-88ms"      repeatCount="indefinite"    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      path="M 112.66666666666666 66 A 8 8 0 1 1 112.66666666666666 82 A 8 8 0 1 1 112.66666666666666 66 "      begin="-176ms"      repeatCount="indefinite"    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      path="M 138 66 A 8 8 0 1 1 138 82 A 8 8 0 1 1 138 66 "      begin="-264ms"      repeatCount="indefinite"    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      path="M 62 92 A 8 8 0 1 1 62 108 A 8 8 0 1 1 62 92 "      begin="-88ms"      repeatCount="indefinite"    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      path="M 87.33333333333333 92 A 8 8 0 1 1 87.33333333333333 108 A 8 8 0 1 1 87.33333333333333 92 "      begin="-176ms"      repeatCount="indefinite"    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      path="M 112.66666666666666 92 A 8 8 0 1 1 112.66666666666666 108 A 8 8 0 1 1 112.66666666666666 92 "      begin="-264ms"      repeatCount="indefinite"    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      path="M 138 92 A 8 8 0 1 1 138 108 A 8 8 0 1 1 138 92 "      begin="-352ms"      repeatCount="indefinite"    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      path="M 62 118 A 8 8 0 1 1 62 134 A 8 8 0 1 1 62 118 "      begin="-176ms"      repeatCount="indefinite"    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      path="M 87.33333333333333 118 A 8 8 0 1 1 87.33333333333333 134 A 8 8 0 1 1 87.33333333333333 118 "      begin="-264ms"      repeatCount="indefinite"    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      path="M 112.66666666666666 118 A 8 8 0 1 1 112.66666666666666 134 A 8 8 0 1 1 112.66666666666666 118 "      begin="-352ms"      repeatCount="indefinite"    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      path="M 138 118 A 8 8 0 1 1 138 134 A 8 8 0 1 1 138 118 "      begin="-440ms"      repeatCount="indefinite"    ></animateMotion>  </circle></svg>

Conclusão

A animação de dezembro encerra a série retomando muitos dos conceitos explorados ao longo do ano. Usando caminhos simples, organizados em uma grade, junto com pequenos deslocamentos temporais, para sugerir um movimento orgânico. Ao distribuir esses atrasos por linhas e colunas, o movimento passa a se propagar pelo grid, criando um ritmo visual contínuo e interessante de observar.

Com isso, fecho este ciclo de experimentação. Mais do que os resultados finais, o valor dessa série está no processo de entender melhor o SVG, testar ideias e documentar cada passo do caminho.

Resultado



Código

<svg  id="svg"  xmlns="http://www.w3.org/2000/svg"  viewBox="0 0 200 200"  width="200"  height="200">  <rect    id="rect"    width="199"    height="199"    rx="6"    x="0.5"    y="0.5"    fill="white"    stroke-width="1"    stroke="lightgray"  ></rect>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      begin="-0ms"      repeatCount="indefinite"      path="M 62 66 A 8 8 0 1 1 62 82 A 8 8 0 1 1 62 66 "    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      begin="-88ms"      repeatCount="indefinite"      path="M 87.33333333333333 66 A 8 8 0 1 1 87.33333333333333 82 A 8 8 0 1 1 87.33333333333333 66 "    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      begin="-176ms"      repeatCount="indefinite"      path="M 112.66666666666666 66 A 8 8 0 1 1 112.66666666666666 82 A 8 8 0 1 1 112.66666666666666 66 "    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      begin="-264ms"      repeatCount="indefinite"      path="M 138 66 A 8 8 0 1 1 138 82 A 8 8 0 1 1 138 66 "    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      begin="-88ms"      repeatCount="indefinite"      path="M 62 92 A 8 8 0 1 1 62 108 A 8 8 0 1 1 62 92 "    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      begin="-176ms"      repeatCount="indefinite"      path="M 87.33333333333333 92 A 8 8 0 1 1 87.33333333333333 108 A 8 8 0 1 1 87.33333333333333 92 "    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      begin="-264ms"      repeatCount="indefinite"      path="M 112.66666666666666 92 A 8 8 0 1 1 112.66666666666666 108 A 8 8 0 1 1 112.66666666666666 92 "    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      begin="-352ms"      repeatCount="indefinite"      path="M 138 92 A 8 8 0 1 1 138 108 A 8 8 0 1 1 138 92 "    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      begin="-176ms"      repeatCount="indefinite"      path="M 62 118 A 8 8 0 1 1 62 134 A 8 8 0 1 1 62 118 "    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      begin="-264ms"      repeatCount="indefinite"      path="M 87.33333333333333 118 A 8 8 0 1 1 87.33333333333333 134 A 8 8 0 1 1 87.33333333333333 118 "    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      begin="-352ms"      repeatCount="indefinite"      path="M 112.66666666666666 118 A 8 8 0 1 1 112.66666666666666 134 A 8 8 0 1 1 112.66666666666666 118 "    ></animateMotion>  </circle>  <circle r="8" fill="black">    <animateMotion      dur="1100ms"      begin="-440ms"      repeatCount="indefinite"      path="M 138 118 A 8 8 0 1 1 138 134 A 8 8 0 1 1 138 118 "    ></animateMotion>  </circle></svg>

Leitura recomendada