Creating your first animation
We want to create the following animation (click the "Play" button below to see it in action):
Using Japit, we can describe this animation with the following code. Don't worry if you don't understand it yet! We'll go through it step by step.
import { $center, $fill, createAnimation } from 'japit';
const svg = document.querySelector('svg');
svg.style.width = '1000px';
svg.style.height = '500px';
const setup = (b) => {
b.select(1)
.fill('green')
.circle((c) => c.radius(100).centerX(300).centerY(150));
b.select(2)
.fill('purple')
.rectangle((r) => r.topLeftX(700).topLeftY(50).width(100).height(200));
b.select('1-2')
.stroke($fill(1))
.strokeWidth(5)
.zIndex(-1)
.line((l) => l.start($center(1)).end($center(2)));
};
const moveRectangle = (b) => {
b.duration(1);
b.select(2).circle((c) => c.centerY(375));
};
const changeColors = (b) => {
b.duration(0.5);
b.select(1).fill($fill(2));
};
const player = createAnimation(svg, [setup, moveRectangle, changeColors]);
player.play();
Let's start by getting a high-level overview of the code.
Creating the high-level structure
First, we need a canvas to draw our animation on. As Japit is a library for animating SVGs, we'll start by querying an SVG element that is already present in our DOM and set its size:
const svg = document.querySelector('svg');
svg.style.width = '1000px';
svg.style.height = '500px';
Next, we create three functions, setup
, moveRectangle
, and changeColors
, that describe our animation:
const setup = (b) => {
// ...
};
const moveRectangle = (b) => {
// ...
};
const changeColors = (b) => {
// ...
};
The setup
function defines the initial state of our animation; the moveRectangle
function how the rectangle moves down and turns into a circle; and changeColors
how the circle and the line turn purple. We'll take a closer look at how we achieve these particular effects down below, but for now we'll skip to the remaining two lines:
const player = createAnimation(svg, [setup, moveRectangle, changeColors]);
player.play();
We pass the SVG element and an array containing the setup
, moveRectangle
, and changeColors
functions to createAnimation
. The function returns an AnimationPlayer
object, which can play the three steps of our animation in order. Then we call play
on it to start playing the animation.
Describing the actual animation
Let's take a closer look at setup
:
const setup = (b) => {
b.select(1)
.fill('green')
.circle((c) => c.radius(100).centerX(300).centerY(150));
b.select(2)
.fill('purple')
.rectangle((r) => r.topLeftX(700).topLeftY(50).width(100).height(200));
b.select('1-2')
.stroke($fill(1))
.strokeWidth(5)
.zIndex(-1)
.line((l) => l.start($center(1)).end($center(2)));
};
Creating elements
In Japit, we refer to every element in our animation via an identifier, which is a Number, String, or Symbol. Here we use
1
as identifier for the left circle,2
for the right rectangle, and'1-2'
for the line connecting them.
To change an element with a given identifier, we call the select
method on the AnimationBuilder
b
and pass in the identifier. There is no need to explicitly create the elements as Japit will create them for us on the fly.
After selecting an element, we can change its properties by calling methods on the TransitionBuilder
returned by select
. Here we set the fill color of 1
to green and change its shape to a circle with radius 100
at x-coordinate 300
and y-coordinate 100
via:
b.select(1)
.fill('green')
.circle((c) => c.radius(100).centerX(300).centerY(150));
Similarly, we create the rectangle with identifier 2
by calling:
b.select(2)
.fill('purple')
.rectangle((r) => r.topLeftX(700).topLeftY(50).width(100).height(200));
Expressing dependencies
Last, we construct the line '1-2'
connecting the two shapes. However, this time we don't specify its fill and endpoints explicitly. Instead, we use the $fill
and $center
functions to set its fill to the fill of 1
and its endpoints to the centers of 1
and 2
, respectively:
b.select('1-2')
.stroke($fill(1))
.strokeWidth(5)
.zIndex(-1)
.line((l) => l.start($center(1)).end($center(2)));
Animating values
It's time to start animating. We move the rectangle down and turn it into a circle via:
const moveRectangle = (b) => {
b.duration(1);
b.select(2).circle((c) => c.centerY(375));
};
Calling b.duration(1)
sets the duration of the animation to one second. Then we select the rectangle via its identifier 2
and change its shape to a circle with y-coordinate of 375
. Notice that Japit automatically infers the unspecified values like the x-coordinate and radius of the circle from the shape of the rectangle.
Observe how the endpoint of the line is automatically updated to match the center of 2
as we set the endpoint of '1-2'
to $center(2)
above.
Last, we change the fill color of 1
to the fill color of 2
:
const changeColors = (b) => {
b.duration(0.5);
b.select(1).fill($fill(2));
};
Now, the stroke of '1-2'
is equal to the fill of 1
, which is in turn equal to the fill of 2
, resulting in all three elements being 'purple'.
There is no difference between setting values and animating them. Setting a value just corresponds to an animation with a duration of 0
. As 0
is the default duration, there is no need to explicitly specify it in setup
.