1 | ;
|
2 | import { 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 |
|
50 | export type EasingFunction = (t: number) => number;
|
51 |
|
52 | /**
|
53 | * @deprecated Please use {@link EasingFunction} type instead.
|
54 | */
|
55 | export type EasingFn = EasingFunction;
|
56 |
|
57 | export type EasingFunctionFactory = { factory: () => EasingFunction };
|
58 |
|
59 | /**
|
60 | * @deprecated Please use {@link EasingFunctionFactory} type instead.
|
61 | */
|
62 | export 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 | */
|
69 | function 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 | */
|
80 | function 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 | */
|
91 | function 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 | */
|
102 | function 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 | */
|
113 | function 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 | */
|
126 | function 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 | */
|
136 | function 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 | */
|
146 | function 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 | */
|
161 | function 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 | */
|
178 | function 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 | */
|
191 | function 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 | */
|
218 | function 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 |
|
233 | function 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 | */
|
246 | function in_(easing: EasingFunction): EasingFunction {
|
247 | 'worklet';
|
248 | return easing;
|
249 | }
|
250 |
|
251 | /**
|
252 | * Runs an easing function backwards.
|
253 | */
|
254 | function 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 | */
|
267 | function 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 | */
|
284 | function 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 |
|
296 | const 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 |
|
316 | export const Easing = EasingObject;
|