BaaS_Driver_Android_App/components/home/SemiCircleProgress.tsx

148 lines
3.9 KiB
TypeScript

import React, { useEffect, useRef, useState } from "react";
import { View, StyleSheet, Text, Animated } from "react-native";
import Svg, { Circle, Defs, LinearGradient, Stop } from "react-native-svg";
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
const CircleProgressBar = ({
progress,
status,
}: {
progress: number;
status: number;
}) => {
const radius = 20;
const strokeWidth = 5;
const viewBoxPadding = 4;
const viewBoxSize = (radius + strokeWidth) * 2 + viewBoxPadding;
const center = viewBoxSize / 2;
const circumference = 2 * Math.PI * radius;
const animatedValue = useRef(new Animated.Value(0)).current;
const [displayProgress, setDisplayProgress] = useState(0);
useEffect(() => {
if (progress === undefined) {
animatedValue.setValue(0);
setDisplayProgress(0);
} else {
Animated.timing(animatedValue, {
toValue: progress,
duration: 500,
useNativeDriver: false,
}).start();
}
}, [progress]);
useEffect(() => {
const listenerId = animatedValue.addListener(({ value }) => {
setDisplayProgress(Math.round(value));
});
return () => animatedValue.removeListener(listenerId);
}, []);
const getColor = (progress: number) => {
if (progress <= 20) return "#D51D10";
if (progress <= 50) return "#FF7B00";
return "#009E71";
};
const animatedColor = getColor(displayProgress);
const dashOffset = animatedValue.interpolate({
inputRange: [0, 100],
outputRange: [circumference, circumference - 0.7 * circumference],
});
const progressDashArray = `${circumference} ${circumference}`;
const backgroundDashArray = `${0.7 * circumference} ${0.3 * circumference}`;
return (
<View style={styles.container}>
<Svg
width={258.75}
height={258.75}
viewBox={`0 0 ${viewBoxSize} ${viewBoxSize}`}
style={styles.circleContainer}
>
<Defs>
<LinearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<Stop offset="0%" stopColor="#e66465" />
<Stop offset="100%" stopColor="#9198e5" />
</LinearGradient>
</Defs>
<Circle
r={radius}
cx={center}
cy={center}
stroke="#D8DDE7"
strokeWidth={strokeWidth}
fill="none"
strokeDasharray={backgroundDashArray}
strokeLinecap="round"
/>
<AnimatedCircle
r={radius}
cx={center}
cy={center}
fill="none"
strokeLinecap="round"
style={{
stroke: animatedColor,
strokeWidth: strokeWidth,
strokeDasharray: progressDashArray,
strokeDashoffset: dashOffset,
}}
/>
</Svg>
<View style={styles.batteryPercent}>
<Text style={{ fontSize: 60, fontWeight: "bold", fontFamily: "Inter" }}>
{progress === undefined ? "---" : displayProgress}
</Text>
<Text style={{ fontSize: 20, fontWeight: "bold" }}>
{progress === undefined ? null : "%"}
</Text>
</View>
<View style={styles.batterySoc}>
<Text style={{ fontSize: 14, fontWeight: "bold", color: "#565F70" }}>
{status === 1 ? "Charging" : "Discharging"}
</Text>
</View>
</View>
);
};
// Keep the styles the same as before
const styles = StyleSheet.create({
container: {
position: "relative",
alignItems: "center",
},
circleContainer: {
transform: [{ rotate: "144deg" }],
},
batteryPercent: {
position: "absolute",
top: 80,
justifyContent: "center",
alignItems: "baseline",
display: "flex",
flexDirection: "row",
},
batterySoc: {
position: "absolute",
top: 210,
justifyContent: "center",
transform: [{ translateX: 0 }],
},
batteryStatus: {
position: "absolute",
top: 300,
justifyContent: "center",
transform: [{ translateX: 0 }],
},
});
export default CircleProgressBar;