Pular para o conteúdo principal

Animações de Carregamento: Agosto

· Leitura de 8 minutos

Oitava 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 é composta por círculos que percorrem uma curva de Lissajous.

Introdução

Criei essa animação com SVG. A estrutura segue o padrão das anteriores:

<!-- definições de tamanho --><svg>  <defs>    <!-- caminho que os círculos percorrem -->    <path />  </defs>  <!-- plano de fundo -->  <rect />  <!-- desenho do caminho que os círculos percorrem, para debug -->  <use />  <!-- oito círculos como este -->  <animateMotion>    <mpath></mpath>  </animateMotion></svg>

Como funciona

info

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

Tamanho

Mantive o tamanho igual às 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"    stroke-width="1"    rx="6"  /></svg>

Caminho

Para criar o caminho, usei JavaScript para gerar a curva de Lissajous dinamicamente:

// dimensõesconst WIDTH = 200;const HEIGHT = 200;const X_CENTER = WIDTH * (1 / 2);const Y_CENTER = HEIGHT * (1 / 2);const X_MARGIN = 25; // distância entre a curva e as bordas horizontaisconst Y_MARGIN = 75; // distância entre a curva e as bordas verticaisconst X_RADIUS = (WIDTH - 2 * X_MARGIN) * (1 / 2);const Y_RADIUS = (HEIGHT - 2 * Y_MARGIN) * (1 / 2);// curvaconst TAU = 2 * Math.PI;const POINTS_AMOUNT = 100; // quanto mais pontos, mais suave é a curvaconst A_FREQUENCY = 1;const B_FREQUENCY = 3;const OFFSET = -1 * (1 / 2) * Math.PI; // deslocamento para que a curva comece à esquerdalet d = "";for (let i = 0; i < POINTS_AMOUNT; i++) {  const pointIndex = i / POINTS_AMOUNT;  const at = A_FREQUENCY * TAU * pointIndex + OFFSET;  const bt = B_FREQUENCY * TAU * pointIndex + OFFSET;  const x = X_CENTER + X_RADIUS * Math.sin(at);  const y = Y_CENTER + Y_RADIUS * Math.cos(bt);  if (i === 0) {    d += `M${x},${y} `;    continue;  }  d += `L${x},${y} `;}d += `z`;// M25,100 L25.14799536787963,104.68453286464312 ... L25.14799536787963,95.31546713535694 z

Resultado



Código

<svg>  <def>    <path      id="path"      d="        M25,100        L25.14799536787963,104.68453286464312        ...        L25,99.99999999999994        z      "    />  </def>  <rect />  <use href="#path" stroke="lightgray" fill="none" /></svg>

Círculos e suas animações

Com o caminho pronto, o próximo passo foi criar os círculos e definir como eles se movimentariam sobre ele.

Animações que percorrem o caminho

A ideia é simples: cada círculo apenas segue o caminho que foi definido. Ao se moverem de um extremo ao outro, uma curva de Bézier ease-in-out é aplicada, ela começa mais lenta, acelera no meio, e desacelera no final.

Os elementos ellipse compartilham os seguintes atributos:

  • fill="black": cor de preenchimento da elipse
  • rx="8": raio horizontal da elipse
  • ry="8": raio vertical da elipse

Os elementos animateMotion compartilham os seguintes atributos:

  • dur="20000ms": duração total da animação, 20 segundos
  • begin="<atraso>": atraso antes do início da animação, cada círculo tem um atraso igualmente espaçado
  • repeatCount="indefinite": a animação se repete indefinidamente
  • calcMode="spline": usa uma curva de Bézier para a interpolação
  • keyPoints="0; 0.5; 1": pontos-chave da animação
  • keyTimes="0; 0.5; 1": tempos correspondentes aos pontos-chave
  • keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6": curvas de Bézier para a interpolação
keyTimeskeyPointskeySplines
000.5, 0.4, 0.5, 0.6
0.50.50.5, 0.4, 0.5, 0.6
11-

Os elementos mpath compartilham um atributo:

  • href="#path": referência ao caminho que a animação deve seguir

Resultado



Código

<svg>  <def>    <path />  </def>  <rect />  <use />  <!-- começo: círculo 1 -->  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-20000ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>    <!-- fim: círculo 1 -->  </ellipse>  <!-- começo: círculo 2 -->  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-17500ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>    <!-- fim: círculo 2 -->  </ellipse>  <!-- começo: círculo 3 -->  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-15000ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>    <!-- fim: círculo 3 -->  </ellipse>  <!-- começo: círculo 4 -->  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-12500ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>    <!-- fim: círculo 4 -->  </ellipse>  <!-- começo: círculo 5 -->  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-10000ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>    <!-- fim: círculo 5 -->  </ellipse>  <!-- começo: círculo 6 -->  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-7500ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>    <!-- fim: círculo 6 -->  </ellipse>  <!-- começo: círculo 7 -->  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-5000ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>    <!-- fim: círculo 7 -->  </ellipse>  <!-- começo: círculo 8 -->  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-2500ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>    <!-- fim: círculo 8 -->  </ellipse></svg>

Conclusão

A oitava animação foi uma experiência ótima. Trabalhar com curvas de Lissajous trouxe um visual único. Além disso, a aplicação da curva de Bézier na animação dos círculos foi essencial para garantir que eles não se sobrepusessem, permitindo que cada elemento tivesse seu próprio espaço visual. A utilização de JavaScript me deu a liberdade de experimentar de maneira dinâmica com o número de pontos na curva e seu posicionamento, possibilitando ajustes finos e testes em tempo real.

Resultado



Código

<svg  xmlns="http://www.w3.org/2000/svg"  viewBox="0 0 200 200"  width="200"  height="200">  <def>    <path      id="path"      d="        M25,100        L25.14799536787963,104.68453286464312        L25.591397401414156,109.20311381711696        L26.328456195348352,113.39566987447492        L27.356262915352673,117.11367764821722        L28.67076127786349,120.22542485937369        L30.266763558381143,122.62067631165048        L32.137971065048546,124.21457902821578        L34.27699899671023,124.9506682107068        L36.67540558734887,124.80286753286194        L39.32372542187894,123.77641290737884        L42.21150679181581,121.9076670010966        L45.32735294339413,119.26283106939474        L48.658967055348356,115.93559974371725        L52.19320076884828,112.04384185254288        L55.916106078064516,107.72542485937369        L59.81299037657526,103.1333308391076        L63.868474442371365,98.43023701176716        L68.06655313261956,93.78275282087864        L72.39065854864916,89.35551771087319        L76.82372542187895,85.30536869268818        L81.34825846263588,81.77578431446472        L85.94640140607065,78.89180186244963        L90.60000748267719,76.75558785279371        L95.29071103530148,75.44281873178278        L100,75        L104.70928896469852,75.44281873178278        L109.39999251732283,76.75558785279372        L114.05359859392937,78.89180186244963        L118.6517415373641,81.7757843144647        L123.17627457812105,85.30536869268818        L127.60934145135084,89.35551771087317        L131.93344686738047,93.78275282087864        L136.13152555762866,98.43023701176718        L140.18700962342476,103.1333308391076        L144.0838939219355,107.72542485937367        L147.80679923115173,112.04384185254287        L151.34103294465166,115.93559974371723        L154.67264705660585,119.26283106939474        L157.78849320818418,121.9076670010966        L160.67627457812105,123.77641290737884        L163.32459441265112,124.80286753286194        L165.72300100328977,124.9506682107068        L167.86202893495147,124.21457902821578        L169.73323644161886,122.6206763116505        L171.3292387221365,120.22542485937369        L172.64373708464734,117.1136776482172        L173.67154380465166,113.39566987447493        L174.40860259858584,109.20311381711694        L174.85200463212038,104.68453286464315        L175,100.00000000000001        L174.85200463212038,95.31546713535687        L174.40860259858584,90.79688618288307        L173.67154380465166,86.60433012552508        L172.64373708464734,82.88632235178277        L171.3292387221365,79.77457514062633        L169.73323644161883,77.3793236883495        L167.86202893495147,75.78542097178422        L165.72300100328977,75.0493317892932        L163.32459441265115,75.19713246713805        L160.67627457812105,76.22358709262116        L157.7884932081842,78.0923329989034        L154.67264705660585,80.73716893060526        L151.34103294465166,84.06440025628275        L147.80679923115173,87.95615814745713        L144.0838939219355,92.2745751406263        L140.18700962342473,96.8666691608924        L136.13152555762863,101.56976298823285        L131.9334468673804,106.21724717912137        L127.60934145135089,110.64448228912678        L123.17627457812107,114.69463130731182        L118.65174153736415,118.22421568553526        L114.05359859392934,121.10819813755037        L109.39999251732284,123.24441214720628        L104.70928896469849,124.55718126821722        L100.00000000000001,125        L95.29071103530153,124.55718126821722        L90.60000748267717,123.24441214720629        L85.94640140607068,121.10819813755037        L81.34825846263587,118.22421568553528        L76.82372542187895,114.69463130731184        L72.39065854864913,110.64448228912681        L68.06655313261962,106.21724717912139        L63.86847444237137,101.56976298823288        L59.81299037657529,96.86666916089243        L55.91610607806452,92.27457514062637        L52.1932007688483,87.95615814745712        L48.65896705534835,84.06440025628278        L45.32735294339415,80.7371689306053        L42.2115067918158,78.0923329989034        L39.32372542187895,76.22358709262116        L36.675405587348855,75.19713246713806        L34.27699899671023,75.0493317892932        L32.13797106504852,75.78542097178422        L30.26676355838117,77.37932368834947        L28.67076127786349,79.7745751406263        L27.356262915352673,82.88632235178282        L26.328456195348352,86.60433012552502        L25.59139740141417,90.79688618288304        L25.14799536787963,95.31546713535694        L25,99.99999999999994        z      "    />  </def>  <rect    width="199"    height="199"    x="0.5"    y="0.5"    fill="white"    stroke="lightgray"    stroke-width="1"    rx="6"  />  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-20000ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>  </ellipse>  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-17500ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>  </ellipse>  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-15000ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>  </ellipse>  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-12500ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>  </ellipse>  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-10000ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>  </ellipse>  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-7500ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>  </ellipse>  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-5000ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>  </ellipse>  <ellipse fill="black" rx="8" ry="8">    <animateMotion      dur="20000ms"      begin="-2500ms"      repeatCount="indefinite"      calcMode="spline"      keyPoints="0; 0.5; 1"      keyTimes="0; 0.5; 1"      keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6"    >      <mpath href="#path" />    </animateMotion>  </ellipse></svg>

Leitura recomendada