Graphs.swift 55 KB

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