@@ -224,14 +224,42 @@ struct MeasurementChartView: View {
|
||
| 224 | 224 |
let maximumSampleValue: Double? |
| 225 | 225 |
} |
| 226 | 226 |
|
| 227 |
+ private enum LegendStatistic: CaseIterable, Hashable {
|
|
| 228 |
+ case minimum |
|
| 229 |
+ case average |
|
| 230 |
+ case maximum |
|
| 231 |
+ case last |
|
| 232 |
+ case total |
|
| 233 |
+ |
|
| 234 |
+ var title: String {
|
|
| 235 |
+ switch self {
|
|
| 236 |
+ case .minimum: return "Min" |
|
| 237 |
+ case .average: return "Avg" |
|
| 238 |
+ case .maximum: return "Max" |
|
| 239 |
+ case .last: return "Last" |
|
| 240 |
+ case .total: return "Total" |
|
| 241 |
+ } |
|
| 242 |
+ } |
|
| 243 |
+ } |
|
| 244 |
+ |
|
| 245 |
+ private struct SeriesLegendValue: Identifiable {
|
|
| 246 |
+ let statistic: LegendStatistic |
|
| 247 |
+ let text: String |
|
| 248 |
+ |
|
| 249 |
+ var id: LegendStatistic {
|
|
| 250 |
+ statistic |
|
| 251 |
+ } |
|
| 252 |
+ } |
|
| 253 |
+ |
|
| 227 | 254 |
private struct SeriesLegendEntry: Identifiable {
|
| 228 | 255 |
let id: SeriesKind |
| 229 | 256 |
let name: String |
| 230 | 257 |
let tint: Color |
| 231 |
- let minimumText: String |
|
| 232 |
- let averageText: String |
|
| 233 |
- let maximumText: String |
|
| 234 |
- let lastText: String |
|
| 258 |
+ let values: [SeriesLegendValue] |
|
| 259 |
+ |
|
| 260 |
+ func text(for statistic: LegendStatistic) -> String? {
|
|
| 261 |
+ values.first { $0.statistic == statistic }?.text
|
|
| 262 |
+ } |
|
| 235 | 263 |
} |
| 236 | 264 |
|
| 237 | 265 |
private let minimumTimeSpan: TimeInterval = 1 |
@@ -771,34 +799,90 @@ struct MeasurementChartView: View {
|
||
| 771 | 799 |
} |
| 772 | 800 |
|
| 773 | 801 |
let averageValue = samples.reduce(0) { $0 + $1.value } / Double(samples.count)
|
| 802 |
+ let values = legendValues( |
|
| 803 |
+ for: series.kind, |
|
| 804 |
+ minimumValue: minimumValue, |
|
| 805 |
+ averageValue: averageValue, |
|
| 806 |
+ maximumValue: maximumValue, |
|
| 807 |
+ lastValue: lastValue |
|
| 808 |
+ ) |
|
| 774 | 809 |
|
| 775 | 810 |
return [ |
| 776 | 811 |
SeriesLegendEntry( |
| 777 | 812 |
id: series.kind, |
| 778 | 813 |
name: series.kind.displayName, |
| 779 | 814 |
tint: series.kind.tint, |
| 780 |
- minimumText: legendValueText(minimumValue, for: series.kind), |
|
| 781 |
- averageText: legendValueText(averageValue, for: series.kind), |
|
| 782 |
- maximumText: legendValueText(maximumValue, for: series.kind), |
|
| 783 |
- lastText: legendValueText(lastValue, for: series.kind) |
|
| 815 |
+ values: values |
|
| 784 | 816 |
) |
| 785 | 817 |
] |
| 786 | 818 |
} |
| 787 | 819 |
|
| 820 |
+ private func legendValues( |
|
| 821 |
+ for kind: SeriesKind, |
|
| 822 |
+ minimumValue: Double, |
|
| 823 |
+ averageValue: Double, |
|
| 824 |
+ maximumValue: Double, |
|
| 825 |
+ lastValue: Double |
|
| 826 |
+ ) -> [SeriesLegendValue] {
|
|
| 827 |
+ switch kind {
|
|
| 828 |
+ case .energy: |
|
| 829 |
+ return [ |
|
| 830 |
+ SeriesLegendValue( |
|
| 831 |
+ statistic: .total, |
|
| 832 |
+ text: legendValueText(lastValue, for: kind) |
|
| 833 |
+ ) |
|
| 834 |
+ ] |
|
| 835 |
+ case .batteryPercent: |
|
| 836 |
+ return [ |
|
| 837 |
+ SeriesLegendValue( |
|
| 838 |
+ statistic: .minimum, |
|
| 839 |
+ text: legendValueText(minimumValue, for: kind) |
|
| 840 |
+ ), |
|
| 841 |
+ SeriesLegendValue( |
|
| 842 |
+ statistic: .maximum, |
|
| 843 |
+ text: legendValueText(maximumValue, for: kind) |
|
| 844 |
+ ), |
|
| 845 |
+ SeriesLegendValue( |
|
| 846 |
+ statistic: .last, |
|
| 847 |
+ text: legendValueText(lastValue, for: kind) |
|
| 848 |
+ ) |
|
| 849 |
+ ] |
|
| 850 |
+ case .power, .voltage, .current, .temperature: |
|
| 851 |
+ return [ |
|
| 852 |
+ SeriesLegendValue( |
|
| 853 |
+ statistic: .minimum, |
|
| 854 |
+ text: legendValueText(minimumValue, for: kind) |
|
| 855 |
+ ), |
|
| 856 |
+ SeriesLegendValue( |
|
| 857 |
+ statistic: .average, |
|
| 858 |
+ text: legendValueText(averageValue, for: kind) |
|
| 859 |
+ ), |
|
| 860 |
+ SeriesLegendValue( |
|
| 861 |
+ statistic: .maximum, |
|
| 862 |
+ text: legendValueText(maximumValue, for: kind) |
|
| 863 |
+ ), |
|
| 864 |
+ SeriesLegendValue( |
|
| 865 |
+ statistic: .last, |
|
| 866 |
+ text: legendValueText(lastValue, for: kind) |
|
| 867 |
+ ) |
|
| 868 |
+ ] |
|
| 869 |
+ } |
|
| 870 |
+ } |
|
| 871 |
+ |
|
| 788 | 872 |
@ViewBuilder |
| 789 | 873 |
private func chartLegend(entries: [SeriesLegendEntry]) -> some View {
|
| 790 | 874 |
if !entries.isEmpty {
|
| 791 | 875 |
let nameWidth: CGFloat = compactLayout ? 88 : (isLargeDisplay ? 128 : 108) |
| 792 | 876 |
let valueWidth: CGFloat = compactLayout ? 78 : (isLargeDisplay ? 108 : 92) |
| 877 |
+ let statistics = legendStatistics(for: entries) |
|
| 793 | 878 |
|
| 794 | 879 |
ScrollView(.horizontal, showsIndicators: false) {
|
| 795 | 880 |
VStack(alignment: .leading, spacing: compactLayout ? 5 : 7) {
|
| 796 | 881 |
HStack(spacing: compactLayout ? 8 : 10) {
|
| 797 | 882 |
legendHeaderText("Measurement", width: nameWidth, alignment: .leading)
|
| 798 |
- legendHeaderText("Min", width: valueWidth)
|
|
| 799 |
- legendHeaderText("Avg", width: valueWidth)
|
|
| 800 |
- legendHeaderText("Max", width: valueWidth)
|
|
| 801 |
- legendHeaderText("Last", width: valueWidth)
|
|
| 883 |
+ ForEach(statistics, id: \.self) { statistic in
|
|
| 884 |
+ legendHeaderText(statistic.title, width: valueWidth) |
|
| 885 |
+ } |
|
| 802 | 886 |
} |
| 803 | 887 |
|
| 804 | 888 |
ForEach(entries) { entry in
|
@@ -814,10 +898,9 @@ struct MeasurementChartView: View {
|
||
| 814 | 898 |
} |
| 815 | 899 |
.frame(width: nameWidth, alignment: .leading) |
| 816 | 900 |
|
| 817 |
- legendValueText(entry.minimumText, width: valueWidth) |
|
| 818 |
- legendValueText(entry.averageText, width: valueWidth) |
|
| 819 |
- legendValueText(entry.maximumText, width: valueWidth) |
|
| 820 |
- legendValueText(entry.lastText, width: valueWidth) |
|
| 901 |
+ ForEach(statistics, id: \.self) { statistic in
|
|
| 902 |
+ legendValueText(entry.text(for: statistic) ?? "-", width: valueWidth) |
|
| 903 |
+ } |
|
| 821 | 904 |
} |
| 822 | 905 |
} |
| 823 | 906 |
} |
@@ -835,6 +918,12 @@ struct MeasurementChartView: View {
|
||
| 835 | 918 |
} |
| 836 | 919 |
} |
| 837 | 920 |
|
| 921 |
+ private func legendStatistics(for entries: [SeriesLegendEntry]) -> [LegendStatistic] {
|
|
| 922 |
+ LegendStatistic.allCases.filter { statistic in
|
|
| 923 |
+ entries.contains { $0.text(for: statistic) != nil }
|
|
| 924 |
+ } |
|
| 925 |
+ } |
|
| 926 |
+ |
|
| 838 | 927 |
private func legendHeaderText( |
| 839 | 928 |
_ text: String, |
| 840 | 929 |
width: CGFloat, |