[7520D797-9D35-42F7-8641-CBA52A27A99C.jpeg]Updated: 29 April 2022 Hi FF community, Hope this custom widget useful for someone..A customizable Bar chart
Preview:[21869643-EB68-4378-9399-2F253F77C576.gif]
Package (pubspec dependency):
fl_chart
https://pub.dev/packages/fl_chart
Additional parameters:[C3DE4122-9EB7-4522-846C-94D9C4AC28E7.jpeg]
Code:
import 'dart:async';
import 'dart:math';
import 'package:fl_chart/fl_chart.dart';
class BarChartSample1 extends StatefulWidget {
const BarChartSample1({
Key key,
this.width,
this.height,
this.title,
this.subtitle,
this.titleColor,
this.subtitleColor,
this.backgroundColor,
this.barColor,
this.barTouchedColor,
this.fullBarValue,
this.value0,
this.value1,
this.value2,
this.value3,
this.value4,
this.value5,
this.value6,
this.bottomTitle0,
this.bottomTitle1,
this.bottomTitle2,
this.bottomTitle3,
this.bottomTitle4,
this.bottomTitle5,
this.bottomTitle6,
this.description0,
this.description1,
this.description2,
this.description3,
this.description4,
this.description5,
this.description6,
}) : super(key: key);
final double width;
final double height;
final String title;
final String subtitle;
final Color titleColor;
final Color subtitleColor;
final Color backgroundColor;
final Color barColor;
final Color barTouchedColor;
final double fullBarValue;
final double value0;
final double value1;
final double value2;
final double value3;
final double value4;
final double value5;
final double value6;
final String bottomTitle0;
final String bottomTitle1;
final String bottomTitle2;
final String bottomTitle3;
final String bottomTitle4;
final String bottomTitle5;
final String bottomTitle6;
final String description0;
final String description1;
final String description2;
final String description3;
final String description4;
final String description5;
final String description6;
@override
_BarChartSample1State createState() => _BarChartSample1State();
}
class _BarChartSample1State extends State {
//final Color barBackgroundColor = const Color(0xff72d8bf);
final Duration animDuration = const Duration(milliseconds: 250);
int touchedIndex = -1;
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1,
child: Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18)),
color: widget.backgroundColor,
child: Stack(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Text(
widget.title,
style: TextStyle(
color: widget.titleColor,
fontSize: 24,
fontWeight: FontWeight.bold),
),
const SizedBox(
height: 4,
),
Text(
widget.subtitle,
style: TextStyle(
color: widget.subtitleColor,
fontSize: 18,
fontWeight: FontWeight.bold),
),
const SizedBox(
height: 38,
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: BarChart(
mainBarData(),
swapAnimationDuration: animDuration,
),
),
),
const SizedBox(
height: 12,
),
],
),
),
],
),
),
);
}
BarChartGroupData makeGroupData(
int x,
double y, {
bool isTouched = false,
Color barColor = Colors.white,
double width = 22,
List showTooltips = const [],
}) {
return BarChartGroupData(
x: x,
barRods: [
BarChartRodData(
toY: isTouched ? y + 1 : y,
color: isTouched ? widget.barTouchedColor : widget.barColor,
width: width,
borderSide: isTouched
? BorderSide(color: widget.barTouchedColor.darken(), width: 1)
: const BorderSide(color: Colors.white, width: 0),
backDrawRodData: BackgroundBarChartRodData(
show: true,
toY: widget.fullBarValue,
color: widget.barColor,
),
),
],
showingTooltipIndicators: showTooltips,
);
}
List showingGroups() => List.generate(7, (i) {
switch (i) {
case 0:
return makeGroupData(0, widget.value0,
isTouched: i == touchedIndex);
case 1:
return makeGroupData(1, widget.value1,
isTouched: i == touchedIndex);
case 2:
return makeGroupData(2, widget.value2,
isTouched: i == touchedIndex);
case 3:
return makeGroupData(3, widget.value3,
isTouched: i == touchedIndex);
case 4:
return makeGroupData(4, widget.value4,
isTouched: i == touchedIndex);
case 5:
return makeGroupData(5, widget.value5,
isTouched: i == touchedIndex);
case 6:
return makeGroupData(6, widget.value6,
isTouched: i == touchedIndex);
default:
return throw Error();
}
});
BarChartData mainBarData() {
return BarChartData(
barTouchData: BarTouchData(
touchTooltipData: BarTouchTooltipData(
tooltipBgColor: Colors.blueGrey,
getTooltipItem: (group, groupIndex, rod, rodIndex) {
String description;
switch (group.x.toInt()) {
case 0:
description = widget.description0;
break;
case 1:
description = widget.description1;
break;
case 2:
description = widget.description2;
break;
case 3:
description = widget.description3;
break;
case 4:
description = widget.description4;
break;
case 5:
description = widget.description5;
break;
case 6:
description = widget.description6;
break;
default:
throw Error();
}
return BarTooltipItem(
description + '\n',
const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18,
),
children: [
TextSpan(
text: (rod.toY - 1).toString(),
style: TextStyle(
color: widget.barTouchedColor,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
],
);
}),
touchCallback: (FlTouchEvent event, barTouchResponse) {
setState(() {
if (!event.isInterestedForInteractions ||
barTouchResponse == null ||
barTouchResponse.spot == null) {
touchedIndex = -1;
return;
}
touchedIndex = barTouchResponse.spot.touchedBarGroupIndex;
});
},
),
titlesData: FlTitlesData(
show: true,
rightTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: getTitles,
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: false,
),
),
),
borderData: FlBorderData(
show: false,
),
barGroups: showingGroups(),
gridData: FlGridData(show: false),
);
}
Widget getTitles(double value, TitleMeta meta) {
const style = TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 14,
);
Widget text;
switch (value.toInt()) {
case 0:
text = Text(widget.bottomTitle0, style: style);
break;
case 1:
text = Text(widget.bottomTitle1, style: style);
break;
case 2:
text = Text(widget.bottomTitle2, style: style);
break;
case 3:
text = Text(widget.bottomTitle3, style: style);
break;
case 4:
text = Text(widget.bottomTitle4, style: style);
break;
case 5:
text = Text(widget.bottomTitle5, style: style);
break;
case 6:
text = Text(widget.bottomTitle6, style: style);
break;
default:
text = Text('', style: style);
break;
}
return Padding(padding: const EdgeInsets.only(top: 16), child: text);
}
Future refreshState() async {
setState(() {});
await Future.delayed(
animDuration + const Duration(milliseconds: 50));
}
}
extension ColorExtension on Color {
/// Convert the color to a darken color based on the [percent]
Color darken([int percent = 40]) {
assert(1 <= percent && percent <= 100);
final value = 1 - percent / 100;
return Color.fromARGB(alpha, (red * value).round(), (green * value).round(),
(blue * value).round());
}
}
Of course, you can modify, add and delete according to your needs and your use-case....😉👍