Skip to content

Commit

Permalink
enhancement to support horizontal bar chart.
Browse files Browse the repository at this point in the history
  • Loading branch information
MrRoy121 committed Dec 14, 2024
1 parent 3c59913 commit 9b12441
Show file tree
Hide file tree
Showing 2 changed files with 561 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,375 @@
import 'package:fl_chart_app/presentation/resources/app_resources.dart';
import 'package:fl_chart_app/util/app_utils.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';

class BarChartHoriSample5 extends StatefulWidget {
const BarChartHoriSample5({super.key});

@override
State<StatefulWidget> createState() => BarChartHoriSample5State();
}

class BarChartHoriSample5State extends State<BarChartHoriSample5> {
static const double barWidth = 22;
static const shadowOpacity = 0.2;
static const mainItems = <int, List<double>>{
0: [2, 3, 2.5, 8],
1: [-1.8, -2.7, -3, -6.5],
2: [1.5, 2, 3.5, 6],
3: [1.5, 1.5, 4, 6.5],
4: [-2, -2, -5, -9],
5: [-1.2, -1.5, -4.3, -10],
6: [1.2, 4.8, 5, 5],
};
int touchedIndex = -1;

@override
void initState() {
super.initState();
}

Widget bottomTitles(double value, TitleMeta meta) {
const style = TextStyle(color: Colors.white, fontSize: 10);
String text;
switch (value.toInt()) {
case 0:
text = 'Mon';
break;
case 1:
text = 'Tue';
break;
case 2:
text = 'Wed';
break;
case 3:
text = 'Thu';
break;
case 4:
text = 'Fri';
break;
case 5:
text = 'Sat';
break;
case 6:
text = 'Sun';
break;
default:
text = '';
break;
}
return SideTitleWidget(
axisSide: meta.axisSide,
child: Transform.rotate(
// THIS TO ROTATE ALL THE TEXT
angle: -1.5708,
child: Text(text, style: style)),
);
}

Widget topTitles(double value, TitleMeta meta) {
const style = TextStyle(color: Colors.white, fontSize: 10);
String text;
switch (value.toInt()) {
case 0:
text = 'Mon';
break;
case 1:
text = 'Tue';
break;
case 2:
text = 'Wed';
break;
case 3:
text = 'Thu';
break;
case 4:
text = 'Fri';
break;
case 5:
text = 'Sat';
break;
case 6:
text = 'Sun';
break;
default:
return Container();
}
return SideTitleWidget(
axisSide: meta.axisSide,
child: Transform.rotate(
// THIS TO ROTATE ALL THE TEXT
angle: -1.5708,
child: Text(text, style: style)),
);
}

Widget leftTitles(double value, TitleMeta meta) {
const style = TextStyle(color: Colors.white, fontSize: 10);
String text;
if (value == 0) {
text = '0';
} else {
text = '${value.toInt()}0k';
}
return SideTitleWidget(
angle: AppUtils().degreeToRadian(value < 0 ? -45 : 45),
axisSide: meta.axisSide,
space: 4,
child: Transform.rotate(
// THIS TO ROTATE ALL THE TEXT
angle: -1.5708,
child: Text(
text,
style: style,
textAlign: TextAlign.center,
),
),
);
}

Widget rightTitles(double value, TitleMeta meta) {
const style = TextStyle(color: Colors.white, fontSize: 10);
String text;
if (value == 0) {
text = '0';
} else {
text = '${value.toInt()}0k';
}
return SideTitleWidget(
angle: AppUtils().degreeToRadian(90),
axisSide: meta.axisSide,
space: 0,
child: Transform.rotate(
// THIS TO ROTATE ALL THE TEXT
angle: 3.15,
child: Text(
text,
style: style,
textAlign: TextAlign.center,
),
),
);
}

BarChartGroupData generateGroup(
int x,
double value1,
double value2,
double value3,
double value4,
) {
final isTop = value1 > 0;
final sum = value1 + value2 + value3 + value4;
final isTouched = touchedIndex == x;
return BarChartGroupData(
x: x,
groupVertically: true,
showingTooltipIndicators: isTouched ? [0] : [],
barRods: [
BarChartRodData(
toY: sum,
width: barWidth,
borderRadius: isTop
? const BorderRadius.only(
topLeft: Radius.circular(6),
topRight: Radius.circular(6),
)
: const BorderRadius.only(
bottomLeft: Radius.circular(6),
bottomRight: Radius.circular(6),
),
rodStackItems: [
BarChartRodStackItem(
0,
value1,
AppColors.contentColorGreen,
BorderSide(
color: Colors.white,
width: isTouched ? 2 : 0,
),
),
BarChartRodStackItem(
value1,
value1 + value2,
AppColors.contentColorYellow,
BorderSide(
color: Colors.white,
width: isTouched ? 2 : 0,
),
),
BarChartRodStackItem(
value1 + value2,
value1 + value2 + value3,
AppColors.contentColorPink,
BorderSide(
color: Colors.white,
width: isTouched ? 2 : 0,
),
),
BarChartRodStackItem(
value1 + value2 + value3,
value1 + value2 + value3 + value4,
AppColors.contentColorBlue,
BorderSide(
color: Colors.white,
width: isTouched ? 2 : 0,
),
),
],
),
BarChartRodData(
toY: -sum,
width: barWidth,
color: Colors.transparent,
borderRadius: isTop
? const BorderRadius.only(
bottomLeft: Radius.circular(6),
bottomRight: Radius.circular(6),
)
: const BorderRadius.only(
topLeft: Radius.circular(6),
topRight: Radius.circular(6),
),
rodStackItems: [
BarChartRodStackItem(
0,
-value1,
AppColors.contentColorGreen.withOpacity(isTouched ? shadowOpacity * 2 : shadowOpacity),
const BorderSide(color: Colors.transparent),
),
BarChartRodStackItem(
-value1,
-(value1 + value2),
AppColors.contentColorYellow.withOpacity(isTouched ? shadowOpacity * 2 : shadowOpacity),
const BorderSide(color: Colors.transparent),
),
BarChartRodStackItem(
-(value1 + value2),
-(value1 + value2 + value3),
AppColors.contentColorPink.withOpacity(isTouched ? shadowOpacity * 2 : shadowOpacity),
const BorderSide(color: Colors.transparent),
),
BarChartRodStackItem(
-(value1 + value2 + value3),
-(value1 + value2 + value3 + value4),
AppColors.contentColorBlue.withOpacity(isTouched ? shadowOpacity * 2 : shadowOpacity),
const BorderSide(color: Colors.transparent),
),
],
),
],
);
}

bool isShadowBar(int rodIndex) => rodIndex == 1;

@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 0.8,
child: Padding(
padding: const EdgeInsets.only(top: 16),
child: BarChart(
isHorizontal: true,
BarChartData(
alignment: BarChartAlignment.center,
maxY: 20,
minY: -20,
groupsSpace: 12,
barTouchData: BarTouchData(
handleBuiltInTouches: false,
touchTooltipData: BarTouchTooltipData(
rotateAngle: 270,
fitInsideVertically: true,
tooltipMargin: 8,
tooltipPadding: const EdgeInsets.all(10),
),
touchCallback: (FlTouchEvent event, barTouchResponse) {
if (!event.isInterestedForInteractions || barTouchResponse == null || barTouchResponse.spot == null) {
setState(() {
touchedIndex = -1;
});
return;
}
final rodIndex = barTouchResponse.spot!.touchedRodDataIndex;
if (isShadowBar(rodIndex)) {
setState(() {
touchedIndex = -1;
});
return;
}
setState(() {
touchedIndex = barTouchResponse.spot!.touchedBarGroupIndex;
});
},
),
titlesData: FlTitlesData(
show: true,
topTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 32,
getTitlesWidget: topTitles,
),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 32,
getTitlesWidget: bottomTitles,
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: leftTitles,
interval: 5,
reservedSize: 42,
),
),
rightTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: rightTitles,
interval: 5,
reservedSize: 42,
),
),
),
gridData: FlGridData(
show: true,
checkToShowHorizontalLine: (value) => value % 5 == 0,
getDrawingHorizontalLine: (value) {
if (value == 0) {
return FlLine(
color: AppColors.borderColor.withOpacity(0.1),
strokeWidth: 3,
);
}
return FlLine(
color: AppColors.borderColor.withOpacity(0.05),
strokeWidth: 0.8,
);
},
),
borderData: FlBorderData(
show: false,
),
barGroups: mainItems.entries
.map(
(e) => generateGroup(
e.key,
e.value[0],
e.value[1],
e.value[2],
e.value[3],
),
)
.toList(),
),
),
),
);
}
}
Loading

0 comments on commit 9b12441

Please sign in to comment.