Graphs.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. //
  2. // Graphs.swift
  3. // LoopFollow
  4. //
  5. // Created by Jon Fawcett on 6/16/20.
  6. // Copyright © 2020 Jon Fawcett. All rights reserved.
  7. //
  8. import Foundation
  9. import Charts
  10. import UIKit
  11. extension MainViewController {
  12. func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
  13. if chartView == BGChartFull {
  14. BGChart.moveViewToX(entry.x)
  15. }
  16. }
  17. func chartTranslated(_ chartView: ChartViewBase, dX: CGFloat, dY: CGFloat) {
  18. if chartView == BGChart {
  19. let currentMatrix = chartView.viewPortHandler.touchMatrix
  20. //BGChartFull.viewPortHandler.refresh(newMatrix: currentMatrix, chart: BGChartFull, invalidate: true)
  21. //BGChartFull.highlightValue(x: Double(currentMatrix.tx), y: Double(currentMatrix.ty), dataSetIndex: 0)
  22. }
  23. }
  24. func createGraph(){
  25. self.BGChart.clear()
  26. print("enter graph")
  27. // Create the BG Graph Data
  28. let entries = bgData
  29. var bgChartEntry = [ChartDataEntry]()
  30. var colors = [NSUIColor]()
  31. var maxBG: Int = UserDefaultsRepository.minBGScale.value
  32. if bgData.count > 0 {
  33. print("graph - bg")
  34. for i in 0..<entries.count{
  35. var dateString = String(entries[i].date).prefix(10)
  36. let dateSecondsOnly = Double(String(dateString))!
  37. if entries[i].sgv > maxBG - 40 {
  38. maxBG = entries[i].sgv + 40
  39. }
  40. let value = ChartDataEntry(x: Double(entries[i].date), y: Double(entries[i].sgv))
  41. bgChartEntry.append(value)
  42. if Double(entries[i].sgv) >= Double(UserDefaultsRepository.highLine.value) {
  43. colors.append(NSUIColor.systemYellow)
  44. } else if Double(entries[i].sgv) <= Double(UserDefaultsRepository.lowLine.value) {
  45. colors.append(NSUIColor.systemRed)
  46. } else {
  47. colors.append(NSUIColor.systemGreen)
  48. }
  49. }
  50. }
  51. // Add Prediction Data
  52. if predictionData.count > 0 && bgData.count > 0 && UserDefaultsRepository.graphPrediction.value {
  53. print("graph prediction")
  54. var startingTime = bgChartEntry[bgChartEntry.count - 1].x + 300
  55. var i = 0
  56. // Add 1 hour of predictions
  57. while i < 12 {
  58. var predictionVal = Double(predictionData[i])
  59. // Below can be turned on to prevent out of range on the graph if desired.
  60. // It currently just drops them out of view
  61. if predictionVal > 400 {
  62. // predictionVal = 400
  63. } else if predictionVal < 0 {
  64. // predictionVal = 0
  65. }
  66. let value = ChartDataEntry(x: startingTime + 5, y: predictionVal)
  67. bgChartEntry.append(value)
  68. colors.append(NSUIColor.systemPurple)
  69. startingTime += 300
  70. i += 1
  71. }
  72. }
  73. // Setup BG line details
  74. let lineBG = LineChartDataSet(entries:bgChartEntry, label: "")
  75. lineBG.circleRadius = 3
  76. lineBG.circleColors = [NSUIColor.systemGreen]
  77. lineBG.drawCircleHoleEnabled = false
  78. lineBG.axisDependency = YAxis.AxisDependency.right
  79. lineBG.highlightEnabled = false
  80. lineBG.drawValuesEnabled = false
  81. if UserDefaultsRepository.showLines.value {
  82. lineBG.lineWidth = 2
  83. } else {
  84. lineBG.lineWidth = 0
  85. }
  86. if UserDefaultsRepository.showDots.value {
  87. lineBG.drawCirclesEnabled = true
  88. } else {
  89. lineBG.drawCirclesEnabled = false
  90. }
  91. lineBG.setDrawHighlightIndicators(false)
  92. lineBG.valueFont.withSize(50)
  93. if colors.count > 0 {
  94. print("graph colors")
  95. for i in 1..<colors.count{
  96. lineBG.addColor(colors[i])
  97. lineBG.circleColors.append(colors[i])
  98. }
  99. }
  100. // create Basal graph data
  101. var chartEntry = [ChartDataEntry]()
  102. var maxBasal = UserDefaultsRepository.minBasalScale.value
  103. if basalData.count > 0 && UserDefaultsRepository.graphBasal.value {
  104. print("graph basal")
  105. for i in 0..<basalData.count{
  106. let value = ChartDataEntry(x: Double(basalData[i].date), y: Double(basalData[i].basalRate))
  107. chartEntry.append(value)
  108. if basalData[i].basalRate > maxBasal {
  109. maxBasal = basalData[i].basalRate
  110. }
  111. }
  112. }
  113. // Setup Basal line details
  114. let lineBasal = LineChartDataSet(entries:chartEntry, label: "")
  115. lineBasal.setDrawHighlightIndicators(false)
  116. lineBasal.setColor(NSUIColor.systemBlue, alpha: 0.5)
  117. lineBasal.lineWidth = 0
  118. lineBasal.drawFilledEnabled = true
  119. lineBasal.fillColor = NSUIColor.systemBlue.withAlphaComponent(0.8)
  120. lineBasal.drawCirclesEnabled = false
  121. lineBasal.axisDependency = YAxis.AxisDependency.left
  122. lineBasal.highlightEnabled = false
  123. lineBasal.drawValuesEnabled = false
  124. // Boluses
  125. var chartEntryBolus = [ChartDataEntry]()
  126. if bolusData.count > 0 && UserDefaultsRepository.graphBolus.value {
  127. print("graph bolus")
  128. for i in 0..<bolusData.count{
  129. let formatter = NumberFormatter()
  130. formatter.minimumFractionDigits = 0
  131. formatter.maximumFractionDigits = 2
  132. formatter.minimumIntegerDigits = 1
  133. let value = ChartDataEntry(x: Double(bolusData[i].date), y: Double(bolusData[i].sgv + 10), data: formatter.string(from: NSNumber(value: bolusData[i].value)))
  134. chartEntryBolus.append(value)
  135. }
  136. }
  137. let lineBolus = LineChartDataSet(entries:chartEntryBolus, label: "")
  138. lineBolus.circleRadius = 7
  139. lineBolus.circleColors = [NSUIColor.systemBlue.withAlphaComponent(0.75)]
  140. lineBolus.drawCircleHoleEnabled = false
  141. lineBolus.setDrawHighlightIndicators(false)
  142. lineBolus.setColor(NSUIColor.systemBlue, alpha: 1.0)
  143. lineBolus.drawCirclesEnabled = true
  144. lineBolus.lineWidth = 0
  145. lineBolus.axisDependency = YAxis.AxisDependency.right
  146. lineBolus.valueFormatter = ChartYDataValueFormatter()
  147. lineBolus.drawValuesEnabled = true
  148. lineBolus.valueTextColor = NSUIColor.label
  149. // Carbs
  150. var chartEntryCarbs = [ChartDataEntry]()
  151. if carbData.count > 0 && UserDefaultsRepository.graphCarbs.value {
  152. print("graph carbs")
  153. for i in 0..<carbData.count{
  154. let formatter = NumberFormatter()
  155. formatter.minimumFractionDigits = 0
  156. formatter.maximumFractionDigits = 2
  157. formatter.minimumIntegerDigits = 1
  158. let value = ChartDataEntry(x: Double(carbData[i].date), y: Double(carbData[i].sgv + 30), data: formatter.string(from: NSNumber(value: carbData[i].value)))
  159. chartEntryCarbs.append(value)
  160. }
  161. }
  162. let lineCarbs = LineChartDataSet(entries:chartEntryCarbs, label: "")
  163. lineCarbs.circleRadius = 7
  164. lineCarbs.circleColors = [NSUIColor.systemOrange.withAlphaComponent(0.75)]
  165. lineCarbs.drawCircleHoleEnabled = false
  166. lineCarbs.setDrawHighlightIndicators(false)
  167. lineCarbs.setColor(NSUIColor.systemBlue, alpha: 1.0)
  168. lineCarbs.drawCirclesEnabled = true
  169. lineCarbs.lineWidth = 0
  170. lineCarbs.axisDependency = YAxis.AxisDependency.right
  171. lineCarbs.valueFormatter = ChartYDataValueFormatter()
  172. lineCarbs.drawValuesEnabled = true
  173. lineCarbs.valueTextColor = NSUIColor.label
  174. // Setup the chart data of all lines
  175. let data = LineChartData()
  176. data.addDataSet(lineBG)
  177. data.addDataSet(lineBasal)
  178. data.addDataSet(lineBolus)
  179. data.addDataSet(lineCarbs)
  180. data.setValueFont(UIFont.systemFont(ofSize: 12))
  181. // Add marker popups for bolus and carbs
  182. // Changed to display values
  183. //let marker = PillMarker(color: .secondarySystemBackground, font: UIFont.boldSystemFont(ofSize: 14), textColor: .label)
  184. //BGChart.marker = marker
  185. // Clear limit lines so they don't add multiples when changing the settings
  186. BGChart.rightAxis.removeAllLimitLines()
  187. //Add lower red line based on low alert value
  188. let ll = ChartLimitLine()
  189. ll.limit = Double(UserDefaultsRepository.lowLine.value)
  190. ll.lineColor = NSUIColor.systemRed.withAlphaComponent(0.5)
  191. BGChart.rightAxis.addLimitLine(ll)
  192. //Add upper yellow line based on low alert value
  193. let ul = ChartLimitLine()
  194. ul.limit = Double(UserDefaultsRepository.highLine.value)
  195. ul.lineColor = NSUIColor.systemYellow.withAlphaComponent(0.5)
  196. BGChart.rightAxis.addLimitLine(ul)
  197. // Setup the main graph overall details
  198. BGChart.xAxis.valueFormatter = ChartXValueFormatter()
  199. BGChart.xAxis.granularity = 1800
  200. BGChart.xAxis.labelTextColor = NSUIColor.label
  201. BGChart.xAxis.labelPosition = XAxis.LabelPosition.bottom
  202. BGChart.leftAxis.enabled = true
  203. BGChart.leftAxis.labelPosition = YAxis.LabelPosition.insideChart
  204. BGChart.leftAxis.axisMaximum = maxBasal
  205. BGChart.leftAxis.axisMinimum = 0.0
  206. BGChart.leftAxis.drawGridLinesEnabled = false
  207. BGChart.rightAxis.labelTextColor = NSUIColor.label
  208. BGChart.rightAxis.labelPosition = YAxis.LabelPosition.insideChart
  209. BGChart.rightAxis.axisMinimum = 40
  210. BGChart.rightAxis.axisMaximum = Double(maxBG)
  211. BGChart.legend.enabled = false
  212. BGChart.scaleYEnabled = false
  213. BGChart.drawGridBackgroundEnabled = false
  214. //BGChart.gridBackgroundColor = NSUIColor.secondarySystemBackground
  215. BGChart.data = data
  216. // This must be called after the data is loaded
  217. BGChart.setExtraOffsets(left: 10, top: 10, right: 10, bottom: 10)
  218. BGChart.setVisibleXRangeMinimum(10)
  219. if firstGraphLoad {
  220. BGChart.zoom(scaleX: 18, scaleY: 1, x: 1, y: 1)
  221. firstGraphLoad = false
  222. }
  223. if minAgoBG < 1 {
  224. BGChart.moveViewToAnimated(xValue: dateTimeUtils.getNowTimeIntervalUTC() - (BGChart.visibleXRange * 0.7), yValue: 0.0, axis: .right, duration: 1, easingOption: .easeInBack)
  225. }
  226. if bgData.count > 0 {
  227. createSmallBGGraph(bgChartEntry: bgChartEntry, colors: colors)
  228. }
  229. }
  230. func createSmallBGGraph(bgChartEntry: [ChartDataEntry], colors: [NSUIColor]){
  231. print("small graph")
  232. //24 Hour Small Graph
  233. let line2 = LineChartDataSet(entries:bgChartEntry, label: "Number")
  234. line2.drawCirclesEnabled = false
  235. //line2.setDrawHighlightIndicators(false)
  236. line2.highlightEnabled = true
  237. line2.drawHorizontalHighlightIndicatorEnabled = false
  238. line2.drawVerticalHighlightIndicatorEnabled = false
  239. line2.highlightColor = NSUIColor.label
  240. line2.drawValuesEnabled = false
  241. line2.lineWidth = 2
  242. for i in 1..<colors.count{
  243. line2.addColor(colors[i])
  244. line2.circleColors.append(colors[i])
  245. }
  246. let data2 = LineChartData()
  247. data2.addDataSet(line2)
  248. BGChartFull.highlightPerDragEnabled = true
  249. BGChartFull.leftAxis.enabled = false
  250. BGChartFull.rightAxis.enabled = false
  251. BGChartFull.xAxis.enabled = false
  252. BGChartFull.legend.enabled = false
  253. BGChartFull.scaleYEnabled = false
  254. BGChartFull.scaleXEnabled = false
  255. BGChartFull.drawGridBackgroundEnabled = false
  256. BGChartFull.data = data2
  257. }
  258. }