CobIobChart.swift 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import Charts
  2. import Foundation
  3. import SwiftUI
  4. extension MainChartView {
  5. var cobIobChart: some View {
  6. Chart {
  7. drawCurrentTimeMarker()
  8. drawIOB()
  9. drawCOB(dummy: false)
  10. if let selectedCOBValue {
  11. PointMark(
  12. x: .value("Time", selectedCOBValue.deliverAt ?? now, unit: .minute),
  13. y: .value("Value", selectedCOBValue.cob)
  14. )
  15. .symbolSize(CGSize(width: 15, height: 15))
  16. .foregroundStyle(Color.orange.opacity(0.8))
  17. .position(by: .value("Axis", "COB"))
  18. PointMark(
  19. x: .value("Time", selectedCOBValue.deliverAt ?? now, unit: .minute),
  20. y: .value("Value", selectedCOBValue.cob)
  21. )
  22. .symbolSize(CGSize(width: 6, height: 6))
  23. .foregroundStyle(Color.primary)
  24. .position(by: .value("Axis", "COB"))
  25. }
  26. if let selectedIOBValue {
  27. PointMark(
  28. x: .value("Time", selectedIOBValue.deliverAt ?? now, unit: .minute),
  29. y: .value("Value", Int(truncating: selectedIOBValue.iob ?? 0))
  30. )
  31. .symbolSize(CGSize(width: 15, height: 15))
  32. .foregroundStyle(Color.darkerBlue.opacity(0.8))
  33. .position(by: .value("Axis", "IOB"))
  34. PointMark(
  35. x: .value("Time", selectedIOBValue.deliverAt ?? now, unit: .minute),
  36. y: .value("Value", Int(truncating: selectedIOBValue.iob ?? 0))
  37. )
  38. .symbolSize(CGSize(width: 6, height: 6))
  39. .foregroundStyle(Color.primary)
  40. .position(by: .value("Axis", "IOB"))
  41. }
  42. }
  43. .chartForegroundStyleScale([
  44. "COB": Color.orange,
  45. "IOB": Color.darkerBlue
  46. ])
  47. .chartLegend(.hidden)
  48. .frame(minHeight: geo.size.height * 0.12)
  49. .frame(width: fullWidth(viewWidth: screenSize.width))
  50. .chartXScale(domain: startMarker ... endMarker)
  51. .backport.chartXSelection(value: $selection)
  52. .chartXAxis { basalChartXAxis }
  53. .chartYAxis { cobIobChartYAxis }
  54. .chartYScale(domain: combinedYDomain())
  55. }
  56. func combinedYDomain() -> ClosedRange<Double> {
  57. let minValue = min(state.minValueCobChart, state.minValueIobChart)
  58. let maxValue = max(state.maxValueCobChart, state.maxValueIobChart)
  59. return Double(minValue) ... Double(maxValue)
  60. }
  61. func drawCOB(dummy: Bool) -> some ChartContent {
  62. ForEach(state.enactedAndNonEnactedDeterminations) { cob in
  63. let amount = Int(cob.cob)
  64. let date: Date = cob.deliverAt ?? Date()
  65. if dummy {
  66. LineMark(x: .value("Time", date), y: .value("Value", amount))
  67. .foregroundStyle(Color.clear)
  68. .position(by: .value("Axis", "COB"))
  69. AreaMark(x: .value("Time", date), y: .value("Value", amount))
  70. .foregroundStyle(Color.clear)
  71. .position(by: .value("Axis", "COB"))
  72. } else {
  73. LineMark(x: .value("Time", date), y: .value("Value", amount))
  74. .foregroundStyle(by: .value("Type", "COB"))
  75. .position(by: .value("Axis", "COB"))
  76. AreaMark(x: .value("Time", date), y: .value("Value", amount))
  77. .foregroundStyle(by: .value("Type", "COB"))
  78. .position(by: .value("Axis", "COB"))
  79. .opacity(0.2)
  80. }
  81. }
  82. }
  83. func drawIOB() -> some ChartContent {
  84. ForEach(state.enactedAndNonEnactedDeterminations) { iob in
  85. let rawAmount = iob.iob?.doubleValue ?? 0
  86. // as iob and cob share the same y axis and cob is usually >> iob we need to weigh iob visually
  87. let amount: Double = rawAmount > 0 ? rawAmount * 3 : rawAmount * 4
  88. let date: Date = iob.deliverAt ?? Date()
  89. AreaMark(x: .value("Time", date), y: .value("Amount", amount))
  90. .foregroundStyle(by: .value("Type", "IOB"))
  91. .position(by: .value("Axis", "IOB"))
  92. .opacity(0.2)
  93. LineMark(x: .value("Time", date), y: .value("Amount", amount))
  94. .foregroundStyle(by: .value("Type", "IOB"))
  95. .position(by: .value("Axis", "IOB"))
  96. }
  97. }
  98. }