mirror of
https://github.com/status-im/react-native-gifted-charts.git
synced 2025-02-23 17:18:24 +00:00
Merge pull request #80 from Abhinandan-Kushwaha/feat/negative-values
Added support for negative values in Bar Chart
This commit is contained in:
commit
6ce00c6fab
@ -10,7 +10,9 @@
|
||||
| width | number | Width of the Bar chart | width of the parent |
|
||||
| height | number | Height of the Bar chart (excluding the bottom label) | 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 |
|
||||
| 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 |
|
||||
| stepHeight | number | Height of 1 step/section in the Y axis | 20 |
|
||||
| spacing | number | Distance between 2 consecutive bars in the Bar chart | 20 |
|
||||
@ -19,6 +21,7 @@
|
||||
| showScrollIndicator | Boolean | To show horizontal scroll indicator | false |
|
||||
| showLine | Boolean | To show a Line chart over the Bar chart with the same data | false |
|
||||
| lineConfig | lineConfigType | Properties of the Line chart shown over the Bar chart (lineConfigType) is described below | defaultLineConfig |
|
||||
| autoShiftLabels | Boolean | When set to true, automatically shifts the X axis labels for negative values | false |
|
||||
|
||||
---
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-gifted-charts",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"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",
|
||||
"files": [
|
||||
|
@ -223,12 +223,13 @@ const Animated2DWithGradient = (props: propTypes) => {
|
||||
height: item.barWidth || 30,
|
||||
width: item.barWidth || 30,
|
||||
justifyContent:
|
||||
props.horizontal && !props.intactTopLabel
|
||||
(props.horizontal && !props.intactTopLabel) || item.value < 0
|
||||
? 'center'
|
||||
: 'flex-end',
|
||||
alignItems: 'center',
|
||||
opacity: opacity,
|
||||
},
|
||||
item.value < 0 && {transform:[{rotate:'180deg'}]},
|
||||
props.horizontal &&
|
||||
!props.intactTopLabel && {transform: [{rotate: '270deg'}]},
|
||||
item.topLabelContainerStyle,
|
||||
@ -242,4 +243,4 @@ const Animated2DWithGradient = (props: propTypes) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default Animated2DWithGradient;
|
||||
export default Animated2DWithGradient;
|
@ -57,6 +57,7 @@ type Props = {
|
||||
horizontal: Boolean;
|
||||
intactTopLabel: Boolean;
|
||||
barBorderRadius?: number;
|
||||
autoShiftLabels?: Boolean;
|
||||
};
|
||||
type itemType = {
|
||||
value?: number;
|
||||
@ -99,8 +100,9 @@ const RenderBars = (props: Props) => {
|
||||
appearingOpacity,
|
||||
opacity,
|
||||
animationDuration,
|
||||
autoShiftLabels,
|
||||
} = props;
|
||||
const renderLabel = (label: String, labelTextStyle: any) => {
|
||||
const renderLabel = (label: String, labelTextStyle: any, value: number) => {
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
@ -119,10 +121,12 @@ const RenderBars = (props: Props) => {
|
||||
rotateLabel
|
||||
? props.horizontal
|
||||
? {transform: [{rotate: '330deg'}]}
|
||||
: {transform: [{rotate: '60deg'}]}
|
||||
: {transform: [{rotate: value < 0 ? '240deg' : '60deg'}, {translateX: value < 0 ? 56 : 0}, {translateY: value < 0 ? 32 : 0}]}
|
||||
: props.horizontal
|
||||
? {transform: [{rotate: '-90deg'}]}
|
||||
: {},
|
||||
: value < 0
|
||||
?{transform:[{rotate:'180deg'},{translateY:autoShiftLabels?0:32}]}
|
||||
:{},
|
||||
]}>
|
||||
{item.labelComponent ? (
|
||||
item.labelComponent()
|
||||
@ -137,7 +141,7 @@ const RenderBars = (props: Props) => {
|
||||
);
|
||||
};
|
||||
|
||||
const renderAnimatedLabel = (label: String, labelTextStyle: any) => {
|
||||
const renderAnimatedLabel = (label: String, labelTextStyle: any, value: number) => {
|
||||
return (
|
||||
<Animated.View
|
||||
style={[
|
||||
@ -150,9 +154,11 @@ const RenderBars = (props: Props) => {
|
||||
30) +
|
||||
spacing / 2,
|
||||
position: 'absolute',
|
||||
left: -4,
|
||||
bottom: rotateLabel ? -40 : -25,
|
||||
opacity: appearingOpacity,
|
||||
},
|
||||
value < 0 && {transform:[{rotate:'180deg'}]},
|
||||
rotateLabel
|
||||
? props.horizontal
|
||||
? {transform: [{rotate: '330deg'}]}
|
||||
@ -244,11 +250,12 @@ const RenderBars = (props: Props) => {
|
||||
height: item.barWidth || props.barWidth || 30,
|
||||
width: item.barWidth || props.barWidth || 30,
|
||||
justifyContent:
|
||||
props.horizontal && !props.intactTopLabel
|
||||
(props.horizontal && !props.intactTopLabel) || item.value < 0
|
||||
? 'center'
|
||||
: 'flex-end',
|
||||
alignItems: 'center',
|
||||
},
|
||||
item.value < 0 && {transform:[{rotate:'180deg'}]},
|
||||
props.horizontal &&
|
||||
!props.intactTopLabel && {transform: [{rotate: '270deg'}]},
|
||||
item.topLabelContainerStyle,
|
||||
@ -270,12 +277,13 @@ const RenderBars = (props: Props) => {
|
||||
// overflow: 'visible',
|
||||
marginBottom: 60,
|
||||
width: item.barWidth || props.barWidth || 30,
|
||||
height: item.topLabelComponent
|
||||
height: item.value>=0 &&(!isThreeD || isAnimated) && item.topLabelComponent
|
||||
? (item.topLabelComponentHeight || 30) +
|
||||
(item.value * (containerHeight || 200)) / (maxValue || 200)
|
||||
: (item.value * (containerHeight || 200)) / (maxValue || 200),
|
||||
(Math.abs(item.value) * (containerHeight || 200)) / (maxValue || 200)
|
||||
: (Math.abs(item.value) * (containerHeight || 200)) / (maxValue || 200),
|
||||
marginRight: spacing,
|
||||
},
|
||||
item.value < 0 && {transform:[{translateY:(Math.abs(item.value) * (containerHeight || 200)) / (maxValue || 200)},{rotateZ:'180deg'}]},
|
||||
// !isThreeD && !item.showGradient && !props.showGradient &&
|
||||
// { backgroundColor: item.frontColor || props.frontColor || 'black' },
|
||||
side !== 'right' && {zIndex: data.length - index},
|
||||
@ -325,7 +333,7 @@ const RenderBars = (props: Props) => {
|
||||
topLabelComponent={item.topLabelComponent}
|
||||
opacity={opacity || 1}
|
||||
animationDuration={animationDuration || 800}
|
||||
height={(item.value * (containerHeight || 200)) / (maxValue || 200)}
|
||||
height={(Math.abs(item.value) * (containerHeight || 200)) / (maxValue || 200)}
|
||||
intactTopLabel={props.intactTopLabel}
|
||||
horizontal={props.horizontal}
|
||||
/>
|
||||
@ -350,7 +358,8 @@ const RenderBars = (props: Props) => {
|
||||
opacity={opacity || 1}
|
||||
horizontal={props.horizontal}
|
||||
intactTopLabel={props.intactTopLabel}
|
||||
height={(item.value * (containerHeight || 200)) / (maxValue || 200)}
|
||||
height={(Math.abs(item.value) * (containerHeight || 200)) / (maxValue || 200)}
|
||||
value={item.value}
|
||||
/>
|
||||
)
|
||||
) : item.showGradient || props.showGradient ? (
|
||||
@ -364,7 +373,7 @@ const RenderBars = (props: Props) => {
|
||||
roundedTop={props.roundedTop || false}
|
||||
gradientColor={props.gradientColor}
|
||||
frontColor={props.frontColor || 'black'}
|
||||
height={(item.value * (containerHeight || 200)) / (maxValue || 200)}
|
||||
height={(Math.abs(item.value) * (containerHeight || 200)) / (maxValue || 200)}
|
||||
cappedBars={props.cappedBars}
|
||||
capThickness={props.capThickness}
|
||||
capColor={props.capColor}
|
||||
@ -387,7 +396,7 @@ const RenderBars = (props: Props) => {
|
||||
gradientColor={props.gradientColor}
|
||||
noGradient
|
||||
frontColor={props.frontColor || 'black'}
|
||||
height={(item.value * (containerHeight || 200)) / (maxValue || 200)}
|
||||
height={(Math.abs(item.value) * (containerHeight || 200)) / (maxValue || 200)}
|
||||
cappedBars={props.cappedBars}
|
||||
capThickness={props.capThickness}
|
||||
capColor={props.capColor}
|
||||
@ -408,7 +417,7 @@ const RenderBars = (props: Props) => {
|
||||
noGradient
|
||||
noAnimation
|
||||
frontColor={props.frontColor || 'black'}
|
||||
height={(item.value * (containerHeight || 200)) / (maxValue || 200)}
|
||||
height={(Math.abs(item.value) * (containerHeight || 200)) / (maxValue || 200)}
|
||||
cappedBars={props.cappedBars}
|
||||
capThickness={props.capThickness}
|
||||
capColor={props.capColor}
|
||||
@ -419,10 +428,10 @@ const RenderBars = (props: Props) => {
|
||||
/>
|
||||
)}
|
||||
{isAnimated
|
||||
? renderAnimatedLabel(item.label || '', item.labelTextStyle)
|
||||
: renderLabel(item.label || '', item.labelTextStyle)}
|
||||
? renderAnimatedLabel(item.label || '', item.labelTextStyle,item.value)
|
||||
: renderLabel(item.label || '', item.labelTextStyle,item.value)}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
export default RenderBars;
|
||||
export default RenderBars;
|
@ -24,7 +24,9 @@ type PropTypes = {
|
||||
width?: number;
|
||||
height?: number;
|
||||
noOfSections?: number;
|
||||
noOfSectionsBelowXAxis?: number;
|
||||
maxValue?: number;
|
||||
minValue?: number;
|
||||
stepHeight?: number;
|
||||
stepValue?: number;
|
||||
spacing?: number;
|
||||
@ -114,6 +116,7 @@ type PropTypes = {
|
||||
yAxisLabelTexts?: Array<string>;
|
||||
yAxisLabelPrefix?: String;
|
||||
yAxisLabelSuffix?: String;
|
||||
autoShiftLabels?: Boolean;
|
||||
};
|
||||
type lineConfigType = {
|
||||
curved?: Boolean;
|
||||
@ -216,13 +219,14 @@ export const BarChart = (props: PropTypes) => {
|
||||
const containerHeight = props.height || 200;
|
||||
const noOfSections = props.noOfSections || 10;
|
||||
const horizSections = [{value: '0'}];
|
||||
const horizSectionsBelow = [];
|
||||
const stepHeight = props.stepHeight || containerHeight / noOfSections;
|
||||
const data = useMemo(() => props.data || [], [props.data]);
|
||||
const spacing = props.spacing === 0 ? 0 : props.spacing ? props.spacing : 20;
|
||||
const labelWidth = props.labelWidth || 0;
|
||||
|
||||
let totalWidth = spacing;
|
||||
let maxItem = 0;
|
||||
let maxItem = 0, minItem = 0;
|
||||
if (props.stackData) {
|
||||
props.stackData.forEach(stackItem => {
|
||||
// console.log('stackItem', stackItem);
|
||||
@ -243,6 +247,9 @@ export const BarChart = (props: PropTypes) => {
|
||||
if (item.value > maxItem) {
|
||||
maxItem = item.value;
|
||||
}
|
||||
if(item.value < minItem){
|
||||
minItem = item.value;
|
||||
}
|
||||
totalWidth +=
|
||||
(item.barWidth || props.barWidth || 30) +
|
||||
(item.spacing === 0 ? 0 : item.spacing || spacing);
|
||||
@ -256,11 +263,16 @@ export const BarChart = (props: PropTypes) => {
|
||||
maxItem = parseFloat(maxItem.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;
|
||||
|
||||
const stepValue = props.stepValue || maxValue / noOfSections;
|
||||
const noOfSectionsBelowXAxis = props.noOfSectionsBelowXAxis || (-minValue / stepValue);
|
||||
const disableScroll = props.disableScroll || false;
|
||||
const showScrollIndicator = props.showScrollIndicator || false;
|
||||
const initialSpacing =
|
||||
@ -326,6 +338,7 @@ export const BarChart = (props: PropTypes) => {
|
||||
const heightValue = useMemo(() => new Animated.Value(0), []);
|
||||
const opacValue = useMemo(() => new Animated.Value(0), []);
|
||||
const widthValue = useMemo(() => new Animated.Value(0), []);
|
||||
const autoShiftLabels = props.autoShiftLabels || false;
|
||||
|
||||
const labelsAppear = useCallback(() => {
|
||||
opacValue.setValue(0);
|
||||
@ -505,6 +518,19 @@ export const BarChart = (props: PropTypes) => {
|
||||
: 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 animatedHeight = heightValue.interpolate({
|
||||
inputRange: [0, 1],
|
||||
@ -683,6 +709,81 @@ export const BarChart = (props: PropTypes) => {
|
||||
</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: horizontal
|
||||
? props.width || totalWidth
|
||||
: props.width || totalWidth + 11,
|
||||
},
|
||||
index===0&&{marginTop:stepHeight/2}
|
||||
]}>
|
||||
<View
|
||||
style={[
|
||||
styles.leftLabel,
|
||||
{
|
||||
borderRightWidth: yAxisThickness,
|
||||
borderColor: yAxisColor,
|
||||
},
|
||||
horizontal &&
|
||||
!yAxisAtTop && {
|
||||
transform: [{translateX: totalWidth + yAxisThickness}],
|
||||
},
|
||||
{
|
||||
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},
|
||||
horizontal && {
|
||||
transform: [
|
||||
{rotate: '270deg'},
|
||||
{translateY: yAxisAtTop ? 0 : 50},
|
||||
],
|
||||
},
|
||||
]}>
|
||||
{label}
|
||||
</Text>
|
||||
) : null}
|
||||
</View>
|
||||
<View
|
||||
style={[
|
||||
styles.leftPart,
|
||||
{backgroundColor: backgroundColor},
|
||||
]}>
|
||||
{hideRules ? null : (
|
||||
<Rule
|
||||
config={{
|
||||
thickness: rulesThickness,
|
||||
color: rulesColor,
|
||||
width: horizontal
|
||||
? props.width || totalWidth
|
||||
: (props.width || totalWidth) + 11,
|
||||
dashWidth: dashWidth,
|
||||
dashGap: dashGap,
|
||||
type: rulesType,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -975,7 +1076,7 @@ export const BarChart = (props: PropTypes) => {
|
||||
style={[
|
||||
styles.container,
|
||||
{
|
||||
height: containerHeight,
|
||||
height: containerHeight + horizSectionsBelow.length * stepHeight,
|
||||
},
|
||||
props.width && {width: props.width},
|
||||
horizontal && {transform: [{rotate: '90deg'}, {translateY: -15}]},
|
||||
@ -995,8 +1096,9 @@ export const BarChart = (props: PropTypes) => {
|
||||
contentContainerStyle={[
|
||||
{
|
||||
// backgroundColor: 'yellow',
|
||||
height: containerHeight + 130,
|
||||
height: containerHeight + 130 + horizSectionsBelow.length * stepHeight,
|
||||
paddingLeft: initialSpacing,
|
||||
paddingBottom:horizSectionsBelow.length * stepHeight,
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
!props.width && {width: totalWidth},
|
||||
@ -1083,10 +1185,11 @@ export const BarChart = (props: PropTypes) => {
|
||||
horizontal={horizontal}
|
||||
intactTopLabel={intactTopLabel}
|
||||
barBorderRadius={props.barBorderRadius}
|
||||
autoShiftLabels={autoShiftLabels}
|
||||
/>
|
||||
))}
|
||||
</Fragment>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
};
|
@ -87,7 +87,7 @@ const AnimatedBar = (props: animatedBarPropTypes) => {
|
||||
const elevate = () => {
|
||||
LayoutAnimation.configureNext({
|
||||
duration: animationDuration,
|
||||
update: {type: 'linear', property: 'scaleXY'},
|
||||
update: {type: 'linear', property: 'scaleY'},
|
||||
});
|
||||
setHeight(props.height);
|
||||
};
|
||||
@ -95,7 +95,7 @@ const AnimatedBar = (props: animatedBarPropTypes) => {
|
||||
const layoutAppear = () => {
|
||||
LayoutAnimation.configureNext({
|
||||
duration: Platform.OS == 'ios' ? animationDuration : 20,
|
||||
create: {type: 'linear', property: 'scaleXY'},
|
||||
create: {type: 'linear', property: 'scaleY'},
|
||||
// update: { type: 'linear' }
|
||||
});
|
||||
setInitialRender(false);
|
||||
@ -237,4 +237,4 @@ const AnimatedBar = (props: animatedBarPropTypes) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default AnimatedBar;
|
||||
export default AnimatedBar;
|
@ -20,6 +20,7 @@ type PropTypes = {
|
||||
side: String;
|
||||
horizontal: Boolean;
|
||||
intactTopLabel: Boolean;
|
||||
value: number;
|
||||
};
|
||||
|
||||
type TriangleProps = {
|
||||
@ -59,6 +60,7 @@ const ThreeDBar = (props: PropTypes) => {
|
||||
const width = props.width;
|
||||
const sideWidth = props.sideWidth;
|
||||
const height = props.height;
|
||||
const value = props.value;
|
||||
|
||||
const showGradient = props.showGradient || false;
|
||||
const gradientColor = props.gradientColor || 'white';
|
||||
@ -160,12 +162,13 @@ const ThreeDBar = (props: PropTypes) => {
|
||||
style={[
|
||||
{
|
||||
position: 'absolute',
|
||||
top: width * -2,
|
||||
top: value < 0 ? width * -1 : width * -2,
|
||||
height: (width * 3) / 2,
|
||||
width: width,
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
},
|
||||
value < 0 && {transform:[{rotate:'180deg'}]},
|
||||
props.horizontal &&
|
||||
!props.intactTopLabel && {transform: [{rotate: '270deg'}]},
|
||||
props.side === 'right'
|
||||
@ -182,4 +185,4 @@ const ThreeDBar = (props: PropTypes) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default ThreeDBar;
|
||||
export default ThreeDBar;
|
Loading…
x
Reference in New Issue
Block a user