瀏覽代碼

Add common y scale calculation

Yakov Karpov 5 年之前
父節點
當前提交
8ac2184d8f

+ 4 - 0
FreeAPS.xcodeproj/project.pbxproj

@@ -234,6 +234,7 @@
 		6610FA2E25FAED29004781D7 /* APSDataFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6610FA1325FAED29004781D7 /* APSDataFormatter.swift */; };
 		6610FA2E25FAED29004781D7 /* APSDataFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6610FA1325FAED29004781D7 /* APSDataFormatter.swift */; };
 		6610FA2F25FAED29004781D7 /* getChartWidth().swift in Sources */ = {isa = PBXBuildFile; fileRef = 6610FA1425FAED29004781D7 /* getChartWidth().swift */; };
 		6610FA2F25FAED29004781D7 /* getChartWidth().swift in Sources */ = {isa = PBXBuildFile; fileRef = 6610FA1425FAED29004781D7 /* getChartWidth().swift */; };
 		6632A0DC746872439A858B44 /* ISFEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79BDA519C9B890FD9A5DFCF3 /* ISFEditorDataFlow.swift */; };
 		6632A0DC746872439A858B44 /* ISFEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79BDA519C9B890FD9A5DFCF3 /* ISFEditorDataFlow.swift */; };
+		66C5083C25FD97FA00E4D76A /* MainChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C5083B25FD97FA00E4D76A /* MainChartView.swift */; };
 		69A31254F2451C20361D172F /* BolusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 223EC0494F55A91E3EA69EF4 /* BolusViewModel.swift */; };
 		69A31254F2451C20361D172F /* BolusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 223EC0494F55A91E3EA69EF4 /* BolusViewModel.swift */; };
 		69B9A368029F7EB39F525422 /* CREditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA5E04A2761F6EEA6568E1 /* CREditorViewModel.swift */; };
 		69B9A368029F7EB39F525422 /* CREditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA5E04A2761F6EEA6568E1 /* CREditorViewModel.swift */; };
 		6B9625766B697D1C98E455A2 /* PumpSettingsEditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72778B68C3004F71F6E79BDC /* PumpSettingsEditorViewModel.swift */; };
 		6B9625766B697D1C98E455A2 /* PumpSettingsEditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72778B68C3004F71F6E79BDC /* PumpSettingsEditorViewModel.swift */; };
@@ -530,6 +531,7 @@
 		6610FA1225FAED29004781D7 /* getGlucoseArrowImage().swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "getGlucoseArrowImage().swift"; sourceTree = "<group>"; };
 		6610FA1225FAED29004781D7 /* getGlucoseArrowImage().swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "getGlucoseArrowImage().swift"; sourceTree = "<group>"; };
 		6610FA1325FAED29004781D7 /* APSDataFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APSDataFormatter.swift; sourceTree = "<group>"; };
 		6610FA1325FAED29004781D7 /* APSDataFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APSDataFormatter.swift; sourceTree = "<group>"; };
 		6610FA1425FAED29004781D7 /* getChartWidth().swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "getChartWidth().swift"; sourceTree = "<group>"; };
 		6610FA1425FAED29004781D7 /* getChartWidth().swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "getChartWidth().swift"; sourceTree = "<group>"; };
+		66C5083B25FD97FA00E4D76A /* MainChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainChartView.swift; sourceTree = "<group>"; };
 		67F94DD2853CF42BA4E30616 /* BasalProfileEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorDataFlow.swift; sourceTree = "<group>"; };
 		67F94DD2853CF42BA4E30616 /* BasalProfileEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorDataFlow.swift; sourceTree = "<group>"; };
 		680C4420C9A345D46D90D06C /* ManualTempBasalProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ManualTempBasalProvider.swift; sourceTree = "<group>"; };
 		680C4420C9A345D46D90D06C /* ManualTempBasalProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ManualTempBasalProvider.swift; sourceTree = "<group>"; };
 		6BA56D2DCAB9E0A8AF24D984 /* BasalProfileEditorBuilder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorBuilder.swift; sourceTree = "<group>"; };
 		6BA56D2DCAB9E0A8AF24D984 /* BasalProfileEditorBuilder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorBuilder.swift; sourceTree = "<group>"; };
@@ -1359,6 +1361,7 @@
 			children = (
 			children = (
 				6610FA0625FAED29004781D7 /* PredictionsChartView.swift */,
 				6610FA0625FAED29004781D7 /* PredictionsChartView.swift */,
 				6610FA0725FAED29004781D7 /* PointChartView.swift */,
 				6610FA0725FAED29004781D7 /* PointChartView.swift */,
+				66C5083B25FD97FA00E4D76A /* MainChartView.swift */,
 			);
 			);
 			path = Charts;
 			path = Charts;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -1902,6 +1905,7 @@
 				BF1667ADE69E4B5B111CECAE /* ManualTempBasalProvider.swift in Sources */,
 				BF1667ADE69E4B5B111CECAE /* ManualTempBasalProvider.swift in Sources */,
 				C967DACD3B1E638F8B43BE06 /* ManualTempBasalViewModel.swift in Sources */,
 				C967DACD3B1E638F8B43BE06 /* ManualTempBasalViewModel.swift in Sources */,
 				7BCFACB97C821041BA43A114 /* ManualTempBasalRootView.swift in Sources */,
 				7BCFACB97C821041BA43A114 /* ManualTempBasalRootView.swift in Sources */,
+				66C5083C25FD97FA00E4D76A /* MainChartView.swift in Sources */,
 				38A00B2325FC2B55006BC0B0 /* LRUCache.swift in Sources */,
 				38A00B2325FC2B55006BC0B0 /* LRUCache.swift in Sources */,
 				91732A8060347C0E67024D80 /* AutotuneConfigBuilder.swift in Sources */,
 				91732A8060347C0E67024D80 /* AutotuneConfigBuilder.swift in Sources */,
 				3083261C4B268E353F36CD0B /* AutotuneConfigDataFlow.swift in Sources */,
 				3083261C4B268E353F36CD0B /* AutotuneConfigDataFlow.swift in Sources */,

+ 74 - 0
FreeAPS/Sources/Charts/Views/Charts/MainChartView.swift

@@ -0,0 +1,74 @@
+import SwiftUI
+
+struct MainChartView: View {
+    let maxWidth: CGFloat
+    let showHours: Int
+    let glucoseData: [BloodGlucose]
+    var predictionsData: [PredictionLineData]?
+    var body: some View {
+        let allValues = getAllValues()
+        let minValue = allValues.min() ?? 40
+        let maxValue = allValues.max() ?? 400
+
+        return HStack {
+            PointChartView(
+                minValue: minValue,
+                maxValue: maxValue,
+                maxWidth: maxWidth,
+                showHours: showHours,
+                glucoseData: glucoseData
+            ) { value in
+                GlucosePointView(value: value)
+            }
+            PredictionsChartView(
+                minValue: minValue,
+                maxValue: maxValue,
+                maxWidth: maxWidth,
+                data: predictionsData,
+                showHours: showHours
+            )
+        }
+    }
+}
+
+extension MainChartView {
+    func getAllValues() -> [Int] {
+        let glucoseValues = glucoseData.compactMap(\.sgv)
+        guard let predictionValues = getPredictionValues() else {
+            return glucoseValues
+        }
+        return glucoseValues + predictionValues
+    }
+
+    func getPredictionValues() -> [Int]? {
+        if let predictions = predictionsData {
+            return predictions.flatMap { prediction in
+                prediction.values.compactMap(\.sgv)
+            }
+        }
+        return nil
+    }
+}
+
+struct MainChartView_Previews: PreviewProvider {
+    static let glucoseData = Array(SampleData.sampleData[0 ... 70])
+    static let predictionsData = [
+        PredictionLineData(
+            type: .iob,
+            values: Array(SampleData.sampleData[0 ... 10])
+        ),
+        PredictionLineData(type: .cob, values: Array(SampleData.sampleData[1 ... 21])),
+        PredictionLineData(
+            type: .uam,
+            values: Array(SampleData.sampleData[21 ... 30])
+        ),
+        PredictionLineData(type: .zt, values: Array(SampleData.sampleData[31 ... 40]))
+    ]
+
+    static var previews: some View {
+        ScrollView(.horizontal) {
+            MainChartView(maxWidth: 400, showHours: 1, glucoseData: glucoseData, predictionsData: predictionsData)
+        }
+        .preferredColorScheme(/*@START_MENU_TOKEN@*/ .dark/*@END_MENU_TOKEN@*/)
+    }
+}

+ 5 - 5
FreeAPS/Sources/Charts/Views/Charts/PointChartView.swift

@@ -3,7 +3,7 @@ import SwiftUI
 struct PointChartView<PointEntry: View>: View {
 struct PointChartView<PointEntry: View>: View {
     let minValue: Int
     let minValue: Int
     let maxValue: Int
     let maxValue: Int
-    let width: CGFloat
+    let maxWidth: CGFloat
     let showHours: Int
     let showHours: Int
     let glucoseData: [BloodGlucose]
     let glucoseData: [BloodGlucose]
     let pointEntry: (_: Int?) -> PointEntry
     let pointEntry: (_: Int?) -> PointEntry
@@ -15,12 +15,12 @@ struct PointChartView<PointEntry: View>: View {
         let firstEntryTime = glucoseData
         let firstEntryTime = glucoseData
             .map(\.date)
             .map(\.date)
             .first ?? UInt64(Date().timeIntervalSince1970)
             .first ?? UInt64(Date().timeIntervalSince1970)
-        
+
         var width: CGFloat = 0
         var width: CGFloat = 0
         if let lastGlucose = glucoseData.last {
         if let lastGlucose = glucoseData.last {
             width = calculateXPosition(glucose: lastGlucose, firstEntryTime: firstEntryTime)
             width = calculateXPosition(glucose: lastGlucose, firstEntryTime: firstEntryTime)
         }
         }
-        
+
         return GeometryReader { geometry in
         return GeometryReader { geometry in
             ForEach(
             ForEach(
                 getGlucosePoints(
                 getGlucosePoints(
@@ -39,7 +39,7 @@ struct PointChartView<PointEntry: View>: View {
 extension PointChartView {
 extension PointChartView {
     func calculateXPosition(glucose: BloodGlucose, firstEntryTime: UInt64) -> CGFloat {
     func calculateXPosition(glucose: BloodGlucose, firstEntryTime: UInt64) -> CGFloat {
         let xPositionIndex = CGFloat(glucose.date - firstEntryTime) / CGFloat(300 * showHours)
         let xPositionIndex = CGFloat(glucose.date - firstEntryTime) / CGFloat(300 * showHours)
-        return (xPositionIndex * width / CGFloat(Double(showHours) * hoursMultiplier)) + pointSize
+        return (xPositionIndex * maxWidth / CGFloat(Double(showHours) * hoursMultiplier)) + pointSize
     }
     }
 
 
     func getGlucosePoints(
     func getGlucosePoints(
@@ -88,7 +88,7 @@ struct PointChartView_Previews: PreviewProvider {
                 PointChartView(
                 PointChartView(
                     minValue: 3,
                     minValue: 3,
                     maxValue: 8,
                     maxValue: 8,
-                    width: 500,
+                    maxWidth: 500,
                     showHours: 1,
                     showHours: 1,
                     glucoseData: testingData
                     glucoseData: testingData
                 ) { value in
                 ) { value in

+ 16 - 11
FreeAPS/Sources/Charts/Views/Charts/PredictionsChartView.swift

@@ -1,22 +1,27 @@
 import SwiftUI
 import SwiftUI
 
 
 public struct PredictionsChartView: View {
 public struct PredictionsChartView: View {
+    let minValue: Int
+    let maxValue: Int
+    let maxWidth: CGFloat
     var data: [PredictionLineData]?
     var data: [PredictionLineData]?
-    let width: CGFloat
     let showHours: Int
     let showHours: Int
 
 
     public var body: some View {
     public var body: some View {
         ZStack {
         ZStack {
             if let data = data {
             if let data = data {
                 ForEach(data, id: \.self) { predictionLine in
                 ForEach(data, id: \.self) { predictionLine in
-                    PointChartView(
-                        minValue: 30,
-                        maxValue: 300,
-                        width: 500,
-                        showHours: 1,
-                        glucoseData: predictionLine.values
-                    ) { value in
-                        PredictionPointView(predictionType: predictionLine.type, value: value)
+                    HStack {
+                        PointChartView(
+                            minValue: minValue,
+                            maxValue: maxValue,
+                            maxWidth: maxWidth,
+                            showHours: showHours,
+                            glucoseData: predictionLine.values
+                        ) { value in
+                            PredictionPointView(predictionType: predictionLine.type, value: value)
+                        }
+                        Spacer()
                     }
                     }
                 }
                 }
             }
             }
@@ -30,7 +35,7 @@ struct PredictionsChartView_Previews: PreviewProvider {
             type: .iob,
             type: .iob,
             values: Array(SampleData.sampleData[0 ... 10])
             values: Array(SampleData.sampleData[0 ... 10])
         ),
         ),
-        PredictionLineData(type: .cob, values: Array(SampleData.sampleData[1 ... 20])),
+        PredictionLineData(type: .cob, values: Array(SampleData.sampleData[1 ... 21])),
         PredictionLineData(
         PredictionLineData(
             type: .uam,
             type: .uam,
             values: Array(SampleData.sampleData[21 ... 30])
             values: Array(SampleData.sampleData[21 ... 30])
@@ -40,7 +45,7 @@ struct PredictionsChartView_Previews: PreviewProvider {
 
 
     static var previews: some View {
     static var previews: some View {
         ScrollView(.horizontal) {
         ScrollView(.horizontal) {
-            PredictionsChartView(data: data, width: 400, showHours: 1)
+            PredictionsChartView(minValue: 30, maxValue: 180, maxWidth: 400, data: data, showHours: 1)
         }
         }
         .preferredColorScheme(/*@START_MENU_TOKEN@*/ .dark/*@END_MENU_TOKEN@*/)
         .preferredColorScheme(/*@START_MENU_TOKEN@*/ .dark/*@END_MENU_TOKEN@*/)
     }
     }

+ 1 - 1
FreeAPS/Sources/Modules/Home/View/HomeRootView.swift

@@ -18,7 +18,7 @@ extension Home {
                             PointChartView(
                             PointChartView(
                                 minValue: 20,
                                 minValue: 20,
                                 maxValue: 300,
                                 maxValue: 300,
-                                width: geo.size.width,
+                                maxWidth: geo.size.width,
                                 showHours: showHours,
                                 showHours: showHours,
                                 glucoseData: SampleData.sampleData
                                 glucoseData: SampleData.sampleData
                             ) { value in
                             ) { value in