# Animation
Note
The following functions are in the vjmap namespace. Remember to prefix with vjmap before execution, e.g. vjmap.createAnimation
# Animation
animate executes keyframe or spring animations.
createAnimation({
from: 0,
to: 100,
onUpdate: latest => console.log(latest)
})
2
3
4
5
It can animate numbers:
createAnimation({ from: 0, to: 100 })
Or strings of the same type:
createAnimation({ from: "0px", to: "100px" })
createAnimation({ from: "#fff", to: "#000" })
2
Strings can be quite complex, such as box shadows or SVG path definitions. The only limitation is that the numbers and colors they contain must be in the same order:
createAnimation({
from: "0px 0px 0px rgba(0, 0, 0, 0)",
to: "10px 10px 0px rgba(0, 0, 0, 0.2)"
})
2
3
4
The animation type will be auto-detected from the provided options, or you can manually select by defining type as "keyframes", "spring", or "decay".
# Options
These options can be set for all animations:
# from
Initial value to start the animation.
Defaults to 0
createAnimation({
from: "linear-gradient(#e66465, #9198e5)",
to: "linear-gradient(#9198e5, #e66465)"
})
2
3
4
# elapsed
Set initial elapsed time in milliseconds. Use negative values for delay.
createAnimation({
to: 100,
elapsed: -300
})
2
3
4
# repeat
Number of times to repeat the animation. Set to Infinity to repeat forever.
createAnimation({
to: 100,
repeat: 2
})
2
3
4
# repeatDelay
Duration to wait before repeating the animation, in milliseconds.
createAnimation({
to: 100,
repeat: 2,
repeatDelay: 200
})
2
3
4
5
# repeatType
Either "loop", "mirror" or "reverse". Default is "loop".
"loop": Repeat animation from0."mirror":Alternately swapfrom/tovalues."reverse":Alternately reverse the animation.
createAnimation({
to: 100,
repeat: 2,
repeatType: "reverse"
})
2
3
4
5
# type
animate will auto-detect the animation type from the provided options. You can also manually select a specific type by defining type as "keyframes", "spring", or "decay".
createAnimation({
to: 100,
type: "spring"
})
2
3
4
# Lifecycle Events
The following lifecycle events are available for all animations:
# onUpdate
Called every frame as the animation triggers with the latest computed value.
createAnimation({
to: 100,
onUpdate: latest => console.log(latest)
})
2
3
4
# onPlay
Called when the animation starts. Currently, this runs automatically when animate is called.
createAnimation({
to: 100,
onPlay: () => {}
})
2
3
4
# onComplete
Called when the animation completes successfully.
createAnimation({
to: 100,
onComplete:() => {}
})
2
3
4
# onRepeat
Called when the animation repeats.
createAnimation({
to: 100,
repeat: 2,
onRepeat: () => {}
})
2
3
4
5
# onStop
Called when the animation is stopped by the stop control.
const animation = createAnimation({
to: 100,
onStop: () => {}
})
animation.stop()
2
3
4
5
6
Keyframe Options
Keyframe animation is the default type and can be defined with from and to options:
createAnimation({ from: 0, to: 100 })
Or as a series of keyframes provided to the to option:
createAnimation({ to: [0, 100, 200] })
# to
Single value to animate, or array of values to animate.
createAnimation({
to: ["#0ff", "#f00", "#0f0"]
})
2
3
If to is an array, any defined from will be ignored.
# duration
Defines the animation duration in milliseconds.
createAnimation({
to: 100,
duration: 300
})
2
3
4
# ease
An easing function or array of functions for easing between each keyframe.
nimate({
to: 100,
ease: linear
})
createAnimation({
to: ["#fff", "#000", "#f00"],
ease: [linear, easeInOut]
})
2
3
4
5
6
7
8
9
If set to an array, the length of this array must be one less than the number of values being animated between.
# offset
An array of values between 0 and 1 that defines at which point in the overall animation each keyframe should be reached.
The array length should match the number of defined keyframes.
createAnimation({
to: ["#fff", "#000", "#f00"],
offset: [0, 0.2, 1]
})
2
3
4
# Spring Options
Springs are great for creating natural-feeling interfaces and interruptible dynamic animations.
Spring animation will be used if any of the stiffness, damping, or mass options are detected.
Note: Spring simulation is inherently numerical, so if given a color, array, or object, it will run the animation from 0 to 100 and interpolate to the given value.
# to
Single value to animate.
createAnimation({
to: 100,
type: "spring"
})
2
3
4
If to is an array, any defined from will be ignored.
# stiffness
Defines the stiffness of the spring. Higher stiffness produces faster animation.
Default is 100
createAnimation({
to: 100,
stiffness: 1000
})
2
3
4
# damping
This is the counterforce to stiffness. When you decrease this value relative to stiffness, the spring becomes more elastic and the animation lasts longer. Similarly, higher relative values will have less elasticity and result in shorter animation.
Default is 10
createAnimation({
to: 100,
damping: 50
})
2
3
4
# mass
This is the mass of the animated object. Heavier objects take longer to accelerate and decelerate.
Default is 1.
createAnimation({
to: 100,
mass: 2
})
2
3
4
# velocity
Initial velocity of the animation, in units per second.
createAnimation({
to: 100,
velocity: 1000
})
2
3
4
# duration
Duration of the spring in milliseconds.
Will be overridden by stiffness, mass, or damping.
createAnimation({
to: 100,
duration: 1000
})
2
3
4
# bounce
Bounciness of the spring, as a value between 0 and 1, where 0 has no bounce.
Will be overridden by stiffness, mass, or damping.
createAnimation({
to: 100,
bounce: 0.2
})
2
3
4
# restDelta
Distance from the animation target at which the animation can be considered complete. Animation completes when both restDelta and restSpeed are satisfied.
createAnimation({
to: 100,
restDelta: 0.5
})
2
3
4
# restSpeed
Absolute velocity in units per second below which the animation can be considered complete. Animation completes when both restDelta and restSpeed are satisfied. Default is 10.
js createAnimation({ to: 100, restSpeed: 5 })
# Playback Control
createAnimation returns PlaybackControls, which can be used to control animation playback.
Currently this only includes a stop method, but may be extended with more.
# stop
Stop the animation.
const playback = createAnimation({ from: 0, to: 100 })
playback.stop()
2
# inertia
The inertia animation is used to gradually decelerate a number.
# Options
In addition to from, onUpdate, and onComplete, inertia also supports:
# velocity
Initial velocity of the animation, in units per second.
inertia({
from: 0,
velocity: 100
})
2
3
4
# power
Constant used to calculate the target value. Higher power = further target.
Default is 0.8.
inertia({
from: 0,
power: 0.3
})
2
3
4
# timeConstant
Adjusting the time constant changes the deceleration duration.
Default is 350.
inertia({
from: 0,
velocity: 100,
timeConstant: 400
})
2
3
4
5
# modifyTarget
A function that receives the calculated target and returns a new target. Used to snap the target to a grid.
const roundToNearest = target => v => Math.ceil(v / target) * target
inertia({
from: 0,
velocity: 100,
modifyTarget: roundToNearest(100)
})
2
3
4
5
6
7
# min
Minimum value. The animation will switch from gradual deceleration and use spring animation to snap to this point.
inertia({
from: 50,
velocity: -100,
min: 0
})
2
3
4
5
# max
Maximum value. The animation will switch from gradual deceleration and use spring animation to snap to this point.
inertia({
from: 50,
velocity: 100,
max: 100
})
2
3
4
5
# bounceStiffness
Defines the stiffness of the spring when the animation hits min or max. Higher stiffness produces faster animation.
Default is 500
inertia({
from: 0,
velocity: 100,
max: 50,
bounceStiffness: 1000
})
2
3
4
5
6
# bounceDamping
This is the counterforce to bounceStiffness. When you decrease this value relative to bounceStiffness, the spring becomes more elastic and the animation lasts longer. Similarly, higher relative values will have less elasticity and result in shorter animation.
Default is 10
inertia({
from: 0,
velocity: 100,
max: 50,
bounceDamping: 300
})
2
3
4
5
6
# restDelta
Distance from the animation target at which the animation can be considered complete.
inertia({
from: 0,
velocity: 100,
restDelta: 0.5
})
2
3
4
5
# Iterators
Iterators let you run animations with a high degree of control.
Each can be initialized with the matching options above (decay uses a subset of inertia's options, excluding bounce- options):
const animation = spring({
from: 0,
to: 100,
stiffness: 200
})
2
3
4
5
Using the returned iterator, you can resolve the animation at a specific timestamp with its next method.
// Resolve animation at 200 milliseconds
const { value, done } = animation.next(200)
2
# Easing
Built-in easing functions
# Functions
Each easing function can be imported like this:
Each function accepts a progress value between 0 and 1 and returns a new value:
const progress = 0.5
const easedProgress = easeInOut(progress)
2
- linear
- easeIn
- easeInOut
- easeOut
- circIn
- circInOut
- circOut
- backIn
- backInOut
- backOut
- anticipate
- bounceIn
- bounceInOut
- bounceOut
# cubicBezier
const easing = cubicBezier(0, .42, 0, 1)
# steps
steps returns an easing function that converts the animation into a series of discrete steps.
const easing = steps(5)
It can optionally accept a second parameter, "start" or "end" (default) to determine whether steps align with the start or end of the animation.
steps(5, "start")
# mirrorEasing
Mirror an existing easing function.
# reverseEasing
Reverse an existing easing function. For example, providing it easeIn returns an easeOut.
const reversed = reverseEasing(linear)
reversed(1) // 0
reversed(0.5) // 0.5
reversed(0) // 1
2
3
4
# createExpoIn
Create an easing function based on the provided exponential power. Higher power means stronger easing.
const expoIn = createExpoIn(4)
The returned easing function is an ease-in, meaning it starts slow and ends fast. mirrorEasing and reverseEasing can be used to create ease-in and ease-out variants:
const expoIn = createExpoIn(4)
const expoOut = mirrorEasing(easeIn)
const expoInOut = reverseEasing(easeIn)
2
3
# createBackIn
Create an easing function with overshoot. It accepts a power value; higher power means stronger overshoot.
const backIn = createBackIn(4)
The returned easing function is an ease-in, meaning overshoot occurs at the start of the animation. mirrorEasing and reverseEasing can be used to create ease-in and ease-out variants:
const backIn = createBackIn(4)
const backOut = mirrorEasing(easeIn)
const backInOut = reverseEasing(easeIn)
2
3
# createAnticipate
Create an easing that pulls back slightly before animating with overshoot. The stronger the power, the greater the overshoot.
const anticipate = createAnticipate(4)
# General
# angle
Returns the angle between two points in degrees.
angle(
{ x: 0, y: 0 },
{ x: 45, y: 100 }
)
2
3
4
# attract
attract(5, 10, 12)
# attractExpo
attractExpo(5, 10, 12)
# clamp
Clamp a value to a given range.
const min = 50
const max = 100
clamp(min, max, 150) // 100
2
3
# degreesToRadians
Convert degrees to radians.
degreesToRadians(45) // 0.785...
# distance
Returns the distance between two numbers, two 2D points, or two 3D points.
distance(10, 50)
distance({ x: 0, y: 0 }, { x: 45, y: 100 })
distance({ x: 0, y: 0, z: 100 }, { x: 45, y: 100, z: 0 })
2
3
# interpolate
Creates a function that interpolates from a linear number sequence to a non-linear number sequence, strings of the same number format, colors, or their arrays/objects.
const mapXToOpacity = interpolate(
[-100, 0, 100],
[0, 1, 0]
)
mapXToOpacity(-50) // 0.5
const mapProgressToValues = interpolate(
[0, 1],
[
{ x: 0, color: "#fff" },
{ x: 100, color: "#000" }
]
)
mapProgressToValues(0.5) // { x: 50, color: "#888" }
const rescale = interpolate(
[0, 1],
[100, 200],
{ clamp: false }
)
rescale(2) // 300
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Options
interpolate accepts an optional third parameter, an options object.
- clamp: Clamp values to the given range. Default is true.
- ease: An Easing function or array of easing functions to ease the interpolation of each segment.
- mixer: A function that, when given from and to values, returns a new function that accepts a progress value between 0 and 1 and blends between these two values.
# isPoint
Returns true if the provided argument is a 2D point.
isPoint({ x: 0 }) // false
isPoint({ x: 0, y: 0 }) // true
2
# isPoint3D
Returns true if the provided argument is a 3D point.
isPoint3D({ x: 0 }) // false
isPoint3D({ x: 0, y: 0 }) // false
isPoint3D({ x: 0, y: 0, z: 0 }) // true
2
3
# mix
Will blend between two values, with progress given as the third parameter.
mix(0, 100, 0.5) // 50
mix(0, 100, 2) // 200
2
# mixColor
Returns a function that, when given a progress value, blends between two colors. Accepts hex, rgba, and hsla colors.
mixColor("#000", "#fff")(0.5) // "rgba(125, 125, 125, 1)"
# mixComplex
Returns a function that, when given a progress value, blends between two strings with the same number and color order.
mixComplex("100px #fff", "0px #000")(0.5) // "50px rgba(125, 125, 125, 1)"
# pointFromVector
Given a point, angle in degrees, and distance, returns a new point.
const point = { x: 0, y: 0 }
const angle = 45
const distance = 100
pointFromVector(point, angle, distance)
2
3
4
5
# progress
Given a min and max range and a value, returns the value normalized to a 0-1 progress range.
const min = 100
const max = 200
progress(min, max, 150) // 0.5
2
3
# radiansToDegrees
Convert radians to degrees.
radiansToDegrees(0.785) // 45
# snap
Creates a function that snaps numbers to the nearest position in the provided array or fixed interval.
// Snap to regular intervals
const snapTo = snap(45);
snapTo(1); // 0
snapTo(40); // 45
snapTo(50); // 45
snapTo(80); // 90
// Snap to values in an array
const snapTo = snap([-100, -50, 100, 200]);
snapTo(-200); // -100
snapTo(-76); // -100
snapTo(-74); // -50
2
3
4
5
6
7
8
9
10
11
12
13
14
# toDecimal
Round a number to a specific decimal place.
toDecimal(3.3333); // 3.33
toDecimal(6.6666, 1); // 6.67
2
# velocityPerFrame
velocityPerFrame(50, 16.7); // 0.835
# velocityPerSecond
velocityPerSecond(1, 16.7); // 59.880...
# wrap
wrap(0, 1, 0.5); // 0.5
wrap(0, 1, 1.5); // 0.5
2