stage-js
Version:
2D HTML5 Rendering and Layout
251 lines (234 loc) • 6.62 kB
text/typescript
/** @internal */
export const IDENTITY = (x: any) => {
return x;
};
export type EasingFunctionQuery = string;
export type EasingFunction = (p: number) => number;
/** @internal */
type EasingFactories = (...params: any[]) => EasingFunction;
// todo: pass additional params as ...rest, instead of factories/curring? (`fc`)
export class Easing {
static init(
query: EasingName | EasingFunctionQuery | EasingFunction,
params?: number[],
): EasingFunction | undefined {
if (typeof query === "function") return query;
if (typeof query !== "string") return undefined;
let easing: EasingFunction;
if (query.indexOf("(") === -1) {
easing = initEasing(query, params);
} else {
const tokens = /^((\w|-)+)?(\((.*)\))?$/i.exec(query);
if (tokens || tokens.length) {
const name2 = tokens[1];
const params2 = JSON.parse("[" + tokens[4] + "]") as number[];
easing = initEasing(name2, params2);
}
}
return easing;
}
}
/** @internal */
const initEasing = (query: string, params?: number[]): EasingFunction => {
let easing: EasingFunction;
const easingFunction = EasingFunctions[query];
const easingFactory = EasingFactories[query];
if (easingFunction) {
easing = easingFunction;
} else if (easingFactory) {
if (params) {
easing = easingFactory.apply(null, params);
} else {
easing = easingFactory();
}
}
return easing;
};
/** @internal */ const out = (f: EasingFunction) => (t: number) => 1 - f(1 - t);
/** @internal */ const inOut = (f: EasingFunction) => (t: number) =>
t < 0.5 ? f(2 * t) / 2 : 1 - f(2 * (1 - t)) / 2;
/** @internal */ const outIn = (f: EasingFunction) => (t: number) =>
t < 0.5 ? 1 - f(2 * (1 - t)) / 2 : f(2 * t) / 2;
/** @internal */ const linear: EasingFunction = (t: number) => t;
/** @internal */ const quad: EasingFunction = (t: number) => t * t;
/** @internal */ const cubic: EasingFunction = (t: number) => t * t * t;
/** @internal */ const quart: EasingFunction = (t: number) => t * t * t * t;
/** @internal */ const quint: EasingFunction = (t: number) => t * t * t * t * t;
/** @internal */ const sin: EasingFunction = (t: number) => 1 - Math.cos((t * Math.PI) / 2);
/** @internal */ const exp: EasingFunction = (t: number) =>
t == 0 ? 0 : Math.pow(2, 10 * (t - 1));
/** @internal */ const circle: EasingFunction = (t: number) => 1 - Math.sqrt(1 - t * t);
/** @internal */ const bounce: EasingFunction = (t: number) =>
t < 1 / 2.75
? 7.5625 * t * t
: t < 2 / 2.75
? 7.5625 * (t -= 1.5 / 2.75) * t + 0.75
: t < 2.5 / 2.75
? 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375
: 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
/** @internal */ const poly =
(e: number = 3): EasingFunction =>
(t: number) =>
Math.pow(t, e);
/** @internal */ const elastic = (a: number = 1, p: number = 0.45): EasingFunction => {
/** @internal */ const s = (p / (2 * Math.PI)) * Math.asin(1 / a);
return (t: number) => 1 + a * Math.pow(2, -10 * t) * Math.sin(((t - s) * (2 * Math.PI)) / p);
};
/** @internal */ const back = (s: number = 1.70158): EasingFunction => {
return (t: number) => t * t * ((s + 1) * t - s);
};
/** @internal */ const EasingFunctions = {
"linear": linear,
"linear-in": linear,
"linear-out": out(linear),
"linear-in-out": inOut(linear),
"linear-out-in": outIn(linear),
"quad": quad,
"quad-in": quad,
"quad-out": out(quad),
"quad-in-out": inOut(quad),
"quad-out-in": outIn(quad),
"cubic": cubic,
"cubic-in": cubic,
"cubic-out": out(cubic),
"cubic-in-out": inOut(cubic),
"cubic-out-in": outIn(cubic),
"quart": quart,
"quart-in": quart,
"quart-out": out(quart),
"quart-in-out": inOut(quart),
"quart-out-in": outIn(quart),
"quint": quint,
"quint-in": quint,
"quint-out": out(quint),
"quint-in-out": inOut(quint),
"quint-out-in": outIn(quint),
"sin": sin,
"sin-in": sin,
"sin-out": out(sin),
"sin-in-out": inOut(sin),
"sin-out-in": outIn(sin),
"sine": sin,
"sine-in": sin,
"sine-out": out(sin),
"sine-in-out": inOut(sin),
"sine-out-in": outIn(sin),
"exp": exp,
"exp-in": exp,
"exp-out": out(exp),
"exp-in-out": inOut(exp),
"exp-out-in": outIn(exp),
"expo": exp,
"expo-in": exp,
"expo-out": out(exp),
"expo-in-out": inOut(exp),
"expo-out-in": outIn(exp),
"circle": circle,
"circle-in": circle,
"circle-out": out(circle),
"circle-in-out": inOut(circle),
"circle-out-in": outIn(circle),
"circ": circle,
"circ-in": circle,
"circ-out": out(circle),
"circ-in-out": inOut(circle),
"circ-out-in": outIn(circle),
"bounce": bounce,
"bounce-in": bounce,
"bounce-out": out(bounce),
"bounce-in-out": inOut(bounce),
"bounce-out-in": outIn(bounce),
};
/** @internal */ const EasingFactories = {
"poly": poly,
"poly-in": poly,
"poly-out": (e: number) => out(poly(e)),
"poly-in-out": (e: number) => inOut(poly(e)),
"poly-out-in": (e: number) => outIn(poly(e)),
"elastic": elastic,
"elastic-in": elastic,
"elastic-out": (a: number, p: number) => out(elastic(a, p)),
"elastic-in-out": (a: number, p: number) => inOut(elastic(a, p)),
"elastic-out-in": (a: number, p: number) => outIn(elastic(a, p)),
"back": back,
"back-in": back,
"back-out": (s: number) => out(back(s)),
"back-in-out": (s: number) => inOut(back(s)),
"back-out-in": (s: number) => outIn(back(s)),
};
export type EasingName =
| "linear"
| "linear-in"
| "linear-out"
| "linear-in-out"
| "linear-out-in"
| "quad"
| "quad-in"
| "quad-out"
| "quad-in-out"
| "quad-out-in"
| "cubic"
| "cubic-in"
| "cubic-out"
| "cubic-in-out"
| "cubic-out-in"
| "quart"
| "quart-in"
| "quart-out"
| "quart-in-out"
| "quart-out-in"
| "quint"
| "quint-in"
| "quint-out"
| "quint-in-out"
| "quint-out-in"
| "sin"
| "sin-in"
| "sin-out"
| "sin-in-out"
| "sin-out-in"
| "sine"
| "sine-in"
| "sine-out"
| "sine-in-out"
| "sine-out-in"
| "exp"
| "exp-in"
| "exp-out"
| "exp-in-out"
| "exp-out-in"
| "expo"
| "expo-in"
| "expo-out"
| "expo-in-out"
| "expo-out-in"
| "circle"
| "circle-in"
| "circle-out"
| "circle-in-out"
| "circle-out-in"
| "circ"
| "circ-in"
| "circ-out"
| "circ-in-out"
| "circ-out-in"
| "bounce"
| "bounce-in"
| "bounce-out"
| "bounce-in-out"
| "bounce-out-in"
| "poly"
| "poly-in"
| "poly-out"
| "poly-in-out"
| "poly-out-in"
| "elastic"
| "elastic-in"
| "elastic-out"
| "elastic-in-out"
| "elastic-out-in"
| "back"
| "back-in"
| "back-out"
| "back-in-out"
| "back-out-in";