-
Notifications
You must be signed in to change notification settings - Fork 0
/
circle-progress.tsx
126 lines (108 loc) · 3.04 KB
/
circle-progress.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import React from 'react';
import {TextInput, View, Button, StyleSheet} from 'react-native';
import Animated, {
interpolateColor,
useAnimatedProps,
useDerivedValue,
useSharedValue,
withTiming,
} from 'react-native-reanimated';
import {Circle, Svg} from 'react-native-svg';
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
const AnimatedText = Animated.createAnimatedComponent(TextInput);
const radius = 45;
// Formula for circumference
// C=2×π×r
const circumference = radius * Math.PI * 2;
const duration = 200;
export const ProgressCircle = () => {
// determines how much of the circle's stroke is visible
const strokeOffset = useSharedValue(circumference);
const percentage = useDerivedValue(() => {
const number = ((circumference - strokeOffset.value) / circumference) * 100;
return withTiming(number, {duration: duration});
});
const strokeColor = useDerivedValue(() => {
return interpolateColor(
percentage.value,
[0, 50, 100],
['#6FCB4F', '#76C865', '#4CA22F'],
);
});
const animatedCircleProps = useAnimatedProps(() => {
return {
strokeDashoffset: withTiming(strokeOffset.value, {
duration: duration,
}),
stroke: strokeColor.value,
};
});
// TODO: fix initial text
const animatedTextProps = useAnimatedProps(() => {
const initialText =
percentage.value === 0 ? '0%' : `${Math.round(percentage.value)} %`;
return {
text: initialText,
};
});
const handlePress = () => {
if (percentage.value >= 100) {
return;
} // Add this condition to prevent further progress
let targetValue = ((100 - (percentage.value + 10)) / 100) * circumference;
strokeOffset.value = withTiming(targetValue, {duration: duration / 10});
};
const resetProgress = () => {
strokeOffset.value = withTiming(circumference, {duration: duration * 2});
};
const slices = Array(10)
.fill(0)
.map((_, index) => (
<Circle
key={index}
cx="50"
cy="50"
r="45"
stroke="#E7E7E7"
strokeWidth="10"
fill="transparent"
/>
));
return (
<View style={styles.container}>
<AnimatedText
style={styles.textStyle}
// @ts-ignore
animatedProps={animatedTextProps}
/>
<Svg height="50%" width="50%" viewBox="0 0 100 100">
{slices}
<AnimatedCircle
animatedProps={animatedCircleProps}
cx="50"
cy="50"
r="45"
strokeDasharray={`${circumference}`}
strokeWidth="10"
fill="transparent"
strokeLinecap="round"
/>
</Svg>
<Button title="Update Progress" color={'black'} onPress={handlePress} />
<Button title="reset Progress" color={'black'} onPress={resetProgress} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
textStyle: {
fontSize: 24,
fontWeight: 'bold',
position: 'absolute',
paddingBottom: 50,
},
});