Skip to main content

Loading Animations: August

· 8 min read

Eighth of twelve animations.


Loading Animations (13 part series)
  1. Introduction
  2. January
  3. February
  4. March
  5. April
  6. May
  7. June
  8. July
  9. August
  10. September
  11. October
  12. November
  13. December

Animation

The animation consists of circles traversing a Lissajous curve.

Introduction

I created this animation with SVG. The structure follows the pattern of the previous ones:

<!-- size definitions --><svg>  <defs>    <!-- path that the circles follow -->    <path />  </defs>  <!-- background -->  <rect />  <!-- drawing the path that the circles follow, for debug -->  <use />  <!-- eight circles like this -->  <animateMotion>    <mpath></mpath>  </animateMotion></svg>

How it works

info

I omitted some elements and attributes in the blocks below to keep the explanation concise.

Size

I kept the size the same as the previous animations.

Result



Code

<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>

Path

To create the path, I used JavaScript to dynamically generate the Lissajous curve:

// dimensionsconst WIDTH = 200;const HEIGHT = 200;const X_CENTER = WIDTH * (1 / 2);const Y_CENTER = HEIGHT * (1 / 2);const X_MARGIN = 25; // distance between the curve and the horizontal edgesconst Y_MARGIN = 75; // distance between the curve and the vertical edgesconst X_RADIUS = (WIDTH - 2 * X_MARGIN) * (1 / 2);const Y_RADIUS = (HEIGHT - 2 * Y_MARGIN) * (1 / 2);// curveconst TAU = 2 * Math.PI;const POINTS_AMOUNT = 100; // higher number of points makes the curve smootherconst A_FREQUENCY = 1;const B_FREQUENCY = 3;const OFFSET = -1 * (1 / 2) * Math.PI; // offset to start the curve on the leftlet 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

Result



Code

<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>

Circles and their animations

With the path ready, the next step was to create the circles and define how they would move along it.

Animations that follow the path

The idea is simple: each circle just follows the path that was defined. When moving from one end to the other, an ease-in-out Bézier curve is applied, it starts slower, accelerates in the middle, and decelerates at the end.

The ellipse elements share the following attributes:

  • fill="black": fill color of the ellipse
  • rx="8": horizontal radius of the ellipse
  • ry="8": vertical radius of the ellipse

The animateMotion elements share the following attributes:

  • dur="20000ms": total duration of the animation, 20 seconds
  • begin="<delay>": delay before the animation starts, each circle has an equally spaced delay
  • repeatCount="indefinite": the animation repeats indefinitely
  • calcMode="spline": uses a Bézier curve for interpolation
  • keyPoints="0; 0.5; 1": key points of the animation
  • keyTimes="0; 0.5; 1": times corresponding to the key points
  • keySplines="0.5, 0.4, 0.5, 0.6; 0.5, 0.4, 0.5, 0.6": Bézier curves for interpolation
keyTimeskeyPointskeySplines
000.5, 0.4, 0.5, 0.6
0.50.50.5, 0.4, 0.5, 0.6
11-

The mpath elements share an attribute:

  • href="#path": reference to the path that the animation should follow

Result



Code

<svg>  <def>    <path />  </def>  <rect />  <use />  <!-- start: circle 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>    <!-- end: circle 1 -->  </ellipse>  <!-- start: circle 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>    <!-- end: circle 2 -->  </ellipse>  <!-- start: circle 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>    <!-- end: circle 3 -->  </ellipse>  <!-- start: circle 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>    <!-- end: circle 4 -->  </ellipse>  <!-- start: circle 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>    <!-- end: circle 5 -->  </ellipse>  <!-- start: circle 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>    <!-- end: circle 6 -->  </ellipse>  <!-- start: circle 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>    <!-- end: circle 7 -->  </ellipse>  <!-- start: circle 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>    <!-- end: circle 8 -->  </ellipse></svg>

Conclusion

The eighth animation was a great experience. Working with Lissajous curves brought a unique visual aspect. Additionally, the application of the Bézier curve in the animation of the circles was essential to ensure that they did not overlap, allowing each element to have its own visual space. The use of JavaScript gave me the freedom to experiment dynamically with the number of points on the curve and their positioning, enabling fine-tuning and real-time testing.

Result



Code

<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>

Recommended Reading