From 4206e03ec7ce357633902734c582c1bd45b24cd4 Mon Sep 17 00:00:00 2001 From: Anna Stefaniv Date: Wed, 7 May 2025 15:57:07 -0700 Subject: [PATCH 1/5] When dates are selected in the calendar picker, the date labels change automatically --- .../components/custom_time_range_picker.dart | 101 +++++++++--------- 1 file changed, 53 insertions(+), 48 deletions(-) diff --git a/extras/log_file_client/lib/components/custom_time_range_picker.dart b/extras/log_file_client/lib/components/custom_time_range_picker.dart index 2dedcc7a..7b959c06 100644 --- a/extras/log_file_client/lib/components/custom_time_range_picker.dart +++ b/extras/log_file_client/lib/components/custom_time_range_picker.dart @@ -20,63 +20,69 @@ class CustomTimeRangePicker extends StatefulWidget { } class _CustomTimeRangePickerState extends State { - late DateTime minTime; - late DateTime maxTime; + late DateTimeRange selectedRange; @override void initState() { super.initState(); - minTime = widget.timeRange.start; - maxTime = widget.timeRange.end; + selectedRange = widget.timeRange; } void onDatesSelected(DateTimeRange value) { - minTime = DateTime( - value.start.year, - value.start.month, - value.start.day, - minTime.hour, - minTime.minute, - ); - maxTime = DateTime( - value.end.year, - value.end.month, - value.end.day, - maxTime.hour, - maxTime.minute, - ); + setState(() { + selectedRange = DateTimeRange( + start: DateTime( + value.start.year, + value.start.month, + value.start.day, + selectedRange.start.hour, + selectedRange.start.minute, + ), + end: DateTime( + value.end.year, + value.end.month, + value.end.day, + selectedRange.end.hour, + selectedRange.end.minute, + ), + ); + }); } void onTimeSelected(TimeOfDay time, RangeEndpointType type) { if (type == RangeEndpointType.start) { - minTime = DateTime( - minTime.year, - minTime.month, - minTime.day, - time.hour, - time.minute, + selectedRange = DateTimeRange( + start: DateTime( + selectedRange.start.year, + selectedRange.start.month, + selectedRange.start.day, + time.hour, + time.minute, + ), + end: selectedRange.end, ); } else if (type == RangeEndpointType.end) { - maxTime = DateTime( - maxTime.year, - maxTime.month, - maxTime.day, - time.hour, - time.minute, + selectedRange = DateTimeRange( + start: selectedRange.start, + end: DateTime( + selectedRange.end.year, + selectedRange.end.month, + selectedRange.end.day, + time.hour, + time.minute, + ), ); } } void onApplied() { // Ensure the time range is within the available range - if (minTime.isBefore(widget.timeRange.start)) { - minTime = widget.timeRange.start; - } - if (maxTime.isAfter(widget.timeRange.end)) { - maxTime = widget.timeRange.end; - } + selectedRange = DateTimeRange( + start: selectedRange.start.isAfter(widget.timeRange.start) ? selectedRange.start : widget.timeRange.start, + end: selectedRange.end.isBefore(widget.timeRange.end) ? selectedRange.end : widget.timeRange.end, + ); - widget.onApplied(DateTimeRange(start: minTime, end: maxTime)); + widget.onApplied(selectedRange); } @override @@ -95,10 +101,7 @@ class _CustomTimeRangePickerState extends State { ), Padding( padding: const EdgeInsets.only(bottom: 8), - child: TextButton( - onPressed: onApplied, - child: const Text('Apply'), - ), + child: TextButton(onPressed: onApplied, child: const Text('Apply')), ), ], ), @@ -141,8 +144,8 @@ class _CustomTimeRangePickerState extends State { Widget _dateDisplay(RangeEndpointType type) { return Text( type == RangeEndpointType.start - ? DateFormat.yMMMd('en_US').format(minTime) - : DateFormat.yMMMd('en_US').format(maxTime), + ? DateFormat.yMMMd('en_US').format(selectedRange.start) + : DateFormat.yMMMd('en_US').format(selectedRange.end), style: const TextStyle(fontSize: 16), ); } @@ -153,8 +156,9 @@ class _CustomTimeRangePickerState extends State { height: 300, child: RangeDatePicker( centerLeadingDate: true, - minDate: minTime, - maxDate: maxTime, + minDate: widget.timeRange.start, + maxDate: widget.timeRange.end, + selectedRange: selectedRange, onRangeSelected: onDatesSelected, splashColor: Colors.transparent, daysOfTheWeekTextStyle: TextStyle( @@ -172,9 +176,10 @@ class _CustomTimeRangePickerState extends State { } Widget _timePicker(RangeEndpointType type) { - final TimeOfDay selectedTime = type == RangeEndpointType.start - ? TimeOfDay(hour: minTime.hour, minute: minTime.minute) - : TimeOfDay(hour: maxTime.hour, minute: maxTime.minute); + final TimeOfDay selectedTime = + type == RangeEndpointType.start + ? TimeOfDay(hour: selectedRange.start.hour, minute: selectedRange.start.minute) + : TimeOfDay(hour: selectedRange.end.hour, minute: selectedRange.end.minute); return SizedBox( height: 100, From d82f9d8a8b84e3bb77b4218fbc8948c84c7871af Mon Sep 17 00:00:00 2001 From: Anna Stefaniv Date: Wed, 7 May 2025 16:38:31 -0700 Subject: [PATCH 2/5] Optimized viewing larger datasets by displaying smaller amount of data points --- .../lib/components/graph_view.dart | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/extras/log_file_client/lib/components/graph_view.dart b/extras/log_file_client/lib/components/graph_view.dart index 8ce89a33..429f8d3e 100644 --- a/extras/log_file_client/lib/components/graph_view.dart +++ b/extras/log_file_client/lib/components/graph_view.dart @@ -30,10 +30,13 @@ class _GraphViewState extends State { late double timeInterval; late DateFormat timeFormat; + int scatterGranularity = 1; + @override void initState() { super.initState(); - now = widget.now ?? DateTime.now(); + // now = widget.now ?? DateTime.now(); + now = widget.now ?? DateTime.parse('2025-04-14 08:03'); avaliableTimeRange = DateTimeRange( start: widget.logData.first.time, end: widget.logData.last.time, @@ -79,6 +82,7 @@ class _GraphViewState extends State { displayedTimeRange = timeRange; _displayedTimeRangeIndices = calculateTimeRange(timeRange); calculateTimeAxisFormat(); + calculateGranularity(); }); } @@ -116,6 +120,17 @@ class _GraphViewState extends State { } } + void calculateGranularity() { + final Duration duration = displayedTimeRange.duration; + if (duration <= Duration(days: 5)) { + scatterGranularity = 1; + } else if (duration <= Duration(days: 20)) { + scatterGranularity = 3; + } else { + scatterGranularity = 10; + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -248,11 +263,13 @@ class _GraphViewState extends State { List _chartSeries(List logData) { final MarkerSettings markerSettings = MarkerSettings(height: 2, width: 2); + final subsampledLogData = _subsampleData(logData, scatterGranularity); + return [ ScatterSeries( legendItemText: 'pH', name: 'pH', - dataSource: logData, + dataSource: subsampledLogData, xValueMapper: (LogDataLine log, _) => log.time, yValueMapper: (LogDataLine log, _) => log.phCurrent, color: _showPH ? Colors.green : Colors.transparent, @@ -264,7 +281,7 @@ class _GraphViewState extends State { ScatterSeries( legendItemText: 'pH setpoint', name: 'pH setpoint', - dataSource: logData, + dataSource: subsampledLogData, xValueMapper: (LogDataLine log, _) => log.time, yValueMapper: (LogDataLine log, _) => log.phTarget, color: _showPH ? Colors.green.shade800 : Colors.transparent, @@ -276,7 +293,7 @@ class _GraphViewState extends State { ScatterSeries( legendItemText: 'temp', name: 'temp', - dataSource: logData, + dataSource: subsampledLogData, xValueMapper: (LogDataLine log, _) => log.time, yValueMapper: (LogDataLine log, _) => log.tempMean, color: _showTemp ? Colors.blue : Colors.transparent, @@ -288,7 +305,7 @@ class _GraphViewState extends State { ScatterSeries( legendItemText: 'temp setpoint', name: 'temp setpoint', - dataSource: logData, + dataSource: subsampledLogData, xValueMapper: (LogDataLine log, _) => log.time, yValueMapper: (LogDataLine log, _) => log.tempTarget, color: _showTemp ? Colors.blue.shade800 : Colors.transparent, @@ -299,4 +316,15 @@ class _GraphViewState extends State { ), ]; } + + List _subsampleData(List logData, int granularity) { + final List subSampledData = []; + + for (int i = 0; i < logData.length; i += scatterGranularity) { + subSampledData.add(logData[i]); + } + + return subSampledData; + } + } From 0a6136fd9b5f1a155c3c215e0020ba008227c4c4 Mon Sep 17 00:00:00 2001 From: Anna Stefaniv Date: Wed, 7 May 2025 16:39:59 -0700 Subject: [PATCH 3/5] Formatting --- .../components/custom_time_range_picker.dart | 17 +++++++++++------ .../lib/components/graph_view.dart | 1 - 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/extras/log_file_client/lib/components/custom_time_range_picker.dart b/extras/log_file_client/lib/components/custom_time_range_picker.dart index 7b959c06..3cf3202c 100644 --- a/extras/log_file_client/lib/components/custom_time_range_picker.dart +++ b/extras/log_file_client/lib/components/custom_time_range_picker.dart @@ -78,8 +78,12 @@ class _CustomTimeRangePickerState extends State { void onApplied() { // Ensure the time range is within the available range selectedRange = DateTimeRange( - start: selectedRange.start.isAfter(widget.timeRange.start) ? selectedRange.start : widget.timeRange.start, - end: selectedRange.end.isBefore(widget.timeRange.end) ? selectedRange.end : widget.timeRange.end, + start: selectedRange.start.isAfter(widget.timeRange.start) + ? selectedRange.start + : widget.timeRange.start, + end: selectedRange.end.isBefore(widget.timeRange.end) + ? selectedRange.end + : widget.timeRange.end, ); widget.onApplied(selectedRange); @@ -176,10 +180,11 @@ class _CustomTimeRangePickerState extends State { } Widget _timePicker(RangeEndpointType type) { - final TimeOfDay selectedTime = - type == RangeEndpointType.start - ? TimeOfDay(hour: selectedRange.start.hour, minute: selectedRange.start.minute) - : TimeOfDay(hour: selectedRange.end.hour, minute: selectedRange.end.minute); + final TimeOfDay selectedTime = type == RangeEndpointType.start + ? TimeOfDay( + hour: selectedRange.start.hour, minute: selectedRange.start.minute) + : TimeOfDay( + hour: selectedRange.end.hour, minute: selectedRange.end.minute); return SizedBox( height: 100, diff --git a/extras/log_file_client/lib/components/graph_view.dart b/extras/log_file_client/lib/components/graph_view.dart index 429f8d3e..bffe13f3 100644 --- a/extras/log_file_client/lib/components/graph_view.dart +++ b/extras/log_file_client/lib/components/graph_view.dart @@ -326,5 +326,4 @@ class _GraphViewState extends State { return subSampledData; } - } From 829d6a9735c1dca37119a73206a4f6f0d5547ea8 Mon Sep 17 00:00:00 2001 From: Anna Stefaniv Date: Wed, 7 May 2025 16:46:09 -0700 Subject: [PATCH 4/5] formatting --- .../lib/components/custom_time_range_picker.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/extras/log_file_client/lib/components/custom_time_range_picker.dart b/extras/log_file_client/lib/components/custom_time_range_picker.dart index 3cf3202c..35fe9a52 100644 --- a/extras/log_file_client/lib/components/custom_time_range_picker.dart +++ b/extras/log_file_client/lib/components/custom_time_range_picker.dart @@ -182,9 +182,13 @@ class _CustomTimeRangePickerState extends State { Widget _timePicker(RangeEndpointType type) { final TimeOfDay selectedTime = type == RangeEndpointType.start ? TimeOfDay( - hour: selectedRange.start.hour, minute: selectedRange.start.minute) + hour: selectedRange.start.hour, + minute: selectedRange.start.minute, + ) : TimeOfDay( - hour: selectedRange.end.hour, minute: selectedRange.end.minute); + hour: selectedRange.end.hour, + minute: selectedRange.end.minute, + ); return SizedBox( height: 100, From e287dbaf8bcb5fd69fd9c348711d01b1e20bef71 Mon Sep 17 00:00:00 2001 From: Anna Stefaniv Date: Fri, 9 May 2025 08:29:19 -0700 Subject: [PATCH 5/5] Changed datetime back to now --- extras/log_file_client/lib/components/graph_view.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extras/log_file_client/lib/components/graph_view.dart b/extras/log_file_client/lib/components/graph_view.dart index bffe13f3..254e3c07 100644 --- a/extras/log_file_client/lib/components/graph_view.dart +++ b/extras/log_file_client/lib/components/graph_view.dart @@ -35,8 +35,7 @@ class _GraphViewState extends State { @override void initState() { super.initState(); - // now = widget.now ?? DateTime.now(); - now = widget.now ?? DateTime.parse('2025-04-14 08:03'); + now = widget.now ?? DateTime.now(); avaliableTimeRange = DateTimeRange( start: widget.logData.first.time, end: widget.logData.last.time,