244 lines
7.9 KiB
Dart
244 lines
7.9 KiB
Dart
import 'dart:math' as math;
|
|
|
|
import 'package:fl_chart/fl_chart.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../../../themes/charts/appChartColors.dart';
|
|
|
|
class BarChartSample7 extends StatefulWidget {
|
|
BarChartSample7({super.key});
|
|
|
|
final shadowColor = const Color(0xFFCCCCCC);
|
|
final dataList = [
|
|
_BarData(AppColors.contentColorYellow, 18, 18),
|
|
_BarData(AppColors.contentColorGreen, 17, 8),
|
|
_BarData(AppColors.contentColorOrange, 10, 15),
|
|
_BarData(AppColors.contentColorPink, 2.5, 5),
|
|
_BarData(AppColors.contentColorBlue, 2, 2.5),
|
|
_BarData(AppColors.contentColorRed, 2, 2),
|
|
];
|
|
|
|
@override
|
|
State<BarChartSample7> createState() => _BarChartSample7State();
|
|
}
|
|
|
|
class _BarChartSample7State extends State<BarChartSample7> {
|
|
BarChartGroupData generateBarGroup(
|
|
int x,
|
|
Color color,
|
|
double value,
|
|
double shadowValue,
|
|
) {
|
|
return BarChartGroupData(
|
|
x: x,
|
|
barRods: [
|
|
BarChartRodData(toY: value, color: color, width: 6),
|
|
BarChartRodData(toY: shadowValue, color: widget.shadowColor, width: 6),
|
|
],
|
|
showingTooltipIndicators: touchedGroupIndex == x ? [0] : [],
|
|
);
|
|
}
|
|
|
|
int touchedGroupIndex = -1;
|
|
|
|
int rotationTurns = 1;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return SelectionArea(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(24),
|
|
child: Column(
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Expanded(child: Container()),
|
|
const Text(
|
|
'Horizontal Bar Chart',
|
|
style: TextStyle(color: AppColors.mainTextColor1, fontSize: 20),
|
|
),
|
|
Expanded(
|
|
child: Align(
|
|
alignment: Alignment.centerRight,
|
|
child: Tooltip(
|
|
message: 'Rotate the chart 90 degrees (cw)',
|
|
child: IconButton(
|
|
onPressed: () {
|
|
setState(() {
|
|
rotationTurns += 1;
|
|
});
|
|
},
|
|
icon: RotatedBox(
|
|
quarterTurns: rotationTurns - 1,
|
|
child: const Icon(Icons.rotate_90_degrees_cw),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 18),
|
|
AspectRatio(
|
|
aspectRatio: 1.4,
|
|
child: BarChart(
|
|
BarChartData(
|
|
alignment: BarChartAlignment.spaceBetween,
|
|
rotationQuarterTurns: rotationTurns,
|
|
borderData: FlBorderData(
|
|
show: true,
|
|
border: Border.symmetric(
|
|
horizontal: BorderSide(
|
|
color: AppColors.borderColor.withValues(alpha: 0.2),
|
|
),
|
|
),
|
|
),
|
|
titlesData: FlTitlesData(
|
|
show: true,
|
|
leftTitles: const AxisTitles(
|
|
drawBelowEverything: true,
|
|
sideTitles: SideTitles(showTitles: true, reservedSize: 30),
|
|
),
|
|
bottomTitles: AxisTitles(
|
|
sideTitles: SideTitles(
|
|
showTitles: true,
|
|
reservedSize: 50,
|
|
getTitlesWidget: (value, meta) {
|
|
final index = value.toInt();
|
|
return SideTitleWidget(
|
|
meta: meta,
|
|
child: Text('data'),
|
|
// child: _IconWidget(
|
|
// color: widget.dataList[index].color,
|
|
// isSelected: touchedGroupIndex == index,
|
|
// ),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
// rightTitles: const AxisTitles(),
|
|
// topTitles: const AxisTitles(),
|
|
),
|
|
gridData: FlGridData(
|
|
show: true,
|
|
drawVerticalLine: false,
|
|
getDrawingHorizontalLine: (value) => FlLine(
|
|
color: AppColors.borderColor.withValues(alpha: 0.2),
|
|
strokeWidth: 1,
|
|
),
|
|
),
|
|
barGroups: widget.dataList.asMap().entries.map((e) {
|
|
final index = e.key;
|
|
final data = e.value;
|
|
return generateBarGroup(
|
|
index,
|
|
data.color,
|
|
data.value,
|
|
data.shadowValue,
|
|
);
|
|
}).toList(),
|
|
maxY: 20,
|
|
barTouchData: BarTouchData(
|
|
enabled: true,
|
|
handleBuiltInTouches: false,
|
|
touchTooltipData: BarTouchTooltipData(
|
|
getTooltipColor: (group) => Colors.transparent,
|
|
tooltipMargin: 0,
|
|
getTooltipItem:
|
|
(
|
|
BarChartGroupData group,
|
|
int groupIndex,
|
|
BarChartRodData rod,
|
|
int rodIndex,
|
|
) {
|
|
return BarTooltipItem(
|
|
rod.toY.toString(),
|
|
TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
color: rod.color,
|
|
fontSize: 18,
|
|
shadows: const [
|
|
Shadow(color: Colors.black26, blurRadius: 12),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
touchCallback: (event, response) {
|
|
if (event.isInterestedForInteractions &&
|
|
response != null &&
|
|
response.spot != null) {
|
|
setState(() {
|
|
touchedGroupIndex = response.spot!.touchedBarGroupIndex;
|
|
});
|
|
} else {
|
|
setState(() {
|
|
touchedGroupIndex = -1;
|
|
});
|
|
}
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
) );
|
|
}
|
|
}
|
|
|
|
class _BarData {
|
|
const _BarData(this.color, this.value, this.shadowValue);
|
|
|
|
final Color color;
|
|
final double value;
|
|
final double shadowValue;
|
|
}
|
|
|
|
class _IconWidget extends ImplicitlyAnimatedWidget {
|
|
const _IconWidget({required this.color, required this.isSelected})
|
|
: super(duration: const Duration(milliseconds: 300));
|
|
final Color color;
|
|
final bool isSelected;
|
|
|
|
@override
|
|
ImplicitlyAnimatedWidgetState<ImplicitlyAnimatedWidget> createState() =>
|
|
_IconWidgetState();
|
|
}
|
|
|
|
class _IconWidgetState extends AnimatedWidgetBaseState<_IconWidget> {
|
|
Tween<double>? _rotationTween;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final rotation = math.pi * 4 * _rotationTween!.evaluate(animation);
|
|
final scale = 1 + _rotationTween!.evaluate(animation) * 0.5;
|
|
return Transform(
|
|
transform: Matrix4.identity()..scale(0.8),
|
|
// transform: Matrix4.rotationZ(rotation)..scaled(scale, scale, scale),
|
|
// transform: Matrix4.rotationZ(rotation)..scale(scale, scale, scale),
|
|
origin: const Offset(14, 14),
|
|
child: Icon(
|
|
widget.isSelected ? Icons.face_retouching_natural : Icons.face,
|
|
color: widget.color,
|
|
size: 28,
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
void forEachTween(TweenVisitor<dynamic> visitor) {
|
|
_rotationTween =
|
|
visitor(
|
|
_rotationTween,
|
|
widget.isSelected ? 1.0 : 0.0,
|
|
(dynamic value) => Tween<double>(
|
|
begin: value as double,
|
|
end: widget.isSelected ? 1.0 : 0.0,
|
|
),
|
|
)
|
|
as Tween<double>?;
|
|
}
|
|
}
|