import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart' as intl; import 'dart:math'; import '../model/reading.dart'; class ReadingGraph extends StatelessWidget { const ReadingGraph({super.key, required List readings}) : _readings = readings; final List _readings; @override Widget build(BuildContext context) { if (_readings.isEmpty) { return Text('No readings on record.'); } final spots = _readings .map( (e) => FlSpot( e.dateTime.millisecondsSinceEpoch.toDouble() / 1000 / 60, e.value), ) .toList(); return LineChart( LineChartData( maxY: _readings.map((e) => e.value).reduce(max) + 0.05, minY: _readings.map((e) => e.value).reduce(min) - 0.05, lineBarsData: [ LineChartBarData( isCurved: true, color: Colors.cyan, barWidth: 2, isStrokeCapRound: true, dotData: const FlDotData(show: false), spots: _readings .map( (e) => FlSpot( e.dateTime.millisecondsSinceEpoch.toDouble() / 1000 / 60, e.value), ) .toList(), ) ], titlesData: FlTitlesData( bottomTitles: getBottomTitles(spots), topTitles: const AxisTitles(sideTitles: SideTitles()), rightTitles: const AxisTitles(sideTitles: SideTitles()), ), ), ); } AxisTitles getBottomTitles(List spots) { final maxX = double.parse( spots.map((e) => (e.x)).reduce(max).toStringAsFixed(0)); final minX = double.parse( spots.map((e) => e.x).reduce(min).toStringAsFixed(0)); final middle = double.parse(spots[spots.length ~/ 2].x.toStringAsFixed(0)) + 4; return AxisTitles( sideTitles: SideTitles( interval: 1, showTitles: true, getTitlesWidget: (value, meta) { String text = ''; if (value == maxX) { text = getDate(spots.first.x); } else if (double.parse(value.toStringAsFixed(0)) == minX) { text = getDate(spots.last.x); } else if (value == middle) { text = getDate(middle); } return Text(text); }, ), ); } String getDate(double value) { intl.DateFormat hmFormat = intl.DateFormat('Hm'); return hmFormat.format( DateTime.fromMillisecondsSinceEpoch((value * 1000 * 60).toInt())); } }