Reputation: 2674
I am trying to animate a component in ReactJS native so that it orbits continuously around a point in a circular fashion. Basically, I need a timer that continuously increases that I can use to set the X, Y coordinates as something like {x: r * Math.sin(timer), y: r * Math.cos(timer)}
I found this guide which has some really helpful information about interpolation but I am still not having any success:
http://browniefed.com/react-native-animation-book/INTERPOLATION.html
How can I update the position of my component like this?
Bonus question: How can I make the animation continuous?
Upvotes: 3
Views: 3152
Reputation: 2674
I ended up figuring out a way to do this, although it is not ideal and I'd appreciate any other input. Here is my code:
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
rotation: new Animated.Value(0),
pos: new Animated.ValueXY()
}
}
componentDidMount() {
this.animate(10000);
}
animate(speed) {
Animated.parallel([
Animated.timing(this.state.rotation, {
toValue: 360,
duration: speed,
easing: Easing.linear
}),
Animated.timing(this.state.pos, {
toValue: {x: 360, y: 360},
duration: speed,
easing: Easing.linear,
extrapolate: 'clamp'
})
]).start(() => {
// Cycle the animation
this.state.rotation.setValue(0);
this.state.pos.setValue({x: 0, y: 0});
this.animate(speed);
});
}
render() {
let range = new Array(360);
for (let i = 0; i < 360; i++) {
range[i] = i;
}
var radius = 51,
offset = 40;
return (
<View style={this.props.style}>
<Animated.View style={{position: 'absolute', transform: [
// Map the inputs [0..360) to x, y values
{translateX: this.state.pos.x.interpolate({
inputRange: range,
outputRange: range.map(i => offset + radius * Math.cos(i * Math.PI / 180))
})},
{translateY: this.state.pos.y.interpolate({
inputRange: range,
outputRange: range.map(i => offset - radius * Math.sin(i * Math.PI / 180))
})},
{rotate: this.state.rotation.interpolate({
inputRange: [0, 360],
outputRange: ['360deg', '0deg']
})}
]}}>
<Image source={require('image.png')}/>
</Animated.View>
</View>
)
}
}
Basically, I use the interpolate function to map the the Animated.Value
pos
to the result of my function for all 360 degrees. I think this could be improved by having a sort of map function instead of an interpolate function. Does anyone know if there is one?
Upvotes: 2
Reputation: 22797
Since react-native interpolation doesn't support function callback, I made a helper function:
function withFunction(callback) {
let inputRange = [], outputRange = [], steps = 50;
/// input range 0-1
for (let i=0; i<=steps; ++i) {
let key = i/steps;
inputRange.push(key);
outputRange.push(callback(key));
}
return { inputRange, outputRange };
}
Apply animation to translateX and translateY:
transform: [
{
translateX:
this.rotate.interpolate(
withFunction( (value) => Math.cos(Math.PI*value*2) * radius )
)
},
{
translateY:
this.rotate.interpolate(
withFunction( (value) => Math.sin(Math.PI*value*2) * radius )
)
},
]
Visual result:
And to make animation continuous, I did something like this:
rotate = new Animated.Value(0);
componentDidMount() {
setInterval( () => {
let step = 0.05;
let final = this.rotate._value+step;
if (final >= 1) final = 0;
this.rotate.setValue(final);
}, 50);
}
Upvotes: 5