Skip to main content

Loading Animations: March

· 10 min read

Third of twelve animations.


Loading Animations (5 part series)
  1. Introduction
  2. January
  3. February
  4. March
  5. April

Animation

Result:

Introduction

I created this animation using SVG, following a structure similar to the previous ones:

<!-- dimensions --><svg>  <defs>    <!-- path traced by the circles -->    <path />  </defs>  <!-- background -->  <rect />  <!-- drawing of the path traced by the circles, for debugging -->  <use />  <!-- three circles like this -->  <ellipse>    <!-- animation that moves the circle along the path -->    <animateMotion>      <mpath />    </animateMotion>    <!-- animation that stretches the circle along the x axis -->    <animate />    <!-- animation that stretches the circle along the y axis -->    <animate />  </ellipse></svg>

How it works

info

To keep the explanation concise, I've left out some elements and attributes from the following code blocks.

Dimensions

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"    strokeWidth="1"    rx="6"  /></svg>

Path

Inside defs, I defined the path that the circles follow. It is referenced by its id, motion-path. The path follows the shape of an infinity symbol, drawn with four arc (A) commands.

  • M52,100: The path starts at the far left.
    • x = 52 is the square width (200) minus the diameter of both circles (2 * 48 = 96), divided by both sides ((200 - 96) / 2 = 52).
    • y = 100 is the vertical center of the square.
  • All arcs have the same values for the first four arguments.
    • rx,ry = 24,24: same horizontal and vertical radius.
    • x-axis-rotation = 0: no rotation.
    • large-arc-flag = 0: the arc should follow the shortest path between start and end points.
  • A24,24 0 0 1 100,100:
    • sweep-flag = 1: sets the arc direction clockwise.
    • x = 100: horizontal center.
    • y = 100: vertical center.
  • A24,24 0 0 0 148,100:
    • sweep-flag = 0: sets the arc direction counterclockwise.
    • x = 148: far right (200 - 52 = 148).
    • y = 100: vertical center.
  • A24,24 0 0 0 100,100:
    • sweep-flag = 0: sets the arc direction counterclockwise.
    • x = 100: horizontal center.
    • y = 100: vertical center.
  • A24,24 0 0 1 52,100:
    • sweep-flag = 1: sets the arc direction clockwise.
    • x = 52: far left (0 + 52 = 52).
    • y = 100: vertical center.
  • z: closes the path.

After defining the rect (the background), I used a use element to visualize the path, since elements inside defs are not rendered. The use element is removed at the end of the animation.

Result



Code

<svg>  <defs>    <path      id="motion-path"      d="M52,100 A24,24 0 0 1 100,100 A24,24 0 0 0 148,100 A24,24 0 0 0 100,100 A24,24 0 0 1 52,100 z"    />  </defs>  <rect />  <use href="#motion-path" fill="none" stroke="lightgray" stroke-width="1" /></svg>

Circles and their animations

The idea was for the circles to follow the infinity-shaped path. When moving downward, they should accelerate. During acceleration, they should experience a subtle distortion to indicate speed.

info

The final animation duration is two seconds. In this section, the animations last ten seconds to make them more noticeable.

Animations that follow the path

First, I created the animation that defines the back-and-forth movement of the circles. My goal was to create just one animation, changing the start time for each circle.

Animating one circle

Starting with one of the circles, I used an ellipse element, as it allows defining separate radii for the x and y axes. The mpath element references path#motion-path, while animateMotion defines the animation.

In the animateMotion element, I set the attributes as follows:

  • repeatCount="indefinite": the animation repeats indefinitely.
  • dur="10000ms": duration is ten seconds for demonstration purposes.
  • calcMode="spline": enables the use of Bézier curves in the keySplines attribute.

Since these attributes work together, I represented the values of keyTimes, keyPoints, and keySplines in a table:

keyTimeskeyPointskeySplines
000.6, 0.3, 0.4, 0.7
0.50.50.6, 0.3, 0.4, 0.7
11-

How they work:

  • keyTimes: defines at which specific moments during the animation duration the keyPoints occur, ranging from 0 to 1.
  • keyPoints: defines where the circle should be along the path, ranging from 0 to 1.
  • keySplines: defines Bézier curves to smooth the transition between keyPoints.

Graph representation:

keyPointskeyTimes101

  • The x and y axes represent keyTimes and keyPoints values, respectively.
  • The dark gray lines at the top and right indicate intervals where keySplines values apply.
  • The 0.6,0.3,0.4,0.7 curve starts slow, speeds up in the middle, and slows down at the end.

In the first half of the animation (keyTimes and keyPoints from 0 to 0.5), the circle moves from the far left to the far right following the Bézier curve (0.6, 0.3, 0.4, 0.7), starting slow, accelerating in the middle, and slowing down at the end. In the second half (keyTimes and keyPoints from 0.5 to 1), the same happens in reverse, moving from the far right back to the far left.

One circle animated



Code

<svg>  <defs>    <path />  </defs>  <rect />  <use />  <ellipse rx="8" ry="8" fill="black">    <animateMotion      repeatCount="indefinite"      calcMode="spline"      dur="10000ms"      keyTimes="0; 0.5; 1"      keyPoints="0; 0.5; 1"      keySplines="0.6,0.3,0.4,0.7; 0.6,0.3,0.4,0.7"    >      <mpath href="#motion-path" />    </animateMotion>  </ellipse></svg>

Animating other circles

As with the first circle, I used two more ellipse elements. The animateMotion attributes are the same as the first circle, except the animation starts one-third of the way through:

  • begin="-3333.3333ms" and begin="-6666.6666ms": define when the animation starts.

All circles animated



Code

<svg>  <defs>    <path />  </defs>  <rect />  <use />  <ellipse>    <animateMotion>      <mpath />    </animateMotion>  </ellipse>  <ellipse>    <animateMotion      repeatCount="indefinite"      calcMode="spline"      dur="10000ms"      begin="-3333.3333ms"      keyTimes="0; 0.5; 1"      keyPoints="0; 0.5; 1"      keySplines="0.6,0.3,0.4,0.7; 0.6,0.3,0.4,0.7"    >      <mpath />    </animateMotion>  </ellipse>  <ellipse>    <animateMotion      repeatCount="indefinite"      calcMode="spline"      dur="10000ms"      begin="-6666.6666ms"      keyTimes="0; 0.5; 1"      keyPoints="0; 0.5; 1"      keySplines="0.6,0.3,0.4,0.7; 0.6,0.3,0.4,0.7"    >      <mpath />    </animateMotion>  </ellipse></svg>

Stretching Animations

Next, I created animations that distort the circles in some way.

Animating rx and ry of one circle

To convey speed, I created two animations that, together, stretch the circles horizontally and vertically.

In animateMotion, I set rotate="auto" so the circle follows the path rotation, making the distortion effects rotate automatically as well.

The animate elements share the same attribute values:

  • repeatCount="indefinite": the animation repeats indefinitely.
  • dur="10000ms": duration is ten seconds for demonstration purposes.
  • keyTimes="0; .25; .5; .75; 1": defines when values will be applied during the animation, ranging from 0 to 1.

For the values attribute:

attributeName="rx"attributeName="ry"Description
88Starts round
8.47.6Stretches horizontally, compresses vertically to indicate speed when moving down
88Returns to round shape when moving up
8.47.6Stretches again when moving down
88Returns to round shape when moving up

One circle animated



Code

<svg>  <defs>    <path />  </defs>  <rect />  <use />  <ellipse>    <animateMotion      repeatCount="indefinite"      calcMode="spline"      dur="10000ms"      keyTimes="0; 0.5; 1"      keyPoints="0; 0.5; 1"      keySplines="0.6,0.3,0.4,0.7; 0.6,0.3,0.4,0.7"      rotate="auto"    >      <mpath />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="10000ms"      keyTimes="0; .25; .5; .75; 1"      values="8; 8.4; 8; 8.4; 8"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="10000ms"      keyTimes="0; .25; .5; .75; 1"      values="8; 7.6; 8; 7.6; 8"    />  </ellipse>  <ellipse>    <animateMotion>      <mpath />    </animateMotion>  </ellipse>  <ellipse>    <animateMotion>      <mpath />    </animateMotion>  </ellipse></svg>

All circles animated



Code

<svg>  <defs>    <path />  </defs>  <rect />  <use />  <ellipse>    <animateMotion>      <mpath />    </animateMotion>    <animate />    <animate />  </ellipse>  <ellipse>    <animateMotion      repeatCount="indefinite"      calcMode="spline"      dur="10000ms"      begin="-3333.3333ms"      keyTimes="0; 0.5; 1"      keyPoints="0; 0.5; 1"      keySplines="0.6,0.3,0.4,0.7; 0.6,0.3,0.4,0.7"      rotate="auto"    >      <mpath />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="10000ms"      keyTimes="0; .25; .5; .75; 1"      values="8; 8.4; 8; 8.4; 8"      begin="-3333.3333ms"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="10000ms"      keyTimes="0; .25; .5; .75; 1"      values="8; 7.6; 8; 7.6; 8"      begin="-3333.3333ms"    />  </ellipse>  <ellipse>    <animateMotion      repeatCount="indefinite"      calcMode="spline"      dur="10000ms"      begin="-6666.6666ms"      keyTimes="0; 0.5; 1"      keyPoints="0; 0.5; 1"      keySplines="0.6,0.3,0.4,0.7; 0.6,0.3,0.4,0.7"      rotate="auto"    >      <mpath />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="10000ms"      keyTimes="0; .25; .5; .75; 1"      values="8; 8.4; 8; 8.4; 8"      begin="-6666.6666ms"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="10000ms"      keyTimes="0; .25; .5; .75; 1"      values="8; 7.6; 8; 7.6; 8"      begin="-6666.6666ms"    />  </ellipse></svg>

Conclusion

This animation was simpler to develop, mainly because there is no interaction between the circles, and they all share the same animation. Additionally, I didn’t use any new elements or attributes this time but applied everything I learned from previous animations.

During development, I used JavaScript to perform calculations and generate the d attribute value for the path element. This allowed for quick testing of different radius values. For example:

// ellipse
const radius = 24;

// rect
const width = 200;
const height = 200;
const xCenter = width / 2;
const yCenter = height / 2;
const xMargin = (width - 2 * (2 * radius)) / 2;
const yMargin = (height - 2 * radius) / 2;

// path
const motionPath = `
M${xMargin},${yCenter}
A${radius},${radius} 0 0 1 ${xCenter},${yCenter}
A${radius},${radius} 0 0 0 ${width - xMargin},${yCenter}
A${radius},${radius} 0 0 0 ${xCenter},${yCenter}
A${radius},${radius} 0 0 1 ${xMargin},${yCenter}
z
`;

Using JavaScript for calculations like this is a practice I plan to apply in future animations.

Result



Code

<svg  xmlns="http://www.w3.org/2000/svg"  viewBox="0 0 200 200"  width="200"  height="200">  <defs>    <path      id="motion-path"      d="M52,100 A24,24 0 0 1 100,100 A24,24 0 0 0 148,100 A24,24 0 0 0 100,100 A24,24 0 0 1 52,100 z"    />  </defs>  <rect    width="199"    height="199"    x="0.5"    y="0.5"    fill="white"    stroke="lightgray"    stroke-width="1"    rx="6"  />  <ellipse rx="8" ry="8" fill="black">    <animateMotion      repeatCount="indefinite"      calcMode="spline"      dur="1400ms"      keyTimes="0; 0.5; 1"      keyPoints="0; 0.5; 1"      keySplines="0.6,0.3,0.4,0.7; 0.6,0.3,0.4,0.7"      rotate="auto"    >      <mpath href="#motion-path" />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="1400ms"      keyTimes="0; .25; .5; .75; 1"      values="8; 8.4; 8; 8.4; 8"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="1400ms"      keyTimes="0; .25; .5; .75; 1"      values="8; 7.6; 8; 7.6; 8"    />  </ellipse>  <ellipse rx="8" ry="8" fill="black">    <animateMotion      repeatCount="indefinite"      calcMode="spline"      dur="1400ms"      begin="-466.6666ms"      keyTimes="0; 0.5; 1"      keyPoints="0; 0.5; 1"      keySplines="0.6,0.3,0.4,0.7; 0.6,0.3,0.4,0.7"      rotate="auto"    >      <mpath href="#motion-path" />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="1400ms"      keyTimes="0; .25; .5; .75; 1"      values="8; 8.4; 8; 8.4; 8"      begin="-466.6666ms"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="1400ms"      keyTimes="0; .25; .5; .75; 1"      values="8; 7.6; 8; 7.6; 8"      begin="-466.6666ms"    />  </ellipse>  <ellipse rx="8" ry="8" fill="black">    <animateMotion      repeatCount="indefinite"      calcMode="spline"      dur="1400ms"      begin="-933.3333ms"      keyTimes="0; 0.5; 1"      keyPoints="0; 0.5; 1"      keySplines="0.6,0.3,0.4,0.7; 0.6,0.3,0.4,0.7"      rotate="auto"    >      <mpath href="#motion-path" />    </animateMotion>    <animate      attributeName="rx"      repeatCount="indefinite"      dur="1400ms"      keyTimes="0; .25; .5; .75; 1"      values="8; 8.4; 8; 8.4; 8"      begin="-933.3333ms"    />    <animate      attributeName="ry"      repeatCount="indefinite"      dur="1400ms"      keyTimes="0; .25; .5; .75; 1"      values="8; 7.6; 8; 7.6; 8"      begin="-933.3333ms"    />  </ellipse></svg>

Recommended reading