react-native-bar-graph
Version:
Customizable bar graph react native
175 lines (165 loc) • 4.8 kB
JavaScript
import React, { useEffect, useRef } from "react";
import {
View,
Text,
StyleSheet,
Animated,
TouchableOpacity,
Dimensions,
ScrollView,
} from "react-native";
const Bargraph = ({
data = [],
height = 200,
width = Dimensions.get("window").width - 40,
barWidth = 22,
spacing = 20,
numOfYAxisLabels = 4,
showGrid = true,
onPresscnt = () => {},
style = {},
valueKey = "", // ✅ key for Y-axis value
labelKey = "", // ✅ key for X-axis label
}) => {
const maxValue = Math.max(...data.map((item) => item?.[valueKey] || 0));
const animatedValue = useRef(new Animated.Value(0)).current;
useEffect(() => {
Animated.timing(animatedValue, {
toValue: 1,
duration: 800,
useNativeDriver: false,
}).start();
}, []);
const chartContentWidth = data.length * (barWidth + spacing) + 20;
return (
<View style={{ width }}>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{ width: chartContentWidth }}
>
<View>
<View style={[styles.wrapper, { height }]}>
<View style={[styles.wrapper, { height: height + 20 }]}>
{showGrid &&
Array.from({ length: numOfYAxisLabels + 1 }, (_, i) => (
<View
key={i}
style={[
styles.gridLine,
{
top: (i * height) / numOfYAxisLabels,
width: chartContentWidth,
},
]}
/>
))}
<View style={[styles.chartContainer, { height }]}>
{data.map((item, index) => {
const safeMax = maxValue === 0 ? 1 : maxValue;
const value = item?.[valueKey] || 0;
const label = item?.[labelKey] || "";
const barHeight = animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, (value / safeMax) * height],
});
const isMaxTarget = value === maxValue;
return (
<View
key={index}
style={[styles.barItem, { width: barWidth + spacing }]}
>
<Animated.Text style={styles.countValue}>
{value}
</Animated.Text>
<TouchableOpacity onPress={() => onPresscnt(item)}>
<Animated.View
style={[
styles.cntStyle,
{
height: barHeight,
width: barWidth,
},
]}
>
{isMaxTarget && value > 0 && (
<Text style={styles.countAboveBar}>{value}</Text>
)}
</Animated.View>
</TouchableOpacity>
</View>
);
})}
</View>
</View>
</View>
<View style={[styles.xAxisLabels]}>
{data.map((item, index) => (
<View
key={index}
style={[styles.dtWrapper, { width: barWidth + spacing }]}
>
<Text style={styles.dtStyles}>{item?.[labelKey]}</Text>
</View>
))}
</View>
</View>
</ScrollView>
</View>
);
};
export default Bargraph;
const styles = StyleSheet.create({
wrapper: {
flexDirection: "row",
paddingHorizontal: 10,
},
gridLine: {
position: "absolute",
height: 1,
backgroundColor: "#ddd",
},
chartContainer: {
flexDirection: "row",
alignItems: "flex-end",
},
barItem: {
alignItems: "center",
justifyContent: "flex-end",
},
xAxisLabels: {
flexDirection: "row",
justifyContent: "flex-start",
paddingHorizontal: 10,
paddingVertical: 6,
marginLeft: 20,
},
countValue: {
fontSize: 10,
marginBottom: 4,
fontFamily: "Poppins-SemiBold",
},
countAboveBar: {
fontSize: 10,
marginBottom: 10,
color: "#fff",
fontFamily: "Poppins-SemiBold",
textAlign: "center",
transform: [{ rotate: "-65deg" }],
},
cntStyle: {
backgroundColor: "green",
borderTopLeftRadius: 4,
borderTopRightRadius: 4,
},
dtWrapper: {
height: 50,
alignItems: "center",
justifyContent: "flex-start",
transform: [{ rotate: "-70deg" }],
},
dtStyles: {
fontSize: 10,
fontFamily: "Poppins-Medium",
},
});