MainChartView2.swift 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import Charts
  2. import SwiftUI
  3. struct MainChartView2: View {
  4. @Binding var tempBasals: [PumpHistoryEvent]
  5. @Binding var glucose: [BloodGlucose]
  6. @Binding var screenHours: Int16
  7. @Binding var highGlucose: Decimal
  8. @Binding var lowGlucose: Decimal
  9. @Binding var carbs: [CarbsEntry]
  10. var body: some View {
  11. VStack(alignment: .center, spacing: 8, content: {
  12. GlucoseChart(glucose: $glucose, screenHours: $screenHours, highGlucose: $highGlucose, lowGlucose: $lowGlucose)
  13. .padding(.bottom, 20)
  14. CarbsChart(carbs: $carbs, screenHours: $screenHours)
  15. .padding(.bottom, 8)
  16. BasalChart(tempBasals: $tempBasals, screenHours: $screenHours)
  17. .padding(.bottom, 8)
  18. Legend()
  19. })
  20. }
  21. }
  22. // MARK: GLUCOSE FOR CHART
  23. struct GlucoseChart: View {
  24. @Binding var glucose: [BloodGlucose]
  25. @Binding var screenHours: Int16
  26. @Binding var highGlucose: Decimal
  27. @Binding var lowGlucose: Decimal
  28. var body: some View {
  29. VStack {
  30. let filteredGlucose: [BloodGlucose] = filterGlucoseData(for: screenHours)
  31. Chart(filteredGlucose) {
  32. RuleMark(y: .value("High", highGlucose))
  33. .foregroundStyle(Color.loopYellow)
  34. .lineStyle(StrokeStyle(lineWidth: 1, dash: [5]))
  35. RuleMark(y: .value("Low", lowGlucose))
  36. .foregroundStyle(Color.loopRed)
  37. .lineStyle(StrokeStyle(lineWidth: 1, dash: [5]))
  38. PointMark(
  39. x: .value("Time", $0.dateString),
  40. y: .value("Value", $0.value)
  41. )
  42. .foregroundStyle(
  43. $0.value > Double(highGlucose) ? Color.yellow.gradient :
  44. $0.value < Double(lowGlucose) ? Color.red.gradient : Color.green.gradient
  45. )
  46. .symbolSize(12)
  47. }
  48. .frame(height: 250)
  49. .chartXAxis(.hidden)
  50. }
  51. }
  52. private func filterGlucoseData(for hours: Int16) -> [BloodGlucose] {
  53. guard hours > 0 else {
  54. return glucose
  55. }
  56. let currentDate = Date()
  57. let startDate = Calendar.current.date(byAdding: .hour, value: -Int(hours), to: currentDate) ?? currentDate
  58. return glucose.filter { $0.dateString >= startDate }
  59. }
  60. }
  61. // MARK: BASAL FOR CHART
  62. struct BasalChart: View {
  63. @Binding var tempBasals: [PumpHistoryEvent]
  64. @Binding var screenHours: Int16
  65. var body: some View {
  66. VStack {
  67. let filteredBasal: [PumpHistoryEvent] = filterBasalData(for: screenHours)
  68. Chart(filteredBasal) {
  69. BarMark(
  70. x: .value("Time", $0.timestamp),
  71. y: .value("Value", $0.rate ?? 0)
  72. )
  73. .foregroundStyle(Color.blue.gradient)
  74. .cornerRadius(0)
  75. }
  76. .frame(height: 80)
  77. // .rotationEffect(.degrees(180))
  78. // .chartXAxis(.hidden)
  79. .chartYAxis(.hidden)
  80. }
  81. }
  82. private func filterBasalData(for hours: Int16) -> [PumpHistoryEvent] {
  83. guard hours > 0 else {
  84. return tempBasals
  85. }
  86. let currentDate = Date()
  87. let startDate = Calendar.current.date(byAdding: .hour, value: -Int(hours), to: currentDate) ?? currentDate
  88. return tempBasals.filter { $0.timestamp >= startDate }
  89. }
  90. }
  91. // MARK: COB
  92. struct CarbsChart: View {
  93. @Binding var carbs: [CarbsEntry]
  94. @Binding var screenHours: Int16
  95. var body: some View {
  96. let currentDate = Date()
  97. let startDate = Calendar.current.date(byAdding: .hour, value: -Int(screenHours), to: currentDate) ?? currentDate
  98. VStack {
  99. let filteredCarbs: [CarbsEntry] = filterCarbData(for: screenHours)
  100. Chart(filteredCarbs) {
  101. BarMark(
  102. x: .value("Time", $0.createdAt),
  103. y: .value("Value", $0.carbs)
  104. )
  105. .foregroundStyle(Color.loopYellow.gradient)
  106. .cornerRadius(0)
  107. }
  108. .frame(height: 80)
  109. .chartYAxis(.hidden)
  110. // .chartXScale(domain: Int(startDate.timeIntervalSince1970) ... Int(currentDate.timeIntervalSince1970))
  111. // .chartXScale(domain: 0 ... 5)
  112. }
  113. }
  114. private func filterCarbData(for hours: Int16) -> [CarbsEntry] {
  115. guard hours > 0 else {
  116. return carbs
  117. }
  118. let currentDate = Date()
  119. let startDate = Calendar.current.date(byAdding: .hour, value: -Int(hours), to: currentDate) ?? currentDate
  120. return carbs.filter { $0.createdAt >= startDate }
  121. }
  122. }
  123. // MARK: LEGEND PANEL FOR CHART
  124. struct Legend: View {
  125. var body: some View {
  126. HStack {
  127. Image(systemName: "line.diagonal")
  128. .rotationEffect(Angle(degrees: 45))
  129. .foregroundColor(.green)
  130. Text("BG")
  131. .foregroundColor(.secondary)
  132. Spacer()
  133. Image(systemName: "line.diagonal")
  134. .rotationEffect(Angle(degrees: 45))
  135. .foregroundColor(.insulin)
  136. Text("IOB")
  137. .foregroundColor(.secondary)
  138. Spacer()
  139. Image(systemName: "line.diagonal")
  140. .rotationEffect(Angle(degrees: 45))
  141. .foregroundColor(.purple)
  142. Text("ZT")
  143. .foregroundColor(.secondary)
  144. Spacer()
  145. Image(systemName: "line.diagonal")
  146. .frame(height: 10)
  147. .rotationEffect(Angle(degrees: 45))
  148. .foregroundColor(.loopYellow)
  149. Text("COB")
  150. .foregroundColor(.secondary)
  151. Spacer()
  152. Image(systemName: "line.diagonal")
  153. .rotationEffect(Angle(degrees: 45))
  154. .foregroundColor(.orange)
  155. Text("UAM")
  156. .foregroundColor(.secondary)
  157. }
  158. .font(.caption2)
  159. .padding(.horizontal, 40)
  160. .padding(.vertical, 1)
  161. }
  162. }