react-native-rewards
Version:
This package lets you easily add microinteractions to your app and reward users with the rain of confettis or flying emoji in seconds.
129 lines (120 loc) • 3.55 kB
JavaScript
import React from 'react';
import {Animated } from 'react-native';
export function ConfettiItem({ color, translateX, translateY, opacity, rotateX, rotateZ }) {
const spinX = rotateX.interpolate({
inputRange: [0, 10],
outputRange: ['0deg', '360deg'],
});
const spinZ = rotateZ.interpolate({
inputRange: [0, 10],
outputRange: ['0deg', '360deg'],
});
const itemStyle = {
backgroundColor: color,
height: 8,
width: 8,
opacity,
transform: [
{ translateX },
{ translateY },
{ rotateX: spinX },
{ rotateZ: spinZ },
],
position: 'absolute',
};
return (
<Animated.View style={itemStyle}/>
);
}
export function generateConfettiItems(translations, count, colors) {
const items = [];
for (let i = 0; i < count; i++) {
const { transform, opacity, rotateX, rotateZ } = translations[i];
const item = (
<ConfettiItem
key={i}
color={colors[i % colors.length]}
translateX={transform.x}
translateY={transform.y}
rotateX={rotateX}
rotateZ={rotateZ}
opacity={opacity}
/>
);
items.push(item);
}
return items;
}
export function generateConfettiInitialTranslations(count = 20, initialOpacity = 1) {
const translations = [];
for (let i = 0; i < count; i++) {
const translation = {
transform: new Animated.ValueXY(0, 0),
opacity: new Animated.Value(initialOpacity),
rotateX: new Animated.Value(0),
rotateZ: new Animated.Value(0),
};
translations.push(translation);
}
return translations;
}
export function generateConfettiAnimations(translations, params) {
return translations.map((item, index) => generateConfettiAnimation(item, index, translations.length, params));
}
function generateConfettiAnimation({ transform, opacity, rotateX, rotateZ }, index, count, params) {
const { initialSpeed, spread, deacceleration, rotationXSpeed, rotationZSpeed } = params;
const degrees = 0;
const angle = degrees * Math.PI / 180;
const vx = Math.cos(angle);
const vy = Math.sin(angle);
const spreadSpeed = (Math.random() - 0.5) * 3 * initialSpeed * spread;
const flySpeed = (-1.0 - Math.random() * 2) * initialSpeed;
const xSpeed = spreadSpeed * vx + flySpeed * vy;
const ySpeed = flySpeed * vx + flySpeed * vy;
const upAnimation =
Animated.decay(transform, {
// coast to a stop
velocity: { x: xSpeed, y: ySpeed }, // velocity from gesture release
deceleration: 0.989 + (1 - deacceleration) / 100,
});
const duration = 2000 + Math.random() * 100;
const downAnimation = Animated.timing( // Animate over time
transform.y, // The animated value to drive
{
toValue: 100 + Math.random() * 100, // Animate to opacity: 1 (opaque)
duration, // Make it take a while
},
);
const disapearAnimation = Animated.timing( // Animate over time
opacity, // The animated value to drive
{
toValue: 0, // Animate to opacity: 1 (opaque)
duration, // Make it take a while
},
);
const rotateXAnimation = Animated.timing(
rotateX,
{
toValue: (Math.random() * 3) * rotationXSpeed,
duration,
},
);
const rotateZAnimation = Animated.timing(
rotateZ,
{
toValue: (Math.random() * 5) * rotationZSpeed,
duration,
},
);
Animated.parallel([
Animated.sequence([
upAnimation,
Animated.parallel([
disapearAnimation,
downAnimation,
]),
]),
rotateXAnimation,
rotateZAnimation,
]).start();
}