react-native-gifted-charts
react-native-gifted-charts copied to clipboard
Bar chart width (spacing)
Hello, thanks for your package!
I wanted to ask, how should I calculate the bar width and spacing? For example, I have 5 groups of bars. Each group has 5 bars in it.
I've added spacing 16 between groups and 2 between bars, bar width - 8 (from the example). It works totally fine, however, if I rotate, it won't resize.
I assume it happens since the total sum of width is not filled, like, in MpAndroidChart, the total sum should be "1" - so you should calculate every bar and space and it should give you 1. But how to calculate size here?
For better understanding, I will provide you my code.
to not dive into data manipulations, result data is:
import React from 'react';
import {BarChart, barDataItem} from 'react-native-gifted-charts';
import {View} from 'react-native-ui-lib';
import ChartLabel from './ChartLabel';
const data = [
{
values: [5, 40, 77, 81, 43],
label: 'Hemoglobin',
color: '#7CDE86',
},
{
values: [40, 5, 50, 23, 79],
label: 'White blood cell',
color: '#7CD8DE',
},
{
values: [10, 55, 35, 90, 82],
label: 'Mean corpuscular volume',
color: '#7C9DDE',
},
{
values: [22, 45, 50, 60, 30],
label: 'Hematocrit',
color: '#A17CDE',
},
{
values: [30, 25, 10, 60, 15],
label: 'Platelet',
color: '#DC7CDE',
},
];
const xAxisLabels = ['01.02', '11.02', '19.02', '12.03', '13.03'];
const res: barDataItem[] = [];
for (let i = 0; i < data.length; i++) {
data.forEach((item, j, array) => {
const obj = {
value: item.values[i],
frontColor: item.color,
};
const label = {
labelWidth: 40,
labelComponent: () => <ChartLabel label={xAxisLabels[i]} />,
};
const spacing = 2;
if (j === 0) {
res.push({...obj, ...label, spacing});
} else if (j === array.length - 1) {
res.push({...obj});
} else {
res.push({...obj, spacing});
}
});
}
export default function Chart() {
return (
<View style={{flex: 1}}>
<BarChart
disableScroll
isAnimated
data={res}
barWidth={8}
spacing={16}
roundedTop
noOfSections={3}
xAxisThickness={0}
yAxisThickness={0}
dashWidth={20}
dashGap={12}
/>
</View>
);
}
Thanks in advance!
Solved.
For anyone, who needs the code:
import React, {useState} from 'react';
import {BarChart, barDataItem} from 'react-native-gifted-charts';
import {View} from 'react-native-ui-lib';
import ChartLabel from './ChartLabel';
const data = [
{
values: [5, 40, 77, 81, 43],
label: 'Hemoglobin',
color: '#7CDE86',
},
{
values: [40, 5, 50, 23, 79],
label: 'White blood cell',
color: '#7CD8DE',
},
{
values: [10, 55, 35, 90, 82],
label: 'Mean corpuscular volume',
color: '#7C9DDE',
},
{
values: [22, 45, 50, 60, 30],
label: 'Hematocrit',
color: '#A17CDE',
},
{
values: [30, 25, 10, 60, 15],
label: 'Platelet',
color: '#DC7CDE',
},
];
const xAxisLabels = ['01.02', '11.02', '19.02', '12.03', '13.03'];
const getData = (barSpace: number, labelWidth: number, groupWidth: number) => {
const res: barDataItem[] = [];
for (let i = 0; i < data.length; i++) {
data.forEach((item, j, array) => {
const obj = {
value: item.values[i],
frontColor: item.color,
};
const label = {
labelWidth,
labelComponent: () => (
<ChartLabel
label={xAxisLabels[i]}
labelWidth={labelWidth}
groupWidth={groupWidth}
/>
),
};
const spacing = barSpace;
if (j === 0) {
res.push({...obj, ...label, spacing});
} else if (j === array.length - 1) {
res.push({...obj});
} else {
res.push({...obj, spacing});
}
});
}
return res;
};
export default function Chart() {
const [width, setWidth] = useState(0);
const groupSpace = (width * 0.2) / (xAxisLabels.length - 1);
const groupWidth = (width * 0.8) / xAxisLabels.length;
const barSpace = (groupWidth * 0.2) / (xAxisLabels.length - 1);
const barWidth = (groupWidth * 0.8) / xAxisLabels.length;
const labelWidth = 40;
return (
<View
flex
onLayout={({
nativeEvent: {
layout: {width: calculatedWidth},
},
}) => setWidth(calculatedWidth - labelWidth)}>
<BarChart
disablePress
disableScroll
isAnimated
data={getData(barSpace, labelWidth, groupWidth)}
barWidth={barWidth}
spacing={groupSpace}
roundedTop
roundedBottom
noOfSections={3}
xAxisThickness={0}
yAxisThickness={0}
dashWidth={20}
dashGap={12}
initialSpacing={0}
endSpacing={0}
/>
</View>
);
}
IMO, these calculations should be done by the library, so, probably, take it into account
Also, please, take in mind, that I had to use transform: [{translateX: (groupWidth - labelWidth) / 2}]
for the label component so it can be in the middle.
And one more thing, when you click on the first bar in the group, opacity applies to label too. Only if you click on the first bar, not others, so it leads one more bug. Had to disable press