Files
fl_chart/example/lib/presentation/samples/line/line_chart_sample5.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

290 lines
9.1 KiB
Dart

import 'package:fl_chart/fl_chart.dart';
import 'package:fl_chart_app/presentation/resources/app_resources.dart';
import 'package:flutter/material.dart';
class LineChartSample5 extends StatefulWidget {
const LineChartSample5({
super.key,
Color? gradientColor1,
Color? gradientColor2,
Color? gradientColor3,
Color? indicatorStrokeColor,
}) : gradientColor1 = gradientColor1 ?? AppColors.contentColorBlue,
gradientColor2 = gradientColor2 ?? AppColors.contentColorPink,
gradientColor3 = gradientColor3 ?? AppColors.contentColorRed,
indicatorStrokeColor = indicatorStrokeColor ?? AppColors.mainTextColor1;
final Color gradientColor1;
final Color gradientColor2;
final Color gradientColor3;
final Color indicatorStrokeColor;
@override
State<LineChartSample5> createState() => _LineChartSample5State();
}
class _LineChartSample5State extends State<LineChartSample5> {
List<int> showingTooltipOnSpots = [1, 3, 5];
List<FlSpot> get allSpots => const [
FlSpot(0, 1),
FlSpot(1, 2),
FlSpot(2, 1.5),
FlSpot(3, 3),
FlSpot(4, 3.5),
FlSpot(5, 5),
FlSpot(6, 8),
];
Widget bottomTitleWidgets(double value, TitleMeta meta, double chartWidth) {
final style = TextStyle(
fontWeight: FontWeight.bold,
color: AppColors.contentColorPink,
fontFamily: 'Digital',
fontSize: 18 * chartWidth / 500,
);
String text;
switch (value.toInt()) {
case 0:
text = '00:00';
break;
case 1:
text = '04:00';
break;
case 2:
text = '08:00';
break;
case 3:
text = '12:00';
break;
case 4:
text = '16:00';
break;
case 5:
text = '20:00';
break;
case 6:
text = '23:59';
break;
default:
return Container();
}
return SideTitleWidget(
meta: meta,
child: Text(text, style: style),
);
}
@override
Widget build(BuildContext context) {
final lineBarsData = [
LineChartBarData(
showingIndicators: showingTooltipOnSpots,
spots: allSpots,
isCurved: true,
barWidth: 4,
shadow: const Shadow(
blurRadius: 8,
),
belowBarData: BarAreaData(
show: true,
gradient: LinearGradient(
colors: [
widget.gradientColor1.withValues(alpha: 0.4),
widget.gradientColor2.withValues(alpha: 0.4),
widget.gradientColor3.withValues(alpha: 0.4),
],
),
),
dotData: const FlDotData(show: false),
gradient: LinearGradient(
colors: [
widget.gradientColor1,
widget.gradientColor2,
widget.gradientColor3,
],
stops: const [0.1, 0.4, 0.9],
),
),
];
final tooltipsOnBar = lineBarsData[0];
return AspectRatio(
aspectRatio: 2.5,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 24.0,
vertical: 10,
),
child: LayoutBuilder(builder: (context, constraints) {
return LineChart(
LineChartData(
showingTooltipIndicators: showingTooltipOnSpots.map((index) {
return ShowingTooltipIndicators([
LineBarSpot(
tooltipsOnBar,
lineBarsData.indexOf(tooltipsOnBar),
tooltipsOnBar.spots[index],
),
]);
}).toList(),
lineTouchData: LineTouchData(
enabled: true,
handleBuiltInTouches: false,
touchCallback:
(FlTouchEvent event, LineTouchResponse? response) {
if (response == null || response.lineBarSpots == null) {
return;
}
if (event is FlTapUpEvent) {
final spotIndex = response.lineBarSpots!.first.spotIndex;
setState(() {
if (showingTooltipOnSpots.contains(spotIndex)) {
showingTooltipOnSpots.remove(spotIndex);
} else {
showingTooltipOnSpots.add(spotIndex);
}
});
}
},
mouseCursorResolver:
(FlTouchEvent event, LineTouchResponse? response) {
if (response == null || response.lineBarSpots == null) {
return SystemMouseCursors.basic;
}
return SystemMouseCursors.click;
},
getTouchedSpotIndicator:
(LineChartBarData barData, List<int> spotIndexes) {
return spotIndexes.map((index) {
return TouchedSpotIndicatorData(
const FlLine(
color: Colors.pink,
),
FlDotData(
show: true,
getDotPainter: (spot, percent, barData, index) =>
FlDotCirclePainter(
radius: 8,
color: lerpGradient(
barData.gradient!.colors,
barData.gradient!.stops!,
percent / 100,
),
strokeWidth: 2,
strokeColor: widget.indicatorStrokeColor,
),
),
);
}).toList();
},
touchTooltipData: LineTouchTooltipData(
getTooltipColor: (touchedSpot) => Colors.pink,
tooltipBorderRadius: BorderRadius.circular(8),
getTooltipItems: (List<LineBarSpot> lineBarsSpot) {
return lineBarsSpot.map((lineBarSpot) {
return LineTooltipItem(
lineBarSpot.y.toString(),
const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
);
}).toList();
},
),
),
lineBarsData: lineBarsData,
minY: 0,
titlesData: FlTitlesData(
leftTitles: const AxisTitles(
axisNameWidget: Text('count'),
axisNameSize: 24,
sideTitles: SideTitles(
showTitles: false,
reservedSize: 0,
),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
interval: 1,
getTitlesWidget: (value, meta) {
return bottomTitleWidgets(
value,
meta,
constraints.maxWidth,
);
},
reservedSize: 30,
),
),
rightTitles: const AxisTitles(
axisNameWidget: Text('count'),
sideTitles: SideTitles(
showTitles: false,
reservedSize: 0,
),
),
topTitles: const AxisTitles(
axisNameWidget: Text(
'Wall clock',
textAlign: TextAlign.left,
),
axisNameSize: 24,
sideTitles: SideTitles(
showTitles: true,
reservedSize: 0,
),
),
),
gridData: const FlGridData(show: false),
borderData: FlBorderData(
show: true,
border: Border.all(
color: AppColors.borderColor,
),
),
),
);
}),
),
);
}
}
/// Lerps between a [LinearGradient] colors, based on [t]
Color lerpGradient(List<Color> colors, List<double> stops, double t) {
if (colors.isEmpty) {
throw ArgumentError('"colors" is empty.');
} else if (colors.length == 1) {
return colors[0];
}
if (stops.length != colors.length) {
stops = [];
/// provided gradientColorStops is invalid and we calculate it here
colors.asMap().forEach((index, color) {
final percent = 1.0 / (colors.length - 1);
stops.add(percent * index);
});
}
for (var s = 0; s < stops.length - 1; s++) {
final leftStop = stops[s];
final rightStop = stops[s + 1];
final leftColor = colors[s];
final rightColor = colors[s + 1];
if (t <= leftStop) {
return leftColor;
} else if (t < rightStop) {
final sectionT = (t - leftStop) / (rightStop - leftStop);
return Color.lerp(leftColor, rightColor, sectionT)!;
}
}
return colors.last;
}