Graphs.swift 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  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 chartTranslated(_ chartView: ChartViewBase, dX: CGFloat, dY: CGFloat) {
  22. if chartView == BGChart {
  23. let currentMatrix = chartView.viewPortHandler.touchMatrix
  24. //BGChartFull.viewPortHandler.refresh(newMatrix: currentMatrix, chart: BGChartFull, invalidate: true)
  25. //BGChartFull.highlightValue(x: Double(currentMatrix.tx), y: Double(currentMatrix.ty), dataSetIndex: 0)
  26. }
  27. }
  28. func chartScaled(_ chartView: ChartViewBase, scaleX: CGFloat, scaleY: CGFloat) {
  29. print("Chart Scaled: \(BGChart.scaleX), \(BGChart.scaleY)")
  30. // dont store huge values
  31. var scale: Float = Float(BGChart.scaleX)
  32. if(scale > ScaleXMax ) {
  33. scale = ScaleXMax
  34. }
  35. UserDefaultsRepository.chartScaleX.value = Float(scale)
  36. }
  37. func createGraph(){
  38. self.BGChart.clear()
  39. // Create the BG Graph Data
  40. let entries = bgData
  41. var bgChartEntry = [ChartDataEntry]()
  42. var colors = [NSUIColor]()
  43. var maxBG: Float = UserDefaultsRepository.minBGScale.value
  44. // Setup BG line details
  45. let lineBG = LineChartDataSet(entries:bgChartEntry, label: "")
  46. lineBG.circleRadius = 3
  47. lineBG.circleColors = [NSUIColor.systemGreen]
  48. lineBG.drawCircleHoleEnabled = false
  49. lineBG.axisDependency = YAxis.AxisDependency.right
  50. lineBG.highlightEnabled = true
  51. lineBG.drawValuesEnabled = false
  52. if UserDefaultsRepository.showLines.value {
  53. lineBG.lineWidth = 2
  54. } else {
  55. lineBG.lineWidth = 0
  56. }
  57. if UserDefaultsRepository.showDots.value {
  58. lineBG.drawCirclesEnabled = true
  59. } else {
  60. lineBG.drawCirclesEnabled = false
  61. }
  62. lineBG.setDrawHighlightIndicators(false)
  63. lineBG.valueFont.withSize(50)
  64. // Setup Prediction line details
  65. var predictionChartEntry = [ChartDataEntry]()
  66. let linePrediction = LineChartDataSet(entries:predictionChartEntry, label: "")
  67. linePrediction.circleRadius = 3
  68. linePrediction.circleColors = [NSUIColor.systemPurple]
  69. linePrediction.colors = [NSUIColor.systemPurple]
  70. linePrediction.drawCircleHoleEnabled = false
  71. linePrediction.axisDependency = YAxis.AxisDependency.right
  72. linePrediction.highlightEnabled = true
  73. linePrediction.drawValuesEnabled = false
  74. if UserDefaultsRepository.showLines.value {
  75. linePrediction.lineWidth = 2
  76. } else {
  77. linePrediction.lineWidth = 0
  78. }
  79. if UserDefaultsRepository.showDots.value {
  80. linePrediction.drawCirclesEnabled = true
  81. } else {
  82. linePrediction.drawCirclesEnabled = false
  83. }
  84. linePrediction.setDrawHighlightIndicators(false)
  85. linePrediction.valueFont.withSize(50)
  86. // create Basal graph data
  87. var chartEntry = [ChartDataEntry]()
  88. var maxBasal = UserDefaultsRepository.minBasalScale.value
  89. let lineBasal = LineChartDataSet(entries:chartEntry, label: "")
  90. lineBasal.setDrawHighlightIndicators(false)
  91. lineBasal.setColor(NSUIColor.systemBlue, alpha: 0.5)
  92. lineBasal.lineWidth = 0
  93. lineBasal.drawFilledEnabled = true
  94. lineBasal.fillColor = NSUIColor.systemBlue
  95. lineBasal.fillAlpha = 0.5
  96. lineBasal.drawCirclesEnabled = false
  97. lineBasal.axisDependency = YAxis.AxisDependency.left
  98. lineBasal.highlightEnabled = true
  99. lineBasal.drawValuesEnabled = false
  100. lineBasal.fillFormatter = basalFillFormatter()
  101. // Boluses
  102. var chartEntryBolus = [ChartDataEntry]()
  103. let lineBolus = LineChartDataSet(entries:chartEntryBolus, label: "")
  104. lineBolus.circleRadius = 5
  105. lineBolus.circleColors = [NSUIColor.systemBlue.withAlphaComponent(0.75)]
  106. lineBolus.drawCircleHoleEnabled = false
  107. lineBolus.setDrawHighlightIndicators(false)
  108. lineBolus.setColor(NSUIColor.systemBlue, alpha: 1.0)
  109. lineBolus.lineWidth = 0
  110. lineBolus.axisDependency = YAxis.AxisDependency.right
  111. lineBolus.valueFormatter = ChartYDataValueFormatter()
  112. lineBolus.valueTextColor = NSUIColor.label
  113. lineBolus.fillFormatter = BolusFillFormatter()
  114. lineBolus.fillColor = NSUIColor.systemBlue
  115. lineBolus.fillAlpha = 0.6
  116. if UserDefaultsRepository.graphBars.value {
  117. lineBolus.drawCirclesEnabled = false
  118. lineBolus.drawFilledEnabled = true
  119. } else {
  120. lineBolus.drawCirclesEnabled = true
  121. lineBolus.drawFilledEnabled = false
  122. }
  123. if UserDefaultsRepository.showValues.value {
  124. lineBolus.drawValuesEnabled = true
  125. lineBolus.highlightEnabled = false
  126. } else {
  127. lineBolus.drawValuesEnabled = false
  128. lineBolus.highlightEnabled = true
  129. }
  130. // Carbs
  131. var chartEntryCarbs = [ChartDataEntry]()
  132. let lineCarbs = LineChartDataSet(entries:chartEntryCarbs, label: "")
  133. lineCarbs.circleRadius = 5
  134. lineCarbs.circleColors = [NSUIColor.systemOrange.withAlphaComponent(0.75)]
  135. lineCarbs.drawCircleHoleEnabled = false
  136. lineCarbs.setDrawHighlightIndicators(false)
  137. lineCarbs.setColor(NSUIColor.systemBlue, alpha: 1.0)
  138. lineCarbs.lineWidth = 0
  139. lineCarbs.axisDependency = YAxis.AxisDependency.right
  140. lineCarbs.valueFormatter = ChartYDataValueFormatter()
  141. lineCarbs.valueTextColor = NSUIColor.label
  142. lineCarbs.fillFormatter = CarbFillFormatter()
  143. lineCarbs.fillColor = NSUIColor.systemOrange
  144. lineCarbs.fillAlpha = 0.6
  145. if UserDefaultsRepository.graphBars.value {
  146. lineCarbs.drawCirclesEnabled = false
  147. lineCarbs.drawFilledEnabled = true
  148. } else {
  149. lineCarbs.drawCirclesEnabled = true
  150. lineCarbs.drawFilledEnabled = false
  151. }
  152. if UserDefaultsRepository.showValues.value {
  153. lineCarbs.drawValuesEnabled = true
  154. lineCarbs.highlightEnabled = false
  155. } else {
  156. lineCarbs.drawValuesEnabled = false
  157. lineCarbs.highlightEnabled = true
  158. }
  159. // create Scheduled Basal graph data
  160. var chartBasalScheduledEntry = [ChartDataEntry]()
  161. let lineBasalScheduled = LineChartDataSet(entries:chartBasalScheduledEntry, label: "")
  162. lineBasalScheduled.setDrawHighlightIndicators(false)
  163. lineBasalScheduled.setColor(NSUIColor.systemBlue, alpha: 0.8)
  164. lineBasalScheduled.lineWidth = 2
  165. lineBasalScheduled.drawFilledEnabled = false
  166. lineBasalScheduled.drawCirclesEnabled = false
  167. lineBasalScheduled.axisDependency = YAxis.AxisDependency.left
  168. lineBasalScheduled.highlightEnabled = false
  169. lineBasalScheduled.drawValuesEnabled = false
  170. lineBasalScheduled.lineDashLengths = [10.0, 5.0]
  171. // create Override graph data
  172. var chartOverrideEntry = [ChartDataEntry]()
  173. let lineOverride = LineChartDataSet(entries:chartOverrideEntry, label: "")
  174. lineOverride.setDrawHighlightIndicators(false)
  175. lineOverride.lineWidth = 0
  176. lineOverride.drawFilledEnabled = true
  177. lineOverride.fillFormatter = OverrideFillFormatter()
  178. lineOverride.fillColor = NSUIColor.systemGreen
  179. lineOverride.fillAlpha = 0.6
  180. lineOverride.drawCirclesEnabled = false
  181. lineOverride.axisDependency = YAxis.AxisDependency.right
  182. lineOverride.highlightEnabled = true
  183. lineOverride.drawValuesEnabled = false
  184. // BG Check
  185. var chartEntryBGCheck = [ChartDataEntry]()
  186. let lineBGCheck = LineChartDataSet(entries:chartEntryBGCheck, label: "")
  187. lineBGCheck.circleRadius = 5
  188. lineBGCheck.circleColors = [NSUIColor.systemRed.withAlphaComponent(0.75)]
  189. lineBGCheck.drawCircleHoleEnabled = false
  190. lineBGCheck.setDrawHighlightIndicators(false)
  191. lineBGCheck.setColor(NSUIColor.systemRed, alpha: 1.0)
  192. lineBGCheck.drawCirclesEnabled = true
  193. lineBGCheck.lineWidth = 0
  194. lineBGCheck.highlightEnabled = false
  195. lineBGCheck.axisDependency = YAxis.AxisDependency.right
  196. lineBGCheck.valueFormatter = ChartYDataValueFormatter()
  197. lineBGCheck.drawValuesEnabled = UserDefaultsRepository.showValues.value
  198. // Setup the chart data of all lines
  199. let data = LineChartData()
  200. data.addDataSet(lineBG) // Dataset 0
  201. data.addDataSet(linePrediction) // Dataset 1
  202. data.addDataSet(lineBasal) // Dataset 2
  203. data.addDataSet(lineBolus) // Dataset 3
  204. data.addDataSet(lineCarbs) // Dataset 4
  205. data.addDataSet(lineBasalScheduled) // Dataset 5
  206. data.addDataSet(lineOverride) // Dataset 6
  207. data.addDataSet(lineBGCheck) // Dataset 7
  208. data.setValueFont(UIFont.systemFont(ofSize: 12))
  209. // Add marker popups for bolus and carbs
  210. let marker = PillMarker(color: .secondarySystemBackground, font: UIFont.boldSystemFont(ofSize: 14), textColor: .label)
  211. BGChart.marker = marker
  212. // Clear limit lines so they don't add multiples when changing the settings
  213. BGChart.rightAxis.removeAllLimitLines()
  214. //Add lower red line based on low alert value
  215. let ll = ChartLimitLine()
  216. ll.limit = Double(UserDefaultsRepository.lowLine.value)
  217. ll.lineColor = NSUIColor.systemRed.withAlphaComponent(0.5)
  218. BGChart.rightAxis.addLimitLine(ll)
  219. //Add upper yellow line based on low alert value
  220. let ul = ChartLimitLine()
  221. ul.limit = Double(UserDefaultsRepository.highLine.value)
  222. ul.lineColor = NSUIColor.systemYellow.withAlphaComponent(0.5)
  223. BGChart.rightAxis.addLimitLine(ul)
  224. // Add Now Line
  225. createNowLine()
  226. startGraphNowTimer()
  227. // Setup the main graph overall details
  228. BGChart.xAxis.valueFormatter = ChartXValueFormatter()
  229. BGChart.xAxis.granularity = 1800
  230. BGChart.xAxis.labelTextColor = NSUIColor.label
  231. BGChart.xAxis.labelPosition = XAxis.LabelPosition.bottom
  232. BGChart.xAxis.drawGridLinesEnabled = false
  233. BGChart.leftAxis.enabled = true
  234. BGChart.leftAxis.labelPosition = YAxis.LabelPosition.insideChart
  235. BGChart.leftAxis.axisMaximum = maxBasal
  236. BGChart.leftAxis.axisMinimum = 0
  237. BGChart.leftAxis.drawGridLinesEnabled = false
  238. BGChart.leftAxis.granularityEnabled = true
  239. BGChart.leftAxis.granularity = 0.5
  240. //BGChart.leftAxis.inverted = true
  241. BGChart.rightAxis.labelTextColor = NSUIColor.label
  242. BGChart.rightAxis.labelPosition = YAxis.LabelPosition.insideChart
  243. BGChart.rightAxis.axisMinimum = 0.0
  244. BGChart.rightAxis.axisMaximum = 400.0
  245. BGChart.rightAxis.gridLineDashLengths = [5.0, 5.0]
  246. BGChart.rightAxis.drawGridLinesEnabled = false
  247. BGChart.rightAxis.valueFormatter = ChartYMMOLValueFormatter()
  248. BGChart.rightAxis.granularityEnabled = true
  249. BGChart.rightAxis.granularity = 50
  250. BGChart.legend.enabled = false
  251. BGChart.scaleYEnabled = false
  252. BGChart.drawGridBackgroundEnabled = true
  253. BGChart.gridBackgroundColor = NSUIColor.secondarySystemBackground
  254. BGChart.highlightValue(nil, callDelegate: false)
  255. BGChart.data = data
  256. BGChart.setExtraOffsets(left: 10, top: 10, right: 10, bottom: 10)
  257. }
  258. func createNowLine() {
  259. BGChart.xAxis.removeAllLimitLines()
  260. let ul = ChartLimitLine()
  261. ul.limit = Double(dateTimeUtils.getNowTimeIntervalUTC())
  262. ul.lineColor = NSUIColor.systemGray.withAlphaComponent(0.5)
  263. ul.lineWidth = 1
  264. BGChart.xAxis.addLimitLine(ul)
  265. }
  266. func updateBGGraphSettings() {
  267. let dataIndex = 0
  268. let dataIndexPrediction = 1
  269. let lineBG = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  270. let linePrediction = BGChart.lineData!.dataSets[dataIndexPrediction] as! LineChartDataSet
  271. if UserDefaultsRepository.showLines.value {
  272. lineBG.lineWidth = 2
  273. linePrediction.lineWidth = 2
  274. } else {
  275. lineBG.lineWidth = 0
  276. linePrediction.lineWidth = 0
  277. }
  278. if UserDefaultsRepository.showDots.value {
  279. lineBG.drawCirclesEnabled = true
  280. linePrediction.drawCirclesEnabled = true
  281. } else {
  282. lineBG.drawCirclesEnabled = false
  283. linePrediction.drawCirclesEnabled = false
  284. }
  285. BGChart.rightAxis.axisMinimum = 0
  286. // Clear limit lines so they don't add multiples when changing the settings
  287. BGChart.rightAxis.removeAllLimitLines()
  288. //Add lower red line based on low alert value
  289. let ll = ChartLimitLine()
  290. ll.limit = Double(UserDefaultsRepository.lowLine.value)
  291. ll.lineColor = NSUIColor.systemRed.withAlphaComponent(0.5)
  292. BGChart.rightAxis.addLimitLine(ll)
  293. //Add upper yellow line based on low alert value
  294. let ul = ChartLimitLine()
  295. ul.limit = Double(UserDefaultsRepository.highLine.value)
  296. ul.lineColor = NSUIColor.systemYellow.withAlphaComponent(0.5)
  297. BGChart.rightAxis.addLimitLine(ul)
  298. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  299. BGChart.data?.notifyDataChanged()
  300. BGChart.notifyDataSetChanged()
  301. }
  302. func updateBGGraph() {
  303. let dataIndex = 0
  304. let entries = bgData
  305. var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  306. var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  307. mainChart.clear()
  308. smallChart.clear()
  309. var maxBG = UserDefaultsRepository.minBGScale.value
  310. var maxBGOffset: Float = 0.0
  311. if UserDefaultsRepository.offsetCarbsBolus.value {
  312. maxBGOffset = 40.0
  313. }
  314. var colors = [NSUIColor]()
  315. for i in 0..<entries.count{
  316. if Float(entries[i].sgv) > maxBG - maxBGOffset {
  317. maxBG = Float(entries[i].sgv) + maxBGOffset
  318. }
  319. let value = ChartDataEntry(x: Double(entries[i].date), y: Double(entries[i].sgv), data: bgUnits.toDisplayUnits(String(entries[i].sgv)))
  320. mainChart.addEntry(value)
  321. smallChart.addEntry(value)
  322. if Double(entries[i].sgv) >= Double(UserDefaultsRepository.highLine.value) {
  323. colors.append(NSUIColor.systemYellow)
  324. } else if Double(entries[i].sgv) <= Double(UserDefaultsRepository.lowLine.value) {
  325. colors.append(NSUIColor.systemRed)
  326. } else {
  327. colors.append(NSUIColor.systemGreen)
  328. }
  329. }
  330. // Set Colors
  331. let lineBG = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  332. let lineBGSmall = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  333. lineBG.colors.removeAll()
  334. lineBG.circleColors.removeAll()
  335. lineBGSmall.colors.removeAll()
  336. lineBGSmall.circleColors.removeAll()
  337. if colors.count > 0 {
  338. if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Graph: colors") }
  339. for i in 0..<colors.count{
  340. mainChart.addColor(colors[i])
  341. mainChart.circleColors.append(colors[i])
  342. smallChart.addColor(colors[i])
  343. smallChart.circleColors.append(colors[i])
  344. }
  345. }
  346. BGChart.rightAxis.axisMaximum = 400
  347. BGChart.setVisibleXRangeMinimum(600)
  348. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  349. BGChart.data?.notifyDataChanged()
  350. BGChart.notifyDataSetChanged()
  351. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  352. BGChartFull.data?.notifyDataChanged()
  353. BGChartFull.notifyDataSetChanged()
  354. if firstGraphLoad {
  355. var scaleX = CGFloat(UserDefaultsRepository.chartScaleX.value)
  356. print("Scale: \(scaleX)")
  357. if( scaleX > CGFloat(ScaleXMax) ) {
  358. scaleX = CGFloat(ScaleXMax)
  359. UserDefaultsRepository.chartScaleX.value = ScaleXMax
  360. }
  361. BGChart.zoom(scaleX: scaleX, scaleY: 1, x: 1, y: 1)
  362. firstGraphLoad = false
  363. }
  364. if BGChart.chartXMax > dateTimeUtils.getNowTimeIntervalUTC() {
  365. BGChart.moveViewToAnimated(xValue: dateTimeUtils.getNowTimeIntervalUTC() - (BGChart.visibleXRange * 0.7), yValue: 0.0, axis: .right, duration: 1, easingOption: .easeInBack)
  366. }
  367. }
  368. func updatePredictionGraph() {
  369. let dataIndex = 1
  370. var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  371. var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  372. mainChart.clear()
  373. smallChart.clear()
  374. if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Graph: print prediction") }
  375. var colors = [NSUIColor]()
  376. for i in 0..<predictionData.count {
  377. var predictionVal = Double(predictionData[i].sgv)
  378. // Below can be turned on to prevent out of range on the graph if desired.
  379. // It currently just drops them out of view
  380. if predictionVal > 400 {
  381. predictionVal = 400
  382. colors.append(NSUIColor.systemYellow)
  383. } else if predictionVal < 0 {
  384. predictionVal = 0
  385. colors.append(NSUIColor.systemRed)
  386. } else {
  387. colors.append(NSUIColor.systemPurple)
  388. }
  389. let value = ChartDataEntry(x: predictionData[i].date, y: predictionVal)
  390. mainChart.addEntry(value)
  391. smallChart.addEntry(value)
  392. }
  393. smallChart.circleColors.removeAll()
  394. smallChart.colors.removeAll()
  395. mainChart.colors.removeAll()
  396. mainChart.circleColors.removeAll()
  397. if colors.count > 0 {
  398. if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Graph: prediction colors") }
  399. for i in 0..<colors.count{
  400. mainChart.addColor(colors[i])
  401. mainChart.circleColors.append(colors[i])
  402. smallChart.addColor(colors[i])
  403. smallChart.circleColors.append(colors[i])
  404. }
  405. }
  406. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  407. BGChart.data?.notifyDataChanged()
  408. BGChart.notifyDataSetChanged()
  409. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  410. BGChartFull.data?.notifyDataChanged()
  411. BGChartFull.notifyDataSetChanged()
  412. }
  413. func updateBasalGraph() {
  414. var dataIndex = 2
  415. BGChart.lineData?.dataSets[dataIndex].clear()
  416. var maxBasal = UserDefaultsRepository.minBasalScale.value
  417. for i in 0..<basalData.count{
  418. let value = ChartDataEntry(x: Double(basalData[i].date), y: Double(basalData[i].basalRate))
  419. BGChart.data?.dataSets[dataIndex].addEntry(value)
  420. if basalData[i].basalRate > maxBasal {
  421. maxBasal = basalData[i].basalRate
  422. }
  423. }
  424. BGChart.leftAxis.axisMaximum = maxBasal
  425. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  426. BGChart.data?.notifyDataChanged()
  427. BGChart.notifyDataSetChanged()
  428. }
  429. func updateBasalScheduledGraph() {
  430. var dataIndex = 5
  431. BGChart.lineData?.dataSets[dataIndex].clear()
  432. for i in 0..<basalScheduleData.count{
  433. let value = ChartDataEntry(x: Double(basalScheduleData[i].date), y: Double(basalScheduleData[i].basalRate))
  434. BGChart.data?.dataSets[dataIndex].addEntry(value)
  435. }
  436. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  437. BGChart.data?.notifyDataChanged()
  438. BGChart.notifyDataSetChanged()
  439. }
  440. func updateBolusGraph() {
  441. var dataIndex = 3
  442. var yTop: Double = 370
  443. var yBottom: Double = 345
  444. BGChart.lineData?.dataSets[dataIndex].clear()
  445. for i in 0..<bolusData.count{
  446. let formatter = NumberFormatter()
  447. formatter.minimumFractionDigits = 0
  448. formatter.maximumFractionDigits = 2
  449. formatter.minimumIntegerDigits = 0
  450. var offset = 0
  451. if UserDefaultsRepository.offsetCarbsBolus.value {
  452. offset = 10
  453. }
  454. if UserDefaultsRepository.graphBars.value {
  455. var dateSpread = bolusData[i].value * 2 * 60
  456. if dateSpread < 60 { dateSpread * 2 }
  457. var startDotTime = bolusData[i].date
  458. var startInnerDotTime = bolusData[i].date + 1
  459. var endInnerDotTime = bolusData[i].date + dateSpread - 1
  460. var endDotTime = bolusData[i].date + dateSpread
  461. if i < bolusData.count - 1 {
  462. if endDotTime >= bolusData[i + 1].date {
  463. endDotTime = bolusData[i + 1].date - 4
  464. endInnerDotTime = endDotTime - 1
  465. // Skip this loop if it's too short of a time to add the dots
  466. if endDotTime <= startDotTime { continue }
  467. }
  468. }
  469. let preStartDot = ChartDataEntry(x: Double(startDotTime), y: yBottom, data: "hide")
  470. BGChart.data?.dataSets[dataIndex].addEntry(preStartDot)
  471. let startDot = ChartDataEntry(x: Double(startInnerDotTime), y: yTop, data: formatter.string(from: NSNumber(value: bolusData[i].value)))
  472. BGChart.data?.dataSets[dataIndex].addEntry(startDot)
  473. let preEndDot = ChartDataEntry(x: Double(endInnerDotTime), y: yTop, data: formatter.string(from: NSNumber(value: bolusData[i].value)))
  474. BGChart.data?.dataSets[dataIndex].addEntry(preEndDot)
  475. let endDot = ChartDataEntry(x: Double(endDotTime), y: yBottom, data: "hide")
  476. BGChart.data?.dataSets[dataIndex].addEntry(endDot)
  477. } else {
  478. let dot = ChartDataEntry(x: Double(bolusData[i].date), y: Double(bolusData[i].sgv + offset), data: formatter.string(from: NSNumber(value: bolusData[i].value)))
  479. BGChart.data?.dataSets[dataIndex].addEntry(dot)
  480. }
  481. }
  482. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  483. BGChart.data?.notifyDataChanged()
  484. BGChart.notifyDataSetChanged()
  485. }
  486. func updateCarbGraph() {
  487. var dataIndex = 4
  488. var yTop: Double = 340
  489. var yBottom: Double = 315
  490. BGChart.lineData?.dataSets[dataIndex].clear()
  491. for i in 0..<carbData.count{
  492. let formatter = NumberFormatter()
  493. formatter.minimumFractionDigits = 0
  494. formatter.maximumFractionDigits = 2
  495. formatter.minimumIntegerDigits = 1
  496. var offset = 0
  497. if UserDefaultsRepository.offsetCarbsBolus.value {
  498. offset = 30
  499. }
  500. var valueString: String = formatter.string(from: NSNumber(value: carbData[i].value))!
  501. if carbData[i].absorptionTime > 0 && UserDefaultsRepository.showAbsorption.value {
  502. let hours = carbData[i].absorptionTime / 60
  503. valueString += " " + String(hours) + "h"
  504. }
  505. if UserDefaultsRepository.graphBars.value {
  506. var dateSpread = carbData[i].value / 10 * 60 * 2
  507. var startDotTime = carbData[i].date
  508. var startInnerDotTime = carbData[i].date + 1
  509. var endInnerDotTime = carbData[i].date + dateSpread - 1
  510. var endDotTime = carbData[i].date + dateSpread
  511. if i < carbData.count - 1 {
  512. if endDotTime >= carbData[i + 1].date {
  513. endDotTime = carbData[i + 1].date - 4
  514. endInnerDotTime = endDotTime - 1
  515. // Skip this loop if it's too short of a time to add the dots
  516. if endDotTime <= startDotTime { continue }
  517. }
  518. }
  519. let preStartDot = ChartDataEntry(x: Double(startDotTime), y: yBottom, data: "hide")
  520. BGChart.data?.dataSets[dataIndex].addEntry(preStartDot)
  521. let startDot = ChartDataEntry(x: Double(startInnerDotTime), y: yTop, data: valueString)
  522. BGChart.data?.dataSets[dataIndex].addEntry(startDot)
  523. let endDot = ChartDataEntry(x: Double(endInnerDotTime), y: yTop, data: valueString)
  524. BGChart.data?.dataSets[dataIndex].addEntry(endDot)
  525. let postEndDot = ChartDataEntry(x: Double(endDotTime), y: yBottom, data: "hide")
  526. BGChart.data?.dataSets[dataIndex].addEntry(postEndDot)
  527. } else {
  528. let dot = ChartDataEntry(x: Double(carbData[i].date), y: Double(carbData[i].sgv + offset), data: valueString)
  529. BGChart.data?.dataSets[dataIndex].addEntry(dot)
  530. }
  531. }
  532. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  533. BGChart.data?.notifyDataChanged()
  534. BGChart.notifyDataSetChanged()
  535. }
  536. func updateBGCheckGraph() {
  537. var dataIndex = 7
  538. BGChart.lineData?.dataSets[dataIndex].clear()
  539. for i in 0..<bgCheckData.count{
  540. let formatter = NumberFormatter()
  541. formatter.minimumFractionDigits = 0
  542. formatter.maximumFractionDigits = 2
  543. formatter.minimumIntegerDigits = 1
  544. let value = ChartDataEntry(x: Double(bgCheckData[i].date), y: Double(bgCheckData[i].sgv), data: formatter.string(from: NSNumber(value: bgCheckData[i].sgv)))
  545. BGChart.data?.dataSets[dataIndex].addEntry(value)
  546. }
  547. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  548. BGChart.data?.notifyDataChanged()
  549. BGChart.notifyDataSetChanged()
  550. }
  551. func createSmallBGGraph(){
  552. let entries = bgData
  553. var bgChartEntry = [ChartDataEntry]()
  554. var colors = [NSUIColor]()
  555. let lineBG = LineChartDataSet(entries:bgChartEntry, label: "")
  556. lineBG.drawCirclesEnabled = false
  557. //line2.setDrawHighlightIndicators(false)
  558. lineBG.highlightEnabled = true
  559. lineBG.drawHorizontalHighlightIndicatorEnabled = false
  560. lineBG.drawVerticalHighlightIndicatorEnabled = false
  561. lineBG.highlightColor = NSUIColor.label
  562. lineBG.drawValuesEnabled = false
  563. lineBG.lineWidth = 2
  564. // Setup Prediction line details
  565. var predictionChartEntry = [ChartDataEntry]()
  566. let linePrediction = LineChartDataSet(entries:predictionChartEntry, label: "")
  567. linePrediction.drawCirclesEnabled = false
  568. //line2.setDrawHighlightIndicators(false)
  569. linePrediction.setColor(NSUIColor.systemPurple)
  570. linePrediction.highlightEnabled = true
  571. linePrediction.drawHorizontalHighlightIndicatorEnabled = false
  572. linePrediction.drawVerticalHighlightIndicatorEnabled = false
  573. linePrediction.highlightColor = NSUIColor.label
  574. linePrediction.drawValuesEnabled = false
  575. linePrediction.lineWidth = 2
  576. let data = LineChartData()
  577. data.addDataSet(lineBG)
  578. data.addDataSet(linePrediction)
  579. BGChartFull.highlightPerDragEnabled = true
  580. BGChartFull.leftAxis.enabled = false
  581. BGChartFull.rightAxis.enabled = false
  582. BGChartFull.xAxis.enabled = false
  583. BGChartFull.legend.enabled = false
  584. BGChartFull.scaleYEnabled = false
  585. BGChartFull.scaleXEnabled = false
  586. BGChartFull.drawGridBackgroundEnabled = false
  587. BGChartFull.data = data
  588. }
  589. func updateOverrideGraph() {
  590. var dataIndex = 6
  591. var yTop: Double = 399
  592. var yBottom: Double = 375
  593. var chart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  594. chart.clear()
  595. var colors = [NSUIColor]()
  596. for i in 0..<overrideGraphData.count{
  597. let multiplier = overrideGraphData[i].insulNeedsScaleFactor as! Double * 100.0
  598. //let labelText = String(format: "%.0f%%", multiplier)
  599. let labelText = overrideGraphData[i].reason
  600. // Start Dot
  601. // Shift dots 30 seconds to create an empty 0 space between consecutive temps
  602. let preStartDot = ChartDataEntry(x: Double(overrideGraphData[i].date), y: yBottom, data: "hide")
  603. BGChart.data?.dataSets[dataIndex].addEntry(preStartDot)
  604. let value = ChartDataEntry(x: Double(overrideGraphData[i].date + 1), y: yTop, data: labelText)
  605. BGChart.data?.dataSets[dataIndex].addEntry(value)
  606. if Double(overrideGraphData[i].insulNeedsScaleFactor) == 1.0 {
  607. colors.append(NSUIColor.systemGray.withAlphaComponent(0.0))
  608. } else if i >= overrideGraphData.count - 2 {
  609. colors.append(NSUIColor.systemGreen)
  610. } else {
  611. colors.append(NSUIColor.systemGray.withAlphaComponent(CGFloat(overrideGraphData[i].insulNeedsScaleFactor / 2)))
  612. }
  613. // End Dot
  614. let endDot = ChartDataEntry(x: Double(overrideGraphData[i].endDate - 1), y: yTop, data: labelText)
  615. BGChart.data?.dataSets[dataIndex].addEntry(endDot)
  616. // Post end dot
  617. let postEndDot = ChartDataEntry(x: Double(overrideGraphData[i].endDate), y: yBottom, data: "hide")
  618. BGChart.data?.dataSets[dataIndex].addEntry(postEndDot)
  619. if Double(overrideGraphData[i].insulNeedsScaleFactor) == 1.0 {
  620. colors.append(NSUIColor.systemGray.withAlphaComponent(0.0))
  621. } else if i >= overrideGraphData.count - 2 {
  622. colors.append(NSUIColor.systemGreen)
  623. } else {
  624. colors.append(NSUIColor.systemGray.withAlphaComponent(CGFloat(overrideGraphData[i].insulNeedsScaleFactor / 2)))
  625. }
  626. }
  627. // Set Colors
  628. let line = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  629. line.colors.removeAll()
  630. line.circleColors.removeAll()
  631. if colors.count > 0 {
  632. for i in 0..<colors.count{
  633. chart.addColor(colors[i])
  634. chart.circleColors.append(colors[i])
  635. }
  636. }
  637. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  638. BGChart.data?.notifyDataChanged()
  639. BGChart.notifyDataSetChanged()
  640. }
  641. }