import { Text } from '@/components/ui/text'; import { useColor } from '@/hooks/useColor'; import { useEffect, useState } from 'react'; import { LayoutChangeEvent, View, ViewStyle } from 'react-native'; import Animated, { useAnimatedProps, useSharedValue, withTiming, } from 'react-native-reanimated'; import Svg, { Circle, Defs, LinearGradient, Stop, Text as SvgText, } from 'react-native-svg'; // Animated SVG Components const AnimatedCircle = Animated.createAnimatedComponent(Circle); interface ChartConfig { padding?: number; animated?: boolean; duration?: number; gradient?: boolean; } interface ChartDataPoint { label: string; value: number; color?: string; } type Props = { data: ChartDataPoint[]; config?: ChartConfig; style?: ViewStyle; }; export const RadialBarChart = ({ data, config = {}, style }: Props) => { const [containerSize, setContainerSize] = useState(200); const { padding = 20, animated = true, duration = 1000, gradient = false, } = config; const primaryColor = useColor('primary'); const mutedColor = useColor('mutedForeground'); const animationProgress = useSharedValue(0); const handleLayout = (event: LayoutChangeEvent) => { const { width, height } = event.nativeEvent.layout; const size = Math.min(width, height); if (size > 0) { setContainerSize(size); } }; useEffect(() => { if (animated) { animationProgress.value = withTiming(1, { duration }); } else { animationProgress.value = 1; } }, [data, animated, duration]); if (!data.length) return null; const maxValue = Math.max(...data.map((d) => d.value)); const size = containerSize || 200; const center = size / 2; const maxRadius = (size - padding * 2) / 2; const strokeWidth = maxRadius / (data.length + 1); const colors = [ primaryColor, useColor('blue'), useColor('green'), useColor('orange'), useColor('purple'), useColor('pink'), ]; return ( {gradient && data.map((item, index) => ( ))} {data.map((item, index) => { const radius = maxRadius - index * strokeWidth - strokeWidth / 2; const circumference = 2 * Math.PI * radius; const progressRatio = item.value / maxValue; const circleAnimatedProps = useAnimatedProps(() => { const animatedProgress = animationProgress.value * progressRatio; const strokeDashoffset = circumference - animatedProgress * circumference; return { strokeDashoffset, }; }); return ( ); })} {/* Center values */} {data.length > 0 && ( <> {data.reduce((sum, item) => sum + item.value, 0)} Total )} {/* Legend */} {data.map((item, index) => ( {item.label}: {item.value} ))} ); };