Interpolation
During an animation, Presenter.js calculates a progress value and uses it to produce the intermediate value of every animated property:
- The animation's
easingfunction converts elapsed time into eased progress. - An interpolator converts that progress into a value between the property's starting and ending values.
Presenter.js includes easing functions such as Easing.LINEAR and
Easing.CUBIC; it also includes default interpolators for numbers and colors.
Both parts of the process can be customized.
Custom Easing Functions
Define a custom easing function by writing a function that obeys the type:
type EasingFunction = (t: number) => number;
An easing function accepts a normalized time from 0 at the start of an
animation to 1 at the end and returns its progress. It should return 0 for
an input of 0 and 1 for an input of 1. Values outside that range can
create effects such as overshooting the destination.
This easing function uses a cosine wave whose size decreases over time, making the object bounce around its destination before settling:
import { Animate, Slide, type EasingFunction } from "presenter";
const bounceAtEnd: EasingFunction = (time) => 1 - Math.cos(time * Math.PI * 3) * (1 - time);
const slide = Slide({ objects: [label, circle], animations: [ Animate(circle, { x: 2500 }, { duration: 1600, easing: bounceAtEnd, }), ],});Pass any function with the EasingFunction signature to the easing option of
Animate. The resulting progress is then passed to the interpolator for each
property in that animation.
Custom Interpolator Functions
Define a custom interpolator by creating a value that follows the interface:
interface Interpolator<T> {
check: (value: unknown, propertyName: string) => value is T;
interpolate: (from: T, to: T, proportion: number) => T;
}
An Interpolator<T> has two functions:
check(value, propertyName)determines whether the interpolator handles a value. Presenter.js calls it for both the starting and ending values.interpolate(from, to, proportion)returns the value to render at the current eased proportion.
Here is a small interpolator that moves an object's x position in 400-pixel
steps:
import { Animate, Slide, type Interpolator } from "presenter";
const snapToGrid: Interpolator<number> = { check: (value, propertyName): value is number => propertyName === "x" && typeof value === "number", interpolate: (from, to, progress) => Math.round((from + (to - from) * progress) / 400) * 400,};
const slide = Slide({ objects: [box], animations: [ Animate(box, { x: 3200 }, { duration: 1600, interpolators: [snapToGrid], }), ],});Provide custom interpolators through the interpolators option. Presenter.js
checks them in array order before its built-in interpolators and uses the first
one that matches both values. Built-in number and color interpolation remains
available when none of the custom entries match.
Interpolating numeric text
Text objects normally don't have special interpolation handling so they fall
back to default behavior, where changing a Text object's text property from
"0" to "100" is an immediate change rather than a smooth one. A custom
interpolator can recognize numeric strings and calculate the text for each
frame:
import { Animate, Easing, Slide, Text, type Interpolator } from "presenter";
const interpolateNumericText: Interpolator<string> = { check: (value, propertyName): value is string => propertyName === "text" && typeof value === "string" && !Number.isNaN(Number(value)), interpolate: (from, to, progress) => String(Math.round(Number(from) + (Number(to) - Number(from)) * progress)),};
const counter = Text("0", { /* ... additional properties ... */});
const slide = Slide({ objects: [label, counter], animations: [ Animate(counter, { text: "100" }, { duration: 1600, easing: Easing.CUBIC, interpolators: [interpolateNumericText], }), ],});