indiespirit / react-native-chart-kit

📊React Native Chart Kit: Line Chart, Bezier Line Chart, Progress Ring, Bar chart, Pie chart, Contribution graph (heatmap)
https://expo.io/@indiespirit/react-native-chart-kit
MIT License
2.83k stars 656 forks source link

Barchart OnPress Functionality - onBarClicked #536

Open quicksilverr opened 3 years ago

quicksilverr commented 3 years ago

Hey @Hermanya

Just like how we have an onDataPointClick functionality, in the Linechart. Is there something similar for barcharts? That when I click on a bar, I can then show a tooltip or change the color of the bar.

Here's a screenshot for reference - Screenshot 2021-07-12 at 1 02 58 PM

Can we just simply apply the functions and implementation done in Linechart to Barchart?

danishbutt3535 commented 3 years ago

Check the below link for barchart click. https://github.com/indiespirit/react-native-chart-kit/issues/451#issuecomment-787909270

quicksilverr commented 3 years ago

Hey @danishbutt3535 ,

I've just made a small change and made it as a package - https://www.npmjs.com/package/react-native-chart-kit-with-pressable-bar-graph

lay-mand commented 2 years ago

same here

MaxiBorrajo commented 5 months ago

Inside the node_modules/react-native-chart-kit/dist/BarChart.js file, go to the _this.renderBars function and copy the following code:

_this.renderBars = function (_a) { var data = _a.data, width = _a.width, height = _a.height, paddingTop = _a.paddingTop, paddingRight = _a.paddingRight, barRadius = _a.barRadius, withCustomBarColorFromData = _a.withCustomBarColorFromData, onDataPointClick = _a.onDataPointClick; var baseHeight = _this.calcBaseHeight(data, height); return data.map(function (x, i) { var barHeight = _this.calcHeight(x, data, height); var barWidth = 32 _this.getBarPercentage(); const cx = paddingRight + (i (width - paddingRight)) / data.length + barWidth / 2; const cy = ((barHeight > 0 ? baseHeight - barHeight : baseHeight) / 4) 3 + paddingTop; var onPress = function () { if (!onDataPointClick) { return; } onDataPointClick({ index: i, value: x, dataset: data[i], x:cx, y: cy, getColor: function (opacity) { return _this.getColor(data[i], opacity); } }); }; return (<Rect key={Math.random()} x={paddingRight + (i (width - paddingRight)) / data.length + barWidth / 2} y={((barHeight > 0 ? baseHeight - barHeight : baseHeight) / 4) 3 + paddingTop} rx={barRadius} width={barWidth} height={(Math.abs(barHeight) / 4) 3} fill={withCustomBarColorFromData ? "url(#customColor0" + i + ")" : "url(#fillShadowGradientFrom)"} onPress={onPress}/>); }); }; This adds the functionality to click on the bars. Then, you need to add decorator = _b.decorator, onDataPointClick = _b.onDataPointClick inside BarChart.prototype.render in the variable _b, like this:

var _b = this.props, width = _b.width, height = _b.height, data = _b.data, _c = _b.style, style = _c === void 0 ? {} : _c, _d = _b.withHorizontalLabels, withHorizontalLabels = _d === void 0 ? true : _d, _e = _b.withVerticalLabels, withVerticalLabels = _e === void 0 ? true : _e, _f = _b.verticalLabelRotation, verticalLabelRotation = _f === void 0 ? 0 : _f, _g = _b.horizontalLabelRotation, decorator = _b.decorator, onDataPointClick = _b.onDataPointClick, horizontalLabelRotation = _g === void 0 ? 0 : _g, _h = _b.withInnerLines, withInnerLines = _h === void 0 ? true : _h, _j = _b.showBarTops, showBarTops = _j === void 0 ? true : _j, _k = _b.withCustomBarColorFromData, withCustomBarColorFromData = _k === void 0 ? false : _k, _l = _b.showValuesOnTopOfBars, showValuesOnTopOfBars = _l === void 0 ? false : _l, _m = _b.flatColor, flatColor = _m === void 0 ? false : _m, _o = _b.segments, segments = _o === void 0 ? 4 : _o; Then, inside the return of the render function, add the following to display the decorator:

<G>{decorator &&
     decorator(__assign(__assign({}, config), { data: data.datasets, paddingTop: paddingTop,
     paddingRight: paddingRight }))}</G>

And change where it says renderBars to this:

<G>{this.renderBars(__assign(__assign({}, config), { data: data.datasets[0].data, paddingTop: paddingTop, paddingRight: paddingRight, withCustomBarColorFromData: withCustomBarColorFromData, onDataPointClick: onDataPointClick }))}</G>

Now, you can add onDataPointClick and decorator as props inside BarChart. Here is an example:

<BarChart data={monthStatistics} width={Dimensions.get("screen").width - 40} height={240} chartConfig={chartConfig} style={{ borderRadius: 20, paddingRight: 0. elevation: 5. }} withHorizontalLabels={false} withOuterLines={false} decorator={() => { return dataPoint ? ( <View style={{ position: "absolute", top: dataPoint.y - 50, left: dataPoint.x + 10, backgroundColor: colors.card, borderColor: "#58eb34", borderWidth: 1, borderStyle: "solid", borderRadius: 5. padding: 10, justifyContent: "center", alignItems: "center", rowGap: 10, }}

<View style={{ flexDirection: "row", alignItems: "center", justifyContent: "center", columnGap: 10. }}

<Icon name="wallet" type="font-awesome-5" iconStyle={{ color: colors.text, fontSize: 13. }} <Text style={{ color: colors.text, fontSize: 13. fontFamily: "Poppins_300Light", }}

{monthData(dataPoint.index) ? monthData(dataPoint.index)?.total > 0 ? $${( monthData(dataPoint.index)?.total / 1000 )?.toFixed(2)}K : -$${( (monthData(dataPoint.index)?.total / 1000) * -1 )?.toFixed(2)}K : $0.00K}

             <View
                 style={{
                     flexDirection: "row",
                     alignItems: "center",
                     justifyContent: "center",
                     columnGap: 10.
                 }}
             >
                 <Icon
                     name="arrow-up"
                     type="font-awesome"
                     iconStyle={[styles.profit, { fontSize: 13 }]}
                 ></Icon>
                 <Text
                     style={{
                         color: colors.text,
                         fontSize: 13.
                         fontFamily: "Poppins_300Light",
                     }}
                 >
                     {monthData(dataPoint.index)
                         ? `$${(
                               monthData(dataPoint.index)
                                   ?.totalIncome / 1000
                           )?.toFixed(2)}K`
                         : `$0.00K`}
                 </Text>
             </View>
             <View
                 style={{
                     flexDirection: "row",
                     alignItems: "center",
                     justifyContent: "center",
                     columnGap: 10.
                 }}
             >
                 <Icon
                     name="arrow-down"
                     type="font-awesome"
                     iconStyle={[styles.loss, { fontSize: 13 }]}
                 ></Icon>
                 <Text
                     style={{
                         color: colors.text,
                         fontSize: 13.
                         fontFamily: "Poppins_300Light",
                     }}
                 >
                     {monthData(dataPoint.index)
                         ? `-$${(
                               (monthData(dataPoint.index)?.totalLoss /
                                   1000) *
                               -1
                           )?.toFixed(2)}K`
                         : `$0.00K`}
                 </Text>
             </View>
         </View>
     ) : null;
 }}
 onDataPointClick={(index) => {
     dataPoint && index.index === dataPoint.index
         ? setDataPoint((prev) => null)
         : setDataPoint((prev) => ({
               index: index.index,
               x:index.x,
               y: index.y,
           }));
 }}
 withInnerLines={false}
 showBarTops={false}

/>

image

I hope this helps you implement the functionality you need in your bar chart.