Files
fl_chart/example/lib/presentation/samples/bar/bar_chart_sample1.dart
zypherift c7e3f36b06
Some checks failed
Code Coverage / upload (push) Has been cancelled
Gh-Pages / build (push) Has been cancelled
Code Verification / verify (push) Has been cancelled
1.0.0
2025-08-09 18:17:34 +02:00

398 lines
11 KiB
Dart

import 'dart:async';
import 'dart:math';
import 'package:fl_chart_app/presentation/resources/app_resources.dart';
import 'package:fl_chart_app/util/extensions/color_extensions.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
class BarChartSample1 extends StatefulWidget {
BarChartSample1({super.key});
List<Color> get availableColors => const <Color>[
AppColors.contentColorPurple,
AppColors.contentColorYellow,
AppColors.contentColorBlue,
AppColors.contentColorOrange,
AppColors.contentColorPink,
AppColors.contentColorRed,
];
final Color barBackgroundColor =
AppColors.contentColorWhite.darken().withValues(alpha: 0.3);
final Color barColor = AppColors.contentColorWhite;
final Color touchedBarColor = AppColors.contentColorGreen;
@override
State<StatefulWidget> createState() => BarChartSample1State();
}
class BarChartSample1State extends State<BarChartSample1> {
final Duration animDuration = const Duration(milliseconds: 250);
int touchedIndex = -1;
bool isPlaying = false;
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1,
child: Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
const Text(
'Mingguan',
style: TextStyle(
color: AppColors.contentColorGreen,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(
height: 4,
),
Text(
'Grafik konsumsi kalori',
style: TextStyle(
color: AppColors.contentColorGreen.darken(),
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(
height: 38,
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: BarChart(
isPlaying ? randomData() : mainBarData(),
duration: animDuration,
),
),
),
const SizedBox(
height: 12,
),
],
),
),
Padding(
padding: const EdgeInsets.all(8),
child: Align(
alignment: Alignment.topRight,
child: IconButton(
icon: Icon(
isPlaying ? Icons.pause : Icons.play_arrow,
color: AppColors.contentColorGreen,
),
onPressed: () {
setState(() {
isPlaying = !isPlaying;
if (isPlaying) {
refreshState();
}
});
},
),
),
)
],
),
);
}
BarChartGroupData makeGroupData(
int x,
double y, {
bool isTouched = false,
Color? barColor,
double width = 22,
List<int> showTooltips = const [],
}) {
barColor ??= widget.barColor;
return BarChartGroupData(
x: x,
barRods: [
BarChartRodData(
toY: isTouched ? y + 1 : y,
color: isTouched ? widget.touchedBarColor : barColor,
width: width,
borderSide: isTouched
? BorderSide(color: widget.touchedBarColor.darken(80))
: const BorderSide(color: Colors.white, width: 0),
backDrawRodData: BackgroundBarChartRodData(
show: true,
toY: 20,
color: widget.barBackgroundColor,
),
),
],
showingTooltipIndicators: showTooltips,
);
}
List<BarChartGroupData> showingGroups() => List.generate(7, (i) {
switch (i) {
case 0:
return makeGroupData(0, 5, isTouched: i == touchedIndex);
case 1:
return makeGroupData(1, 6.5, isTouched: i == touchedIndex);
case 2:
return makeGroupData(2, 5, isTouched: i == touchedIndex);
case 3:
return makeGroupData(3, 7.5, isTouched: i == touchedIndex);
case 4:
return makeGroupData(4, 9, isTouched: i == touchedIndex);
case 5:
return makeGroupData(5, 11.5, isTouched: i == touchedIndex);
case 6:
return makeGroupData(6, 6.5, isTouched: i == touchedIndex);
default:
return throw Error();
}
});
BarChartData mainBarData() {
return BarChartData(
barTouchData: BarTouchData(
touchTooltipData: BarTouchTooltipData(
getTooltipColor: (_) => Colors.blueGrey,
tooltipHorizontalAlignment: FLHorizontalAlignment.right,
tooltipMargin: -10,
getTooltipItem: (group, groupIndex, rod, rodIndex) {
String weekDay;
switch (group.x) {
case 0:
weekDay = 'Monday';
break;
case 1:
weekDay = 'Tuesday';
break;
case 2:
weekDay = 'Wednesday';
break;
case 3:
weekDay = 'Thursday';
break;
case 4:
weekDay = 'Friday';
break;
case 5:
weekDay = 'Saturday';
break;
case 6:
weekDay = 'Sunday';
break;
default:
throw Error();
}
return BarTooltipItem(
'$weekDay\n',
const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18,
),
children: <TextSpan>[
TextSpan(
text: (rod.toY - 1).toString(),
style: const TextStyle(
color: Colors.white, //widget.touchedBarColor,
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: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: getTitles,
reservedSize: 38,
),
),
leftTitles: const AxisTitles(
sideTitles: SideTitles(
showTitles: false,
),
),
),
borderData: FlBorderData(
show: false,
),
barGroups: showingGroups(),
gridData: const 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 = const Text('M', style: style);
break;
case 1:
text = const Text('T', style: style);
break;
case 2:
text = const Text('W', style: style);
break;
case 3:
text = const Text('T', style: style);
break;
case 4:
text = const Text('F', style: style);
break;
case 5:
text = const Text('S', style: style);
break;
case 6:
text = const Text('S', style: style);
break;
default:
text = const Text('', style: style);
break;
}
return SideTitleWidget(
meta: meta,
space: 16,
child: text,
);
}
BarChartData randomData() {
return BarChartData(
barTouchData: const BarTouchData(
enabled: false,
),
titlesData: FlTitlesData(
show: true,
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: getTitles,
reservedSize: 38,
),
),
leftTitles: const AxisTitles(
sideTitles: SideTitles(
showTitles: false,
),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(
showTitles: false,
),
),
rightTitles: const AxisTitles(
sideTitles: SideTitles(
showTitles: false,
),
),
),
borderData: FlBorderData(
show: false,
),
barGroups: List.generate(7, (i) {
switch (i) {
case 0:
return makeGroupData(
0,
Random().nextInt(15).toDouble() + 6,
barColor: widget.availableColors[
Random().nextInt(widget.availableColors.length)],
);
case 1:
return makeGroupData(
1,
Random().nextInt(15).toDouble() + 6,
barColor: widget.availableColors[
Random().nextInt(widget.availableColors.length)],
);
case 2:
return makeGroupData(
2,
Random().nextInt(15).toDouble() + 6,
barColor: widget.availableColors[
Random().nextInt(widget.availableColors.length)],
);
case 3:
return makeGroupData(
3,
Random().nextInt(15).toDouble() + 6,
barColor: widget.availableColors[
Random().nextInt(widget.availableColors.length)],
);
case 4:
return makeGroupData(
4,
Random().nextInt(15).toDouble() + 6,
barColor: widget.availableColors[
Random().nextInt(widget.availableColors.length)],
);
case 5:
return makeGroupData(
5,
Random().nextInt(15).toDouble() + 6,
barColor: widget.availableColors[
Random().nextInt(widget.availableColors.length)],
);
case 6:
return makeGroupData(
6,
Random().nextInt(15).toDouble() + 6,
barColor: widget.availableColors[
Random().nextInt(widget.availableColors.length)],
);
default:
return throw Error();
}
}),
gridData: const FlGridData(show: false),
);
}
Future<dynamic> refreshState() async {
setState(() {});
await Future<dynamic>.delayed(
animDuration + const Duration(milliseconds: 50),
);
if (isPlaying) {
await refreshState();
}
}
}