Pular para o conteúdo principal

Animações de Carregamento: Abril

· Leitura de 22 minutos

Quarta 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

Resultado final:

Introdução

Criei essa animação com SVG, seguindo uma estrutura parecida com as anteriores:

<!-- definições de tamanho --><svg>  <defs>    <!-- caminhos que os círculos percorrem -->    <path />    <path />    <path />    <path />    <path />  </defs>  <!-- plano de fundo -->  <rect />  <!-- desenhos dos caminhos que os círculos percorrem, para debug -->  <g>    <use />    <use />    <use />    <use />    <use />  </g>  <!-- quatro círculos como este -->  <ellipse>    <!-- animações que fazem o círculo percorrer os caminhos -->    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <!-- animação que estica o círculo horizontalmente -->    <animate />    <!-- animação que estica o círculo verticalmente -->    <animate />  </ellipse></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"    strokeWidth="1"    rx="6"  /></svg>

Caminho

O caminho percorrido tem a forma de um pentágono, por onde quatro círculos se movimentam. Sempre que um vértice fica vazio, um dos círculos empurra outro em direção a esse vértice. Os movimentos seguem no sentido horário.

Primeiro, calculei a posição de cada vértice usando JavaScript.

Resultado



Código

// dimensõesconst width = 200;const height = 200;const xCenter = width / 2;const yCenter = height / 2;// pentágonoconst numberOfSides = 5;// vérticesconst radius = 35;const points = [];for (let i = 0; i < numberOfSides; i++) {  const angle = ((2 * Math.PI) / numberOfSides) * i;  const x = radius * Math.cos(angle) + xCenter;  const y = radius * Math.sin(angle) + yCenter;  points.push({ x, y });}/*[  { x: 135,                y: 100                }  { x: 110.81559480312316, y: 133.28697807033038 }  { x: 71.68440519687684,  y: 120.57248383023656 }  { x: 71.68440519687684,  y: 79.42751616976344  }  { x: 110.81559480312315, y: 66.71302192966962  }]*/

Em seguida, calculei os lados. Eles se estendem além dos vértices, criando espaço para que os círculos se movimentem, como se estivessem tomando impulso ou recebendo um empurrão.

Resultado



Código

// dimensõesconst width = 200;const height = 200;const xCenter = width / 2;const yCenter = height / 2;// pentágonoconst numberOfSides = 5;// vérticesconst radius = 35;const points = [];for (let i = 0; i < numberOfSides; i++) {  const angle = ((2 * Math.PI) / numberOfSides) * i;  const x = radius * Math.cos(angle) + xCenter;  const y = radius * Math.sin(angle) + yCenter;  points.push({ x, y });}/*[  { x: 135,                y: 100                }  { x: 110.81559480312316, y: 133.28697807033038 }  { x: 71.68440519687684,  y: 120.57248383023656 }  { x: 71.68440519687684,  y: 79.42751616976344  }  { x: 110.81559480312315, y: 66.71302192966962  }]*/// ladosconst extension = 0.3;const edges = [];for (let i = 0; i < numberOfSides; i++) {  const point1 = points[i];  const point2 = points[i + 1] || points[0];  const dx = point2.x - point1.x;  const dy = point2.y - point1.y;  const length = Math.hypot(dx, dy);  const unitDx = dx / length;  const unitDy = dy / length;  const edgeExtension = length * extension;  const x1 = point1.x - unitDx * edgeExtension;  const y1 = point1.y - unitDy * edgeExtension;  const x2 = point2.x + unitDx * edgeExtension;  const y2 = point2.y + unitDy * edgeExtension;  edges.push({ x1, y1, x2, y2 });}/*[  { x1: 142.25532155906305, y1: 90.01390657890089,  x2: 103.56027324406011, y2: 143.2730714914295  },  { x1: 122.55495168499706, y1: 137.10132634235853, x2: 59.94504831500294,  y2: 116.75813555820842 },  { x1: 71.68440519687684,  y1: 132.9159741283785,  x2: 71.68440519687684,  y2: 67.08402587162149  },  { x1: 59.94504831500295,  y1: 83.24186444179158,  x2: 122.55495168499704, y2: 62.89867365764148  },  { x1: 103.5602732440601,  y1: 56.72692850857051,  x2: 142.25532155906305, y2: 109.98609342109911 }]*/// posição de cada vérticeconst extensionProportion = extension / (1 + 2 * extension);const leftVertice = 0 + extensionProportion; //  0.18749999999999997const rightVertice = 1 - extensionProportion; // 0.8125

Com os lados calculados, defini dentro de defs os paths que os círculos percorrem. Eles serão referenciados pelos seus ids, motion-path-0 a motion-path-4.

Depois do rect, que é o plano de fundo, defini cinco uses para visualizar os caminhos, visto que o que é definido dentro de defs não é renderizado. Os elementos use são removidos na conclusão da animação.

Resultado



Código

<svg>  <defs>    <path      id="motion-path-0"      d="M142.25532155906305,90.01390657890089 L103.56027324406011,143.2730714914295"    />    <path      id="motion-path-1"      d="M122.55495168499706,137.10132634235853 L59.94504831500294,116.75813555820842"    />    <path      id="motion-path-2"      d="M71.68440519687684,132.9159741283785 L71.68440519687684,67.08402587162149"    />    <path      id="motion-path-3"      d="M59.94504831500295,83.24186444179158 L122.55495168499704,62.89867365764148"    />    <path      id="motion-path-4"      d="M103.5602732440601,56.72692850857051 L142.25532155906305,109.98609342109911"    />  </defs>  <rect />  <g fill="none" stroke="lightgray">    <use href="#motion-path-0" />    <use href="#motion-path-1" />    <use href="#motion-path-2" />    <use href="#motion-path-3" />    <use href="#motion-path-4" />  </g></svg>

Círculos e suas animações

info

A duração final da animação é de oito segundos. Nesta seção as animações têm duração de 40 segundos para ficarem mais evidentes.

Animações que percorrem o caminho

Inicialmente, criei as animações do círculo que empurra e do círculo que é empurrado. A ideia era reutilizar essas animações nos outros dois círculos, alterando apenas o tempo de início.

Animando o círculo que empurra

Começando com o círculo que empurra, usei um elemento ellipse, pois ele permite definir o raio nos eixos x e y separadamente.

Defini cinco elementos animateMotion, cada um contendo um elemento mpath que referencia os paths de #motion-path-0 a #motion-path-4. Cada animateMotion possui os seguintes atributos:

  • id: vai de circle_1_path_0 a circle_1_path_4
  • begin: cada animação começa quando a anterior termina, repetindo indefinidamente
    • #circle_1_path_0, 0ms; circle_1_path_4.end: 0ms faz com que esta seja a primeira animação a executar, e circle_1_path_4.end faz com que animação seja executada quando circle_1_path_4 termina
    • #circle_1_path_1 a #circle_1_path_4: começam suas animações quando a animação anterior termina

Os seguinte atributos são iguais para todos os animateMotions:

  • dur="8000ms": a animação dura 40 segundos nos exemplos, cada animateMotion dura 1/5 da duração total, que são oito segundos
  • calcMode="spline": para poder usar curvas de Bézier no atributo keySplines
  • rotate="auto": para que o círculo siga a rotação do caminho
  • keyTimes, keyPoints e keySplines: dado que funcionam juntos, representei os valores dos atributos em uma tabela:
keyTimeskeyPointskeySplines
00.18749999999999997 (vértice esquerdo)0.25, 0.75, 1, 1
0.200.42, 0, 0.58, 1
0.310.42, 0, 0.58, 1
0.50.8125 (vértice direito)0, 0, 1, 1
10.8125 (vértice direito)-

Lembrando como funcionam:

  • keyTimes: define em quais momentos específicos ao longo da animação os keyPoints ocorrerão, varia de 0 a 1
  • keyPoints: define onde o círculo deve estar ao longo do caminho, varia de 0 a 1
  • keySplines: define curvas de Bézier para suavizar a progressão entre keyPoints

Representação em gráfico:

keyPointskeyTimes101

  • Os eixos x e y representam os valores dos atributos keyTimes e keyPoints, respectivamente
  • No topo e à direita, as linhas em cinza escuro representam os intervalos onde os valores do atributo keySplines são aplicados

Ou seja, na primeira metade da animação, o círculo começa no vértice esquerdo, pega impulso e se move rapidamente para a outra extremidade da linha, parando no vértice direito. Dessa forma, a animação seguinte se inicia na mesma posição, mantendo a animação contínua.

Na segunda metade o círculo fica parado, é nesse intervalo que o outro par de círculos é animado.

Apenas o círculo que empurra animado



Código

<svg>  <defs>    <path />    <path />    <path />    <path />    <path />  </defs>  <rect />  <g>    <use />    <use />    <use />    <use />    <use />  </g>  <ellipse rx="8" ry="8" fill="black">    <animateMotion      id="circle_1_path_0"      dur="8000ms"      calcMode="spline"      begin="0ms; circle_1_path_4.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-0" />    </animateMotion>    <animateMotion      id="circle_1_path_1"      dur="8000ms"      calcMode="spline"      begin="circle_1_path_0.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-1" />    </animateMotion>    <animateMotion      id="circle_1_path_2"      dur="8000ms"      calcMode="spline"      begin="circle_1_path_1.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-2" />    </animateMotion>    <animateMotion      id="circle_1_path_3"      dur="8000ms"      calcMode="spline"      begin="circle_1_path_2.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-3" />    </animateMotion>    <animateMotion      id="circle_1_path_4"      dur="8000ms"      calcMode="spline"      begin="circle_1_path_3.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-4" />    </animateMotion>  </ellipse></svg>

Animando o círculo que é empurrado

Assim como com o círculo que empurra, usei um elemento ellipse contendo cinco elementos animateMotion. Cada animateMotion contém um elemento mpath, que desta vez começa referenciando o path#motion-path-1, um path à frente da animação do círculo que empurra.

Cada animateMotion possui os seguintes atributos:

  • id e begin: assim como no círculo que empurra, porém com circle_2_ em vez de circle_1_
  • dur, calcMode, rotate: iguais ao círculo que empurra
  • keyTimes, keyPoints e keySplines:
keyTimeskeyPointskeySplines
00.18749999999999997 (vértice esquerdo)0, 0, 1, 1
0.260.18749999999999997 (vértice esquerdo)0.25, 0.75, 1, 1
0.3610.42, 0, 0.58, 1
0.50.8125 (vértice direito)0.42, 0, 0.58, 1
10.8125 (vértice direito)-

Representação em gráfico:

keyPointskeyTimes101

Ou seja, na primeira metade da animação, o círculo começa no vértice esquerdo, leva o empurrão e se move rapidamente para a outra extremidade da linha, parando no vértice direito. Dessa forma, a animação seguinte se inicia na mesma posição, mantendo a animação contínua.

Na segunda metade o círculo fica parado, é nesse intervalo que o outro par de círculos é animado.

Primeiro par de círculos animado



Código

<svg>  <defs>    <path />    <path />    <path />    <path />    <path />  </defs>  <rect />  <g>    <use />    <use />    <use />    <use />    <use />  </g>  <ellipse>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>  </ellipse>  <ellipse rx="8" ry="8" fill="black">    <animateMotion      id="circle_2_path_0"      dur="8000ms"      calcMode="spline"      begin="0ms; circle_2_path_4.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-1" />    </animateMotion>    <animateMotion      id="circle_2_path_1"      dur="8000ms"      calcMode="spline"      begin="circle_2_path_0.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-2" />    </animateMotion>    <animateMotion      id="circle_2_path_2"      dur="8000ms"      calcMode="spline"      begin="circle_2_path_1.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-3" />    </animateMotion>    <animateMotion      id="circle_2_path_3"      dur="8000ms"      calcMode="spline"      begin="circle_2_path_2.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-4" />    </animateMotion>    <animateMotion      id="circle_2_path_4"      dur="8000ms"      calcMode="spline"      begin="circle_2_path_3.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-0" />    </animateMotion>  </ellipse></svg>

Animações que esticam

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

Animando rx e ry do círculo que empurra

Para transmitir a ideia de impulso e velocidade, criei duas animações que, em conjunto, esticam os círculos horizontal e verticalmente.

Os elementos animate possuem atributos com o mesmo valor:

  • repeatCount="indefinite": a animação repete indefinidamente
  • dur="8000ms": a duração é de oito segundos para os exemplos
  • keyTimes="0; 0.2; 0.3; 0.5; 1": define em quais momentos específicos ao longo da animação os values serão assumidos pelo atributo attributeName, varia de 0 a 1

Para o atributo values:

attributeName="rx"attributeName="ry"Descrição
88Começa redondo
7.68.4Estica verticalmente e encolhe horizontalmente ao pegar impulso
8.47.6Estica horizontalmente e encolhe verticalmente ao empurrar
88Volta a ser redondo
88Se mantém redondo

Apenas o círculo que empurra animado



Código

<svg>  <defs>    <path />    <path />    <path />    <path />    <path />  </defs>  <rect />  <g>    <use />    <use />    <use />    <use />    <use />  </g>  <ellipse>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="8000ms"      keyTimes="0; 0.2; 0.3; 0.5; 1"      values="8; 7.6; 8.4; 8; 8"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="8000ms"      keyTimes="0; 0.2; 0.3; 0.5; 1"      values="8; 8.4; 7.6; 8; 8"    />  </ellipse>  <ellipse>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>  </ellipse></svg>

Animando rx e ry do círculo que é empurrado

Para transmitir a ideia de impacto e velocidade, criei duas animações que, em conjunto, esticam os círculos horizontal e verticalmente.

Os elementos animate possuem atributos com o mesmo valor:

  • repeatCount="indefinite": a animação repete indefinidamente
  • dur="8000ms": a duração é de oito segundos para os exemplos
  • keyTimes="0; 0.26; 0.36; 0.5; 1": define em quais momentos específicos ao longo da animação os values serão assumidos pelo atributo attributeName, varia de 0 a 1

Para o atributo values:

attributeName="rx"attributeName="ry"Descrição
88Começa redondo
88Se mantém redondo
7.68.4Estica verticalmente e encolhe horizontalmente no impacto
88Volta a ser redondo
88Se mantém redondo

Primeiro par de círculos animado



Código

<svg>  <defs>    <path />    <path />    <path />    <path />    <path />  </defs>  <rect />  <g>    <use />    <use />    <use />    <use />    <use />  </g>  <ellipse>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animate />    <animate />  </ellipse>  <ellipse>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="8000ms"      keyTimes="0; 0.26; 0.36; 0.5; 1"      values="8; 8; 7.6; 8; 8"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="8000ms"      keyTimes="0; 0.26; 0.36; 0.5; 1"      values="8; 8; 8.4; 8; 8"    />  </ellipse></svg>

Animando o segundo par de círculos

O segundo par de círculos é basicamente igual ao primeiro, o que muda são:

  • ids de cada animateMotion: é como nos outros círculos, mas começando com circle_3_ e circle_4_
  • begins das animações de cada ellipse: animações começam com antecedência de metade do tempo da animação, -4000ms nos exemplos
  • paths de cada mpath: o terceiro círculo começa em path#motion-path-2, e o quarto em path#motion-path-3

Todos os círculos animados



Código

<svg>  <defs>    <path />    <path />    <path />    <path />    <path />  </defs>  <rect />  <g>    <use />    <use />    <use />    <use />    <use />  </g>  <ellipse>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animate />    <animate />  </ellipse>  <ellipse>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animateMotion>      <mpath />    </animateMotion>    <animate />    <animate />  </ellipse>  <ellipse rx="8" ry="8" fill="black">    <animateMotion      id="circle_3_path_0"      dur="8000ms"      calcMode="spline"      begin="-4000ms; circle_3_path_4.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-2" />    </animateMotion>    <animateMotion      id="circle_3_path_1"      dur="8000ms"      calcMode="spline"      begin="circle_3_path_0.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-3" />    </animateMotion>    <animateMotion      id="circle_3_path_2"      dur="8000ms"      calcMode="spline"      begin="circle_3_path_1.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-4" />    </animateMotion>    <animateMotion      id="circle_3_path_3"      dur="8000ms"      calcMode="spline"      begin="circle_3_path_2.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-0" />    </animateMotion>    <animateMotion      id="circle_3_path_4"      dur="8000ms"      calcMode="spline"      begin="circle_3_path_3.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-1" />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="8000ms"      begin="-4000ms"      keyTimes="0; 0.2; 0.3; 0.5; 1"      values="8; 7.6; 8.4; 8; 8"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="8000ms"      begin="-4000ms"      keyTimes="0; 0.2; 0.3; 0.5; 1"      values="8; 8.4; 7.6; 8; 8"    />  </ellipse>  <ellipse rx="8" ry="8" fill="black">    <animateMotion      id="circle_4_path_0"      dur="8000ms"      calcMode="spline"      begin="-4000ms; circle_4_path_4.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-3" />    </animateMotion>    <animateMotion      id="circle_4_path_1"      dur="8000ms"      calcMode="spline"      begin="circle_4_path_0.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-4" />    </animateMotion>    <animateMotion      id="circle_4_path_2"      dur="8000ms"      calcMode="spline"      begin="circle_4_path_1.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-0" />    </animateMotion>    <animateMotion      id="circle_4_path_3"      dur="8000ms"      calcMode="spline"      begin="circle_4_path_2.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-1" />    </animateMotion>    <animateMotion      id="circle_4_path_4"      dur="8000ms"      calcMode="spline"      begin="circle_4_path_3.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-2" />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="8000ms"      begin="-4000ms"      keyTimes="0; 0.26; 0.36; 0.5; 1"      values="8; 8; 7.6; 8; 8"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="8000ms"      begin="-4000ms"      keyTimes="0; 0.26; 0.36; 0.5; 1"      values="8; 8; 8.4; 8; 8"    />  </ellipse></svg>

Conclusão

Como na animação anterior, usei o JavaScript para calcular os valores de vários atributos, e também usei os gráficos que ilustram como os atributos keyTimes, keyPoints e keySplines funcionam em conjunto. Isso tudo facilitou a experimentação ao longo do desenvolvimento da animação.

Além de aplicar tudo o que aprendi ao longo das animações anteriores, usei pela primeira vez um syncbase value no atributo begin. Isso facilitou bastante o gerenciamento de vários elementos animateMotion usados em conjunto em um mesmo elemento ellipse. É uma ferramenta que planejo usar nas próximas animações.

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-0"      d="M142.25532155906305,90.01390657890089 L103.56027324406011,143.2730714914295"    />    <path      id="motion-path-1"      d="M122.55495168499706,137.10132634235853 L59.94504831500294,116.75813555820842"    />    <path      id="motion-path-2"      d="M71.68440519687684,132.9159741283785 L71.68440519687684,67.08402587162149"    />    <path      id="motion-path-3"      d="M59.94504831500295,83.24186444179158 L122.55495168499704,62.89867365764148"    />    <path      id="motion-path-4"      d="M103.5602732440601,56.72692850857051 L142.25532155906305,109.98609342109911"    />  </defs>  <rect    width="199"    height="199"    x="0.5"    y="0.5"    fill="white"    stroke="lightgray"    stroke-width="1"    rx="6"  />  <!-- início: círculo 1 -->  <ellipse rx="8" ry="8" fill="black">    <animateMotion      id="circle_1_path_0"      dur="1600ms"      calcMode="spline"      begin="0ms; circle_1_path_4.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-0" />    </animateMotion>    <animateMotion      id="circle_1_path_1"      dur="1600ms"      calcMode="spline"      begin="circle_1_path_0.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-1" />    </animateMotion>    <animateMotion      id="circle_1_path_2"      dur="1600ms"      calcMode="spline"      begin="circle_1_path_1.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-2" />    </animateMotion>    <animateMotion      id="circle_1_path_3"      dur="1600ms"      calcMode="spline"      begin="circle_1_path_2.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-3" />    </animateMotion>    <animateMotion      id="circle_1_path_4"      dur="1600ms"      calcMode="spline"      begin="circle_1_path_3.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-4" />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="1600ms"      keyTimes="0; 0.2; 0.3; 0.5; 1"      values="8; 7.6; 8.4; 8; 8"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="1600ms"      keyTimes="0; 0.2; 0.3; 0.5; 1"      values="8; 8.4; 7.6; 8; 8"    />  </ellipse>  <!-- fim: círculo 1 -->  <!-- início: círculo 2 -->  <ellipse rx="8" ry="8" fill="black">    <animateMotion      id="circle_2_path_0"      dur="1600ms"      calcMode="spline"      begin="0ms; circle_2_path_4.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-1" />    </animateMotion>    <animateMotion      id="circle_2_path_1"      dur="1600ms"      calcMode="spline"      begin="circle_2_path_0.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-2" />    </animateMotion>    <animateMotion      id="circle_2_path_2"      dur="1600ms"      calcMode="spline"      begin="circle_2_path_1.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-3" />    </animateMotion>    <animateMotion      id="circle_2_path_3"      dur="1600ms"      calcMode="spline"      begin="circle_2_path_2.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-4" />    </animateMotion>    <animateMotion      id="circle_2_path_4"      dur="1600ms"      calcMode="spline"      begin="circle_2_path_3.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-0" />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="1600ms"      keyTimes="0; 0.26; 0.36; 0.5; 1"      values="8; 8; 7.6; 8; 8"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="1600ms"      keyTimes="0; 0.26; 0.36; 0.5; 1"      values="8; 8; 8.4; 8; 8"    />  </ellipse>  <!-- fim: círculo 2 -->  <!-- início: círculo 3 -->  <ellipse rx="8" ry="8" fill="black">    <animateMotion      id="circle_3_path_0"      dur="1600ms"      calcMode="spline"      begin="-800ms; circle_3_path_4.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-2" />    </animateMotion>    <animateMotion      id="circle_3_path_1"      dur="1600ms"      calcMode="spline"      begin="circle_3_path_0.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-3" />    </animateMotion>    <animateMotion      id="circle_3_path_2"      dur="1600ms"      calcMode="spline"      begin="circle_3_path_1.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-4" />    </animateMotion>    <animateMotion      id="circle_3_path_3"      dur="1600ms"      calcMode="spline"      begin="circle_3_path_2.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-0" />    </animateMotion>    <animateMotion      id="circle_3_path_4"      dur="1600ms"      calcMode="spline"      begin="circle_3_path_3.end"      keyTimes="0; 0.2; 0.3; 0.5; 1"      keyPoints="0.18749999999999997; 0; 1; 0.8125; 0.8125"      keySplines="0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1; 0, 0, 1, 1"      rotate="auto"    >      <mpath href="#motion-path-1" />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="1600ms"      begin="-800ms"      keyTimes="0; 0.2; 0.3; 0.5; 1"      values="8; 7.6; 8.4; 8; 8"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="1600ms"      begin="-800ms"      keyTimes="0; 0.2; 0.3; 0.5; 1"      values="8; 8.4; 7.6; 8; 8"    />  </ellipse>  <!-- fim: círculo 3 -->  <!-- início: círculo 4 -->  <ellipse rx="8" ry="8" fill="black">    <animateMotion      id="circle_4_path_0"      dur="1600ms"      calcMode="spline"      begin="-800ms; circle_4_path_4.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-3" />    </animateMotion>    <animateMotion      id="circle_4_path_1"      dur="1600ms"      calcMode="spline"      begin="circle_4_path_0.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-4" />    </animateMotion>    <animateMotion      id="circle_4_path_2"      dur="1600ms"      calcMode="spline"      begin="circle_4_path_1.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-0" />    </animateMotion>    <animateMotion      id="circle_4_path_3"      dur="1600ms"      calcMode="spline"      begin="circle_4_path_2.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-1" />    </animateMotion>    <animateMotion      id="circle_4_path_4"      dur="1600ms"      calcMode="spline"      begin="circle_4_path_3.end"      keyTimes="0; 0.26; 0.36; 0.5; 1"      keyPoints="0.18749999999999997; 0.18749999999999997; 1; 0.8125; 0.8125"      keySplines="0, 0, 1, 1; 0.25, 0.75, 1, 1; 0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1"      rotate="auto"    >      <mpath href="#motion-path-2" />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="1600ms"      begin="-800ms"      keyTimes="0; 0.26; 0.36; 0.5; 1"      values="8; 8; 7.6; 8; 8"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="1600ms"      begin="-800ms"      keyTimes="0; 0.26; 0.36; 0.5; 1"      values="8; 8; 8.4; 8; 8"    />  </ellipse>  <!-- fim: círculo 4 --></svg>

Leitura recomendada