Graphs.swift 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  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. let ScaleXMax:Float = 150.0
  12. extension MainViewController {
  13. func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
  14. if chartView == BGChartFull {
  15. BGChart.moveViewToX(entry.x)
  16. }
  17. if entry.data as? String == "hide"{
  18. BGChart.highlightValue(nil, callDelegate: false)
  19. }
  20. }
  21. func chartScaled(_ chartView: ChartViewBase, scaleX: CGFloat, scaleY: CGFloat) {
  22. print("Chart Scaled: \(BGChart.scaleX), \(BGChart.scaleY)")
  23. // dont store huge values
  24. var scale: Float = Float(BGChart.scaleX)
  25. if(scale > ScaleXMax ) {
  26. scale = ScaleXMax
  27. }
  28. UserDefaultsRepository.chartScaleX.value = Float(scale)
  29. }
  30. func createGraph(){
  31. // Create the BG Graph Data
  32. let bgChartEntry = [ChartDataEntry]()
  33. let maxBG: Float = UserDefaultsRepository.minBGScale.value
  34. // Setup BG line details
  35. let lineBG = LineChartDataSet(entries:bgChartEntry, label: "")
  36. lineBG.circleRadius = CGFloat(globalVariables.dotBG)
  37. lineBG.circleColors = [NSUIColor.systemGreen]
  38. lineBG.drawCircleHoleEnabled = false
  39. lineBG.axisDependency = YAxis.AxisDependency.right
  40. lineBG.highlightEnabled = true
  41. lineBG.drawValuesEnabled = false
  42. if UserDefaultsRepository.showLines.value {
  43. lineBG.lineWidth = 2
  44. } else {
  45. lineBG.lineWidth = 0
  46. }
  47. if UserDefaultsRepository.showDots.value {
  48. lineBG.drawCirclesEnabled = true
  49. } else {
  50. lineBG.drawCirclesEnabled = false
  51. }
  52. lineBG.setDrawHighlightIndicators(false)
  53. lineBG.valueFont.withSize(50)
  54. // Setup Prediction line details
  55. let predictionChartEntry = [ChartDataEntry]()
  56. let linePrediction = LineChartDataSet(entries:predictionChartEntry, label: "")
  57. linePrediction.circleRadius = CGFloat(globalVariables.dotBG)
  58. linePrediction.circleColors = [NSUIColor.systemPurple]
  59. linePrediction.colors = [NSUIColor.systemPurple]
  60. linePrediction.drawCircleHoleEnabled = false
  61. linePrediction.axisDependency = YAxis.AxisDependency.right
  62. linePrediction.highlightEnabled = true
  63. linePrediction.drawValuesEnabled = false
  64. if UserDefaultsRepository.showLines.value {
  65. linePrediction.lineWidth = 2
  66. } else {
  67. linePrediction.lineWidth = 0
  68. }
  69. if UserDefaultsRepository.showDots.value {
  70. linePrediction.drawCirclesEnabled = true
  71. } else {
  72. linePrediction.drawCirclesEnabled = false
  73. }
  74. linePrediction.setDrawHighlightIndicators(false)
  75. linePrediction.valueFont.withSize(50)
  76. // create Basal graph data
  77. let chartEntry = [ChartDataEntry]()
  78. let maxBasal = UserDefaultsRepository.minBasalScale.value
  79. let lineBasal = LineChartDataSet(entries:chartEntry, label: "")
  80. lineBasal.setDrawHighlightIndicators(false)
  81. lineBasal.setColor(NSUIColor.systemBlue, alpha: 0.5)
  82. lineBasal.lineWidth = 0
  83. lineBasal.drawFilledEnabled = true
  84. lineBasal.fillColor = NSUIColor.systemBlue
  85. lineBasal.fillAlpha = 0.5
  86. lineBasal.drawCirclesEnabled = false
  87. lineBasal.axisDependency = YAxis.AxisDependency.left
  88. lineBasal.highlightEnabled = true
  89. lineBasal.drawValuesEnabled = false
  90. lineBasal.fillFormatter = basalFillFormatter()
  91. // Boluses
  92. let chartEntryBolus = [ChartDataEntry]()
  93. let lineBolus = LineChartDataSet(entries:chartEntryBolus, label: "")
  94. lineBolus.circleRadius = CGFloat(globalVariables.dotBolus)
  95. lineBolus.circleColors = [NSUIColor.systemBlue.withAlphaComponent(0.75)]
  96. lineBolus.drawCircleHoleEnabled = false
  97. lineBolus.setDrawHighlightIndicators(false)
  98. lineBolus.setColor(NSUIColor.systemBlue, alpha: 1.0)
  99. lineBolus.lineWidth = 0
  100. lineBolus.axisDependency = YAxis.AxisDependency.right
  101. lineBolus.valueFormatter = ChartYDataValueFormatter()
  102. lineBolus.valueTextColor = NSUIColor.label
  103. lineBolus.fillColor = NSUIColor.systemBlue
  104. lineBolus.fillAlpha = 0.6
  105. lineBolus.drawCirclesEnabled = true
  106. lineBolus.drawFilledEnabled = false
  107. if UserDefaultsRepository.showValues.value {
  108. lineBolus.drawValuesEnabled = true
  109. lineBolus.highlightEnabled = false
  110. } else {
  111. lineBolus.drawValuesEnabled = false
  112. lineBolus.highlightEnabled = true
  113. }
  114. // Carbs
  115. let chartEntryCarbs = [ChartDataEntry]()
  116. let lineCarbs = LineChartDataSet(entries:chartEntryCarbs, label: "")
  117. lineCarbs.circleRadius = CGFloat(globalVariables.dotCarb)
  118. lineCarbs.circleColors = [NSUIColor.systemOrange.withAlphaComponent(0.75)]
  119. lineCarbs.drawCircleHoleEnabled = false
  120. lineCarbs.setDrawHighlightIndicators(false)
  121. lineCarbs.setColor(NSUIColor.systemBlue, alpha: 1.0)
  122. lineCarbs.lineWidth = 0
  123. lineCarbs.axisDependency = YAxis.AxisDependency.right
  124. lineCarbs.valueFormatter = ChartYDataValueFormatter()
  125. lineCarbs.valueTextColor = NSUIColor.label
  126. lineCarbs.fillColor = NSUIColor.systemOrange
  127. lineCarbs.fillAlpha = 0.6
  128. lineCarbs.drawCirclesEnabled = true
  129. lineCarbs.drawFilledEnabled = false
  130. if UserDefaultsRepository.showValues.value {
  131. lineCarbs.drawValuesEnabled = true
  132. lineCarbs.highlightEnabled = false
  133. } else {
  134. lineCarbs.drawValuesEnabled = false
  135. lineCarbs.highlightEnabled = true
  136. }
  137. // create Scheduled Basal graph data
  138. let chartBasalScheduledEntry = [ChartDataEntry]()
  139. let lineBasalScheduled = LineChartDataSet(entries:chartBasalScheduledEntry, label: "")
  140. lineBasalScheduled.setDrawHighlightIndicators(false)
  141. lineBasalScheduled.setColor(NSUIColor.systemBlue, alpha: 0.8)
  142. lineBasalScheduled.lineWidth = 2
  143. lineBasalScheduled.drawFilledEnabled = false
  144. lineBasalScheduled.drawCirclesEnabled = false
  145. lineBasalScheduled.axisDependency = YAxis.AxisDependency.left
  146. lineBasalScheduled.highlightEnabled = false
  147. lineBasalScheduled.drawValuesEnabled = false
  148. lineBasalScheduled.lineDashLengths = [10.0, 5.0]
  149. // create Override graph data
  150. let chartOverrideEntry = [ChartDataEntry]()
  151. let lineOverride = LineChartDataSet(entries:chartOverrideEntry, label: "")
  152. lineOverride.setDrawHighlightIndicators(false)
  153. lineOverride.lineWidth = 0
  154. lineOverride.drawFilledEnabled = true
  155. lineOverride.fillFormatter = OverrideFillFormatter()
  156. lineOverride.fillColor = NSUIColor.systemGreen
  157. lineOverride.fillAlpha = 0.6
  158. lineOverride.drawCirclesEnabled = false
  159. lineOverride.axisDependency = YAxis.AxisDependency.right
  160. lineOverride.highlightEnabled = true
  161. lineOverride.drawValuesEnabled = false
  162. // BG Check
  163. let chartEntryBGCheck = [ChartDataEntry]()
  164. let lineBGCheck = LineChartDataSet(entries:chartEntryBGCheck, label: "")
  165. lineBGCheck.circleRadius = CGFloat(globalVariables.dotOther)
  166. lineBGCheck.circleColors = [NSUIColor.systemRed.withAlphaComponent(0.75)]
  167. lineBGCheck.drawCircleHoleEnabled = false
  168. lineBGCheck.setDrawHighlightIndicators(false)
  169. lineBGCheck.setColor(NSUIColor.systemRed, alpha: 1.0)
  170. lineBGCheck.drawCirclesEnabled = true
  171. lineBGCheck.lineWidth = 0
  172. lineBGCheck.highlightEnabled = true
  173. lineBGCheck.axisDependency = YAxis.AxisDependency.right
  174. lineBGCheck.valueFormatter = ChartYDataValueFormatter()
  175. lineBGCheck.drawValuesEnabled = false
  176. // Suspend Pump
  177. let chartEntrySuspend = [ChartDataEntry]()
  178. let lineSuspend = LineChartDataSet(entries:chartEntrySuspend, label: "")
  179. lineSuspend.circleRadius = CGFloat(globalVariables.dotOther)
  180. lineSuspend.circleColors = [NSUIColor.systemTeal.withAlphaComponent(0.75)]
  181. lineSuspend.drawCircleHoleEnabled = false
  182. lineSuspend.setDrawHighlightIndicators(false)
  183. lineSuspend.setColor(NSUIColor.systemGray2, alpha: 1.0)
  184. lineSuspend.drawCirclesEnabled = true
  185. lineSuspend.lineWidth = 0
  186. lineSuspend.highlightEnabled = true
  187. lineSuspend.axisDependency = YAxis.AxisDependency.right
  188. lineSuspend.valueFormatter = ChartYDataValueFormatter()
  189. lineSuspend.drawValuesEnabled = false
  190. // Resume Pump
  191. let chartEntryResume = [ChartDataEntry]()
  192. let lineResume = LineChartDataSet(entries:chartEntryResume, label: "")
  193. lineResume.circleRadius = CGFloat(globalVariables.dotOther)
  194. lineResume.circleColors = [NSUIColor.systemTeal.withAlphaComponent(0.75)]
  195. lineResume.drawCircleHoleEnabled = false
  196. lineResume.setDrawHighlightIndicators(false)
  197. lineResume.setColor(NSUIColor.systemGray4, alpha: 1.0)
  198. lineResume.drawCirclesEnabled = true
  199. lineResume.lineWidth = 0
  200. lineResume.highlightEnabled = true
  201. lineResume.axisDependency = YAxis.AxisDependency.right
  202. lineResume.valueFormatter = ChartYDataValueFormatter()
  203. lineResume.drawValuesEnabled = false
  204. // Sensor Start
  205. let chartEntrySensor = [ChartDataEntry]()
  206. let lineSensor = LineChartDataSet(entries:chartEntrySensor, label: "")
  207. lineSensor.circleRadius = CGFloat(globalVariables.dotOther)
  208. lineSensor.circleColors = [NSUIColor.systemIndigo.withAlphaComponent(0.75)]
  209. lineSensor.drawCircleHoleEnabled = false
  210. lineSensor.setDrawHighlightIndicators(false)
  211. lineSensor.setColor(NSUIColor.systemGray3, alpha: 1.0)
  212. lineSensor.drawCirclesEnabled = true
  213. lineSensor.lineWidth = 0
  214. lineSensor.highlightEnabled = true
  215. lineSensor.axisDependency = YAxis.AxisDependency.right
  216. lineSensor.valueFormatter = ChartYDataValueFormatter()
  217. lineSensor.drawValuesEnabled = false
  218. // Notes
  219. let chartEntryNote = [ChartDataEntry]()
  220. let lineNote = LineChartDataSet(entries:chartEntryNote, label: "")
  221. lineNote.circleRadius = CGFloat(globalVariables.dotOther)
  222. lineNote.circleColors = [NSUIColor.systemGray.withAlphaComponent(0.75)]
  223. lineNote.drawCircleHoleEnabled = false
  224. lineNote.setDrawHighlightIndicators(false)
  225. lineNote.setColor(NSUIColor.systemGray3, alpha: 1.0)
  226. lineNote.drawCirclesEnabled = true
  227. lineNote.lineWidth = 0
  228. lineNote.highlightEnabled = true
  229. lineNote.axisDependency = YAxis.AxisDependency.right
  230. lineNote.valueFormatter = ChartYDataValueFormatter()
  231. lineNote.drawValuesEnabled = false
  232. // Setup the chart data of all lines
  233. let data = LineChartData()
  234. data.append(lineBG) // Dataset 0
  235. data.append(linePrediction) // Dataset 1
  236. data.append(lineBasal) // Dataset 2
  237. data.append(lineBolus) // Dataset 3
  238. data.append(lineCarbs) // Dataset 4
  239. data.append(lineBasalScheduled) // Dataset 5
  240. data.append(lineOverride) // Dataset 6
  241. data.append(lineBGCheck) // Dataset 7
  242. data.append(lineSuspend) // Dataset 8
  243. data.append(lineResume) // Dataset 9
  244. data.append(lineSensor) // Dataset 10
  245. data.append(lineNote) // Dataset 11
  246. data.setValueFont(UIFont.systemFont(ofSize: 12))
  247. // Add marker popups for bolus and carbs
  248. let marker = PillMarker(color: .secondarySystemBackground, font: UIFont.boldSystemFont(ofSize: 14), textColor: .label)
  249. BGChart.marker = marker
  250. // Clear limit lines so they don't add multiples when changing the settings
  251. BGChart.rightAxis.removeAllLimitLines()
  252. //Add lower red line based on low alert value
  253. let ll = ChartLimitLine()
  254. ll.limit = Double(UserDefaultsRepository.lowLine.value)
  255. ll.lineColor = NSUIColor.systemRed.withAlphaComponent(0.5)
  256. BGChart.rightAxis.addLimitLine(ll)
  257. //Add upper yellow line based on low alert value
  258. let ul = ChartLimitLine()
  259. ul.limit = Double(UserDefaultsRepository.highLine.value)
  260. ul.lineColor = NSUIColor.systemYellow.withAlphaComponent(0.5)
  261. BGChart.rightAxis.addLimitLine(ul)
  262. // Add vertical lines as configured
  263. createVerticalLines()
  264. startGraphNowTimer()
  265. // Setup the main graph overall details
  266. BGChart.xAxis.valueFormatter = ChartXValueFormatter()
  267. BGChart.xAxis.granularity = 1800
  268. BGChart.xAxis.labelTextColor = NSUIColor.label
  269. BGChart.xAxis.labelPosition = XAxis.LabelPosition.bottom
  270. BGChart.xAxis.drawGridLinesEnabled = false
  271. BGChart.leftAxis.enabled = true
  272. BGChart.leftAxis.labelPosition = YAxis.LabelPosition.insideChart
  273. BGChart.leftAxis.axisMaximum = maxBasal
  274. BGChart.leftAxis.axisMinimum = 0
  275. BGChart.leftAxis.drawGridLinesEnabled = false
  276. BGChart.leftAxis.granularityEnabled = true
  277. BGChart.leftAxis.granularity = 0.5
  278. BGChart.rightAxis.labelTextColor = NSUIColor.label
  279. BGChart.rightAxis.labelPosition = YAxis.LabelPosition.insideChart
  280. BGChart.rightAxis.axisMinimum = 0.0
  281. BGChart.rightAxis.axisMaximum = Double(maxBG)
  282. BGChart.rightAxis.gridLineDashLengths = [5.0, 5.0]
  283. BGChart.rightAxis.drawGridLinesEnabled = false
  284. BGChart.rightAxis.valueFormatter = ChartYMMOLValueFormatter()
  285. BGChart.rightAxis.granularityEnabled = true
  286. BGChart.rightAxis.granularity = 50
  287. BGChart.maxHighlightDistance = 15.0
  288. BGChart.legend.enabled = false
  289. BGChart.scaleYEnabled = false
  290. BGChart.drawGridBackgroundEnabled = true
  291. BGChart.gridBackgroundColor = NSUIColor.secondarySystemBackground
  292. BGChart.highlightValue(nil, callDelegate: false)
  293. BGChart.data = data
  294. BGChart.setExtraOffsets(left: 5, top: 10, right: 5, bottom: 10)
  295. }
  296. func createVerticalLines() {
  297. BGChart.xAxis.removeAllLimitLines()
  298. BGChartFull.xAxis.removeAllLimitLines()
  299. createNowAndDIALines()
  300. createMidnightLines()
  301. }
  302. func createNowAndDIALines() {
  303. let ul = ChartLimitLine()
  304. ul.limit = Double(dateTimeUtils.getNowTimeIntervalUTC())
  305. ul.lineColor = NSUIColor.systemGray.withAlphaComponent(0.5)
  306. ul.lineWidth = 1
  307. BGChart.xAxis.addLimitLine(ul)
  308. if UserDefaultsRepository.show30MinLine.value {
  309. let ul2 = ChartLimitLine()
  310. ul2.limit = Double(dateTimeUtils.getNowTimeIntervalUTC().advanced(by: -30 * 60))
  311. ul2.lineColor = NSUIColor.systemBlue.withAlphaComponent(0.5)
  312. ul2.lineWidth = 1
  313. BGChart.xAxis.addLimitLine(ul2)
  314. }
  315. if UserDefaultsRepository.showDIALines.value {
  316. for i in 1..<7 {
  317. let ul = ChartLimitLine()
  318. ul.limit = Double(dateTimeUtils.getNowTimeIntervalUTC() - Double(i * 60 * 60))
  319. ul.lineColor = NSUIColor.systemGray.withAlphaComponent(0.3)
  320. let dash = 10.0 - Double(i)
  321. let space = 5.0 + Double(i)
  322. ul.lineDashLengths = [CGFloat(dash), CGFloat(space)]
  323. ul.lineWidth = 1
  324. BGChart.xAxis.addLimitLine(ul)
  325. }
  326. }
  327. if UserDefaultsRepository.show90MinLine.value {
  328. let ul3 = ChartLimitLine()
  329. ul3.limit = Double(dateTimeUtils.getNowTimeIntervalUTC().advanced(by: -90 * 60))
  330. ul3.lineColor = NSUIColor.systemOrange.withAlphaComponent(0.5)
  331. ul3.lineWidth = 1
  332. BGChart.xAxis.addLimitLine(ul3)
  333. }
  334. }
  335. func createMidnightLines() {
  336. // Draw a line at midnight: useful when showing multiple days of data
  337. if UserDefaultsRepository.showMidnightLines.value {
  338. var midnightTimeInterval = dateTimeUtils.getTimeIntervalMidnightToday()
  339. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  340. let graphStart = dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours)
  341. while midnightTimeInterval > graphStart {
  342. // Large chart
  343. let ul = ChartLimitLine()
  344. ul.limit = Double(midnightTimeInterval)
  345. ul.lineColor = NSUIColor.systemTeal.withAlphaComponent(0.5)
  346. ul.lineDashLengths = [CGFloat(2), CGFloat(5)]
  347. ul.lineWidth = 1
  348. BGChart.xAxis.addLimitLine(ul)
  349. // Small chart
  350. let sl = ChartLimitLine()
  351. sl.limit = Double(midnightTimeInterval)
  352. sl.lineColor = NSUIColor.systemTeal
  353. sl.lineDashLengths = [CGFloat(2), CGFloat(2)]
  354. sl.lineWidth = 1
  355. BGChartFull.xAxis.addLimitLine(sl)
  356. midnightTimeInterval = midnightTimeInterval.advanced(by: -24*60*60)
  357. }
  358. }
  359. }
  360. func updateBGGraphSettings() {
  361. let dataIndex = 0
  362. let dataIndexPrediction = 1
  363. let lineBG = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  364. let linePrediction = BGChart.lineData!.dataSets[dataIndexPrediction] as! LineChartDataSet
  365. if UserDefaultsRepository.showLines.value {
  366. lineBG.lineWidth = 2
  367. linePrediction.lineWidth = 2
  368. } else {
  369. lineBG.lineWidth = 0
  370. linePrediction.lineWidth = 0
  371. }
  372. if UserDefaultsRepository.showDots.value {
  373. lineBG.drawCirclesEnabled = true
  374. linePrediction.drawCirclesEnabled = true
  375. } else {
  376. lineBG.drawCirclesEnabled = false
  377. linePrediction.drawCirclesEnabled = false
  378. }
  379. BGChart.rightAxis.axisMinimum = 0
  380. // Clear limit lines so they don't add multiples when changing the settings
  381. BGChart.rightAxis.removeAllLimitLines()
  382. //Add lower red line based on low alert value
  383. let ll = ChartLimitLine()
  384. ll.limit = Double(UserDefaultsRepository.lowLine.value)
  385. ll.lineColor = NSUIColor.systemRed.withAlphaComponent(0.5)
  386. BGChart.rightAxis.addLimitLine(ll)
  387. //Add upper yellow line based on low alert value
  388. let ul = ChartLimitLine()
  389. ul.limit = Double(UserDefaultsRepository.highLine.value)
  390. ul.lineColor = NSUIColor.systemYellow.withAlphaComponent(0.5)
  391. BGChart.rightAxis.addLimitLine(ul)
  392. // Re-create vertical markers in case their settings changed
  393. createVerticalLines()
  394. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  395. BGChart.data?.notifyDataChanged()
  396. BGChart.notifyDataSetChanged()
  397. }
  398. func updateBGGraph() {
  399. if UserDefaultsRepository.debugLog.value { writeDebugLog(value: "##### Start BG Graph #####") }
  400. let dataIndex = 0
  401. let entries = bgData
  402. guard !entries.isEmpty else {
  403. return
  404. }
  405. let mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  406. let smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  407. mainChart.removeAll(keepingCapacity: false)
  408. smallChart.removeAll(keepingCapacity: false)
  409. let maxBGOffset: Float = 50
  410. var colors = [NSUIColor]()
  411. for i in 0..<entries.count{
  412. if Float(entries[i].sgv) > topBG - maxBGOffset {
  413. topBG = Float(entries[i].sgv) + maxBGOffset
  414. }
  415. let value = ChartDataEntry(x: Double(entries[i].date), y: Double(entries[i].sgv), data: formatPillText(line1: bgUnits.toDisplayUnits(String(entries[i].sgv)), time: entries[i].date))
  416. if UserDefaultsRepository.debugLog.value { writeDebugLog(value: "BG: " + value.description) }
  417. mainChart.append(value)
  418. smallChart.append(value)
  419. if Double(entries[i].sgv) >= Double(UserDefaultsRepository.highLine.value) {
  420. colors.append(NSUIColor.systemYellow)
  421. } else if Double(entries[i].sgv) <= Double(UserDefaultsRepository.lowLine.value) {
  422. colors.append(NSUIColor.systemRed)
  423. } else {
  424. colors.append(NSUIColor.systemGreen)
  425. }
  426. }
  427. if UserDefaultsRepository.debugLog.value { writeDebugLog(value: "Total Graph BGs: " + mainChart.entries.count.description) }
  428. // Set Colors
  429. let lineBG = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  430. let lineBGSmall = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  431. lineBG.colors.removeAll()
  432. lineBG.circleColors.removeAll()
  433. lineBGSmall.colors.removeAll()
  434. lineBGSmall.circleColors.removeAll()
  435. if colors.count > 0 {
  436. for i in 0..<colors.count{
  437. mainChart.addColor(colors[i])
  438. mainChart.circleColors.append(colors[i])
  439. smallChart.addColor(colors[i])
  440. smallChart.circleColors.append(colors[i])
  441. }
  442. }
  443. if UserDefaultsRepository.debugLog.value { writeDebugLog(value: "Total Colors: " + mainChart.colors.count.description) }
  444. BGChart.rightAxis.axisMaximum = Double(topBG)
  445. BGChart.setVisibleXRangeMinimum(600)
  446. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  447. BGChart.data?.notifyDataChanged()
  448. BGChart.notifyDataSetChanged()
  449. BGChartFull.rightAxis.axisMaximum = Double(topBG)
  450. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  451. BGChartFull.data?.notifyDataChanged()
  452. BGChartFull.notifyDataSetChanged()
  453. if firstGraphLoad {
  454. var scaleX = CGFloat(UserDefaultsRepository.chartScaleX.value)
  455. print("Scale: \(scaleX)")
  456. if( scaleX > CGFloat(ScaleXMax) ) {
  457. scaleX = CGFloat(ScaleXMax)
  458. UserDefaultsRepository.chartScaleX.value = ScaleXMax
  459. }
  460. BGChart.zoom(scaleX: scaleX, scaleY: 1, x: 1, y: 1)
  461. firstGraphLoad = false
  462. }
  463. // Move to current reading everytime new readings load
  464. // Check if auto-scrolling should be performed
  465. if autoScrollPauseUntil == nil || Date() > autoScrollPauseUntil! {
  466. BGChart.moveViewToAnimated(xValue: dateTimeUtils.getNowTimeIntervalUTC() - (BGChart.visibleXRange * 0.7), yValue: 0.0, axis: .right, duration: 1, easingOption: .easeInBack)
  467. }
  468. }
  469. func updatePredictionGraph(color: UIColor? = nil) {
  470. let dataIndex = 1
  471. var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  472. var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  473. mainChart.clear()
  474. smallChart.clear()
  475. var colors = [NSUIColor]()
  476. let maxBGOffset: Float = 20
  477. for i in 0..<predictionData.count {
  478. var predictionVal = Double(predictionData[i].sgv)
  479. if Float(predictionVal) > topBG - maxBGOffset {
  480. topBG = Float(predictionVal) + maxBGOffset
  481. }
  482. if i == 0 {
  483. if UserDefaultsRepository.showDots.value {
  484. colors.append((color ?? NSUIColor.systemPurple).withAlphaComponent(0.0))
  485. } else {
  486. colors.append((color ?? NSUIColor.systemPurple).withAlphaComponent(1.0))
  487. }
  488. } else if predictionVal > 400 {
  489. colors.append(color ?? NSUIColor.systemYellow)
  490. } else if predictionVal < 0 {
  491. colors.append(color ?? NSUIColor.systemRed)
  492. } else {
  493. colors.append(color ?? NSUIColor.systemPurple)
  494. }
  495. let value = ChartDataEntry(x: predictionData[i].date, y: predictionVal, data: formatPillText(line1: bgUnits.toDisplayUnits(String(predictionData[i].sgv)), time: predictionData[i].date))
  496. mainChart.addEntry(value)
  497. smallChart.addEntry(value)
  498. }
  499. smallChart.circleColors.removeAll()
  500. smallChart.colors.removeAll()
  501. mainChart.colors.removeAll()
  502. mainChart.circleColors.removeAll()
  503. if colors.count > 0 {
  504. for i in 0..<colors.count {
  505. mainChart.addColor(colors[i])
  506. mainChart.circleColors.append(colors[i])
  507. smallChart.addColor(colors[i])
  508. smallChart.circleColors.append(colors[i])
  509. }
  510. }
  511. BGChart.rightAxis.axisMaximum = Double(topBG)
  512. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  513. BGChart.data?.notifyDataChanged()
  514. BGChart.notifyDataSetChanged()
  515. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  516. BGChartFull.data?.notifyDataChanged()
  517. BGChartFull.notifyDataSetChanged()
  518. }
  519. func updateBasalGraph() {
  520. var dataIndex = 2
  521. BGChart.lineData?.dataSets[dataIndex].clear()
  522. BGChartFull.lineData?.dataSets[dataIndex].clear()
  523. var maxBasal = UserDefaultsRepository.minBasalScale.value
  524. var maxBasalSmall: Double = 0.0
  525. for i in 0..<basalData.count{
  526. let value = ChartDataEntry(x: Double(basalData[i].date), y: Double(basalData[i].basalRate), data: formatPillText(line1: String(basalData[i].basalRate), time: basalData[i].date))
  527. BGChart.data?.dataSets[dataIndex].addEntry(value)
  528. if UserDefaultsRepository.smallGraphTreatments.value {
  529. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  530. }
  531. if basalData[i].basalRate > maxBasal {
  532. maxBasal = basalData[i].basalRate
  533. }
  534. if basalData[i].basalRate > maxBasalSmall {
  535. maxBasalSmall = basalData[i].basalRate
  536. }
  537. }
  538. BGChart.leftAxis.axisMaximum = maxBasal
  539. BGChartFull.leftAxis.axisMaximum = maxBasalSmall
  540. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  541. BGChart.data?.notifyDataChanged()
  542. BGChart.notifyDataSetChanged()
  543. if UserDefaultsRepository.smallGraphTreatments.value {
  544. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  545. BGChartFull.data?.notifyDataChanged()
  546. BGChartFull.notifyDataSetChanged()
  547. }
  548. }
  549. func updateBasalScheduledGraph() {
  550. var dataIndex = 5
  551. BGChart.lineData?.dataSets[dataIndex].clear()
  552. BGChartFull.lineData?.dataSets[dataIndex].clear()
  553. for i in 0..<basalScheduleData.count{
  554. let value = ChartDataEntry(x: Double(basalScheduleData[i].date), y: Double(basalScheduleData[i].basalRate))
  555. BGChart.data?.dataSets[dataIndex].addEntry(value)
  556. if UserDefaultsRepository.smallGraphTreatments.value {
  557. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  558. }
  559. }
  560. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  561. BGChart.data?.notifyDataChanged()
  562. BGChart.notifyDataSetChanged()
  563. if UserDefaultsRepository.smallGraphTreatments.value {
  564. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  565. BGChartFull.data?.notifyDataChanged()
  566. BGChartFull.notifyDataSetChanged()
  567. }
  568. }
  569. func updateBolusGraph() {
  570. var dataIndex = 3
  571. var yTop: Double = 370
  572. var yBottom: Double = 345
  573. var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  574. var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  575. mainChart.clear()
  576. smallChart.clear()
  577. var colors = [NSUIColor]()
  578. for i in 0..<bolusData.count{
  579. let formatter = NumberFormatter()
  580. formatter.minimumFractionDigits = 0
  581. formatter.maximumFractionDigits = 2
  582. formatter.minimumIntegerDigits = 0
  583. // Check overlapping carbs to shift left if needed
  584. let bolusShift = findNextBolusTime(timeWithin: 240, needle: bolusData[i].date, haystack: bolusData, startingIndex: i)
  585. var dateTimeStamp = bolusData[i].date
  586. // Alpha colors for DIA
  587. let nowTime = dateTimeUtils.getNowTimeIntervalUTC()
  588. let diffTimeHours = (nowTime - dateTimeStamp) / 60 / 60
  589. if diffTimeHours <= 1 {
  590. colors.append(NSUIColor.systemBlue.withAlphaComponent(1.0))
  591. } else if diffTimeHours > 6 {
  592. colors.append(NSUIColor.systemBlue.withAlphaComponent(0.25))
  593. } else {
  594. let thisAlpha = 1.0 - (0.15 * diffTimeHours)
  595. colors.append(NSUIColor.systemBlue.withAlphaComponent(CGFloat(thisAlpha)))
  596. }
  597. if bolusShift {
  598. // Move it half the distance between BG readings
  599. dateTimeStamp = dateTimeStamp - 150
  600. }
  601. // skip if outside of visible area
  602. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  603. if dateTimeStamp < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  604. let dot = ChartDataEntry(x: Double(dateTimeStamp), y: Double(bolusData[i].sgv), data: formatter.string(from: NSNumber(value: bolusData[i].value)))
  605. mainChart.addEntry(dot)
  606. if UserDefaultsRepository.smallGraphTreatments.value {
  607. smallChart.addEntry(dot)
  608. }
  609. }
  610. // Set Colors
  611. let lineBolus = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  612. let lineBolusSmall = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  613. lineBolus.colors.removeAll()
  614. lineBolus.circleColors.removeAll()
  615. lineBolusSmall.colors.removeAll()
  616. lineBolusSmall.circleColors.removeAll()
  617. if colors.count > 0 {
  618. for i in 0..<colors.count{
  619. mainChart.addColor(colors[i])
  620. mainChart.circleColors.append(colors[i])
  621. smallChart.addColor(colors[i])
  622. smallChart.circleColors.append(colors[i])
  623. }
  624. }
  625. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  626. BGChart.data?.notifyDataChanged()
  627. BGChart.notifyDataSetChanged()
  628. if UserDefaultsRepository.smallGraphTreatments.value {
  629. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  630. BGChartFull.data?.notifyDataChanged()
  631. BGChartFull.notifyDataSetChanged()
  632. }
  633. }
  634. func updateCarbGraph() {
  635. var dataIndex = 4
  636. var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  637. var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  638. mainChart.clear()
  639. smallChart.clear()
  640. var colors = [NSUIColor]()
  641. for i in 0..<carbData.count{
  642. let formatter = NumberFormatter()
  643. formatter.minimumFractionDigits = 0
  644. formatter.maximumFractionDigits = 2
  645. formatter.minimumIntegerDigits = 1
  646. var valueString: String = formatter.string(from: NSNumber(value: carbData[i].value))!
  647. var hours = 3
  648. if carbData[i].absorptionTime > 0 && UserDefaultsRepository.showAbsorption.value {
  649. hours = carbData[i].absorptionTime / 60
  650. valueString += " " + String(hours) + "h"
  651. }
  652. // Check overlapping carbs to shift left if needed
  653. let carbShift = findNextCarbTime(timeWithin: 250, needle: carbData[i].date, haystack: carbData, startingIndex: i)
  654. var dateTimeStamp = carbData[i].date
  655. // Alpha colors for DIA
  656. let nowTime = dateTimeUtils.getNowTimeIntervalUTC()
  657. let diffTimeHours = (nowTime - dateTimeStamp) / 60 / 60
  658. if diffTimeHours <= 0.5 {
  659. colors.append(NSUIColor.systemOrange.withAlphaComponent(1.0))
  660. } else if diffTimeHours > Double(hours) {
  661. colors.append(NSUIColor.systemOrange.withAlphaComponent(0.25))
  662. } else {
  663. let thisAlpha = 1.0 - ((0.75 / Double(hours)) * diffTimeHours)
  664. colors.append(NSUIColor.systemOrange.withAlphaComponent(CGFloat(thisAlpha)))
  665. }
  666. // skip if outside of visible area
  667. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  668. if dateTimeStamp < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  669. if carbShift {
  670. dateTimeStamp = dateTimeStamp - 250
  671. }
  672. let dot = ChartDataEntry(x: Double(dateTimeStamp), y: Double(carbData[i].sgv), data: valueString)
  673. BGChart.data?.dataSets[dataIndex].addEntry(dot)
  674. if UserDefaultsRepository.smallGraphTreatments.value {
  675. BGChartFull.data?.dataSets[dataIndex].addEntry(dot)
  676. }
  677. }
  678. // Set Colors
  679. let lineCarbs = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  680. let lineCarbsSmall = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  681. lineCarbs.colors.removeAll()
  682. lineCarbs.circleColors.removeAll()
  683. lineCarbsSmall.colors.removeAll()
  684. lineCarbsSmall.circleColors.removeAll()
  685. if colors.count > 0 {
  686. for i in 0..<colors.count{
  687. mainChart.addColor(colors[i])
  688. mainChart.circleColors.append(colors[i])
  689. smallChart.addColor(colors[i])
  690. smallChart.circleColors.append(colors[i])
  691. }
  692. }
  693. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  694. BGChart.data?.notifyDataChanged()
  695. BGChart.notifyDataSetChanged()
  696. if UserDefaultsRepository.smallGraphTreatments.value {
  697. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  698. BGChartFull.data?.notifyDataChanged()
  699. BGChartFull.notifyDataSetChanged()
  700. }
  701. }
  702. func updateBGCheckGraph() {
  703. var dataIndex = 7
  704. BGChart.lineData?.dataSets[dataIndex].clear()
  705. BGChartFull.lineData?.dataSets[dataIndex].clear()
  706. for i in 0..<bgCheckData.count{
  707. let formatter = NumberFormatter()
  708. formatter.minimumFractionDigits = 0
  709. formatter.maximumFractionDigits = 2
  710. formatter.minimumIntegerDigits = 1
  711. // skip if outside of visible area
  712. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  713. if bgCheckData[i].date < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  714. let value = ChartDataEntry(x: Double(bgCheckData[i].date), y: Double(bgCheckData[i].sgv), data: formatPillText(line1: bgUnits.toDisplayUnits(String(bgCheckData[i].sgv)), time: bgCheckData[i].date))
  715. BGChart.data?.dataSets[dataIndex].addEntry(value)
  716. if UserDefaultsRepository.smallGraphTreatments.value {
  717. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  718. }
  719. }
  720. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  721. BGChart.data?.notifyDataChanged()
  722. BGChart.notifyDataSetChanged()
  723. if UserDefaultsRepository.smallGraphTreatments.value {
  724. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  725. BGChartFull.data?.notifyDataChanged()
  726. BGChartFull.notifyDataSetChanged()
  727. }
  728. }
  729. func updateSuspendGraph() {
  730. var dataIndex = 8
  731. BGChart.lineData?.dataSets[dataIndex].clear()
  732. BGChartFull.lineData?.dataSets[dataIndex].clear()
  733. let thisData = suspendGraphData
  734. for i in 0..<thisData.count{
  735. // skip if outside of visible area
  736. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  737. if thisData[i].date < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  738. let value = ChartDataEntry(x: Double(thisData[i].date), y: Double(thisData[i].sgv), data: formatPillText(line1: "Suspend Pump", time: thisData[i].date))
  739. BGChart.data?.dataSets[dataIndex].addEntry(value)
  740. if UserDefaultsRepository.smallGraphTreatments.value {
  741. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  742. }
  743. }
  744. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  745. BGChart.data?.notifyDataChanged()
  746. BGChart.notifyDataSetChanged()
  747. if UserDefaultsRepository.smallGraphTreatments.value {
  748. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  749. BGChartFull.data?.notifyDataChanged()
  750. BGChartFull.notifyDataSetChanged()
  751. }
  752. }
  753. func updateResumeGraph() {
  754. var dataIndex = 9
  755. BGChart.lineData?.dataSets[dataIndex].clear()
  756. BGChartFull.lineData?.dataSets[dataIndex].clear()
  757. let thisData = resumeGraphData
  758. for i in 0..<thisData.count{
  759. // skip if outside of visible area
  760. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  761. if thisData[i].date < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  762. let value = ChartDataEntry(x: Double(thisData[i].date), y: Double(thisData[i].sgv), data: formatPillText(line1: "Resume Pump", time: thisData[i].date))
  763. BGChart.data?.dataSets[dataIndex].addEntry(value)
  764. if UserDefaultsRepository.smallGraphTreatments.value {
  765. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  766. }
  767. }
  768. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  769. BGChart.data?.notifyDataChanged()
  770. BGChart.notifyDataSetChanged()
  771. if UserDefaultsRepository.smallGraphTreatments.value {
  772. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  773. BGChartFull.data?.notifyDataChanged()
  774. BGChartFull.notifyDataSetChanged()
  775. }
  776. }
  777. func updateSensorStart() {
  778. var dataIndex = 10
  779. BGChart.lineData?.dataSets[dataIndex].clear()
  780. BGChartFull.lineData?.dataSets[dataIndex].clear()
  781. let thisData = sensorStartGraphData
  782. for i in 0..<thisData.count{
  783. // skip if outside of visible area
  784. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  785. if thisData[i].date < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  786. let value = ChartDataEntry(x: Double(thisData[i].date), y: Double(thisData[i].sgv), data: formatPillText(line1: "Start Sensor", time: thisData[i].date))
  787. BGChart.data?.dataSets[dataIndex].addEntry(value)
  788. if UserDefaultsRepository.smallGraphTreatments.value {
  789. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  790. }
  791. }
  792. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  793. BGChart.data?.notifyDataChanged()
  794. BGChart.notifyDataSetChanged()
  795. if UserDefaultsRepository.smallGraphTreatments.value {
  796. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  797. BGChartFull.data?.notifyDataChanged()
  798. BGChartFull.notifyDataSetChanged()
  799. }
  800. }
  801. func updateNotes() {
  802. var dataIndex = 11
  803. BGChart.lineData?.dataSets[dataIndex].clear()
  804. BGChartFull.lineData?.dataSets[dataIndex].clear()
  805. let thisData = noteGraphData
  806. for i in 0..<thisData.count{
  807. // skip if outside of visible area
  808. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  809. if thisData[i].date < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  810. let value = ChartDataEntry(x: Double(thisData[i].date), y: Double(thisData[i].sgv), data: formatPillText(line1: thisData[i].note, time: thisData[i].date))
  811. BGChart.data?.dataSets[dataIndex].addEntry(value)
  812. if UserDefaultsRepository.smallGraphTreatments.value {
  813. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  814. }
  815. }
  816. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  817. BGChart.data?.notifyDataChanged()
  818. BGChart.notifyDataSetChanged()
  819. if UserDefaultsRepository.smallGraphTreatments.value {
  820. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  821. BGChartFull.data?.notifyDataChanged()
  822. BGChartFull.notifyDataSetChanged()
  823. }
  824. }
  825. func createSmallBGGraph(){
  826. let entries = bgData
  827. var bgChartEntry = [ChartDataEntry]()
  828. var colors = [NSUIColor]()
  829. var maxBG: Float = UserDefaultsRepository.minBGScale.value
  830. let lineBG = LineChartDataSet(entries:bgChartEntry, label: "")
  831. lineBG.drawCirclesEnabled = false
  832. //line2.setDrawHighlightIndicators(false)
  833. lineBG.highlightEnabled = true
  834. lineBG.drawHorizontalHighlightIndicatorEnabled = false
  835. lineBG.drawVerticalHighlightIndicatorEnabled = false
  836. lineBG.highlightColor = NSUIColor.label
  837. lineBG.drawValuesEnabled = false
  838. lineBG.lineWidth = 1.5
  839. lineBG.axisDependency = YAxis.AxisDependency.right
  840. // Setup Prediction line details
  841. var predictionChartEntry = [ChartDataEntry]()
  842. let linePrediction = LineChartDataSet(entries:predictionChartEntry, label: "")
  843. linePrediction.drawCirclesEnabled = false
  844. //line2.setDrawHighlightIndicators(false)
  845. linePrediction.setColor(NSUIColor.systemPurple)
  846. linePrediction.highlightEnabled = true
  847. linePrediction.drawHorizontalHighlightIndicatorEnabled = false
  848. linePrediction.drawVerticalHighlightIndicatorEnabled = false
  849. linePrediction.highlightColor = NSUIColor.label
  850. linePrediction.drawValuesEnabled = false
  851. linePrediction.lineWidth = 1.5
  852. linePrediction.axisDependency = YAxis.AxisDependency.right
  853. // create Basal graph data
  854. var chartEntry = [ChartDataEntry]()
  855. var maxBasal = UserDefaultsRepository.minBasalScale.value
  856. let lineBasal = LineChartDataSet(entries:chartEntry, label: "")
  857. lineBasal.setDrawHighlightIndicators(false)
  858. lineBasal.setColor(NSUIColor.systemBlue, alpha: 0.5)
  859. lineBasal.lineWidth = 0
  860. lineBasal.drawFilledEnabled = true
  861. lineBasal.fillColor = NSUIColor.systemBlue
  862. lineBasal.fillAlpha = 0.35
  863. lineBasal.drawCirclesEnabled = false
  864. lineBasal.axisDependency = YAxis.AxisDependency.left
  865. lineBasal.highlightEnabled = false
  866. lineBasal.drawValuesEnabled = false
  867. lineBasal.fillFormatter = basalFillFormatter()
  868. // Boluses
  869. var chartEntryBolus = [ChartDataEntry]()
  870. let lineBolus = LineChartDataSet(entries:chartEntryBolus, label: "")
  871. lineBolus.circleRadius = 2
  872. lineBolus.circleColors = [NSUIColor.systemBlue.withAlphaComponent(0.75)]
  873. lineBolus.drawCircleHoleEnabled = false
  874. lineBolus.setDrawHighlightIndicators(false)
  875. lineBolus.setColor(NSUIColor.systemBlue, alpha: 1.0)
  876. lineBolus.lineWidth = 0
  877. lineBolus.axisDependency = YAxis.AxisDependency.right
  878. lineBolus.valueFormatter = ChartYDataValueFormatter()
  879. lineBolus.valueTextColor = NSUIColor.label
  880. lineBolus.fillColor = NSUIColor.systemBlue
  881. lineBolus.fillAlpha = 0.6
  882. lineBolus.drawCirclesEnabled = true
  883. lineBolus.drawFilledEnabled = false
  884. lineBolus.drawValuesEnabled = false
  885. lineBolus.highlightEnabled = false
  886. // Carbs
  887. var chartEntryCarbs = [ChartDataEntry]()
  888. let lineCarbs = LineChartDataSet(entries:chartEntryCarbs, label: "")
  889. lineCarbs.circleRadius = 2
  890. lineCarbs.circleColors = [NSUIColor.systemOrange.withAlphaComponent(0.75)]
  891. lineCarbs.drawCircleHoleEnabled = false
  892. lineCarbs.setDrawHighlightIndicators(false)
  893. lineCarbs.setColor(NSUIColor.systemBlue, alpha: 1.0)
  894. lineCarbs.lineWidth = 0
  895. lineCarbs.axisDependency = YAxis.AxisDependency.right
  896. lineCarbs.valueFormatter = ChartYDataValueFormatter()
  897. lineCarbs.valueTextColor = NSUIColor.label
  898. lineCarbs.fillColor = NSUIColor.systemOrange
  899. lineCarbs.fillAlpha = 0.6
  900. lineCarbs.drawCirclesEnabled = true
  901. lineCarbs.drawFilledEnabled = false
  902. lineCarbs.drawValuesEnabled = false
  903. lineCarbs.highlightEnabled = false
  904. // create Scheduled Basal graph data
  905. var chartBasalScheduledEntry = [ChartDataEntry]()
  906. let lineBasalScheduled = LineChartDataSet(entries:chartBasalScheduledEntry, label: "")
  907. lineBasalScheduled.setDrawHighlightIndicators(false)
  908. lineBasalScheduled.setColor(NSUIColor.systemBlue, alpha: 0.8)
  909. lineBasalScheduled.lineWidth = 0.5
  910. lineBasalScheduled.drawFilledEnabled = false
  911. lineBasalScheduled.drawCirclesEnabled = false
  912. lineBasalScheduled.axisDependency = YAxis.AxisDependency.left
  913. lineBasalScheduled.highlightEnabled = false
  914. lineBasalScheduled.drawValuesEnabled = false
  915. lineBasalScheduled.lineDashLengths = [2, 1]
  916. // create Override graph data
  917. var chartOverrideEntry = [ChartDataEntry]()
  918. let lineOverride = LineChartDataSet(entries:chartOverrideEntry, label: "")
  919. lineOverride.setDrawHighlightIndicators(false)
  920. lineOverride.lineWidth = 0
  921. lineOverride.drawFilledEnabled = true
  922. lineOverride.fillFormatter = OverrideFillFormatter()
  923. lineOverride.fillColor = NSUIColor.systemGreen
  924. lineOverride.fillAlpha = 0.6
  925. lineOverride.drawCirclesEnabled = false
  926. lineOverride.axisDependency = YAxis.AxisDependency.right
  927. lineOverride.highlightEnabled = true
  928. lineOverride.drawValuesEnabled = false
  929. // BG Check
  930. var chartEntryBGCheck = [ChartDataEntry]()
  931. let lineBGCheck = LineChartDataSet(entries:chartEntryBGCheck, label: "")
  932. lineBGCheck.circleRadius = 2
  933. lineBGCheck.circleColors = [NSUIColor.systemRed.withAlphaComponent(0.75)]
  934. lineBGCheck.drawCircleHoleEnabled = false
  935. lineBGCheck.setDrawHighlightIndicators(false)
  936. lineBGCheck.setColor(NSUIColor.systemRed, alpha: 1.0)
  937. lineBGCheck.drawCirclesEnabled = true
  938. lineBGCheck.lineWidth = 0
  939. lineBGCheck.highlightEnabled = false
  940. lineBGCheck.axisDependency = YAxis.AxisDependency.right
  941. lineBGCheck.valueFormatter = ChartYDataValueFormatter()
  942. lineBGCheck.drawValuesEnabled = false
  943. // Suspend Pump
  944. var chartEntrySuspend = [ChartDataEntry]()
  945. let lineSuspend = LineChartDataSet(entries:chartEntrySuspend, label: "")
  946. lineSuspend.circleRadius = 2
  947. lineSuspend.circleColors = [NSUIColor.systemTeal.withAlphaComponent(0.75)]
  948. lineSuspend.drawCircleHoleEnabled = false
  949. lineSuspend.setDrawHighlightIndicators(false)
  950. lineSuspend.setColor(NSUIColor.systemGray2, alpha: 1.0)
  951. lineSuspend.drawCirclesEnabled = true
  952. lineSuspend.lineWidth = 0
  953. lineSuspend.highlightEnabled = false
  954. lineSuspend.axisDependency = YAxis.AxisDependency.right
  955. lineSuspend.valueFormatter = ChartYDataValueFormatter()
  956. lineSuspend.drawValuesEnabled = false
  957. // Resume Pump
  958. var chartEntryResume = [ChartDataEntry]()
  959. let lineResume = LineChartDataSet(entries:chartEntryResume, label: "")
  960. lineResume.circleRadius = 2
  961. lineResume.circleColors = [NSUIColor.systemTeal.withAlphaComponent(0.75)]
  962. lineResume.drawCircleHoleEnabled = false
  963. lineResume.setDrawHighlightIndicators(false)
  964. lineResume.setColor(NSUIColor.systemGray4, alpha: 1.0)
  965. lineResume.drawCirclesEnabled = true
  966. lineResume.lineWidth = 0
  967. lineResume.highlightEnabled = false
  968. lineResume.axisDependency = YAxis.AxisDependency.right
  969. lineResume.valueFormatter = ChartYDataValueFormatter()
  970. lineResume.drawValuesEnabled = false
  971. // Sensor Start
  972. var chartEntrySensor = [ChartDataEntry]()
  973. let lineSensor = LineChartDataSet(entries:chartEntrySensor, label: "")
  974. lineSensor.circleRadius = 2
  975. lineSensor.circleColors = [NSUIColor.systemIndigo.withAlphaComponent(0.75)]
  976. lineSensor.drawCircleHoleEnabled = false
  977. lineSensor.setDrawHighlightIndicators(false)
  978. lineSensor.setColor(NSUIColor.systemGray3, alpha: 1.0)
  979. lineSensor.drawCirclesEnabled = true
  980. lineSensor.lineWidth = 0
  981. lineSensor.highlightEnabled = false
  982. lineSensor.axisDependency = YAxis.AxisDependency.right
  983. lineSensor.valueFormatter = ChartYDataValueFormatter()
  984. lineSensor.drawValuesEnabled = false
  985. // Notes
  986. var chartEntryNote = [ChartDataEntry]()
  987. let lineNote = LineChartDataSet(entries:chartEntryNote, label: "")
  988. lineNote.circleRadius = 2
  989. lineNote.circleColors = [NSUIColor.systemGray.withAlphaComponent(0.75)]
  990. lineNote.drawCircleHoleEnabled = false
  991. lineNote.setDrawHighlightIndicators(false)
  992. lineNote.setColor(NSUIColor.systemGray3, alpha: 1.0)
  993. lineNote.drawCirclesEnabled = true
  994. lineNote.lineWidth = 0
  995. lineNote.highlightEnabled = false
  996. lineNote.axisDependency = YAxis.AxisDependency.right
  997. lineNote.valueFormatter = ChartYDataValueFormatter()
  998. lineNote.drawValuesEnabled = false
  999. // Setup the chart data of all lines
  1000. let data = LineChartData()
  1001. data.append(lineBG) // Dataset 0
  1002. data.append(linePrediction) // Dataset 1
  1003. data.append(lineBasal) // Dataset 2
  1004. data.append(lineBolus) // Dataset 3
  1005. data.append(lineCarbs) // Dataset 4
  1006. data.append(lineBasalScheduled) // Dataset 5
  1007. data.append(lineOverride) // Dataset 6
  1008. data.append(lineBGCheck) // Dataset 7
  1009. data.append(lineSuspend) // Dataset 8
  1010. data.append(lineResume) // Dataset 9
  1011. data.append(lineSensor) // Dataset 10
  1012. data.append(lineNote) // Dataset 11
  1013. BGChartFull.highlightPerDragEnabled = true
  1014. BGChartFull.leftAxis.enabled = false
  1015. BGChartFull.leftAxis.axisMaximum = maxBasal
  1016. BGChartFull.leftAxis.axisMinimum = 0
  1017. BGChartFull.rightAxis.enabled = false
  1018. BGChartFull.rightAxis.axisMinimum = 0.0
  1019. BGChartFull.rightAxis.axisMaximum = Double(maxBG)
  1020. BGChartFull.xAxis.drawLabelsEnabled = false
  1021. BGChartFull.xAxis.drawGridLinesEnabled = false
  1022. BGChartFull.xAxis.drawAxisLineEnabled = false
  1023. BGChartFull.legend.enabled = false
  1024. BGChartFull.scaleYEnabled = false
  1025. BGChartFull.scaleXEnabled = false
  1026. BGChartFull.drawGridBackgroundEnabled = false
  1027. BGChartFull.data = data
  1028. }
  1029. func updateOverrideGraph() {
  1030. var dataIndex = 6
  1031. var yTop: Double = Double(topBG - 5)
  1032. var yBottom: Double = Double(topBG - 25)
  1033. var chart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  1034. var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  1035. chart.clear()
  1036. smallChart.clear()
  1037. let thisData = overrideGraphData
  1038. var colors = [NSUIColor]()
  1039. for i in 0..<thisData.count{
  1040. let thisItem = thisData[i]
  1041. let multiplier = thisItem.insulNeedsScaleFactor as! Double * 100.0
  1042. var labelText = thisItem.reason + "\r\n"
  1043. labelText += String(Int(thisItem.insulNeedsScaleFactor * 100)) + "% "
  1044. if thisItem.correctionRange.count == 2 {
  1045. labelText += String(thisItem.correctionRange[0]) + "-" + String(thisItem.correctionRange[1])
  1046. }
  1047. if thisItem.enteredBy.count > 0 {
  1048. labelText += "\r\nEntered By: " + thisItem.enteredBy
  1049. }
  1050. // Start Dot
  1051. // Shift dots 30 seconds to create an empty 0 space between consecutive temps
  1052. let preStartDot = ChartDataEntry(x: Double(thisItem.date), y: yBottom, data: labelText)
  1053. BGChart.data?.dataSets[dataIndex].addEntry(preStartDot)
  1054. if UserDefaultsRepository.smallGraphTreatments.value {
  1055. BGChartFull.data?.dataSets[dataIndex].addEntry(preStartDot)
  1056. }
  1057. let startDot = ChartDataEntry(x: Double(thisItem.date + 1), y: yTop, data: labelText)
  1058. BGChart.data?.dataSets[dataIndex].addEntry(startDot)
  1059. if UserDefaultsRepository.smallGraphTreatments.value {
  1060. BGChartFull.data?.dataSets[dataIndex].addEntry(startDot)
  1061. }
  1062. // End Dot
  1063. let endDot = ChartDataEntry(x: Double(thisItem.endDate - 2), y: yTop, data: labelText)
  1064. BGChart.data?.dataSets[dataIndex].addEntry(endDot)
  1065. if UserDefaultsRepository.smallGraphTreatments.value {
  1066. BGChartFull.data?.dataSets[dataIndex].addEntry(endDot)
  1067. }
  1068. // Post end dot
  1069. let postEndDot = ChartDataEntry(x: Double(thisItem.endDate - 1), y: yBottom, data: labelText)
  1070. BGChart.data?.dataSets[dataIndex].addEntry(postEndDot)
  1071. if UserDefaultsRepository.smallGraphTreatments.value {
  1072. BGChartFull.data?.dataSets[dataIndex].addEntry(postEndDot)
  1073. }
  1074. }
  1075. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  1076. BGChart.data?.notifyDataChanged()
  1077. BGChart.notifyDataSetChanged()
  1078. if UserDefaultsRepository.smallGraphTreatments.value {
  1079. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  1080. BGChartFull.data?.notifyDataChanged()
  1081. BGChartFull.notifyDataSetChanged()
  1082. }
  1083. }
  1084. func formatPillText(line1: String, time: TimeInterval) -> String {
  1085. let dateFormatter = DateFormatter()
  1086. //let timezoneOffset = TimeZone.current.secondsFromGMT()
  1087. //let epochTimezoneOffset = value + Double(timezoneOffset)
  1088. if dateTimeUtils.is24Hour() {
  1089. dateFormatter.setLocalizedDateFormatFromTemplate("HH:mm")
  1090. } else {
  1091. dateFormatter.setLocalizedDateFormatFromTemplate("hh:mm")
  1092. }
  1093. //let date = Date(timeIntervalSince1970: epochTimezoneOffset)
  1094. let date = Date(timeIntervalSince1970: time)
  1095. let formattedDate = dateFormatter.string(from: date)
  1096. return line1 + "\r\n" + formattedDate
  1097. }
  1098. }