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) { 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), leftTitles: getLeftTitles(spots), topTitles: const AxisTitles(sideTitles: SideTitles()), rightTitles: const AxisTitles(sideTitles: SideTitles()), ), ), ); } AxisTitles getBottomTitles(List spots) { return AxisTitles( sideTitles: SideTitles( interval: 90, reservedSize: 40, showTitles: true, maxIncluded: false, getTitlesWidget: (value, meta) => SideTitleWidget( meta: meta, child: Text(getDate(value)), ), ), ); } AxisTitles getLeftTitles(List spots) { return AxisTitles( sideTitles: SideTitles( reservedSize: 50, showTitles: true, maxIncluded: false, minIncluded: false, getTitlesWidget: (value, meta) => SideTitleWidget( meta: meta, child: Text(value.toStringAsFixed(2)), ), ), ); } String getDate(double value) { intl.DateFormat hmFormat = intl.DateFormat('Hm'); return hmFormat.format( DateTime.fromMillisecondsSinceEpoch((value * 1000 * 60).toInt())); } }