UNPKG

7.21 kBPlain TextView Raw
1'use strict';
2import { Bezier } from './Bezier';
3
4/**
5 * The `Easing` module implements common easing functions. This module is used
6 * by [Animate.timing()](docs/animate.html#timing) to convey physically
7 * believable motion in animations.
8 *
9 * You can find a visualization of some common easing functions at
10 * http://easings.net/
11 *
12 * ### Predefined animations
13 *
14 * The `Easing` module provides several predefined animations through the
15 * following methods:
16 *
17 * - [`back`](docs/easing.html#back) provides a simple animation where the
18 * object goes slightly back before moving forward
19 * - [`bounce`](docs/easing.html#bounce) provides a bouncing animation
20 * - [`ease`](docs/easing.html#ease) provides a simple inertial animation
21 * - [`elastic`](docs/easing.html#elastic) provides a simple spring interaction
22 *
23 * ### Standard functions
24 *
25 * Three standard easing functions are provided:
26 *
27 * - [`linear`](docs/easing.html#linear)
28 * - [`quad`](docs/easing.html#quad)
29 * - [`cubic`](docs/easing.html#cubic)
30 *
31 * The [`poly`](docs/easing.html#poly) function can be used to implement
32 * quartic, quintic, and other higher power functions.
33 *
34 * ### Additional functions
35 *
36 * Additional mathematical functions are provided by the following methods:
37 *
38 * - [`bezier`](docs/easing.html#bezier) provides a cubic bezier curve
39 * - [`circle`](docs/easing.html#circle) provides a circular function
40 * - [`sin`](docs/easing.html#sin) provides a sinusoidal function
41 * - [`exp`](docs/easing.html#exp) provides an exponential function
42 *
43 * The following helpers are used to modify other easing functions.
44 *
45 * - [`in`](docs/easing.html#in) runs an easing function forwards
46 * - [`inOut`](docs/easing.html#inout) makes any easing function symmetrical
47 * - [`out`](docs/easing.html#out) runs an easing function backwards
48 */
49
50export type EasingFunction = (t: number) => number;
51
52/**
53 * @deprecated Please use {@link EasingFunction} type instead.
54 */
55export type EasingFn = EasingFunction;
56
57export type EasingFunctionFactory = { factory: () => EasingFunction };
58
59/**
60 * @deprecated Please use {@link EasingFunctionFactory} type instead.
61 */
62export type EasingFactoryFn = EasingFunctionFactory;
63/**
64 * A linear function, `f(t) = t`. Position correlates to elapsed time one to
65 * one.
66 *
67 * http://cubic-bezier.com/#0,0,1,1
68 */
69function linear(t: number): number {
70 'worklet';
71 return t;
72}
73
74/**
75 * A simple inertial interaction, similar to an object slowly accelerating to
76 * speed.
77 *
78 * http://cubic-bezier.com/#.42,0,1,1
79 */
80function ease(t: number): number {
81 'worklet';
82 return Bezier(0.42, 0, 1, 1)(t);
83}
84
85/**
86 * A quadratic function, `f(t) = t * t`. Position equals the square of elapsed
87 * time.
88 *
89 * http://easings.net/#easeInQuad
90 */
91function quad(t: number): number {
92 'worklet';
93 return t * t;
94}
95
96/**
97 * A cubic function, `f(t) = t * t * t`. Position equals the cube of elapsed
98 * time.
99 *
100 * http://easings.net/#easeInCubic
101 */
102function cubic(t: number): number {
103 'worklet';
104 return t * t * t;
105}
106
107/**
108 * A power function. Position is equal to the Nth power of elapsed time.
109 *
110 * n = 4: http://easings.net/#easeInQuart
111 * n = 5: http://easings.net/#easeInQuint
112 */
113function poly(n: number): EasingFunction {
114 'worklet';
115 return (t) => {
116 'worklet';
117 return Math.pow(t, n);
118 };
119}
120
121/**
122 * A sinusoidal function.
123 *
124 * http://easings.net/#easeInSine
125 */
126function sin(t: number): number {
127 'worklet';
128 return 1 - Math.cos((t * Math.PI) / 2);
129}
130
131/**
132 * A circular function.
133 *
134 * http://easings.net/#easeInCirc
135 */
136function circle(t: number): number {
137 'worklet';
138 return 1 - Math.sqrt(1 - t * t);
139}
140
141/**
142 * An exponential function.
143 *
144 * http://easings.net/#easeInExpo
145 */
146function exp(t: number): number {
147 'worklet';
148 return Math.pow(2, 10 * (t - 1));
149}
150
151/**
152 * A simple elastic interaction, similar to a spring oscillating back and
153 * forth.
154 *
155 * Default bounciness is 1, which overshoots a little bit once. 0 bounciness
156 * doesn't overshoot at all, and bounciness of N \> 1 will overshoot about N
157 * times.
158 *
159 * http://easings.net/#easeInElastic
160 */
161function elastic(bounciness = 1): EasingFunction {
162 'worklet';
163 const p = bounciness * Math.PI;
164 return (t) => {
165 'worklet';
166 return 1 - Math.pow(Math.cos((t * Math.PI) / 2), 3) * Math.cos(t * p);
167 };
168}
169
170/**
171 * Use with `Animated.parallel()` to create a simple effect where the object
172 * animates back slightly as the animation starts.
173 *
174 * Wolfram Plot:
175 *
176 * - http://tiny.cc/back_default (s = 1.70158, default)
177 */
178function back(s = 1.70158): (t: number) => number {
179 'worklet';
180 return (t) => {
181 'worklet';
182 return t * t * ((s + 1) * t - s);
183 };
184}
185
186/**
187 * Provides a simple bouncing effect.
188 *
189 * http://easings.net/#easeInBounce
190 */
191function bounce(t: number): number {
192 'worklet';
193 if (t < 1 / 2.75) {
194 return 7.5625 * t * t;
195 }
196
197 if (t < 2 / 2.75) {
198 const t2 = t - 1.5 / 2.75;
199 return 7.5625 * t2 * t2 + 0.75;
200 }
201
202 if (t < 2.5 / 2.75) {
203 const t2 = t - 2.25 / 2.75;
204 return 7.5625 * t2 * t2 + 0.9375;
205 }
206
207 const t2 = t - 2.625 / 2.75;
208 return 7.5625 * t2 * t2 + 0.984375;
209}
210
211/**
212 * Provides a cubic bezier curve, equivalent to CSS Transitions'
213 * `transition-timing-function`.
214 *
215 * A useful tool to visualize cubic bezier curves can be found at
216 * http://cubic-bezier.com/
217 */
218function bezier(
219 x1: number,
220 y1: number,
221 x2: number,
222 y2: number
223): { factory: () => (x: number) => number } {
224 'worklet';
225 return {
226 factory: () => {
227 'worklet';
228 return Bezier(x1, y1, x2, y2);
229 },
230 };
231}
232
233function bezierFn(
234 x1: number,
235 y1: number,
236 x2: number,
237 y2: number
238): (x: number) => number {
239 'worklet';
240 return Bezier(x1, y1, x2, y2);
241}
242
243/**
244 * Runs an easing function forwards.
245 */
246function in_(easing: EasingFunction): EasingFunction {
247 'worklet';
248 return easing;
249}
250
251/**
252 * Runs an easing function backwards.
253 */
254function out(easing: EasingFunction): EasingFunction {
255 'worklet';
256 return (t) => {
257 'worklet';
258 return 1 - easing(1 - t);
259 };
260}
261
262/**
263 * Makes any easing function symmetrical. The easing function will run
264 * forwards for half of the duration, then backwards for the rest of the
265 * duration.
266 */
267function inOut(easing: EasingFunction): EasingFunction {
268 'worklet';
269 return (t) => {
270 'worklet';
271 if (t < 0.5) {
272 return easing(t * 2) / 2;
273 }
274 return 1 - easing((1 - t) * 2) / 2;
275 };
276}
277
278/**
279 * The `steps` easing function jumps between discrete values at regular intervals,
280 * creating a stepped animation effect. The `n` parameter determines the number of
281 * steps in the animation, and the `roundToNextStep` parameter determines whether the animation
282 * should start at the beginning or end of each step.
283 */
284function steps(n = 10, roundToNextStep = true): EasingFunction {
285 'worklet';
286 return (t) => {
287 'worklet';
288 const value = Math.min(Math.max(t, 0), 1) * n;
289 if (roundToNextStep) {
290 return Math.ceil(value) / n;
291 }
292 return Math.floor(value) / n;
293 };
294}
295
296const EasingObject = {
297 linear,
298 ease,
299 quad,
300 cubic,
301 poly,
302 sin,
303 circle,
304 exp,
305 elastic,
306 back,
307 bounce,
308 bezier,
309 bezierFn,
310 steps,
311 in: in_,
312 out,
313 inOut,
314};
315
316export const Easing = EasingObject;