mirror of
https://github.com/status-im/react-native.git
synced 2025-01-27 01:40:08 +00:00
Add support for extrapolation
Summary: Adds support for the `extrapolate` parameter on the native interpolation node. This is pretty much a 1 to 1 port of the JS implementation. **Test plan** Tested by adding the `extrapolate` parameter in the native animated UIExplorer example. Closes https://github.com/facebook/react-native/pull/9366 Differential Revision: D3824154 fbshipit-source-id: 2ef593af827a8bd3d7b8ab2d53abbdc9516c6022
This commit is contained in:
parent
fab0ff35f1
commit
6d978c3c8b
@ -1071,11 +1071,16 @@ class AnimatedInterpolation extends AnimatedWithChildren {
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
NativeAnimatedHelper.validateInterpolation(this._config);
|
||||
if (__DEV__) {
|
||||
NativeAnimatedHelper.validateInterpolation(this._config);
|
||||
}
|
||||
|
||||
return {
|
||||
...this._config,
|
||||
inputRange: this._config.inputRange,
|
||||
// Only the `outputRange` can contain strings so we don't need to tranform `inputRange` here
|
||||
outputRange: this.__transformDataType(this._config.outputRange),
|
||||
extrapolateLeft: this._config.extrapolateLeft || this._config.extrapolate || 'extend',
|
||||
extrapolateRight: this._config.extrapolateRight || this._config.extrapolate || 'extend',
|
||||
type: 'interpolation',
|
||||
};
|
||||
}
|
||||
|
@ -135,6 +135,9 @@ function validateInterpolation(config: Object): void {
|
||||
var SUPPORTED_INTERPOLATION_PARAMS = {
|
||||
inputRange: true,
|
||||
outputRange: true,
|
||||
extrapolate: true,
|
||||
extrapolateRight: true,
|
||||
extrapolateLeft: true,
|
||||
};
|
||||
for (var key in config) {
|
||||
if (!SUPPORTED_INTERPOLATION_PARAMS.hasOwnProperty(key)) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.facebook.react.animated;
|
||||
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
|
||||
@ -12,6 +13,10 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
/*package*/ class InterpolationAnimatedNode extends ValueAnimatedNode {
|
||||
|
||||
public static final String EXTRAPOLATE_TYPE_IDENTITY = "identity";
|
||||
public static final String EXTRAPOLATE_TYPE_CLAMP = "clamp";
|
||||
public static final String EXTRAPOLATE_TYPE_EXTEND = "extend";
|
||||
|
||||
private static double[] fromDoubleArray(ReadableArray ary) {
|
||||
double[] res = new double[ary.size()];
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
@ -25,19 +30,62 @@ import javax.annotation.Nullable;
|
||||
double inputMin,
|
||||
double inputMax,
|
||||
double outputMin,
|
||||
double outputMax) {
|
||||
double outputMax,
|
||||
String extrapolateLeft,
|
||||
String extrapolateRight) {
|
||||
double result = value;
|
||||
|
||||
// Extrapolate
|
||||
if (result < inputMin) {
|
||||
switch (extrapolateLeft) {
|
||||
case EXTRAPOLATE_TYPE_IDENTITY:
|
||||
return result;
|
||||
case EXTRAPOLATE_TYPE_CLAMP:
|
||||
result = inputMin;
|
||||
break;
|
||||
case EXTRAPOLATE_TYPE_EXTEND:
|
||||
break;
|
||||
default:
|
||||
throw new JSApplicationIllegalArgumentException(
|
||||
"Invalid extrapolation type " + extrapolateLeft + "for left extrapolation");
|
||||
}
|
||||
}
|
||||
|
||||
if (result > inputMax) {
|
||||
switch (extrapolateRight) {
|
||||
case EXTRAPOLATE_TYPE_IDENTITY:
|
||||
return result;
|
||||
case EXTRAPOLATE_TYPE_CLAMP:
|
||||
result = inputMax;
|
||||
break;
|
||||
case EXTRAPOLATE_TYPE_EXTEND:
|
||||
break;
|
||||
default:
|
||||
throw new JSApplicationIllegalArgumentException(
|
||||
"Invalid extrapolation type " + extrapolateRight + "for right extrapolation");
|
||||
}
|
||||
}
|
||||
|
||||
return outputMin + (outputMax - outputMin) *
|
||||
(value - inputMin) / (inputMax - inputMin);
|
||||
(result - inputMin) / (inputMax - inputMin);
|
||||
}
|
||||
|
||||
/*package*/ static double interpolate(double value, double[] inputRange, double[] outputRange) {
|
||||
/*package*/ static double interpolate(
|
||||
double value,
|
||||
double[] inputRange,
|
||||
double[] outputRange,
|
||||
String extrapolateLeft,
|
||||
String extrapolateRight
|
||||
) {
|
||||
int rangeIndex = findRangeIndex(value, inputRange);
|
||||
return interpolate(
|
||||
value,
|
||||
inputRange[rangeIndex],
|
||||
inputRange[rangeIndex + 1],
|
||||
outputRange[rangeIndex],
|
||||
outputRange[rangeIndex + 1]);
|
||||
outputRange[rangeIndex + 1],
|
||||
extrapolateLeft,
|
||||
extrapolateRight);
|
||||
}
|
||||
|
||||
private static int findRangeIndex(double value, double[] ranges) {
|
||||
@ -52,11 +100,15 @@ import javax.annotation.Nullable;
|
||||
|
||||
private final double mInputRange[];
|
||||
private final double mOutputRange[];
|
||||
private final String mExtrapolateLeft;
|
||||
private final String mExtrapolateRight;
|
||||
private @Nullable ValueAnimatedNode mParent;
|
||||
|
||||
public InterpolationAnimatedNode(ReadableMap config) {
|
||||
mInputRange = fromDoubleArray(config.getArray("inputRange"));
|
||||
mOutputRange = fromDoubleArray(config.getArray("outputRange"));
|
||||
mExtrapolateLeft = config.getString("extrapolateLeft");
|
||||
mExtrapolateRight = config.getString("extrapolateRight");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -84,6 +136,6 @@ import javax.annotation.Nullable;
|
||||
throw new IllegalStateException("Trying to update interpolation node that has not been " +
|
||||
"attached to the parent");
|
||||
}
|
||||
mValue = interpolate(mParent.mValue, mInputRange, mOutputRange);
|
||||
mValue = interpolate(mParent.mValue, mInputRange, mOutputRange, mExtrapolateLeft, mExtrapolateRight);
|
||||
}
|
||||
}
|
||||
|
@ -12,53 +12,102 @@ import static org.fest.assertions.api.Assertions.assertThat;
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class NativeAnimatedInterpolationTest {
|
||||
|
||||
private double simpleInterpolation(double value, double[] input, double[] output) {
|
||||
return InterpolationAnimatedNode.interpolate(
|
||||
value,
|
||||
input,
|
||||
output,
|
||||
InterpolationAnimatedNode.EXTRAPOLATE_TYPE_EXTEND,
|
||||
InterpolationAnimatedNode.EXTRAPOLATE_TYPE_EXTEND
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOneToOneMapping() {
|
||||
double[] input = new double[] {0d, 1d};
|
||||
double[] output = new double[] {0d, 1d};
|
||||
assertThat(InterpolationAnimatedNode.interpolate(0, input, output)).isEqualTo(0);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(0.5, input, output)).isEqualTo(0.5);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(0.8, input, output)).isEqualTo(0.8);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(1, input, output)).isEqualTo(1);
|
||||
assertThat(simpleInterpolation(0, input, output)).isEqualTo(0);
|
||||
assertThat(simpleInterpolation(0.5, input, output)).isEqualTo(0.5);
|
||||
assertThat(simpleInterpolation(0.8, input, output)).isEqualTo(0.8);
|
||||
assertThat(simpleInterpolation(1, input, output)).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWiderOutputRange() {
|
||||
double[] input = new double[] {0d, 1d};
|
||||
double[] output = new double[] {100d, 200d};
|
||||
assertThat(InterpolationAnimatedNode.interpolate(0, input, output)).isEqualTo(100);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(0.5, input, output)).isEqualTo(150);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(0.8, input, output)).isEqualTo(180);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(1, input, output)).isEqualTo(200);
|
||||
assertThat(simpleInterpolation(0, input, output)).isEqualTo(100);
|
||||
assertThat(simpleInterpolation(0.5, input, output)).isEqualTo(150);
|
||||
assertThat(simpleInterpolation(0.8, input, output)).isEqualTo(180);
|
||||
assertThat(simpleInterpolation(1, input, output)).isEqualTo(200);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWiderInputRange() {
|
||||
double[] input = new double[] {2000d, 3000d};
|
||||
double[] output = new double[] {1d, 2d};
|
||||
assertThat(InterpolationAnimatedNode.interpolate(2000, input, output)).isEqualTo(1);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(2250, input, output)).isEqualTo(1.25);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(2800, input, output)).isEqualTo(1.8);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(3000, input, output)).isEqualTo(2);
|
||||
assertThat(simpleInterpolation(2000, input, output)).isEqualTo(1);
|
||||
assertThat(simpleInterpolation(2250, input, output)).isEqualTo(1.25);
|
||||
assertThat(simpleInterpolation(2800, input, output)).isEqualTo(1.8);
|
||||
assertThat(simpleInterpolation(3000, input, output)).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManySegments() {
|
||||
double[] input = new double[] {-1d, 1d, 5d};
|
||||
double[] output = new double[] {0, 10d, 20d};
|
||||
assertThat(InterpolationAnimatedNode.interpolate(-1, input, output)).isEqualTo(0);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(0, input, output)).isEqualTo(5);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(1, input, output)).isEqualTo(10);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(2, input, output)).isEqualTo(12.5);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(5, input, output)).isEqualTo(20);
|
||||
assertThat(simpleInterpolation(-1, input, output)).isEqualTo(0);
|
||||
assertThat(simpleInterpolation(0, input, output)).isEqualTo(5);
|
||||
assertThat(simpleInterpolation(1, input, output)).isEqualTo(10);
|
||||
assertThat(simpleInterpolation(2, input, output)).isEqualTo(12.5);
|
||||
assertThat(simpleInterpolation(5, input, output)).isEqualTo(20);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtrapolate() {
|
||||
public void testExtendExtrapolate() {
|
||||
double[] input = new double[] {10d, 20d};
|
||||
double[] output = new double[] {0d, 1d};
|
||||
assertThat(InterpolationAnimatedNode.interpolate(30d, input, output)).isEqualTo(2);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(5d, input, output)).isEqualTo(-0.5);
|
||||
assertThat(simpleInterpolation(30d, input, output)).isEqualTo(2);
|
||||
assertThat(simpleInterpolation(5d, input, output)).isEqualTo(-0.5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClampExtrapolate() {
|
||||
double[] input = new double[] {10d, 20d};
|
||||
double[] output = new double[] {0d, 1d};
|
||||
assertThat(InterpolationAnimatedNode.interpolate(
|
||||
30d,
|
||||
input,
|
||||
output,
|
||||
InterpolationAnimatedNode.EXTRAPOLATE_TYPE_CLAMP,
|
||||
InterpolationAnimatedNode.EXTRAPOLATE_TYPE_CLAMP
|
||||
)).isEqualTo(1);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(
|
||||
5d,
|
||||
input,
|
||||
output,
|
||||
InterpolationAnimatedNode.EXTRAPOLATE_TYPE_CLAMP,
|
||||
InterpolationAnimatedNode.EXTRAPOLATE_TYPE_CLAMP
|
||||
)).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdentityExtrapolate() {
|
||||
double[] input = new double[] {10d, 20d};
|
||||
double[] output = new double[] {0d, 1d};
|
||||
assertThat(InterpolationAnimatedNode.interpolate(
|
||||
30d,
|
||||
input,
|
||||
output,
|
||||
InterpolationAnimatedNode.EXTRAPOLATE_TYPE_IDENTITY,
|
||||
InterpolationAnimatedNode.EXTRAPOLATE_TYPE_IDENTITY
|
||||
)).isEqualTo(30);
|
||||
assertThat(InterpolationAnimatedNode.interpolate(
|
||||
5d,
|
||||
input,
|
||||
output,
|
||||
InterpolationAnimatedNode.EXTRAPOLATE_TYPE_IDENTITY,
|
||||
InterpolationAnimatedNode.EXTRAPOLATE_TYPE_IDENTITY
|
||||
)).isEqualTo(5);
|
||||
}
|
||||
}
|
||||
|
@ -652,7 +652,11 @@ public class NativeAnimatedNodeTraversalTest {
|
||||
"inputRange",
|
||||
JavaOnlyArray.of(10d, 20d),
|
||||
"outputRange",
|
||||
JavaOnlyArray.of(0d, 1d)));
|
||||
JavaOnlyArray.of(0d, 1d),
|
||||
"extrapolateLeft",
|
||||
"extend",
|
||||
"extrapolateRight",
|
||||
"extend"));
|
||||
|
||||
mNativeAnimatedNodesManager.createAnimatedNode(
|
||||
3,
|
||||
|
Loading…
x
Reference in New Issue
Block a user