Última das doze animações.
Animações de Carregamento (série de 13 partes)
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
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írculor="8": raio do círculo
Os elementos animateMotion compartilham os seguintes atributos:
dur="1100ms": duração total da animaçãorepeatCount="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>