FullstackStation / react-native-svg-animated-linear-gradient

A wrap SVG component for animated linear gradient
MIT License
435 stars 110 forks source link

Question: why d3-interpolate instead of Animated.interpolate? #8

Open vsai opened 6 years ago

vsai commented 6 years ago

Isn't there a way to get a similar result using Animated.interpolate? Is there a need to import d3-interpolate as well? Animated is already included within react-native.

virusvn commented 6 years ago

Thank for the question. I have 2 reasons for using d3-interpolate: 1) I intended to build colorful background which is supported better by d3-interpolate (interpolateRgb, interpolateHsl ...). Instead of use primaryColor and secondaryColor, we can interpolate colors from d3-interpolate's functions. This feature is not implemented yet (maybe 2 colors is enough), so d3-interpolate looks like overkill. 2) Have more controllable in d3-interpolate: I used Animated.interpolate when I started this project but not success, or not easy as d3-interpolate does:

this.state = {
       offsetInterpolate: new Animated.Value(0)
}
...
this.offsetValues =  this.state.offsetInterpolate.interpolate({
    inputRange: ['-2', '-1.5', '-1'],
    outputRange: ['1', '1.5', '2']
}
...

 <Svg.Stop
                            offset={this.offsetValues[0]}
                            stopColor={this.props.primaryColor}
                            stopOpacity="1"/>

And, relate to the issue #1 , that bug in Android could be fixed easily because we control interpolate's values.

It would be great if someone can use Animated.interpolate can solve above problems, so we can remove d3-interpolate.

vsai commented 6 years ago

I'm new to react-native and Animated + Svgs in particular. I haven't been able to get the content-loaing to work myself, but in response to your answer, this is as far as I understand it:

1. For Svg.Stop, the offset value can only only be in the range [0,1] (or equivalently [0%, 100%]). I believe you're passing in values that are outside the necessary range.

2. For interpolate: this is a mapping function. It will map this.state.offsetInterpolate value on the inputRange defined onto the `outputRange.

The mapping function you defined:

{
    inputRange: ['-2', '-1.5', '-1'],
    outputRange: ['1', '1.5', '2']
}

is basically a y = x + 3 function, where in this case x = this.state.offsetInterpolate. I believe it would be the equivalent of:

{
    inputRange: [0, 1],
    outputRange: [3, 4],

To prevent the offset output exceeding out of the [0,1] range for the offset, you could use the clamp mapping function: On the docs (https://facebook.github.io/react-native/docs/animations.html):

The default value is extend but you can use clamp to prevent the output value from exceeding outputRange.

Also on the docs:

requestAnimationFrame is a polyfill from the browser that you might be familiar with. It accepts a function as its only argument and calls that function before the next repaint. It is an essential building block for animations that underlies all of the JavaScript-based animation APIs. In general, you shouldn't need to call this yourself - the animation APIs will manage frame updates for you.

Not sure if this is a special case because we're interacting with SVGs, but was a little skeptical because of this.

  1. agreed that manually handling the interpolated result value helps fix the bug for android. but couldn't we do this manual handling after simply using the react-native Animated library too?