From 9ad2c322c0affd0454c087d4e64edaad79f01f63 Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Mon, 31 Aug 2015 13:50:24 -0700 Subject: [PATCH] [RN] improve elastic easing Summary: 1) Makes params more intuitive (only one now, bounciness, which maps intuitively to number of oscillations). 2) Satisfies boundary conditions (f(0) = 0, f(1) = 1) so animation actually goes where you tell it (before it would finish at a random location depending on the input params). 3) Simple test to verify boundary conditions. --- Libraries/Animated/Easing.js | 29 +++++++++++---------- Libraries/Animated/__tests__/Easing-test.js | 8 ++++++ 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Libraries/Animated/Easing.js b/Libraries/Animated/Easing.js index ae90136d1..58969278b 100644 --- a/Libraries/Animated/Easing.js +++ b/Libraries/Animated/Easing.js @@ -59,21 +59,22 @@ class Easing { return Math.pow(2, 10 * (t - 1)); } - static elastic(a: number, p: number): (t: number) => number { - var tau = Math.PI * 2; - // flow isn't smart enough to figure out that s is always assigned to a - // number before being used in the returned function - var s: any; - if (arguments.length < 2) { - p = 0.45; + /** + * A simple elastic interaction, similar to a spring. Default bounciness + * is 1, which overshoots a little bit once. 0 bounciness doesn't overshoot + * at all, and bounciness of N > 1 will overshoot about N times. + * + * Wolfram Plots: + * + * http://tiny.cc/elastic_b_1 (default bounciness = 1) + * http://tiny.cc/elastic_b_3 (bounciness = 3) + */ + static elastic(bounciness: number): (t: number) => number { + if (arguments.length === 0) { + bounciness = 1; } - if (arguments.length) { - s = p / tau * Math.asin(1 / a); - } else { - a = 1; - s = p / 4; - } - return (t) => 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * tau / p); + var p = bounciness * Math.PI; + return (t) => 1 - Math.pow(Math.cos(t * Math.PI / 2), 3) * Math.cos(t * p); }; static back(s: number): (t: number) => number { diff --git a/Libraries/Animated/__tests__/Easing-test.js b/Libraries/Animated/__tests__/Easing-test.js index bee894d6f..b865250d7 100644 --- a/Libraries/Animated/__tests__/Easing-test.js +++ b/Libraries/Animated/__tests__/Easing-test.js @@ -71,6 +71,14 @@ describe('Easing', () => { } }); + it('should satisfy boundary conditions with elastic', () => { + for (var b = 0; b < 4; b += 0.3) { + var easing = Easing.elastic(b); + expect(easing(0)).toBe(0); + expect(easing(1)).toBe(1); + } + }); + function sampleEasingFunction(easing) { var DURATION = 300; var tickCount = Math.round(DURATION * 60 / 1000);