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, { G, Line, Rect, Text as SvgText } from 'react-native-svg';
// Animated SVG Components
const AnimatedRect = Animated.createAnimatedComponent(Rect);
interface ChartConfig {
width?: number;
height?: number;
padding?: number;
showGrid?: boolean;
showLabels?: boolean;
animated?: boolean;
duration?: number;
}
export interface StackedBarDataPoint {
label: string;
values: number[];
}
type Props = {
data: StackedBarDataPoint[];
colors?: string[];
config?: ChartConfig;
style?: ViewStyle;
categories?: string[];
horizontal?: boolean;
};
export const StackedBarChart = ({
data,
colors = [],
config = {},
style,
categories = [],
horizontal = false,
}: Props) => {
const [containerWidth, setContainerWidth] = useState(300);
const {
height = 200,
padding = 20,
showLabels = true,
showGrid = true,
animated = true,
duration = 800,
} = config;
const chartWidth = containerWidth || config.width || 300;
const primaryColor = useColor('primary');
const mutedColor = useColor('mutedForeground');
const animationProgress = useSharedValue(0);
const handleLayout = (event: LayoutChangeEvent) => {
const { width: measuredWidth } = event.nativeEvent.layout;
if (measuredWidth > 0) {
setContainerWidth(measuredWidth);
}
};
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.values.reduce((sum, val) => sum + val, 0))
);
const seriesCount = data[0]?.values.length || 0;
const innerChartWidth = chartWidth - padding * 2;
const chartHeight = height - padding * 2;
// Default colors if not provided
const defaultColors = [
'#8884d8',
'#82ca9d',
'#ffc658',
'#ff7300',
'#00ff00',
'#0088fe',
primaryColor,
];
const seriesColors =
colors.length >= seriesCount
? colors
: [...colors, ...defaultColors].slice(0, seriesCount);
if (horizontal) {
// Horizontal stacked bars
const barHeight = (chartHeight / data.length) * 0.8;
const barSpacing = (chartHeight / data.length) * 0.2;
return (
);
}
// Vertical stacked bars
const barWidth = (innerChartWidth / data.length) * 0.8;
const barSpacing = (innerChartWidth / data.length) * 0.2;
return (
);
};