Allowed negative values for Line and Area charts

This commit is contained in:
abhinandan-kushwaha 2022-03-08 03:22:31 +05:30
parent 450043ff83
commit 2d1b834f3c
5 changed files with 196 additions and 72 deletions

29
App.js
View File

@ -548,17 +548,6 @@ const App = () => {
</View> </View>
); );
}; };
const barData = [
{
value: 15,
label: 'Mon',
},
{value: 30, label: 'Tue'},
{value: 26, label: 'Wed'},
{value: 40, label: 'Thu'},
{value: 16, label: 'Wed'},
{value: 40, label: 'Thu'},
];
const styleObject = { const styleObject = {
marginLeft: -95, marginLeft: -95,
@ -600,6 +589,18 @@ const App = () => {
{value: 190}, {value: 190},
]); ]);
const barData = [
{
value: 15,
label: 'Mon',
},
{value: 30, label: 'Tue'},
{value: -23, label: 'Wed'},
{value: 40, label: 'Thu'},
{value: -16, label: 'Wed'},
{value: 40, label: 'Thu'},
];
return ( return (
<View <View
style={{ style={{
@ -607,8 +608,8 @@ const App = () => {
// marginLeft: 46, // marginLeft: 46,
marginLeft: 20, marginLeft: 20,
}}> }}>
{/* <BarChart backgroundColor={'green'} data={barData} /> */} <BarChart yAxisSide='right' width={260} scrollToEnd curved data={barData} />
<BarChart {/* <BarChart
// isAnimated={true} // isAnimated={true}
isThreeD={true} isThreeD={true}
data={dtt} data={dtt}
@ -634,7 +635,7 @@ const App = () => {
// noOfSections={4} // noOfSections={4}
// innerCircleBorderColor={'gray'} // innerCircleBorderColor={'gray'}
// showTextBackground={true} // showTextBackground={true}
/> /> */}
<TouchableOpacity <TouchableOpacity
onPress={()=>{dtt[1].value+=20;setDtt([...dtt])}}> onPress={()=>{dtt[1].value+=20;setDtt([...dtt])}}>
<Text>Press me</Text> <Text>Press me</Text>

View File

@ -10,7 +10,9 @@
| width | number | Width of the Bar chart | width of the parent | | width | number | Width of the Bar chart | width of the parent |
| height | number | Height of the Bar chart (excluding the bottom label) | 200 | | height | number | Height of the Bar chart (excluding the bottom label) | 200 |
| maxValue | number | Maximum value shown in the Y axis | 200 | | maxValue | number | Maximum value shown in the Y axis | 200 |
| minValue | number | Minimum negative value shown in the Y axis (to be used only if the data set has negative values too) | \_ |
| noOfSections | number | Number of sections in the Y axis | 10 | | noOfSections | number | Number of sections in the Y axis | 10 |
| noOfSectionsBelowXAxis | number | Number of sections in the Y axis below X axis (in case the data set has negative values too) | 0 |
| stepValue | number | Value of 1 step/section in the Y axis | 20 | | stepValue | number | Value of 1 step/section in the Y axis | 20 |
| stepHeight | number | Height of 1 step/section in the Y axis | 20 | | stepHeight | number | Height of 1 step/section in the Y axis | 20 |
| spacing | number | Distance between 2 consecutive bars in the Bar chart | 20 | | spacing | number | Distance between 2 consecutive bars in the Bar chart | 20 |

View File

@ -1,6 +1,6 @@
{ {
"name": "react-native-gifted-charts", "name": "react-native-gifted-charts",
"version": "1.0.5", "version": "1.0.6",
"description": "The most complete library for Bar, Line, Area, Pie and Donut charts in React Native. Allows 2D, 3D, gradient, animations and live data updates.", "description": "The most complete library for Bar, Line, Area, Pie and Donut charts in React Native. Allows 2D, 3D, gradient, animations and live data updates.",
"main": "src/index.tsx", "main": "src/index.tsx",
"files": [ "files": [

View File

@ -235,7 +235,8 @@ export const BarChart = (props: PropTypes) => {
const labelsExtraHeight = props.labelsExtraHeight || 0; const labelsExtraHeight = props.labelsExtraHeight || 0;
let totalWidth = spacing; let totalWidth = spacing;
let maxItem = 0, minItem = 0; let maxItem = 0,
minItem = 0;
if (props.stackData) { if (props.stackData) {
props.stackData.forEach(stackItem => { props.stackData.forEach(stackItem => {
// console.log('stackItem', stackItem); // console.log('stackItem', stackItem);
@ -282,7 +283,7 @@ export const BarChart = (props: PropTypes) => {
} else { } else {
maxItem = maxItem + (10 - (maxItem % 10)); maxItem = maxItem + (10 - (maxItem % 10));
if (minItem !== 0) { if (minItem !== 0) {
minItem = minItem - (10 + (minItem % 10)) minItem = minItem - (10 + (minItem % 10));
} }
} }
@ -290,7 +291,8 @@ export const BarChart = (props: PropTypes) => {
const minValue = props.minValue || minItem; const minValue = props.minValue || minItem;
const stepValue = props.stepValue || maxValue / noOfSections; const stepValue = props.stepValue || maxValue / noOfSections;
const noOfSectionsBelowXAxis = props.noOfSectionsBelowXAxis || (-minValue / stepValue); const noOfSectionsBelowXAxis =
props.noOfSectionsBelowXAxis || -minValue / stepValue;
const disableScroll = props.disableScroll || false; const disableScroll = props.disableScroll || false;
const showScrollIndicator = props.showScrollIndicator || false; const showScrollIndicator = props.showScrollIndicator || false;
const initialSpacing = const initialSpacing =
@ -545,9 +547,10 @@ export const BarChart = (props: PropTypes) => {
} }
horizSectionsBelow.push({ horizSectionsBelow.push({
value: props.yAxisLabelTexts value: props.yAxisLabelTexts
? props.yAxisLabelTexts[noOfSectionsBelowXAxis - i] ?? value.toString() ? props.yAxisLabelTexts[noOfSectionsBelowXAxis - i] ??
value.toString()
: value.toString(), : value.toString(),
}) });
} }
} }
@ -602,7 +605,7 @@ export const BarChart = (props: PropTypes) => {
? props.width || totalWidth ? props.width || totalWidth
: props.width || totalWidth + 11, : props.width || totalWidth + 11,
}, },
yAxisSide === 'right' && {transform:[{rotateY:'180deg'}]} yAxisSide === 'right' && {transform: [{rotateY: '180deg'}]},
]}> ]}>
<View <View
style={[ style={[
@ -628,13 +631,16 @@ export const BarChart = (props: PropTypes) => {
style={[ style={[
yAxisTextStyle, yAxisTextStyle,
index === noOfSections && {marginBottom: stepHeight / -2}, index === noOfSections && {marginBottom: stepHeight / -2},
horizontal ? { horizontal
? {
transform: [ transform: [
{rotate: '270deg'}, {rotate: '270deg'},
{translateY: yAxisAtTop ? 0 : 50}, {translateY: yAxisAtTop ? 0 : 50},
], ],
}: }
yAxisSide === 'right' && {transform:[{rotateY:'180deg'}]} : yAxisSide === 'right' && {
transform: [{rotateY: '180deg'}],
},
]}> ]}>
{label} {label}
</Text> </Text>
@ -745,7 +751,8 @@ export const BarChart = (props: PropTypes) => {
? props.width || totalWidth ? props.width || totalWidth
: props.width || totalWidth + 11, : props.width || totalWidth + 11,
}, },
index===0&&{marginTop:stepHeight/2} yAxisSide === 'right' && {transform: [{rotateY: '180deg'}]},
index === 0 && {marginTop: stepHeight / 2},
]}> ]}>
<View <View
style={[ style={[
@ -762,7 +769,7 @@ export const BarChart = (props: PropTypes) => {
height: index === 0 ? stepHeight * 1.5 : stepHeight, height: index === 0 ? stepHeight * 1.5 : stepHeight,
width: yAxisLabelWidth, width: yAxisLabelWidth,
}, },
index===0&&{marginTop:-stepHeight/2} index === 0 && {marginTop: -stepHeight / 2},
]}> ]}>
{!hideYAxisText ? ( {!hideYAxisText ? (
<Text <Text
@ -777,16 +784,16 @@ export const BarChart = (props: PropTypes) => {
{translateY: yAxisAtTop ? 0 : 50}, {translateY: yAxisAtTop ? 0 : 50},
], ],
}, },
yAxisSide === 'right' && {
transform: [{rotateY: '180deg'}],
},
]}> ]}>
{label} {label}
</Text> </Text>
) : null} ) : null}
</View> </View>
<View <View
style={[ style={[styles.leftPart, {backgroundColor: backgroundColor}]}>
styles.leftPart,
{backgroundColor: backgroundColor},
]}>
{hideRules ? null : ( {hideRules ? null : (
<Rule <Rule
config={{ config={{
@ -803,7 +810,7 @@ export const BarChart = (props: PropTypes) => {
)} )}
</View> </View>
</View> </View>
) );
})} })}
</> </>
); );
@ -1116,7 +1123,8 @@ export const BarChart = (props: PropTypes) => {
}} }}
style={[ style={[
{ {
marginLeft: yAxisSide === 'right' ? -yAxisLabelWidth+10 : yAxisLabelWidth, marginLeft:
yAxisSide === 'right' ? -yAxisLabelWidth + 10 : yAxisLabelWidth,
position: 'absolute', position: 'absolute',
bottom: stepHeight * -0.5 - 60 + xAxisThickness, bottom: stepHeight * -0.5 - 60 + xAxisThickness,
}, },
@ -1127,9 +1135,11 @@ export const BarChart = (props: PropTypes) => {
contentContainerStyle={[ contentContainerStyle={[
{ {
// backgroundColor: 'yellow', // backgroundColor: 'yellow',
height: containerHeight + 130 + horizSectionsBelow.length * stepHeight, height:
containerHeight + 130 + horizSectionsBelow.length * stepHeight,
paddingLeft: initialSpacing, paddingLeft: initialSpacing,
paddingBottom:horizSectionsBelow.length * stepHeight + labelsExtraHeight, paddingBottom:
horizSectionsBelow.length * stepHeight + labelsExtraHeight,
alignItems: 'flex-end', alignItems: 'flex-end',
}, },
!props.width && {width: totalWidth}, !props.width && {width: totalWidth},

View File

@ -33,6 +33,7 @@ type propTypes = {
height?: number; height?: number;
noOfSections?: number; noOfSections?: number;
maxValue?: number; maxValue?: number;
minValue?: number;
stepHeight?: number; stepHeight?: number;
stepValue?: number; stepValue?: number;
spacing?: number; spacing?: number;
@ -192,6 +193,7 @@ type propTypes = {
yAxisLabelSuffix?: String; yAxisLabelSuffix?: String;
scrollToEnd?: Boolean; scrollToEnd?: Boolean;
scrollAnimation?: Boolean; scrollAnimation?: Boolean;
noOfSectionsBelowXAxis?: number;
}; };
type referenceConfigType = { type referenceConfigType = {
thickness: number; thickness: number;
@ -280,7 +282,6 @@ export const LineChart = (props: propTypes) => {
const yAxisLabelSuffix = props.yAxisLabelSuffix || ''; const yAxisLabelSuffix = props.yAxisLabelSuffix || '';
const yAxisSide = props.yAxisSide || 'left'; const yAxisSide = props.yAxisSide || 'left';
if (!initialData) { if (!initialData) {
initialData = [...data]; initialData = [...data];
animations = initialData.map(item => new Animated.Value(item.value)); animations = initialData.map(item => new Animated.Value(item.value));
@ -456,15 +457,39 @@ export const LineChart = (props: propTypes) => {
const xAxisColor = props.xAxisColor || 'black'; const xAxisColor = props.xAxisColor || 'black';
let totalWidth = initialSpacing; let totalWidth = initialSpacing;
let maxItem = 0; let maxItem = 0,
minItem = 0;
data.forEach((item: itemType) => { data.forEach((item: itemType) => {
if (item.value > maxItem) { if (item.value > maxItem) {
maxItem = item.value; maxItem = item.value;
} }
if (item.value < minItem) {
minItem = item.value;
}
totalWidth += spacing; totalWidth += spacing;
}); });
const maxValue = props.maxValue || maxItem || 10; if (props.showFractionalValues || props.roundToDigits) {
maxItem *= 10 * (props.roundToDigits || 1);
maxItem = maxItem + (10 - (maxItem % 10));
maxItem /= 10 * (props.roundToDigits || 1);
maxItem = parseFloat(maxItem.toFixed(props.roundToDigits || 1));
if (minItem !== 0) {
minItem *= 10 * (props.roundToDigits || 1);
minItem = minItem - (10 + (minItem % 10));
minItem /= 10 * (props.roundToDigits || 1);
minItem = parseFloat(minItem.toFixed(props.roundToDigits || 1));
}
} else {
maxItem = maxItem + (10 - (maxItem % 10));
if (minItem !== 0) {
minItem = minItem - (10 + (minItem % 10));
}
}
const maxValue = props.maxValue || maxItem;
const minValue = props.minValue || minItem;
useEffect(() => { useEffect(() => {
// console.log('comes here............') // console.log('comes here............')
@ -767,18 +792,12 @@ export const LineChart = (props: propTypes) => {
xAxisThickness, xAxisThickness,
]); ]);
if (props.showFractionalValues || props.roundToDigits) {
maxItem *= 10 * (props.roundToDigits || 1);
maxItem = maxItem + (10 - (maxItem % 10));
maxItem /= 10 * (props.roundToDigits || 1);
maxItem = parseFloat(maxItem.toFixed(props.roundToDigits || 1));
} else {
maxItem = maxItem + (10 - (maxItem % 10));
}
const horizSections = [{value: '0'}]; const horizSections = [{value: '0'}];
const horizSectionsBelow = [];
const stepHeight = props.stepHeight || containerHeight / noOfSections; const stepHeight = props.stepHeight || containerHeight / noOfSections;
const stepValue = props.stepValue || maxValue / noOfSections; const stepValue = props.stepValue || maxValue / noOfSections;
const noOfSectionsBelowXAxis =
props.noOfSectionsBelowXAxis || -minValue / stepValue;
const thickness1 = props.thickness1; const thickness1 = props.thickness1;
const thickness2 = props.thickness2; const thickness2 = props.thickness2;
const thickness3 = props.thickness3; const thickness3 = props.thickness3;
@ -939,6 +958,20 @@ export const LineChart = (props: propTypes) => {
: value.toString(), : value.toString(),
}); });
} }
if (noOfSectionsBelowXAxis) {
for (let i = 1; i <= noOfSectionsBelowXAxis; i++) {
let value = stepValue * -i;
if (props.showFractionalValues || props.roundToDigits) {
value = parseFloat(value.toFixed(props.roundToDigits || 1));
}
horizSectionsBelow.push({
value: props.yAxisLabelTexts
? props.yAxisLabelTexts[noOfSectionsBelowXAxis - i] ??
value.toString()
: value.toString(),
});
}
}
const renderLabel = ( const renderLabel = (
index: number, index: number,
@ -1078,7 +1111,7 @@ export const LineChart = (props: propTypes) => {
{ {
width: (props.width ? props.width : totalWidth) + 15, width: (props.width ? props.width : totalWidth) + 15,
}, },
yAxisSide === 'right' && {transform:[{rotateY:'180deg'}]} yAxisSide === 'right' && {transform: [{rotateY: '180deg'}]},
]}> ]}>
<View <View
style={[ style={[
@ -1095,7 +1128,9 @@ export const LineChart = (props: propTypes) => {
ellipsizeMode={'clip'} ellipsizeMode={'clip'}
style={[ style={[
yAxisTextStyle, yAxisTextStyle,
yAxisSide === 'right' && {transform:[{rotateY:'180deg'}]}, yAxisSide === 'right' && {
transform: [{rotateY: '180deg'}],
},
index === noOfSections && { index === noOfSections && {
marginBottom: stepHeight / -2, marginBottom: stepHeight / -2,
}, },
@ -1190,6 +1225,70 @@ export const LineChart = (props: propTypes) => {
</View> </View>
); );
})} })}
{horizSectionsBelow.map((sectionItems, index) => {
let label = getLabel(sectionItems.value);
if (hideOrigin && index === horizSections.length - 1) {
label = '';
}
return (
<View
key={index}
style={[
styles.horizBar,
{
width: (props.width ? props.width : totalWidth) + 15,
},
index === 0 && {marginTop: stepHeight / 2},
yAxisSide === 'right' && {transform: [{rotateY: '180deg'}]},
]}>
<View
style={[
styles.leftLabel,
{
borderRightWidth: yAxisThickness,
borderColor: yAxisColor,
marginLeft: 1,
},
{
height: index === 0 ? stepHeight * 1.5 : stepHeight,
width: yAxisLabelWidth,
},
index === 0 && {marginTop: -stepHeight / 2},
]}>
{!hideYAxisText ? (
<Text
numberOfLines={1}
ellipsizeMode={'clip'}
style={[
yAxisTextStyle,
index === 0 && {marginBottom: stepHeight / -2},
yAxisSide === 'right' && {
transform: [{rotateY: '180deg'}],
},
]}>
{label}
</Text>
) : null}
</View>
<View
style={[styles.leftPart, {backgroundColor: backgroundColor}]}>
{hideRules ? null : (
<Rule
config={{
thickness: rulesThickness,
color: rulesColor,
width: (props.width || totalWidth) + 11,
dashWidth: dashWidth,
dashGap: dashGap,
type: rulesType,
}}
/>
)}
</View>
</View>
);
})}
</> </>
); );
}; };
@ -1481,11 +1580,11 @@ export const LineChart = (props: propTypes) => {
<View <View
style={{ style={{
position: 'absolute', position: 'absolute',
height: containerHeight + 10, height: containerHeight + 10 + horizSectionsBelow.length * stepHeight,
bottom: 60, //stepHeight * -0.5 + xAxisThickness, bottom: 60, //stepHeight * -0.5 + xAxisThickness,
width: totalWidth, width: totalWidth,
zIndex: -1, zIndex: -1,
// backgroundColor: 'rgba(200,150,150,0.1)' // backgroundColor: 'rgba(200,150,150,0.6)'
}}> }}>
<Svg> <Svg>
<Path <Path
@ -1587,7 +1686,7 @@ export const LineChart = (props: propTypes) => {
<Animated.View <Animated.View
style={{ style={{
position: 'absolute', position: 'absolute',
height: containerHeight + 10, height: containerHeight + 10 + horizSectionsBelow.length * stepHeight,
bottom: 60, //stepHeight * -0.5 + xAxisThickness, bottom: 60, //stepHeight * -0.5 + xAxisThickness,
width: animatedWidth, width: animatedWidth,
zIndex: -1, zIndex: -1,
@ -1678,16 +1777,25 @@ export const LineChart = (props: propTypes) => {
); );
}; };
console.log('horizSectionsBelow -- >', horizSectionsBelow);
return ( return (
<View style={[styles.container, {height: containerHeight}, yAxisSide === 'right' && {marginLeft: yAxisLabelWidth + yAxisThickness }]}> <View
style={[
styles.container,
{height: containerHeight + horizSectionsBelow.length * stepHeight},
yAxisSide === 'right' && {marginLeft: yAxisLabelWidth + yAxisThickness},
]}>
{props.hideAxesAndRules !== true && renderHorizSections()} {props.hideAxesAndRules !== true && renderHorizSections()}
{/* {sectionsOverlay()} */} {/* {sectionsOverlay()} */}
<ScrollView <ScrollView
horizontal horizontal
contentContainerStyle={[ contentContainerStyle={[
{ {
height: containerHeight + 130, height:
containerHeight + 130 + horizSectionsBelow.length * stepHeight,
width: totalWidth - 20, width: totalWidth - 20,
paddingBottom: horizSectionsBelow.length * stepHeight,
// backgroundColor: 'yellow' // backgroundColor: 'yellow'
}, },
!props.width && {width: totalWidth - 20}, !props.width && {width: totalWidth - 20},
@ -1702,7 +1810,10 @@ export const LineChart = (props: propTypes) => {
showsHorizontalScrollIndicator={showScrollIndicator} showsHorizontalScrollIndicator={showScrollIndicator}
style={[ style={[
{ {
marginLeft: yAxisSide === 'right' ? -yAxisLabelWidth - yAxisThickness + 6 : yAxisLabelWidth + yAxisThickness, marginLeft:
yAxisSide === 'right'
? -yAxisLabelWidth - yAxisThickness + 6
: yAxisLabelWidth + yAxisThickness,
position: 'absolute', position: 'absolute',
bottom: stepHeight * -0.5 - 60, //stepHeight * -0.5 + xAxisThickness, bottom: stepHeight * -0.5 - 60, //stepHeight * -0.5 + xAxisThickness,
paddingRight: 100, paddingRight: 100,