Ninth of twelve animations.
Loading Animations (13 part series)
Animation
Final result:
Introduction
I created this animation in SVG, following a similar structure to the previous ones:
<!-- size definitions --><svg> <!-- background --> <rect></rect> <!-- visualization of paths --> <path></path> <!-- one circle that moves horizontally --> <ellipse> <!-- movement animations --> <animateMotion></animateMotion> <animateMotion></animateMotion> <!-- deformation animations --> <animate></animate> <animate></animate> </ellipse> <!-- eight circles that move vertically --> <ellipse> <!-- movement animations --> <animateMotion></animateMotion> <!-- deformation animations --> <animate></animate> <animate></animate> <!-- visibility change --> <set></set> </ellipse> <!-- eight static circles --> <ellipse> <!-- visibility change --> <set></set> </ellipse></svg>How it works
I've omitted some elements and attributes in the following blocks to keep the explanation more concise.
Size
I kept the same size 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>Paths
The animation uses nine paths:
- 1 horizontal path: the circle moves from one end to the other repeatedly.
- 8 vertical paths: four upper and four lower, where each circle moves deviating from the circle that follows the horizontal path.
After the rect (background), I defined a path to visualize the paths. The path element is removed in the final version of the animation.
<svg> <rect /> <path stroke="lightgray" d=""></path></svg>Horizontal path
- Horizontal distance from edges: 1/6 of the width,
200 / 6 = 33.3333. - Vertical position: 1/2 of the height,
200 / 2 = 100.
Horizontal coordinates:
- Left:
x = 0 + 33.3333 = 33.3333,y = 100, where0is the left edge. This is an addition, since the coordinate is to the right of the edge. - Right:
x = 200 - 33.3333 = 166.6666,y = 100, where200is the right edge. This is a subtraction, since the coordinate is to the left of the edge.
<svg> <rect /> <path stroke="lightgray" d=" M 33.3333, 100 L 166.6666, 100 " ></path></svg>Vertical paths
- Horizontal distance from edges: 1/3 of the width,
200 / 3 = 66.6666. In other words, the vertical paths are one-third from the center. - Gutter spacing:
66.6666 / 3 = 22.2222.
For the top and bottom vertical x coordinates:
x = 66.6666 + 0 * 22.2222 = 66.6666x = 66.6666 + 1 * 22.2222 = 88.8888x = 66.6666 + 2 * 22.2222 = 111.1111x = 66.6666 + 3 * 22.2222 = 133.3333
- Vertical distance: equal to the gutter.
- Start: 1/2 gutter above/below the vertical center.
- End: 1/7 of the height above/below the vertical center.
For the upper vertical y coordinates:
y = (200 / 2) - (22.2222 / 2) = 88.8888, vertical center minus 1/2 gutter.y = (200 / 2) - (200 / 7) = 71.4285, vertical center minus 1/7 of the height.
These are subtractions, since the coordinates are above the vertical center.
<svg> <rect /> <path stroke="lightgray" d=" M 33.3333, 100 L 166.6666, 100 M 66.6666, 88.8888 L 66.6666, 71.4285 M 88.8888, 88.8888 L 88.8888, 71.4285 M 111.1111, 88.8888 L 111.1111, 71.4285 M 133.3333, 88.8888 L 133.3333, 71.4285 " ></path></svg>For the lower vertical y coordinates:
y = (200 / 2) + (22.2222 / 2) = 111.1111, vertical center plus 1/2 gutter.y = (200 / 2) + (200 / 7) = 128.5714, vertical center plus 1/7 of the height.
These are sums, since the coordinates are below the vertical center.
<svg> <rect /> <path stroke="lightgray" d=" M 33.3333, 100 L 166.6666, 100 M 66.6666, 88.8888 L 66.6666, 71.4285 M 88.8888, 88.8888 L 88.8888, 71.4285 M 111.1111, 88.8888 L 111.1111, 71.4285 M 133.3333, 88.8888 L 133.3333, 71.4285 M 66.6666, 111.1111 L 66.6666, 128.5714 M 88.8888, 111.1111 L 88.8888, 128.5714 M 111.1111, 111.1111 L 111.1111, 128.5714 M 133.3333, 111.1111 L 133.3333, 128.5714 " ></path></svg>Result
Code
<svg> <rect /> <path stroke="lightgray" d=" M 33.3333, 100 L 166.6666, 100 M 66.6666, 88.8888 L 66.6666, 71.4285 M 88.8888, 88.8888 L 88.8888, 71.4285 M 111.1111, 88.8888 L 111.1111, 71.4285 M 133.3333, 88.8888 L 133.3333, 71.4285 M 66.6666, 111.1111 L 66.6666, 128.5714 M 88.8888, 111.1111 L 88.8888, 128.5714 M 111.1111, 111.1111 L 111.1111, 128.5714 M 133.3333, 111.1111 L 133.3333, 128.5714 " ></path></svg>Circles and their animations
The full animation lasts 1.5s. In the intermediate examples, I increased it to 15s to highlight the movements.
Animating the horizontal circle movement
I used an ellipse element, which allows you to define the radius on the x and y axes separately. Each movement (back and forth) is controlled by an animateMotion:
id:left_to_rightandright_to_leftbegin: each starts when the other ends (continuous loop)#left_to_right,0ms; right_to_left.end:0msmakes this the first animation to run, andright_to_left.endmakes the animation run whenright_to_leftends.#right_to_left,left_to_right.end: the animation runs whenleft_to_rightends.
path: both use the same coordinates, one goes from left to right, and the other from right to left.#left_to_right:M33.3333,100 L166.6666,100#right_to_left:M166.6666,100 L33.3333,100
Common attributes:
dur="7500ms": 7.5s forward + 7.5s backward = 15s (total duration)calcMode="spline": to be able to use Bézier curves in thekeySplinesattributekeyTimes,keyPointsandkeySplines: since they work together, I represented the attribute values in a table:
keyTimes | keyPoints | keySplines |
|---|---|---|
| 0 | 0 | 0.42, 0, 0.58, 1 |
| 1 | 1 | 0.42, 0, 0.58, 1 |
Here's how they work:
keyTimes: defines at which specific moments throughout the animation thekeyPointswill occur, ranging from0to1.keyPoints: defines where the circle should be along the path, ranging from0to1.keySplines: defines Bézier curves to smooth the progression betweenkeyPoints.
In other words, both animateMotions take the circle from the beginning to the end of their respective paths, using a Bézier curve that starts slowly, accelerates in the middle, and decelerates at the end.
Horizontal circle animated
Code
<svg> <rect /> <path></path> <ellipse rx="8" ry="8"> <animateMotion id="left_to_right" path="M33.3333,100 L166.6666,100" dur="750ms" begin="0ms; right_to_left.end" calcMode="spline" keyPoints="0; 1" keyTimes="0; 1" keySplines="0.42, 0, 0.58, 1" ></animateMotion> <animateMotion id="right_to_left" path="M166.6666,100 L33.3333,100" dur="750ms" begin="left_to_right.end" calcMode="spline" keyPoints="0; 1" keyTimes="0; 1" keySplines="0.42, 0, 0.58, 1" ></animateMotion> </ellipse></svg>Animating the vertical circles movement
Each circle requires two ellipse elements:
- Animated, starts invisible, becomes visible when animating (
transparent->black). - Static, starts visible, disappears when the animating animation begins (
black->transparent).
Visibility control is done via set.
For the animated circles, I used eight ellipse elements containing an animateMotion element, which moves the vertical circle away from the horizontal circle, and a set element, which makes the circle visible.
Each animateMotion has the following attributes:
id:upper_1toupper_4andlower_1tolower_4path: uses the coordinates for the vertical paths, defined previously.
For the begin attribute, after experimenting with start times, I used quarters of the horizontal animation duration, starting the cascade. Where 3750 is 1/2 of the horizontal animation:
3750 * (1 / 4) = 937.53750 * (2 / 4) = 18753750 * (3 / 4) = 2812.53750 * (4 / 4) = 3750
That is, when the horizontal circle starts moving from the left edge to the right:
- The animation for
upper_1andlower_1should start937.5mslater upper_2andlower_2,18755mslaterupper_3andlower_3,2812.55mslaterupper_4andlower_4,37505mslater
And, when the horizontal circle starts moving from the right edge to the left:
- The animation for
upper_4andlower_4should start937.5mslater upper_3andlower_3,18755mslaterupper_2andlower_2,2812.55mslaterupper_1andlower_1,37505msafter
The following attributes are the same for all animateMotions:
dur="3000ms": defines the duration as 3 seconds, 1/5 of the total duration.fill="freeze": keeps the circle in the final position of the animation.calcMode="spline": allows you to use Bézier curves in thekeySplinesattribute.keyTimes,keyPoints, andkeySplines:
keyTimes | keyPoints | keySplines |
|---|---|---|
| 0 | 0 | 0.42, 0, 0.58, 1 |
| 0.5 | 1 | 0.42, 0, 0.58, 1 |
| 1 | 0 | - |
In other words, each animateMotion takes the circle from the beginning to the end and back to the beginning of its path, using a Bézier curve that starts slowly, accelerates in the middle, and decelerates at the end.
Each set has the following attributes:
begin="<parent id>.begin": when the value should be applied, that is, as soon as the parent's animation starts.
The following attributes are the same for all sets:
attributeName="fill": changes the fill attribute.to="black": the value to be applied.fill="freeze": keeps the applied value.
I omitted attributes that are the same between elements to keep the explanation concise.
<svg> <rect /> <path></path> <!-- start: horizontal circle --> <ellipse> <animateMotion id="left_to_right"></animateMotion> <animateMotion id="right_to_left"></animateMotion> </ellipse> <!-- end: horizontal circle --> <!-- start: upper vertical circle 1 --> <ellipse fill="transparent"> <animateMotion id="upper_1" path="M66.6666,88.8888 L66.6666,71.4285" begin="left_to_right.begin+937.5ms; right_to_left.begin+3750ms" ></animateMotion> <set to="black" begin="upper_1.begin"></set> </ellipse> <!-- end: upper vertical circle 1 --> <!-- start: lower vertical circle 1 --> <ellipse fill="transparent"> <animateMotion id="lower_1" path="M66.6666,111.1111 L66.6666,128.5714" begin="left_to_right.begin+937.5ms; right_to_left.begin+3750ms" ></animateMotion> <set to="black" begin="lower_1.begin"></set> </ellipse> <!-- end: lower vertical circle 1 --> <!-- start: upper vertical circle 2 --> <ellipse fill="transparent"> <animateMotion id="upper_2" path="M88.8888,88.8888 L88.8888,71.4285" begin="left_to_right.begin+1875ms; right_to_left.begin+2812.5ms" ></animateMotion> <set to="black" begin="upper_2.begin"></set> </ellipse> <!-- end: upper vertical circle 2 --> <!-- start: lower vertical circle 2 --> <ellipse fill="transparent"> <animateMotion id="lower_2" path="M88.8888,111.1111 L88.8888,128.5714" begin="left_to_right.begin+1875ms; right_to_left.begin+2812.5ms" ></animateMotion> <set to="black" begin="lower_2.begin"></set> </ellipse> <!-- end: lower vertical circle 2 --> <!-- start: upper vertical circle 3 --> <ellipse fill="transparent"> <animateMotion id="upper_3" path="M111.1111,88.8888 L111.1111,71.4285" begin="left_to_right.begin+2812.5ms; right_to_left.begin+1875ms" ></animateMotion> <set to="black" begin="upper_3.begin"></set> </ellipse> <!-- end: upper vertical circle 3 --> <!-- start: lower vertical circle 3 --> <ellipse fill="transparent"> <animateMotion id="lower_4" path="M111.1111,111.1111 L111.1111,128.5714" begin="left_to_right.begin+2812.5ms; right_to_left.begin+1875ms" ></animateMotion> <set to="black" begin="lower_4.begin"></set> </ellipse> <!-- end: lower vertical circle 3 --> <!-- start: upper vertical circle 4 --> <ellipse fill="transparent"> <animateMotion id="upper_4" path="M133.3333,88.8888 L133.3333,71.4285" begin="left_to_right.begin+3750ms; right_to_left.begin+937.5ms" ></animateMotion> <set to="black" begin="upper_4.begin"></set> </ellipse> <!-- end: upper vertical circle 4 --> <!-- start: lower vertical circle 4 --> <ellipse fill="transparent"> <animateMotion id="lower_4" path="M133.3333,111.1111 L133.3333,128.5714" begin="left_to_right.begin+3750ms; right_to_left.begin+937.5ms" ></animateMotion> <set to="black" begin="lower_4.begin"></set> </ellipse> <!-- end: lower vertical circle 4 --></svg>For the static circles, I used eight ellipse elements containing a set element, which have the following attributes:
begin="<animated circle id>.begin": When the value should be applied, that is, as soon as the animated circle's animation starts.
The following attributes are the same for all sets:
attributeName="fill": Changes thefillattribute.to="transparent": The value to be applied.fill="freeze": Keeps the applied value.
I omitted attributes that are the same between elements to keep the explanation concise.
<svg> <rect /> <path></path> <!-- start: horizontal circle --> <ellipse> <animateMotion id="left_to_right"></animateMotion> <animateMotion id="right_to_left"></animateMotion> </ellipse> <!-- end: horizontal circle --> <!-- start: upper vertical circle 1 --> <ellipse fill="transparent"> <animateMotion id="upper_1" path="M66.6666,88.8888 L66.6666,71.4285" begin="left_to_right.begin+937.5ms; right_to_left.begin+3750ms" ></animateMotion> <set to="black" begin="upper_1.begin"></set> </ellipse> <ellipse fill="black"> <set to="transparent" begin="upper_1.begin"></set> </ellipse> <!-- end: upper vertical circle 1 --> <!-- start: lower vertical circle 1 --> <ellipse fill="transparent"> <animateMotion id="lower_1" path="M66.6666,111.1111 L66.6666,128.5714" begin="left_to_right.begin+937.5ms; right_to_left.begin+3750ms" ></animateMotion> <set to="black" begin="lower_1.begin"></set> </ellipse> <ellipse fill="black"> <set to="transparent" begin="lower_1.begin"></set> </ellipse> <!-- end: lower vertical circle 1 --> <!-- start: upper vertical circle 2 --> <ellipse fill="transparent"> <animateMotion id="upper_2" path="M88.8888,88.8888 L88.8888,71.4285" begin="left_to_right.begin+1875ms; right_to_left.begin+2812.5ms" ></animateMotion> <set to="black" begin="upper_2.begin"></set> </ellipse> <ellipse fill="black"> <set to="transparent" begin="upper_2.begin"></set> </ellipse> <!-- end: upper vertical circle 2 --> <!-- start: lower vertical circle 2 --> <ellipse fill="transparent"> <animateMotion id="lower_2" path="M88.8888,111.1111 L88.8888,128.5714" begin="left_to_right.begin+1875ms; right_to_left.begin+2812.5ms" ></animateMotion> <set to="black" begin="lower_2.begin"></set> </ellipse> <ellipse fill="black"> <set to="transparent" begin="lower_2.begin"></set> </ellipse> <!-- end: lower vertical circle 2 --> <!-- start: upper vertical circle 3 --> <ellipse fill="transparent"> <animateMotion id="upper_3" path="M111.1111,88.8888 L111.1111,71.4285" begin="left_to_right.begin+2812.5ms; right_to_left.begin+1875ms" ></animateMotion> <set to="black" begin="upper_3.begin"></set> </ellipse> <ellipse fill="black"> <set to="transparent" begin="upper_3.begin"></set> </ellipse> <!-- end: upper vertical circle 3 --> <!-- start: lower vertical circle 3 --> <ellipse fill="transparent"> <animateMotion id="lower_4" path="M111.1111,111.1111 L111.1111,128.5714" begin="left_to_right.begin+2812.5ms; right_to_left.begin+1875ms" ></animateMotion> <set to="black" begin="lower_4.begin"></set> </ellipse> <ellipse fill="black"> <set to="transparent" begin="lower_4.begin"></set> </ellipse> <!-- end: lower vertical circle 3 --> <!-- start: upper vertical circle 4 --> <ellipse fill="transparent"> <animateMotion id="upper_4" path="M133.3333,88.8888 L133.3333,71.4285" begin="left_to_right.begin+3750ms; right_to_left.begin+937.5ms" ></animateMotion> <set to="black" begin="upper_4.begin"></set> </ellipse> <ellipse fill="black"> <set to="transparent" begin="upper_4.begin"></set> </ellipse> <!-- end: upper vertical circle 4 --> <!-- start: lower vertical circle 4 --> <ellipse fill="transparent"> <animateMotion id="lower_4" path="M133.3333,111.1111 L133.3333,128.5714" begin="left_to_right.begin+3750ms; right_to_left.begin+937.5ms" ></animateMotion> <set to="black" begin="lower_4.begin"></set> </ellipse> <ellipse fill="black"> <set to="transparent" begin="lower_4.begin"></set> </ellipse> <!-- end: lower vertical circle 4 --></svg>Horizontal and vertical circles animated
Code
<svg> <rect></rect> <path></path> <!-- start: horizontal circle --> <ellipse> <animateMotion id="left_to_right"></animateMotion> <animateMotion id="right_to_left"></animateMotion> </ellipse> <!-- end: horizontal circle --> <!-- start: upper vertical circle 1 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="upper_1" path="M66.6666,88.8888 L66.6666,71.4285" dur="3000ms" begin="left_to_right.begin+937.5ms; right_to_left.begin+3750ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <set attributeName="fill" to="black" begin="upper_1.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="66.6666" cy="88.8888"> <set attributeName="fill" to="transparent" begin="upper_1.begin" fill="freeze" ></set> </ellipse> <!-- end: upper vertical circle 1 --> <!-- start: lower vertical circle 1 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="lower_1" path="M66.6666,111.1111 L66.6666,128.5714" dur="3000ms" begin="left_to_right.begin+937.5ms; right_to_left.begin+3750ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <set attributeName="fill" to="black" begin="lower_1.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="66.6666" cy="111.1111"> <set attributeName="fill" to="transparent" begin="lower_1.begin" fill="freeze" ></set> </ellipse> <!-- end: lower vertical circle 1 --> <!-- start: upper vertical circle 2 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="upper_2" path="M88.8888,88.8888 L88.8888,71.4285" dur="3000ms" begin="left_to_right.begin+1875ms; right_to_left.begin+2812.5ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <set attributeName="fill" to="black" begin="upper_2.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="88.8888" cy="88.8888"> <set attributeName="fill" to="transparent" begin="upper_2.begin" fill="freeze" ></set> </ellipse> <!-- end: upper vertical circle 2 --> <!-- start: lower vertical circle 2 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="lower_2" path="M88.8888,111.1111 L88.8888,128.5714" dur="3000ms" begin="left_to_right.begin+1875ms; right_to_left.begin+2812.5ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <set attributeName="fill" to="black" begin="lower_2.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="88.8888" cy="111.1111"> <set attributeName="fill" to="transparent" begin="lower_2.begin" fill="freeze" ></set> </ellipse> <!-- end: lower vertical circle 2 --> <!-- start: upper vertical circle 3 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="upper_3" path="M111.1111,88.8888 L111.1111,71.4285" dur="3000ms" begin="left_to_right.begin+2812.5ms; right_to_left.begin+1875ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <set attributeName="fill" to="black" begin="upper_3.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="111.1111" cy="88.8888"> <set attributeName="fill" to="transparent" begin="upper_3.begin" fill="freeze" ></set> </ellipse> <!-- end: upper vertical circle 3 --> <!-- start: lower vertical circle 3 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="lower_3" path="M111.1111,111.1111 L111.1111,128.5714" dur="3000ms" begin="left_to_right.begin+2812.5ms; right_to_left.begin+1875ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <set attributeName="fill" to="black" begin="lower_3.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="111.1111" cy="111.1111"> <set attributeName="fill" to="transparent" begin="lower_3.begin" fill="freeze" ></set> </ellipse> <!-- end: lower vertical circle 3 --> <!-- start: upper vertical circle 4 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="upper_4" path="M133.3333,88.8888 L133.3333,71.4285" dur="3000ms" begin="left_to_right.begin+3750ms; right_to_left.begin+937.5ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <set attributeName="fill" to="black" begin="upper_4.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="133.3333" cy="88.8888"> <set attributeName="fill" to="transparent" begin="upper_4.begin" fill="freeze" ></set> </ellipse> <!-- end: upper vertical circle 4 --> <!-- start: lower vertical circle 4 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="lower_4" path="M133.3333,111.1111 L133.3333,128.5714" dur="3000ms" begin="left_to_right.begin+3750ms; right_to_left.begin+937.5ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <set attributeName="fill" to="black" begin="lower_4.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="133.3333" cy="111.1111"> <set attributeName="fill" to="transparent" begin="lower_4.begin" fill="freeze" ></set> </ellipse> <!-- end: lower vertical circle 4 --></svg>Animating rx and ry
To convey speed, I added animate to rx and ry, stretching and compressing the circles. The animate elements have the following attributes:
dur: The duration is the same as the respective motion animation.- Horizontal circle:
7500ms - Vertical circles:
3000ms
- Horizontal circle:
begin:- Horizontal circle: `left_to_right.begin; right_to_left.begin, when one of the motion animations begins.
- Vertical circles:
upper_1.begintoupper_4.beginandlower_1.begintolower_4.begin, when their respective motion animations begin.
The following attributes are the same for all animate:
calcMode="spline": to use Bézier curves in thekeySplinesattribute.attributeName,values,keyTimes, andkeySplinesare represented together in the table:
For the values attribute:
keyTimes | attributeName="rx" | attributeName="ry" | keySplines |
|---|---|---|---|
| 0 | 8 | 8 | 0.42, 0, 0.58, 1 |
| 0.5 | 8.4 | 7.6 | 0.42, 0, 0.58, 1 |
| 1 | 8 | 8 | - |
In other words, the circle starts out round, stretches vertically, shrinks horizontally, and then returns to being round. The transition between each value of rx and ry uses a Bézier curve that starts slowly, accelerates in the middle, and decelerates at the end. In the horizontal circle, the animation has an acceleration effect. In the vertical circles, it has a sudden stop effect before returning to the starting point.
Horizontal and vertical circles animated
Code
I omitted attributes that are the same between elements to keep the explanation concise.
<svg> <rect></rect> <path></path> <!-- start: horizontal circle --> <ellipse> <animateMotion id="left_to_right"></animateMotion> <animateMotion id="right_to_left"></animateMotion> <animate attributeName="rx" dur="7500ms" begin="left_to_right.begin; right_to_left.begin" ></animate> <animate attributeName="ry" dur="7500ms" begin="left_to_right.begin; right_to_left.begin" ></animate> </ellipse> <!-- end: horizontal circle --> <!-- start: upper vertical circle 1 --> <ellipse> <animateMotion id="upper_1"></animateMotion> <animate attributeName="rx" dur="3000ms" begin="upper_1.begin"></animate> <animate attributeName="ry" dur="3000ms" begin="upper_1.begin"></animate> <set></set> </ellipse> <ellipse> <set></set> </ellipse> <!-- end: upper vertical circle 1 --> <!-- start: lower vertical circle 1 --> <ellipse> <animateMotion id="lower_1"></animateMotion> <animate attributeName="rx" dur="3000ms" begin="lower_1.begin"></animate> <animate attributeName="ry" dur="3000ms" begin="lower_1.begin"></animate> <set></set> </ellipse> <ellipse> <set></set> </ellipse> <!-- end: lower vertical circle 1 --> <!-- start: upper vertical circle 2 --> <ellipse> <animateMotion id="upper_2"></animateMotion> <animate attributeName="rx" dur="3000ms" begin="upper_2.begin"></animate> <animate attributeName="ry" dur="3000ms" begin="upper_2.begin"></animate> <set></set> </ellipse> <ellipse> <set></set> </ellipse> <!-- end: upper vertical circle 2 --> <!-- start: lower vertical circle 2 --> <ellipse> <animateMotion id="lower_2"></animateMotion> <animate attributeName="rx" dur="3000ms" begin="lower_2.begin"></animate> <animate attributeName="ry" dur="3000ms" begin="lower_2.begin"></animate> <set></set> </ellipse> <ellipse> <set></set> </ellipse> <!-- end: lower vertical circle 2 --> <!-- start: upper vertical circle 3 --> <ellipse> <animateMotion id="upper_3"></animateMotion> <animate attributeName="rx" dur="3000ms" begin="upper_3.begin"></animate> <animate attributeName="ry" dur="3000ms" begin="upper_3.begin"></animate> <set></set> </ellipse> <ellipse> <set></set> </ellipse> <!-- end: upper vertical circle 3 --> <!-- start: lower vertical circle 3 --> <ellipse> <animateMotion id="lower_3"></animateMotion> <animate attributeName="rx" dur="3000ms" begin="lower_3.begin"></animate> <animate attributeName="ry" dur="3000ms" begin="lower_3.begin"></animate> <set></set> </ellipse> <ellipse> <set></set> </ellipse> <!-- end: lower vertical circle 3 --> <!-- start: upper vertical circle 4 --> <ellipse> <animateMotion id="upper_4"></animateMotion> <animate attributeName="rx" dur="3000ms" begin="upper_4.begin"></animate> <animate attributeName="ry" dur="3000ms" begin="upper_4.begin"></animate> <set></set> </ellipse> <ellipse> <set></set> </ellipse> <!-- end: upper vertical circle 4 --> <!-- start: lower vertical circle 4 --> <ellipse> <animateMotion id="lower_4"></animateMotion> <animate attributeName="rx" dur="3000ms" begin="lower_4.begin"></animate> <animate attributeName="ry" dur="3000ms" begin="lower_4.begin"></animate> <set></set> </ellipse> <ellipse> <set></set> </ellipse> <!-- end: lower vertical circle 4 --></svg>Conclusion
This animation was an exercise in combining different SVG techniques: defining trajectories with path, synchronizing movements with animateMotion, controlling visibility with set, and giving more life to elements by animating rx and ry. The result is a simple composition that conveys dynamism, interaction, and rhythm using only native SVG features, without the need for CSS or JavaScript. With this, I completed the ninth of twelve animations in this series.
Result
Code
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="200" height="200"> <rect width="199" height="199" rx="6" x="0.5" y="0.5" fill="white" stroke-width="1" stroke="lightgray" ></rect> <!-- start: horizontal circle --> <ellipse rx="8" ry="8"> <animateMotion id="left_to_right" path="M33.3333,100 L166.6666,100" dur="750ms" begin="0ms; right_to_left.end" calcMode="spline" keyPoints="0; 1" keyTimes="0; 1" keySplines="0.42, 0, 0.58, 1" ></animateMotion> <animateMotion id="right_to_left" path="M166.6666,100 L33.3333,100" dur="750ms" begin="left_to_right.end" calcMode="spline" keyPoints="0; 1" keyTimes="0; 1" keySplines="0.42, 0, 0.58, 1" ></animateMotion> <animate attributeName="rx" dur="750ms" begin="left_to_right.begin; right_to_left.begin" calcMode="spline" values="8; 8.4; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <animate attributeName="ry" dur="750ms" begin="left_to_right.begin; right_to_left.begin" calcMode="spline" values="8; 7.6; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> </ellipse> <!-- end: horizontal circle --> <!-- start: upper vertical circle 1 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="upper_1" path="M66.6666,88.8888 L66.6666,71.4285" dur="300ms" begin="left_to_right.begin+93.75ms; right_to_left.begin+375ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <animate attributeName="rx" dur="300ms" begin="upper_1.begin" calcMode="spline" values="8; 8.4; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <animate attributeName="ry" dur="300ms" begin="upper_1.begin" calcMode="spline" values="8; 7.6; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <set attributeName="fill" to="black" begin="upper_1.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="66.6666" cy="88.8888"> <set attributeName="fill" to="transparent" begin="upper_1.begin" fill="freeze" ></set> </ellipse> <!-- end: upper vertical circle 1 --> <!-- start: lower vertical circle 1 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="lower_1" path="M66.6666,111.1111 L66.6666,128.5714" dur="300ms" begin="left_to_right.begin+93.75ms; right_to_left.begin+375ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <animate attributeName="rx" dur="300ms" begin="lower_1.begin" calcMode="spline" values="8; 8.4; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <animate attributeName="ry" dur="300ms" begin="lower_1.begin" calcMode="spline" values="8; 7.6; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <set attributeName="fill" to="black" begin="lower_1.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="66.6666" cy="111.1111"> <set attributeName="fill" to="transparent" begin="lower_1.begin" fill="freeze" ></set> </ellipse> <!-- end: lower vertical circle 1 --> <!-- start: upper vertical circle 2 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="upper_2" path="M88.8888,88.8888 L88.8888,71.4285" dur="300ms" begin="left_to_right.begin+187.5ms; right_to_left.begin+281.25ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <animate attributeName="rx" dur="300ms" begin="upper_2.begin" calcMode="spline" values="8; 8.4; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <animate attributeName="ry" dur="300ms" begin="upper_2.begin" calcMode="spline" values="8; 7.6; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <set attributeName="fill" to="black" begin="upper_2.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="88.8888" cy="88.8888"> <set attributeName="fill" to="transparent" begin="upper_2.begin" fill="freeze" ></set> </ellipse> <!-- end: upper vertical circle 2 --> <!-- start: lower vertical circle 2 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="lower_2" path="M88.8888,111.1111 L88.8888,128.5714" dur="300ms" begin="left_to_right.begin+187.5ms; right_to_left.begin+281.25ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <animate attributeName="rx" dur="300ms" begin="lower_2.begin" calcMode="spline" values="8; 8.4; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <animate attributeName="ry" dur="300ms" begin="lower_2.begin" calcMode="spline" values="8; 7.6; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <set attributeName="fill" to="black" begin="lower_2.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="88.8888" cy="111.1111"> <set attributeName="fill" to="transparent" begin="lower_2.begin" fill="freeze" ></set> </ellipse> <!-- end: lower vertical circle 2 --> <!-- start: upper vertical circle 3 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="upper_3" path="M111.1111,88.8888 L111.1111,71.4285" dur="300ms" begin="left_to_right.begin+281.25ms; right_to_left.begin+187.5ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <animate attributeName="rx" dur="300ms" begin="upper_3.begin" calcMode="spline" values="8; 8.4; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <animate attributeName="ry" dur="300ms" begin="upper_3.begin" calcMode="spline" values="8; 7.6; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <set attributeName="fill" to="black" begin="upper_3.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="111.1111" cy="88.8888"> <set attributeName="fill" to="transparent" begin="upper_3.begin" fill="freeze" ></set> </ellipse> <!-- end: upper vertical circle 3 --> <!-- start: lower vertical circle 3 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="lower_3" path="M111.1111,111.1111 L111.1111,128.5714" dur="300ms" begin="left_to_right.begin+281.25ms; right_to_left.begin+187.5ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <animate attributeName="rx" dur="300ms" begin="lower_3.begin" calcMode="spline" values="8; 8.4; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <animate attributeName="ry" dur="300ms" begin="lower_3.begin" calcMode="spline" values="8; 7.6; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <set attributeName="fill" to="black" begin="lower_3.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="111.1111" cy="111.1111"> <set attributeName="fill" to="transparent" begin="lower_3.begin" fill="freeze" ></set> </ellipse> <!-- end: lower vertical circle 3 --> <!-- start: upper vertical circle 4 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="upper_4" path="M133.3333,88.8888 L133.3333,71.4285" dur="300ms" begin="left_to_right.begin+375ms; right_to_left.begin+93.75ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <animate attributeName="rx" dur="300ms" begin="upper_4.begin" calcMode="spline" values="8; 8.4; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <animate attributeName="ry" dur="300ms" begin="upper_4.begin" calcMode="spline" values="8; 7.6; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <set attributeName="fill" to="black" begin="upper_4.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="133.3333" cy="88.8888"> <set attributeName="fill" to="transparent" begin="upper_4.begin" fill="freeze" ></set> </ellipse> <!-- end: upper vertical circle 4 --> <!-- start: lower vertical circle 4 --> <ellipse fill="transparent" rx="8" ry="8"> <animateMotion id="lower_4" path="M133.3333,111.1111 L133.3333,128.5714" dur="300ms" begin="left_to_right.begin+375ms; right_to_left.begin+93.75ms" fill="freeze" calcMode="spline" keyPoints="0; 1; 0" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animateMotion> <animate attributeName="rx" dur="300ms" begin="lower_4.begin" calcMode="spline" values="8; 8.4; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <animate attributeName="ry" dur="300ms" begin="lower_4.begin" calcMode="spline" values="8; 7.6; 8" keyTimes="0; 0.5; 1" keySplines="0.42, 0, 0.58, 1; 0.42, 0, 0.58, 1" ></animate> <set attributeName="fill" to="black" begin="lower_4.begin" fill="freeze" ></set> </ellipse> <ellipse fill="black" rx="8" ry="8" cx="133.3333" cy="111.1111"> <set attributeName="fill" to="transparent" begin="lower_4.begin" fill="freeze" ></set> </ellipse> <!-- end: lower vertical circle 4 --></svg>