Graphs.swift 82 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949
  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. import Charts
  12. enum GraphDataIndex: Int {
  13. case bg = 0
  14. case prediction = 1
  15. case basal = 2
  16. case bolus = 3
  17. case carbs = 4
  18. case basalScheduled = 5
  19. case override = 6
  20. case bgCheck = 7
  21. case suspend = 8
  22. case resumePump = 9
  23. case sensorStart = 10
  24. case note = 11
  25. case ztPrediction = 12
  26. case iobPrediction = 13
  27. case cobPrediction = 14
  28. case uamPrediction = 15
  29. case smb = 16
  30. case tempTarget = 17
  31. }
  32. extension GraphDataIndex {
  33. var description: String {
  34. switch self {
  35. case .bg: return "BG"
  36. case .prediction: return "Prediction"
  37. case .basal: return "Basal"
  38. case .bolus: return "Bolus"
  39. case .carbs: return "Carbs"
  40. case .basalScheduled: return "Basal Scheduled"
  41. case .override: return "Override"
  42. case .bgCheck: return "BG Check"
  43. case .suspend: return "Suspend"
  44. case .resumePump: return "Resume Pump"
  45. case .sensorStart: return "Sensor Start"
  46. case .note: return "Note"
  47. case .ztPrediction: return "ZT Prediction"
  48. case .iobPrediction: return "IOB Prediction"
  49. case .cobPrediction: return "COB Prediction"
  50. case .uamPrediction: return "UAM Prediction"
  51. case .smb: return "SMB"
  52. case .tempTarget: return "Temp Target"
  53. }
  54. }
  55. }
  56. class CompositeRenderer: LineChartRenderer {
  57. let tempTargetRenderer: TempTargetRenderer
  58. let triangleRenderer: TriangleRenderer
  59. init(dataProvider: LineChartDataProvider?, animator: Animator?, viewPortHandler: ViewPortHandler?, tempTargetDataSetIndex: Int, smbDataSetIndex: Int) {
  60. self.tempTargetRenderer = TempTargetRenderer(
  61. dataProvider: dataProvider,
  62. animator: animator,
  63. viewPortHandler: viewPortHandler,
  64. tempTargetDataSetIndex: tempTargetDataSetIndex
  65. )
  66. self.triangleRenderer = TriangleRenderer(
  67. dataProvider: dataProvider,
  68. animator: animator,
  69. viewPortHandler: viewPortHandler,
  70. smbDataSetIndex: smbDataSetIndex
  71. )
  72. super.init(dataProvider: dataProvider!, animator: animator!, viewPortHandler: viewPortHandler!)
  73. }
  74. override func drawExtras(context: CGContext) {
  75. super.drawExtras(context: context)
  76. tempTargetRenderer.drawExtras(context: context)
  77. triangleRenderer.drawExtras(context: context)
  78. }
  79. }
  80. class TriangleRenderer: LineChartRenderer {
  81. let smbDataSetIndex: Int
  82. init(dataProvider: LineChartDataProvider?, animator: Animator?, viewPortHandler: ViewPortHandler?, smbDataSetIndex: Int) {
  83. self.smbDataSetIndex = smbDataSetIndex
  84. super.init(dataProvider: dataProvider!, animator: animator!, viewPortHandler: viewPortHandler!)
  85. }
  86. override func drawExtras(context: CGContext) {
  87. super.drawExtras(context: context)
  88. guard let dataProvider = dataProvider else { return }
  89. if dataProvider.lineData?.dataSets.count ?? 0 > smbDataSetIndex, let lineDataSet = dataProvider.lineData?.dataSets[smbDataSetIndex] as? LineChartDataSet {
  90. let trans = dataProvider.getTransformer(forAxis: lineDataSet.axisDependency)
  91. let phaseY = animator.phaseY
  92. for j in 0 ..< lineDataSet.entryCount {
  93. guard let e = lineDataSet.entryForIndex(j) else { continue }
  94. let pt = trans.pixelForValues(x: e.x, y: e.y * phaseY)
  95. context.saveGState()
  96. context.beginPath()
  97. context.move(to: CGPoint(x: pt.x, y: pt.y + 9))
  98. context.addLine(to: CGPoint(x: pt.x - 5, y: pt.y - 1))
  99. context.addLine(to: CGPoint(x: pt.x + 5, y: pt.y - 1))
  100. context.closePath()
  101. context.setFillColor(lineDataSet.circleColors.first!.cgColor)
  102. context.fillPath()
  103. context.restoreGState()
  104. }
  105. }
  106. }
  107. }
  108. class TempTargetChartDataEntry: ChartDataEntry {
  109. var xStart: Double = 0.0
  110. var xEnd: Double = 0.0
  111. var yTop: Double = 0.0
  112. var yBottom: Double = 0.0
  113. required init() {
  114. super.init()
  115. }
  116. init(xStart: Double, xEnd: Double, yTop: Double, yBottom: Double, data: Any?) {
  117. self.xStart = xStart
  118. self.xEnd = xEnd
  119. self.yTop = yTop
  120. self.yBottom = yBottom
  121. super.init(x: xStart, y: yTop)
  122. self.data = data
  123. }
  124. override func copy(with zone: NSZone? = nil) -> Any {
  125. let copy = TempTargetChartDataEntry(
  126. xStart: xStart,
  127. xEnd: xEnd,
  128. yTop: yTop,
  129. yBottom: yBottom,
  130. data: data
  131. )
  132. return copy
  133. }
  134. }
  135. class TempTargetRenderer: LineChartRenderer {
  136. let tempTargetDataSetIndex: Int
  137. init(dataProvider: LineChartDataProvider?, animator: Animator?, viewPortHandler: ViewPortHandler?, tempTargetDataSetIndex: Int) {
  138. self.tempTargetDataSetIndex = tempTargetDataSetIndex
  139. super.init(dataProvider: dataProvider!, animator: animator!, viewPortHandler: viewPortHandler!)
  140. }
  141. override func drawExtras(context: CGContext) {
  142. super.drawExtras(context: context)
  143. guard let dataProvider = dataProvider else { return }
  144. if dataProvider.lineData?.dataSets.count ?? 0 > tempTargetDataSetIndex,
  145. let lineDataSet = dataProvider.lineData?.dataSets[tempTargetDataSetIndex] as? LineChartDataSet {
  146. let trans = dataProvider.getTransformer(forAxis: lineDataSet.axisDependency)
  147. let phaseY = animator.phaseY
  148. for i in 0 ..< lineDataSet.entryCount {
  149. guard let entry = lineDataSet.entryForIndex(i) as? TempTargetChartDataEntry else { continue }
  150. let xStart = entry.xStart
  151. let xEnd = entry.xEnd
  152. let yTop = entry.yTop * phaseY
  153. let yBottom = entry.yBottom * phaseY
  154. let leftTop = trans.pixelForValues(x: xStart, y: yTop)
  155. let rightBottom = trans.pixelForValues(x: xEnd, y: yBottom)
  156. var rect = CGRect(x: leftTop.x, y: leftTop.y, width: rightBottom.x - leftTop.x, height: rightBottom.y - leftTop.y)
  157. if rect.width < 0 {
  158. rect.origin.x += rect.width
  159. rect.size.width = abs(rect.width)
  160. }
  161. if rect.height < 0 {
  162. rect.origin.y += rect.height
  163. rect.size.height = abs(rect.height)
  164. }
  165. context.saveGState()
  166. context.setFillColor(NSUIColor.systemPurple.withAlphaComponent(0.5).cgColor)
  167. context.fill(rect)
  168. context.restoreGState()
  169. }
  170. }
  171. }
  172. }
  173. let ScaleXMax:Float = 150.0
  174. extension MainViewController {
  175. func updateChartRenderers() {
  176. let tempTargetDataIndex = GraphDataIndex.tempTarget.rawValue
  177. let smbDataIndex = GraphDataIndex.smb.rawValue
  178. let compositeRenderer = CompositeRenderer(
  179. dataProvider: BGChart,
  180. animator: BGChart.chartAnimator,
  181. viewPortHandler: BGChart.viewPortHandler,
  182. tempTargetDataSetIndex: tempTargetDataIndex,
  183. smbDataSetIndex: smbDataIndex
  184. )
  185. BGChart.renderer = compositeRenderer
  186. BGChart.data?.notifyDataChanged()
  187. BGChart.notifyDataSetChanged()
  188. }
  189. func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
  190. if chartView == BGChartFull {
  191. BGChart.moveViewToX(entry.x)
  192. }
  193. if entry.data as? String == "hide"{
  194. BGChart.highlightValue(nil, callDelegate: false)
  195. }
  196. }
  197. func chartScaled(_ chartView: ChartViewBase, scaleX: CGFloat, scaleY: CGFloat) {
  198. print("Chart Scaled: \(BGChart.scaleX), \(BGChart.scaleY)")
  199. // dont store huge values
  200. var scale: Float = Float(BGChart.scaleX)
  201. if(scale > ScaleXMax ) {
  202. scale = ScaleXMax
  203. }
  204. UserDefaultsRepository.chartScaleX.value = Float(scale)
  205. }
  206. func createGraph(){
  207. // Create the BG Graph Data
  208. let bgChartEntry = [ChartDataEntry]()
  209. let maxBG: Float = UserDefaultsRepository.minBGScale.value
  210. // Setup BG line details
  211. let lineBG = LineChartDataSet(entries:bgChartEntry, label: "")
  212. lineBG.circleRadius = CGFloat(globalVariables.dotBG)
  213. lineBG.circleColors = [NSUIColor.systemGreen]
  214. lineBG.drawCircleHoleEnabled = false
  215. lineBG.axisDependency = YAxis.AxisDependency.right
  216. lineBG.highlightEnabled = true
  217. lineBG.drawValuesEnabled = false
  218. if UserDefaultsRepository.showLines.value {
  219. lineBG.lineWidth = 2
  220. } else {
  221. lineBG.lineWidth = 0
  222. }
  223. if UserDefaultsRepository.showDots.value {
  224. lineBG.drawCirclesEnabled = true
  225. } else {
  226. lineBG.drawCirclesEnabled = false
  227. }
  228. lineBG.setDrawHighlightIndicators(false)
  229. lineBG.valueFont.withSize(50)
  230. // Setup Prediction line details
  231. let predictionChartEntry = [ChartDataEntry]()
  232. let linePrediction = LineChartDataSet(entries:predictionChartEntry, label: "")
  233. linePrediction.circleRadius = CGFloat(globalVariables.dotBG)
  234. linePrediction.circleColors = [NSUIColor.systemPurple]
  235. linePrediction.colors = [NSUIColor.systemPurple]
  236. linePrediction.drawCircleHoleEnabled = false
  237. linePrediction.axisDependency = YAxis.AxisDependency.right
  238. linePrediction.highlightEnabled = true
  239. linePrediction.drawValuesEnabled = false
  240. if UserDefaultsRepository.showLines.value {
  241. linePrediction.lineWidth = 2
  242. } else {
  243. linePrediction.lineWidth = 0
  244. }
  245. if UserDefaultsRepository.showDots.value {
  246. linePrediction.drawCirclesEnabled = true
  247. } else {
  248. linePrediction.drawCirclesEnabled = false
  249. }
  250. linePrediction.setDrawHighlightIndicators(false)
  251. linePrediction.valueFont.withSize(50)
  252. // create Basal graph data
  253. let chartEntry = [ChartDataEntry]()
  254. let maxBasal = UserDefaultsRepository.minBasalScale.value
  255. let lineBasal = LineChartDataSet(entries:chartEntry, label: "")
  256. lineBasal.setDrawHighlightIndicators(false)
  257. lineBasal.setColor(NSUIColor.systemBlue, alpha: 0.5)
  258. lineBasal.lineWidth = 0
  259. lineBasal.drawFilledEnabled = true
  260. lineBasal.fillColor = NSUIColor.systemBlue
  261. lineBasal.fillAlpha = 0.5
  262. lineBasal.drawCirclesEnabled = false
  263. lineBasal.axisDependency = YAxis.AxisDependency.left
  264. lineBasal.highlightEnabled = true
  265. lineBasal.drawValuesEnabled = false
  266. lineBasal.fillFormatter = basalFillFormatter()
  267. // Boluses
  268. let chartEntryBolus = [ChartDataEntry]()
  269. let lineBolus = LineChartDataSet(entries:chartEntryBolus, label: "")
  270. lineBolus.circleRadius = CGFloat(globalVariables.dotBolus)
  271. lineBolus.circleColors = [NSUIColor.systemBlue.withAlphaComponent(0.75)]
  272. lineBolus.drawCircleHoleEnabled = false
  273. lineBolus.setDrawHighlightIndicators(false)
  274. lineBolus.setColor(NSUIColor.systemBlue, alpha: 1.0)
  275. lineBolus.lineWidth = 0
  276. lineBolus.axisDependency = YAxis.AxisDependency.right
  277. lineBolus.valueFormatter = ChartYDataValueFormatter()
  278. lineBolus.valueTextColor = NSUIColor.label
  279. lineBolus.fillColor = NSUIColor.systemBlue
  280. lineBolus.fillAlpha = 0.6
  281. lineBolus.drawCirclesEnabled = true
  282. lineBolus.drawFilledEnabled = false
  283. if UserDefaultsRepository.showValues.value {
  284. lineBolus.drawValuesEnabled = true
  285. lineBolus.highlightEnabled = false
  286. } else {
  287. lineBolus.drawValuesEnabled = false
  288. lineBolus.highlightEnabled = true
  289. }
  290. // Carbs
  291. let chartEntryCarbs = [ChartDataEntry]()
  292. let lineCarbs = LineChartDataSet(entries:chartEntryCarbs, label: "")
  293. lineCarbs.circleRadius = CGFloat(globalVariables.dotCarb)
  294. lineCarbs.circleColors = [NSUIColor.systemOrange.withAlphaComponent(0.75)]
  295. lineCarbs.drawCircleHoleEnabled = false
  296. lineCarbs.setDrawHighlightIndicators(false)
  297. lineCarbs.setColor(NSUIColor.systemBlue, alpha: 1.0)
  298. lineCarbs.lineWidth = 0
  299. lineCarbs.axisDependency = YAxis.AxisDependency.right
  300. lineCarbs.valueFormatter = ChartYDataValueFormatter()
  301. lineCarbs.valueTextColor = NSUIColor.label
  302. lineCarbs.fillColor = NSUIColor.systemOrange
  303. lineCarbs.fillAlpha = 0.6
  304. lineCarbs.drawCirclesEnabled = true
  305. lineCarbs.drawFilledEnabled = false
  306. if UserDefaultsRepository.showValues.value {
  307. lineCarbs.drawValuesEnabled = true
  308. lineCarbs.highlightEnabled = false
  309. } else {
  310. lineCarbs.drawValuesEnabled = false
  311. lineCarbs.highlightEnabled = true
  312. }
  313. // create Scheduled Basal graph data
  314. let chartBasalScheduledEntry = [ChartDataEntry]()
  315. let lineBasalScheduled = LineChartDataSet(entries:chartBasalScheduledEntry, label: "")
  316. lineBasalScheduled.setDrawHighlightIndicators(false)
  317. lineBasalScheduled.setColor(NSUIColor.systemBlue, alpha: 0.8)
  318. lineBasalScheduled.lineWidth = 2
  319. lineBasalScheduled.drawFilledEnabled = false
  320. lineBasalScheduled.drawCirclesEnabled = false
  321. lineBasalScheduled.axisDependency = YAxis.AxisDependency.left
  322. lineBasalScheduled.highlightEnabled = false
  323. lineBasalScheduled.drawValuesEnabled = false
  324. lineBasalScheduled.lineDashLengths = [10.0, 5.0]
  325. // create Override graph data
  326. let chartOverrideEntry = [ChartDataEntry]()
  327. let lineOverride = LineChartDataSet(entries:chartOverrideEntry, label: "")
  328. lineOverride.setDrawHighlightIndicators(false)
  329. lineOverride.lineWidth = 0
  330. lineOverride.drawFilledEnabled = true
  331. lineOverride.fillFormatter = OverrideFillFormatter()
  332. lineOverride.fillColor = NSUIColor.systemGreen
  333. lineOverride.fillAlpha = 0.6
  334. lineOverride.drawCirclesEnabled = false
  335. lineOverride.axisDependency = YAxis.AxisDependency.right
  336. lineOverride.highlightEnabled = true
  337. lineOverride.drawValuesEnabled = false
  338. // BG Check
  339. let chartEntryBGCheck = [ChartDataEntry]()
  340. let lineBGCheck = LineChartDataSet(entries:chartEntryBGCheck, label: "")
  341. lineBGCheck.circleRadius = CGFloat(globalVariables.dotOther)
  342. lineBGCheck.circleColors = [NSUIColor.systemRed.withAlphaComponent(0.75)]
  343. lineBGCheck.drawCircleHoleEnabled = false
  344. lineBGCheck.setDrawHighlightIndicators(false)
  345. lineBGCheck.setColor(NSUIColor.systemRed, alpha: 1.0)
  346. lineBGCheck.drawCirclesEnabled = true
  347. lineBGCheck.lineWidth = 0
  348. lineBGCheck.highlightEnabled = true
  349. lineBGCheck.axisDependency = YAxis.AxisDependency.right
  350. lineBGCheck.valueFormatter = ChartYDataValueFormatter()
  351. lineBGCheck.drawValuesEnabled = false
  352. // Suspend Pump
  353. let chartEntrySuspend = [ChartDataEntry]()
  354. let lineSuspend = LineChartDataSet(entries:chartEntrySuspend, label: "")
  355. lineSuspend.circleRadius = CGFloat(globalVariables.dotOther)
  356. lineSuspend.circleColors = [NSUIColor.systemTeal.withAlphaComponent(0.75)]
  357. lineSuspend.drawCircleHoleEnabled = false
  358. lineSuspend.setDrawHighlightIndicators(false)
  359. lineSuspend.setColor(NSUIColor.systemGray2, alpha: 1.0)
  360. lineSuspend.drawCirclesEnabled = true
  361. lineSuspend.lineWidth = 0
  362. lineSuspend.highlightEnabled = true
  363. lineSuspend.axisDependency = YAxis.AxisDependency.right
  364. lineSuspend.valueFormatter = ChartYDataValueFormatter()
  365. lineSuspend.drawValuesEnabled = false
  366. // Resume Pump
  367. let chartEntryResume = [ChartDataEntry]()
  368. let lineResume = LineChartDataSet(entries:chartEntryResume, label: "")
  369. lineResume.circleRadius = CGFloat(globalVariables.dotOther)
  370. lineResume.circleColors = [NSUIColor.systemTeal.withAlphaComponent(0.75)]
  371. lineResume.drawCircleHoleEnabled = false
  372. lineResume.setDrawHighlightIndicators(false)
  373. lineResume.setColor(NSUIColor.systemGray4, alpha: 1.0)
  374. lineResume.drawCirclesEnabled = true
  375. lineResume.lineWidth = 0
  376. lineResume.highlightEnabled = true
  377. lineResume.axisDependency = YAxis.AxisDependency.right
  378. lineResume.valueFormatter = ChartYDataValueFormatter()
  379. lineResume.drawValuesEnabled = false
  380. // Sensor Start
  381. let chartEntrySensor = [ChartDataEntry]()
  382. let lineSensor = LineChartDataSet(entries:chartEntrySensor, label: "")
  383. lineSensor.circleRadius = CGFloat(globalVariables.dotOther)
  384. lineSensor.circleColors = [NSUIColor.systemIndigo.withAlphaComponent(0.75)]
  385. lineSensor.drawCircleHoleEnabled = false
  386. lineSensor.setDrawHighlightIndicators(false)
  387. lineSensor.setColor(NSUIColor.systemGray3, alpha: 1.0)
  388. lineSensor.drawCirclesEnabled = true
  389. lineSensor.lineWidth = 0
  390. lineSensor.highlightEnabled = true
  391. lineSensor.axisDependency = YAxis.AxisDependency.right
  392. lineSensor.valueFormatter = ChartYDataValueFormatter()
  393. lineSensor.drawValuesEnabled = false
  394. // Notes
  395. let chartEntryNote = [ChartDataEntry]()
  396. let lineNote = LineChartDataSet(entries:chartEntryNote, label: "")
  397. lineNote.circleRadius = CGFloat(globalVariables.dotOther)
  398. lineNote.circleColors = [NSUIColor.systemGray.withAlphaComponent(0.75)]
  399. lineNote.drawCircleHoleEnabled = false
  400. lineNote.setDrawHighlightIndicators(false)
  401. lineNote.setColor(NSUIColor.systemGray3, alpha: 1.0)
  402. lineNote.drawCirclesEnabled = true
  403. lineNote.lineWidth = 0
  404. lineNote.highlightEnabled = true
  405. lineNote.axisDependency = YAxis.AxisDependency.right
  406. lineNote.valueFormatter = ChartYDataValueFormatter()
  407. lineNote.drawValuesEnabled = false
  408. // Setup COB Prediction line details
  409. let COBpredictionChartEntry = [ChartDataEntry]()
  410. let COBlinePrediction = LineChartDataSet(entries:COBpredictionChartEntry, label: "")
  411. COBlinePrediction.circleRadius = CGFloat(globalVariables.dotBG)
  412. COBlinePrediction.circleColors = [NSUIColor.systemPurple]
  413. COBlinePrediction.colors = [NSUIColor.systemPurple]
  414. COBlinePrediction.drawCircleHoleEnabled = false
  415. COBlinePrediction.axisDependency = YAxis.AxisDependency.right
  416. COBlinePrediction.highlightEnabled = true
  417. COBlinePrediction.drawValuesEnabled = false
  418. if UserDefaultsRepository.showLines.value {
  419. COBlinePrediction.lineWidth = 2
  420. } else {
  421. COBlinePrediction.lineWidth = 0
  422. }
  423. if UserDefaultsRepository.showDots.value {
  424. COBlinePrediction.drawCirclesEnabled = true
  425. } else {
  426. COBlinePrediction.drawCirclesEnabled = false
  427. }
  428. COBlinePrediction.setDrawHighlightIndicators(false)
  429. COBlinePrediction.valueFont.withSize(50)
  430. // Setup IOB Prediction line details
  431. let IOBpredictionChartEntry = [ChartDataEntry]()
  432. let IOBlinePrediction = LineChartDataSet(entries:IOBpredictionChartEntry, label: "")
  433. IOBlinePrediction.circleRadius = CGFloat(globalVariables.dotBG)
  434. IOBlinePrediction.circleColors = [NSUIColor.systemPurple]
  435. IOBlinePrediction.colors = [NSUIColor.systemPurple]
  436. IOBlinePrediction.drawCircleHoleEnabled = false
  437. IOBlinePrediction.axisDependency = YAxis.AxisDependency.right
  438. IOBlinePrediction.highlightEnabled = true
  439. IOBlinePrediction.drawValuesEnabled = false
  440. if UserDefaultsRepository.showLines.value {
  441. IOBlinePrediction.lineWidth = 2
  442. } else {
  443. IOBlinePrediction.lineWidth = 0
  444. }
  445. if UserDefaultsRepository.showDots.value {
  446. IOBlinePrediction.drawCirclesEnabled = true
  447. } else {
  448. IOBlinePrediction.drawCirclesEnabled = false
  449. }
  450. IOBlinePrediction.setDrawHighlightIndicators(false)
  451. IOBlinePrediction.valueFont.withSize(50)
  452. // Setup UAM Prediction line details
  453. let UAMpredictionChartEntry = [ChartDataEntry]()
  454. let UAMlinePrediction = LineChartDataSet(entries:UAMpredictionChartEntry, label: "")
  455. UAMlinePrediction.circleRadius = CGFloat(globalVariables.dotBG)
  456. UAMlinePrediction.circleColors = [NSUIColor.systemPurple]
  457. UAMlinePrediction.colors = [NSUIColor.systemPurple]
  458. UAMlinePrediction.drawCircleHoleEnabled = false
  459. UAMlinePrediction.axisDependency = YAxis.AxisDependency.right
  460. UAMlinePrediction.highlightEnabled = true
  461. UAMlinePrediction.drawValuesEnabled = false
  462. if UserDefaultsRepository.showLines.value {
  463. UAMlinePrediction.lineWidth = 2
  464. } else {
  465. UAMlinePrediction.lineWidth = 0
  466. }
  467. if UserDefaultsRepository.showDots.value {
  468. UAMlinePrediction.drawCirclesEnabled = true
  469. } else {
  470. UAMlinePrediction.drawCirclesEnabled = false
  471. }
  472. linePrediction.setDrawHighlightIndicators(false)
  473. linePrediction.valueFont.withSize(50)
  474. // Setup ZT Prediction line details
  475. let ZTpredictionChartEntry = [ChartDataEntry]()
  476. let ZTlinePrediction = LineChartDataSet(entries:ZTpredictionChartEntry, label: "")
  477. ZTlinePrediction.circleRadius = CGFloat(globalVariables.dotBG)
  478. ZTlinePrediction.circleColors = [NSUIColor.systemPurple]
  479. ZTlinePrediction.colors = [NSUIColor.systemPurple]
  480. ZTlinePrediction.drawCircleHoleEnabled = false
  481. ZTlinePrediction.axisDependency = YAxis.AxisDependency.right
  482. ZTlinePrediction.highlightEnabled = true
  483. ZTlinePrediction.drawValuesEnabled = false
  484. if UserDefaultsRepository.showLines.value {
  485. ZTlinePrediction.lineWidth = 2
  486. } else {
  487. ZTlinePrediction.lineWidth = 0
  488. }
  489. if UserDefaultsRepository.showDots.value {
  490. ZTlinePrediction.drawCirclesEnabled = true
  491. } else {
  492. ZTlinePrediction.drawCirclesEnabled = false
  493. }
  494. ZTlinePrediction.setDrawHighlightIndicators(false)
  495. ZTlinePrediction.valueFont.withSize(50)
  496. // SMB
  497. let chartEntrySmb = [ChartDataEntry]()
  498. let lineSmb = LineChartDataSet(entries: chartEntrySmb, label: "")
  499. lineSmb.circleRadius = CGFloat(globalVariables.dotBolus)
  500. lineSmb.circleColors = [NSUIColor.systemBlue.withAlphaComponent(1.0)]
  501. lineSmb.drawCircleHoleEnabled = false
  502. lineSmb.setDrawHighlightIndicators(false)
  503. lineSmb.setColor(NSUIColor.red, alpha: 1.0)
  504. lineSmb.lineWidth = 0
  505. lineSmb.axisDependency = YAxis.AxisDependency.right
  506. lineSmb.valueFormatter = ChartYDataValueFormatter()
  507. lineSmb.valueTextColor = NSUIColor.label
  508. lineSmb.drawCirclesEnabled = false
  509. lineSmb.drawFilledEnabled = false
  510. if UserDefaultsRepository.showValues.value {
  511. lineSmb.drawValuesEnabled = true
  512. lineSmb.highlightEnabled = false
  513. } else {
  514. lineSmb.drawValuesEnabled = false
  515. lineSmb.highlightEnabled = true
  516. }
  517. // TempTarget graph data
  518. let chartTempTargetEntry = [ChartDataEntry]()
  519. let lineTempTarget = LineChartDataSet(entries:chartTempTargetEntry, label: "")
  520. lineTempTarget.setDrawHighlightIndicators(false)
  521. lineTempTarget.lineWidth = 0
  522. lineTempTarget.drawFilledEnabled = false
  523. lineTempTarget.fillColor = NSUIColor.systemPurple
  524. lineTempTarget.fillAlpha = 0.6
  525. lineTempTarget.drawCirclesEnabled = false
  526. lineTempTarget.axisDependency = YAxis.AxisDependency.right
  527. lineTempTarget.highlightEnabled = true
  528. lineTempTarget.drawValuesEnabled = false
  529. // Setup the chart data of all lines
  530. let data = LineChartData()
  531. data.append(lineBG) // Dataset 0
  532. data.append(linePrediction) // Dataset 1
  533. data.append(lineBasal) // Dataset 2
  534. data.append(lineBolus) // Dataset 3
  535. data.append(lineCarbs) // Dataset 4
  536. data.append(lineBasalScheduled) // Dataset 5
  537. data.append(lineOverride) // Dataset 6
  538. data.append(lineBGCheck) // Dataset 7
  539. data.append(lineSuspend) // Dataset 8
  540. data.append(lineResume) // Dataset 9
  541. data.append(lineSensor) // Dataset 10
  542. data.append(lineNote) // Dataset 11
  543. data.append(ZTlinePrediction) // Dataset 12
  544. data.append(IOBlinePrediction) // Dataset 13
  545. data.append(COBlinePrediction) // Dataset 14
  546. data.append(UAMlinePrediction) // Dataset 15
  547. data.append(lineSmb) // Dataset 16
  548. data.append(lineTempTarget)
  549. data.setValueFont(UIFont.systemFont(ofSize: 12))
  550. // Add marker popups for bolus and carbs
  551. let marker = PillMarker(color: .secondarySystemBackground, font: UIFont.boldSystemFont(ofSize: 14), textColor: .label)
  552. BGChart.marker = marker
  553. // Clear limit lines so they don't add multiples when changing the settings
  554. BGChart.rightAxis.removeAllLimitLines()
  555. //Add lower red line based on low alert value
  556. let ll = ChartLimitLine()
  557. ll.limit = Double(UserDefaultsRepository.lowLine.value)
  558. ll.lineColor = NSUIColor.systemRed.withAlphaComponent(0.5)
  559. BGChart.rightAxis.addLimitLine(ll)
  560. //Add upper yellow line based on low alert value
  561. let ul = ChartLimitLine()
  562. ul.limit = Double(UserDefaultsRepository.highLine.value)
  563. ul.lineColor = NSUIColor.systemYellow.withAlphaComponent(0.5)
  564. BGChart.rightAxis.addLimitLine(ul)
  565. // Add vertical lines as configured
  566. createVerticalLines()
  567. startGraphNowTimer()
  568. // Setup the main graph overall details
  569. BGChart.xAxis.valueFormatter = ChartXValueFormatter()
  570. BGChart.xAxis.granularity = 1800
  571. BGChart.xAxis.labelTextColor = NSUIColor.label
  572. BGChart.xAxis.labelPosition = XAxis.LabelPosition.bottom
  573. BGChart.xAxis.drawGridLinesEnabled = false
  574. BGChart.leftAxis.enabled = true
  575. BGChart.leftAxis.labelPosition = YAxis.LabelPosition.insideChart
  576. BGChart.leftAxis.axisMaximum = maxBasal
  577. BGChart.leftAxis.axisMinimum = 0
  578. BGChart.leftAxis.drawGridLinesEnabled = false
  579. BGChart.leftAxis.granularityEnabled = true
  580. BGChart.leftAxis.granularity = 0.5
  581. BGChart.rightAxis.labelTextColor = NSUIColor.label
  582. BGChart.rightAxis.labelPosition = YAxis.LabelPosition.insideChart
  583. BGChart.rightAxis.axisMinimum = 0.0
  584. BGChart.rightAxis.axisMaximum = Double(maxBG)
  585. BGChart.rightAxis.gridLineDashLengths = [5.0, 5.0]
  586. BGChart.rightAxis.drawGridLinesEnabled = false
  587. BGChart.rightAxis.valueFormatter = ChartYMMOLValueFormatter()
  588. BGChart.rightAxis.granularityEnabled = true
  589. BGChart.rightAxis.granularity = 50
  590. BGChart.maxHighlightDistance = 15.0
  591. BGChart.legend.enabled = false
  592. BGChart.scaleYEnabled = false
  593. BGChart.drawGridBackgroundEnabled = true
  594. BGChart.gridBackgroundColor = NSUIColor.secondarySystemBackground
  595. BGChart.highlightValue(nil, callDelegate: false)
  596. BGChart.data = data
  597. BGChart.setExtraOffsets(left: 5, top: 10, right: 5, bottom: 10)
  598. }
  599. func createVerticalLines() {
  600. BGChart.xAxis.removeAllLimitLines()
  601. BGChartFull.xAxis.removeAllLimitLines()
  602. createNowAndDIALines()
  603. createMidnightLines()
  604. }
  605. func createNowAndDIALines() {
  606. let ul = ChartLimitLine()
  607. ul.limit = Double(dateTimeUtils.getNowTimeIntervalUTC())
  608. ul.lineColor = NSUIColor.systemGray.withAlphaComponent(0.5)
  609. ul.lineWidth = 1
  610. BGChart.xAxis.addLimitLine(ul)
  611. if UserDefaultsRepository.show30MinLine.value {
  612. let ul2 = ChartLimitLine()
  613. ul2.limit = Double(dateTimeUtils.getNowTimeIntervalUTC().advanced(by: -30 * 60))
  614. ul2.lineColor = NSUIColor.systemBlue.withAlphaComponent(0.5)
  615. ul2.lineWidth = 1
  616. BGChart.xAxis.addLimitLine(ul2)
  617. }
  618. if UserDefaultsRepository.showDIALines.value {
  619. for i in 1..<7 {
  620. let ul = ChartLimitLine()
  621. ul.limit = Double(dateTimeUtils.getNowTimeIntervalUTC() - Double(i * 60 * 60))
  622. ul.lineColor = NSUIColor.systemGray.withAlphaComponent(0.3)
  623. let dash = 10.0 - Double(i)
  624. let space = 5.0 + Double(i)
  625. ul.lineDashLengths = [CGFloat(dash), CGFloat(space)]
  626. ul.lineWidth = 1
  627. BGChart.xAxis.addLimitLine(ul)
  628. }
  629. }
  630. if UserDefaultsRepository.show90MinLine.value {
  631. let ul3 = ChartLimitLine()
  632. ul3.limit = Double(dateTimeUtils.getNowTimeIntervalUTC().advanced(by: -90 * 60))
  633. ul3.lineColor = NSUIColor.systemOrange.withAlphaComponent(0.5)
  634. ul3.lineWidth = 1
  635. BGChart.xAxis.addLimitLine(ul3)
  636. }
  637. }
  638. func createMidnightLines() {
  639. // Draw a line at midnight: useful when showing multiple days of data
  640. if UserDefaultsRepository.showMidnightLines.value {
  641. var midnightTimeInterval = dateTimeUtils.getTimeIntervalMidnightToday()
  642. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  643. let graphStart = dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours)
  644. while midnightTimeInterval > graphStart {
  645. // Large chart
  646. let ul = ChartLimitLine()
  647. ul.limit = Double(midnightTimeInterval)
  648. ul.lineColor = NSUIColor.systemTeal.withAlphaComponent(0.5)
  649. ul.lineDashLengths = [CGFloat(2), CGFloat(5)]
  650. ul.lineWidth = 1
  651. BGChart.xAxis.addLimitLine(ul)
  652. // Small chart
  653. let sl = ChartLimitLine()
  654. sl.limit = Double(midnightTimeInterval)
  655. sl.lineColor = NSUIColor.systemTeal
  656. sl.lineDashLengths = [CGFloat(2), CGFloat(2)]
  657. sl.lineWidth = 1
  658. BGChartFull.xAxis.addLimitLine(sl)
  659. midnightTimeInterval = midnightTimeInterval.advanced(by: -24*60*60)
  660. }
  661. }
  662. }
  663. func updateBGGraphSettings() {
  664. let dataIndex = 0
  665. let dataIndexPrediction = 1
  666. let lineBG = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  667. let linePrediction = BGChart.lineData!.dataSets[dataIndexPrediction] as! LineChartDataSet
  668. if UserDefaultsRepository.showLines.value {
  669. lineBG.lineWidth = 2
  670. linePrediction.lineWidth = 2
  671. } else {
  672. lineBG.lineWidth = 0
  673. linePrediction.lineWidth = 0
  674. }
  675. if UserDefaultsRepository.showDots.value {
  676. lineBG.drawCirclesEnabled = true
  677. linePrediction.drawCirclesEnabled = true
  678. } else {
  679. lineBG.drawCirclesEnabled = false
  680. linePrediction.drawCirclesEnabled = false
  681. }
  682. BGChart.rightAxis.axisMinimum = 0
  683. // Clear limit lines so they don't add multiples when changing the settings
  684. BGChart.rightAxis.removeAllLimitLines()
  685. //Add lower red line based on low alert value
  686. let ll = ChartLimitLine()
  687. ll.limit = Double(UserDefaultsRepository.lowLine.value)
  688. ll.lineColor = NSUIColor.systemRed.withAlphaComponent(0.5)
  689. BGChart.rightAxis.addLimitLine(ll)
  690. //Add upper yellow line based on low alert value
  691. let ul = ChartLimitLine()
  692. ul.limit = Double(UserDefaultsRepository.highLine.value)
  693. ul.lineColor = NSUIColor.systemYellow.withAlphaComponent(0.5)
  694. BGChart.rightAxis.addLimitLine(ul)
  695. // Re-create vertical markers in case their settings changed
  696. createVerticalLines()
  697. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  698. BGChart.data?.notifyDataChanged()
  699. BGChart.notifyDataSetChanged()
  700. }
  701. func updateBGGraph() {
  702. if UserDefaultsRepository.debugLog.value { writeDebugLog(value: "##### Start BG Graph #####") }
  703. let dataIndex = 0
  704. let entries = bgData
  705. guard !entries.isEmpty else {
  706. return
  707. }
  708. let mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  709. let smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  710. mainChart.removeAll(keepingCapacity: false)
  711. smallChart.removeAll(keepingCapacity: false)
  712. let maxBGOffset: Float = 50
  713. var colors = [NSUIColor]()
  714. topBG = UserDefaultsRepository.minBGScale.value
  715. for i in 0..<entries.count{
  716. if Float(entries[i].sgv) > topBG - maxBGOffset {
  717. topBG = Float(entries[i].sgv) + maxBGOffset
  718. }
  719. let value = ChartDataEntry(x: Double(entries[i].date), y: Double(entries[i].sgv), data: formatPillText(line1: Localizer.toDisplayUnits(String(entries[i].sgv)), time: entries[i].date))
  720. if UserDefaultsRepository.debugLog.value { writeDebugLog(value: "BG: " + value.description) }
  721. mainChart.append(value)
  722. smallChart.append(value)
  723. if Double(entries[i].sgv) >= Double(UserDefaultsRepository.highLine.value) {
  724. colors.append(NSUIColor.systemYellow)
  725. } else if Double(entries[i].sgv) <= Double(UserDefaultsRepository.lowLine.value) {
  726. colors.append(NSUIColor.systemRed)
  727. } else {
  728. colors.append(NSUIColor.systemGreen)
  729. }
  730. }
  731. if UserDefaultsRepository.debugLog.value { writeDebugLog(value: "Total Graph BGs: " + mainChart.entries.count.description) }
  732. // Set Colors
  733. let lineBG = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  734. let lineBGSmall = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  735. lineBG.colors.removeAll()
  736. lineBG.circleColors.removeAll()
  737. lineBGSmall.colors.removeAll()
  738. lineBGSmall.circleColors.removeAll()
  739. if colors.count > 0 {
  740. for i in 0..<colors.count{
  741. mainChart.addColor(colors[i])
  742. mainChart.circleColors.append(colors[i])
  743. smallChart.addColor(colors[i])
  744. smallChart.circleColors.append(colors[i])
  745. }
  746. }
  747. if UserDefaultsRepository.debugLog.value { writeDebugLog(value: "Total Colors: " + mainChart.colors.count.description) }
  748. BGChart.rightAxis.axisMaximum = Double(calculateMaxBgGraphValue())
  749. BGChart.setVisibleXRangeMinimum(600)
  750. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  751. BGChart.data?.notifyDataChanged()
  752. BGChart.notifyDataSetChanged()
  753. BGChartFull.rightAxis.axisMaximum = Double(calculateMaxBgGraphValue())
  754. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  755. BGChartFull.data?.notifyDataChanged()
  756. BGChartFull.notifyDataSetChanged()
  757. if firstGraphLoad {
  758. var scaleX = CGFloat(UserDefaultsRepository.chartScaleX.value)
  759. print("Scale: \(scaleX)")
  760. if( scaleX > CGFloat(ScaleXMax) ) {
  761. scaleX = CGFloat(ScaleXMax)
  762. UserDefaultsRepository.chartScaleX.value = ScaleXMax
  763. }
  764. BGChart.zoom(scaleX: scaleX, scaleY: 1, x: 1, y: 1)
  765. firstGraphLoad = false
  766. }
  767. // Move to current reading everytime new readings load
  768. // Check if auto-scrolling should be performed
  769. if autoScrollPauseUntil == nil || Date() > autoScrollPauseUntil! {
  770. BGChart.moveViewToAnimated(xValue: dateTimeUtils.getNowTimeIntervalUTC() - (BGChart.visibleXRange * 0.7), yValue: 0.0, axis: .right, duration: 1, easingOption: .easeInBack)
  771. }
  772. }
  773. func updatePredictionGraph(color: UIColor? = nil) {
  774. let dataIndex = 1
  775. var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  776. var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  777. mainChart.clear()
  778. smallChart.clear()
  779. var colors = [NSUIColor]()
  780. let maxBGOffset: Float = 20
  781. topPredictionBG = UserDefaultsRepository.minBGScale.value
  782. for i in 0..<predictionData.count {
  783. var predictionVal = Double(predictionData[i].sgv)
  784. if Float(predictionVal) > topPredictionBG - maxBGOffset {
  785. topPredictionBG = Float(predictionVal) + maxBGOffset
  786. }
  787. if i == 0 {
  788. if UserDefaultsRepository.showDots.value {
  789. colors.append((color ?? NSUIColor.systemPurple).withAlphaComponent(0.0))
  790. } else {
  791. colors.append((color ?? NSUIColor.systemPurple).withAlphaComponent(1.0))
  792. }
  793. } else if predictionVal > 400 {
  794. colors.append(color ?? NSUIColor.systemYellow)
  795. } else if predictionVal < 0 {
  796. colors.append(color ?? NSUIColor.systemRed)
  797. } else {
  798. colors.append(color ?? NSUIColor.systemPurple)
  799. }
  800. let value = ChartDataEntry(x: predictionData[i].date, y: predictionVal, data: formatPillText(line1: Localizer.toDisplayUnits(String(predictionData[i].sgv)), time: predictionData[i].date))
  801. mainChart.addEntry(value)
  802. smallChart.addEntry(value)
  803. }
  804. smallChart.circleColors.removeAll()
  805. smallChart.colors.removeAll()
  806. mainChart.colors.removeAll()
  807. mainChart.circleColors.removeAll()
  808. if colors.count > 0 {
  809. for i in 0..<colors.count {
  810. mainChart.addColor(colors[i])
  811. mainChart.circleColors.append(colors[i])
  812. smallChart.addColor(colors[i])
  813. smallChart.circleColors.append(colors[i])
  814. }
  815. }
  816. BGChart.rightAxis.axisMaximum = Double(calculateMaxBgGraphValue())
  817. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  818. BGChart.data?.notifyDataChanged()
  819. BGChart.notifyDataSetChanged()
  820. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  821. BGChartFull.data?.notifyDataChanged()
  822. BGChartFull.notifyDataSetChanged()
  823. }
  824. func updateBasalGraph() {
  825. var dataIndex = 2
  826. BGChart.lineData?.dataSets[dataIndex].clear()
  827. BGChartFull.lineData?.dataSets[dataIndex].clear()
  828. var maxBasal = UserDefaultsRepository.minBasalScale.value
  829. var maxBasalSmall: Double = 0.0
  830. for i in 0..<basalData.count{
  831. let value = ChartDataEntry(x: Double(basalData[i].date), y: Double(basalData[i].basalRate), data: formatPillText(line1: String(basalData[i].basalRate), time: basalData[i].date))
  832. BGChart.data?.dataSets[dataIndex].addEntry(value)
  833. if UserDefaultsRepository.smallGraphTreatments.value {
  834. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  835. }
  836. if basalData[i].basalRate > maxBasal {
  837. maxBasal = basalData[i].basalRate
  838. }
  839. if basalData[i].basalRate > maxBasalSmall {
  840. maxBasalSmall = basalData[i].basalRate
  841. }
  842. }
  843. BGChart.leftAxis.axisMaximum = maxBasal
  844. BGChartFull.leftAxis.axisMaximum = maxBasalSmall
  845. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  846. BGChart.data?.notifyDataChanged()
  847. BGChart.notifyDataSetChanged()
  848. if UserDefaultsRepository.smallGraphTreatments.value {
  849. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  850. BGChartFull.data?.notifyDataChanged()
  851. BGChartFull.notifyDataSetChanged()
  852. }
  853. }
  854. func updateBasalScheduledGraph() {
  855. var dataIndex = 5
  856. BGChart.lineData?.dataSets[dataIndex].clear()
  857. BGChartFull.lineData?.dataSets[dataIndex].clear()
  858. for i in 0..<basalScheduleData.count{
  859. let value = ChartDataEntry(x: Double(basalScheduleData[i].date), y: Double(basalScheduleData[i].basalRate))
  860. BGChart.data?.dataSets[dataIndex].addEntry(value)
  861. if UserDefaultsRepository.smallGraphTreatments.value {
  862. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  863. }
  864. }
  865. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  866. BGChart.data?.notifyDataChanged()
  867. BGChart.notifyDataSetChanged()
  868. if UserDefaultsRepository.smallGraphTreatments.value {
  869. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  870. BGChartFull.data?.notifyDataChanged()
  871. BGChartFull.notifyDataSetChanged()
  872. }
  873. }
  874. func updateBolusGraph() {
  875. var dataIndex = 3
  876. var yTop: Double = 370
  877. var yBottom: Double = 345
  878. var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  879. var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  880. mainChart.clear()
  881. smallChart.clear()
  882. var colors = [NSUIColor]()
  883. for i in 0..<bolusData.count{
  884. let formatter = NumberFormatter()
  885. formatter.minimumFractionDigits = 0
  886. formatter.maximumFractionDigits = 2
  887. formatter.minimumIntegerDigits = 0
  888. // Check overlapping carbs to shift left if needed
  889. let bolusShift = findNextBolusTime(timeWithin: 240, needle: bolusData[i].date, haystack: bolusData, startingIndex: i)
  890. var dateTimeStamp = bolusData[i].date
  891. colors.append(NSUIColor.systemBlue.withAlphaComponent(1.0))
  892. if bolusShift {
  893. // Move it half the distance between BG readings
  894. dateTimeStamp = dateTimeStamp - 150
  895. }
  896. // skip if outside of visible area
  897. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  898. if dateTimeStamp < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  899. let dot = ChartDataEntry(x: Double(dateTimeStamp), y: Double(bolusData[i].sgv), data: formatter.string(from: NSNumber(value: bolusData[i].value)))
  900. mainChart.addEntry(dot)
  901. if UserDefaultsRepository.smallGraphTreatments.value {
  902. smallChart.addEntry(dot)
  903. }
  904. }
  905. // Set Colors
  906. let lineBolus = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  907. let lineBolusSmall = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  908. lineBolus.colors.removeAll()
  909. lineBolus.circleColors.removeAll()
  910. lineBolusSmall.colors.removeAll()
  911. lineBolusSmall.circleColors.removeAll()
  912. if colors.count > 0 {
  913. for i in 0..<colors.count{
  914. mainChart.addColor(colors[i])
  915. mainChart.circleColors.append(colors[i])
  916. smallChart.addColor(colors[i])
  917. smallChart.circleColors.append(colors[i])
  918. }
  919. }
  920. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  921. BGChart.data?.notifyDataChanged()
  922. BGChart.notifyDataSetChanged()
  923. if UserDefaultsRepository.smallGraphTreatments.value {
  924. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  925. BGChartFull.data?.notifyDataChanged()
  926. BGChartFull.notifyDataSetChanged()
  927. }
  928. }
  929. func updateSmbGraph() {
  930. var dataIndex = 16
  931. var yTop: Double = 370
  932. var yBottom: Double = 345
  933. var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  934. var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  935. mainChart.clear()
  936. smallChart.clear()
  937. let lightBlue = NSUIColor(red: 135/255, green: 206/255, blue: 235/255, alpha: 1.0) // Light Sky Blue
  938. var colors = [NSUIColor]()
  939. for i in 0..<smbData.count {
  940. let formatter = NumberFormatter()
  941. formatter.minimumFractionDigits = 0
  942. formatter.maximumFractionDigits = 2
  943. formatter.minimumIntegerDigits = 0
  944. let bolusShift = findNextBolusTime(timeWithin: 240, needle: smbData[i].date, haystack: smbData, startingIndex: i)
  945. var dateTimeStamp = smbData[i].date
  946. let nowTime = dateTimeUtils.getNowTimeIntervalUTC()
  947. let diffTimeHours = (nowTime - dateTimeStamp) / 60 / 60
  948. if diffTimeHours <= 1 {
  949. colors.append(lightBlue.withAlphaComponent(1.0))
  950. } else if diffTimeHours > 6 {
  951. colors.append(lightBlue.withAlphaComponent(0.25))
  952. } else {
  953. let thisAlpha = 1.0 - (0.15 * diffTimeHours)
  954. colors.append(lightBlue.withAlphaComponent(CGFloat(thisAlpha)))
  955. }
  956. if bolusShift {
  957. dateTimeStamp = dateTimeStamp - 150
  958. }
  959. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  960. if dateTimeStamp < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  961. let dot = ChartDataEntry(x: Double(dateTimeStamp), y: Double(smbData[i].sgv), data: formatter.string(from: NSNumber(value: smbData[i].value)))
  962. mainChart.addEntry(dot)
  963. if UserDefaultsRepository.smallGraphTreatments.value {
  964. smallChart.addEntry(dot)
  965. }
  966. }
  967. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  968. BGChart.data?.notifyDataChanged()
  969. BGChart.notifyDataSetChanged()
  970. if UserDefaultsRepository.smallGraphTreatments.value {
  971. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  972. BGChartFull.data?.notifyDataChanged()
  973. BGChartFull.notifyDataSetChanged()
  974. }
  975. }
  976. func updateCarbGraph() {
  977. var dataIndex = 4
  978. var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  979. var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  980. mainChart.clear()
  981. smallChart.clear()
  982. var colors = [NSUIColor]()
  983. for i in 0..<carbData.count{
  984. let formatter = NumberFormatter()
  985. formatter.minimumFractionDigits = 0
  986. formatter.maximumFractionDigits = 2
  987. formatter.minimumIntegerDigits = 1
  988. var valueString: String = formatter.string(from: NSNumber(value: carbData[i].value))!
  989. var hours = 3
  990. if carbData[i].absorptionTime > 0 && UserDefaultsRepository.showAbsorption.value {
  991. hours = carbData[i].absorptionTime / 60
  992. valueString += " " + String(hours) + "h"
  993. }
  994. // Check overlapping carbs to shift left if needed
  995. let carbShift = findNextCarbTime(timeWithin: 250, needle: carbData[i].date, haystack: carbData, startingIndex: i)
  996. var dateTimeStamp = carbData[i].date
  997. colors.append(NSUIColor.systemOrange.withAlphaComponent(1.0))
  998. // skip if outside of visible area
  999. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  1000. if dateTimeStamp < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  1001. if carbShift {
  1002. dateTimeStamp = dateTimeStamp - 250
  1003. }
  1004. let dot = ChartDataEntry(x: Double(dateTimeStamp), y: Double(carbData[i].sgv), data: valueString)
  1005. BGChart.data?.dataSets[dataIndex].addEntry(dot)
  1006. if UserDefaultsRepository.smallGraphTreatments.value {
  1007. BGChartFull.data?.dataSets[dataIndex].addEntry(dot)
  1008. }
  1009. }
  1010. // Set Colors
  1011. let lineCarbs = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  1012. let lineCarbsSmall = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  1013. lineCarbs.colors.removeAll()
  1014. lineCarbs.circleColors.removeAll()
  1015. lineCarbsSmall.colors.removeAll()
  1016. lineCarbsSmall.circleColors.removeAll()
  1017. if colors.count > 0 {
  1018. for i in 0..<colors.count{
  1019. mainChart.addColor(colors[i])
  1020. mainChart.circleColors.append(colors[i])
  1021. smallChart.addColor(colors[i])
  1022. smallChart.circleColors.append(colors[i])
  1023. }
  1024. }
  1025. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  1026. BGChart.data?.notifyDataChanged()
  1027. BGChart.notifyDataSetChanged()
  1028. if UserDefaultsRepository.smallGraphTreatments.value {
  1029. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  1030. BGChartFull.data?.notifyDataChanged()
  1031. BGChartFull.notifyDataSetChanged()
  1032. }
  1033. }
  1034. func updateBGCheckGraph() {
  1035. var dataIndex = 7
  1036. BGChart.lineData?.dataSets[dataIndex].clear()
  1037. BGChartFull.lineData?.dataSets[dataIndex].clear()
  1038. for i in 0..<bgCheckData.count{
  1039. let formatter = NumberFormatter()
  1040. formatter.minimumFractionDigits = 0
  1041. formatter.maximumFractionDigits = 2
  1042. formatter.minimumIntegerDigits = 1
  1043. // skip if outside of visible area
  1044. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  1045. if bgCheckData[i].date < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  1046. let value = ChartDataEntry(x: Double(bgCheckData[i].date), y: Double(bgCheckData[i].sgv), data: formatPillText(line1: Localizer.toDisplayUnits(String(bgCheckData[i].sgv)), time: bgCheckData[i].date))
  1047. BGChart.data?.dataSets[dataIndex].addEntry(value)
  1048. if UserDefaultsRepository.smallGraphTreatments.value {
  1049. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  1050. }
  1051. }
  1052. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  1053. BGChart.data?.notifyDataChanged()
  1054. BGChart.notifyDataSetChanged()
  1055. if UserDefaultsRepository.smallGraphTreatments.value {
  1056. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  1057. BGChartFull.data?.notifyDataChanged()
  1058. BGChartFull.notifyDataSetChanged()
  1059. }
  1060. }
  1061. func updateSuspendGraph() {
  1062. var dataIndex = 8
  1063. BGChart.lineData?.dataSets[dataIndex].clear()
  1064. BGChartFull.lineData?.dataSets[dataIndex].clear()
  1065. let thisData = suspendGraphData
  1066. for i in 0..<thisData.count{
  1067. // skip if outside of visible area
  1068. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  1069. if thisData[i].date < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  1070. let value = ChartDataEntry(x: Double(thisData[i].date), y: Double(thisData[i].sgv), data: formatPillText(line1: "Suspend Pump", time: thisData[i].date))
  1071. BGChart.data?.dataSets[dataIndex].addEntry(value)
  1072. if UserDefaultsRepository.smallGraphTreatments.value {
  1073. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  1074. }
  1075. }
  1076. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  1077. BGChart.data?.notifyDataChanged()
  1078. BGChart.notifyDataSetChanged()
  1079. if UserDefaultsRepository.smallGraphTreatments.value {
  1080. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  1081. BGChartFull.data?.notifyDataChanged()
  1082. BGChartFull.notifyDataSetChanged()
  1083. }
  1084. }
  1085. func updateResumeGraph() {
  1086. var dataIndex = 9
  1087. BGChart.lineData?.dataSets[dataIndex].clear()
  1088. BGChartFull.lineData?.dataSets[dataIndex].clear()
  1089. let thisData = resumeGraphData
  1090. for i in 0..<thisData.count{
  1091. // skip if outside of visible area
  1092. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  1093. if thisData[i].date < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  1094. let value = ChartDataEntry(x: Double(thisData[i].date), y: Double(thisData[i].sgv), data: formatPillText(line1: "Resume Pump", time: thisData[i].date))
  1095. BGChart.data?.dataSets[dataIndex].addEntry(value)
  1096. if UserDefaultsRepository.smallGraphTreatments.value {
  1097. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  1098. }
  1099. }
  1100. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  1101. BGChart.data?.notifyDataChanged()
  1102. BGChart.notifyDataSetChanged()
  1103. if UserDefaultsRepository.smallGraphTreatments.value {
  1104. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  1105. BGChartFull.data?.notifyDataChanged()
  1106. BGChartFull.notifyDataSetChanged()
  1107. }
  1108. }
  1109. func updateSensorStart() {
  1110. var dataIndex = 10
  1111. BGChart.lineData?.dataSets[dataIndex].clear()
  1112. BGChartFull.lineData?.dataSets[dataIndex].clear()
  1113. let thisData = sensorStartGraphData
  1114. for i in 0..<thisData.count{
  1115. // skip if outside of visible area
  1116. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  1117. if thisData[i].date < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  1118. let value = ChartDataEntry(x: Double(thisData[i].date), y: Double(thisData[i].sgv), data: formatPillText(line1: "Start Sensor", time: thisData[i].date))
  1119. BGChart.data?.dataSets[dataIndex].addEntry(value)
  1120. if UserDefaultsRepository.smallGraphTreatments.value {
  1121. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  1122. }
  1123. }
  1124. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  1125. BGChart.data?.notifyDataChanged()
  1126. BGChart.notifyDataSetChanged()
  1127. if UserDefaultsRepository.smallGraphTreatments.value {
  1128. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  1129. BGChartFull.data?.notifyDataChanged()
  1130. BGChartFull.notifyDataSetChanged()
  1131. }
  1132. }
  1133. func updateNotes() {
  1134. var dataIndex = 11
  1135. BGChart.lineData?.dataSets[dataIndex].clear()
  1136. BGChartFull.lineData?.dataSets[dataIndex].clear()
  1137. let thisData = noteGraphData
  1138. for i in 0..<thisData.count{
  1139. // skip if outside of visible area
  1140. let graphHours = 24 * UserDefaultsRepository.downloadDays.value
  1141. if thisData[i].date < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
  1142. let value = ChartDataEntry(x: Double(thisData[i].date), y: Double(thisData[i].sgv), data: formatPillText(line1: thisData[i].note, time: thisData[i].date))
  1143. BGChart.data?.dataSets[dataIndex].addEntry(value)
  1144. if UserDefaultsRepository.smallGraphTreatments.value {
  1145. BGChartFull.data?.dataSets[dataIndex].addEntry(value)
  1146. }
  1147. }
  1148. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  1149. BGChart.data?.notifyDataChanged()
  1150. BGChart.notifyDataSetChanged()
  1151. if UserDefaultsRepository.smallGraphTreatments.value {
  1152. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  1153. BGChartFull.data?.notifyDataChanged()
  1154. BGChartFull.notifyDataSetChanged()
  1155. }
  1156. }
  1157. func createSmallBGGraph(){
  1158. let entries = bgData
  1159. var bgChartEntry = [ChartDataEntry]()
  1160. var colors = [NSUIColor]()
  1161. var maxBG: Float = UserDefaultsRepository.minBGScale.value
  1162. let lineBG = LineChartDataSet(entries:bgChartEntry, label: "")
  1163. lineBG.drawCirclesEnabled = false
  1164. //line2.setDrawHighlightIndicators(false)
  1165. lineBG.highlightEnabled = true
  1166. lineBG.drawHorizontalHighlightIndicatorEnabled = false
  1167. lineBG.drawVerticalHighlightIndicatorEnabled = false
  1168. lineBG.highlightColor = NSUIColor.label
  1169. lineBG.drawValuesEnabled = false
  1170. lineBG.lineWidth = 1.5
  1171. lineBG.axisDependency = YAxis.AxisDependency.right
  1172. // Setup Prediction line details
  1173. var predictionChartEntry = [ChartDataEntry]()
  1174. let linePrediction = LineChartDataSet(entries:predictionChartEntry, label: "")
  1175. linePrediction.drawCirclesEnabled = false
  1176. //line2.setDrawHighlightIndicators(false)
  1177. linePrediction.setColor(NSUIColor.systemPurple)
  1178. linePrediction.highlightEnabled = true
  1179. linePrediction.drawHorizontalHighlightIndicatorEnabled = false
  1180. linePrediction.drawVerticalHighlightIndicatorEnabled = false
  1181. linePrediction.highlightColor = NSUIColor.label
  1182. linePrediction.drawValuesEnabled = false
  1183. linePrediction.lineWidth = 1.5
  1184. linePrediction.axisDependency = YAxis.AxisDependency.right
  1185. // create Basal graph data
  1186. var chartEntry = [ChartDataEntry]()
  1187. var maxBasal = UserDefaultsRepository.minBasalScale.value
  1188. let lineBasal = LineChartDataSet(entries:chartEntry, label: "")
  1189. lineBasal.setDrawHighlightIndicators(false)
  1190. lineBasal.setColor(NSUIColor.systemBlue, alpha: 0.5)
  1191. lineBasal.lineWidth = 0
  1192. lineBasal.drawFilledEnabled = true
  1193. lineBasal.fillColor = NSUIColor.systemBlue
  1194. lineBasal.fillAlpha = 0.35
  1195. lineBasal.drawCirclesEnabled = false
  1196. lineBasal.axisDependency = YAxis.AxisDependency.left
  1197. lineBasal.highlightEnabled = false
  1198. lineBasal.drawValuesEnabled = false
  1199. lineBasal.fillFormatter = basalFillFormatter()
  1200. // Boluses
  1201. var chartEntryBolus = [ChartDataEntry]()
  1202. let lineBolus = LineChartDataSet(entries:chartEntryBolus, label: "")
  1203. lineBolus.circleRadius = 2
  1204. lineBolus.circleColors = [NSUIColor.systemBlue.withAlphaComponent(0.75)]
  1205. lineBolus.drawCircleHoleEnabled = false
  1206. lineBolus.setDrawHighlightIndicators(false)
  1207. lineBolus.setColor(NSUIColor.systemBlue, alpha: 1.0)
  1208. lineBolus.lineWidth = 0
  1209. lineBolus.axisDependency = YAxis.AxisDependency.right
  1210. lineBolus.valueFormatter = ChartYDataValueFormatter()
  1211. lineBolus.valueTextColor = NSUIColor.label
  1212. lineBolus.fillColor = NSUIColor.systemBlue
  1213. lineBolus.fillAlpha = 0.6
  1214. lineBolus.drawCirclesEnabled = true
  1215. lineBolus.drawFilledEnabled = false
  1216. lineBolus.drawValuesEnabled = false
  1217. lineBolus.highlightEnabled = false
  1218. // Carbs
  1219. var chartEntryCarbs = [ChartDataEntry]()
  1220. let lineCarbs = LineChartDataSet(entries:chartEntryCarbs, label: "")
  1221. lineCarbs.circleRadius = 2
  1222. lineCarbs.circleColors = [NSUIColor.systemOrange.withAlphaComponent(0.75)]
  1223. lineCarbs.drawCircleHoleEnabled = false
  1224. lineCarbs.setDrawHighlightIndicators(false)
  1225. lineCarbs.setColor(NSUIColor.systemBlue, alpha: 1.0)
  1226. lineCarbs.lineWidth = 0
  1227. lineCarbs.axisDependency = YAxis.AxisDependency.right
  1228. lineCarbs.valueFormatter = ChartYDataValueFormatter()
  1229. lineCarbs.valueTextColor = NSUIColor.label
  1230. lineCarbs.fillColor = NSUIColor.systemOrange
  1231. lineCarbs.fillAlpha = 0.6
  1232. lineCarbs.drawCirclesEnabled = true
  1233. lineCarbs.drawFilledEnabled = false
  1234. lineCarbs.drawValuesEnabled = false
  1235. lineCarbs.highlightEnabled = false
  1236. // create Scheduled Basal graph data
  1237. var chartBasalScheduledEntry = [ChartDataEntry]()
  1238. let lineBasalScheduled = LineChartDataSet(entries:chartBasalScheduledEntry, label: "")
  1239. lineBasalScheduled.setDrawHighlightIndicators(false)
  1240. lineBasalScheduled.setColor(NSUIColor.systemBlue, alpha: 0.8)
  1241. lineBasalScheduled.lineWidth = 0.5
  1242. lineBasalScheduled.drawFilledEnabled = false
  1243. lineBasalScheduled.drawCirclesEnabled = false
  1244. lineBasalScheduled.axisDependency = YAxis.AxisDependency.left
  1245. lineBasalScheduled.highlightEnabled = false
  1246. lineBasalScheduled.drawValuesEnabled = false
  1247. lineBasalScheduled.lineDashLengths = [2, 1]
  1248. // create Override graph data
  1249. var chartOverrideEntry = [ChartDataEntry]()
  1250. let lineOverride = LineChartDataSet(entries:chartOverrideEntry, label: "")
  1251. lineOverride.setDrawHighlightIndicators(false)
  1252. lineOverride.lineWidth = 0
  1253. lineOverride.drawFilledEnabled = true
  1254. lineOverride.fillFormatter = OverrideFillFormatter()
  1255. lineOverride.fillColor = NSUIColor.systemGreen
  1256. lineOverride.fillAlpha = 0.6
  1257. lineOverride.drawCirclesEnabled = false
  1258. lineOverride.axisDependency = YAxis.AxisDependency.right
  1259. lineOverride.highlightEnabled = true
  1260. lineOverride.drawValuesEnabled = false
  1261. // BG Check
  1262. var chartEntryBGCheck = [ChartDataEntry]()
  1263. let lineBGCheck = LineChartDataSet(entries:chartEntryBGCheck, label: "")
  1264. lineBGCheck.circleRadius = 2
  1265. lineBGCheck.circleColors = [NSUIColor.systemRed.withAlphaComponent(0.75)]
  1266. lineBGCheck.drawCircleHoleEnabled = false
  1267. lineBGCheck.setDrawHighlightIndicators(false)
  1268. lineBGCheck.setColor(NSUIColor.systemRed, alpha: 1.0)
  1269. lineBGCheck.drawCirclesEnabled = true
  1270. lineBGCheck.lineWidth = 0
  1271. lineBGCheck.highlightEnabled = false
  1272. lineBGCheck.axisDependency = YAxis.AxisDependency.right
  1273. lineBGCheck.valueFormatter = ChartYDataValueFormatter()
  1274. lineBGCheck.drawValuesEnabled = false
  1275. // Suspend Pump
  1276. var chartEntrySuspend = [ChartDataEntry]()
  1277. let lineSuspend = LineChartDataSet(entries:chartEntrySuspend, label: "")
  1278. lineSuspend.circleRadius = 2
  1279. lineSuspend.circleColors = [NSUIColor.systemTeal.withAlphaComponent(0.75)]
  1280. lineSuspend.drawCircleHoleEnabled = false
  1281. lineSuspend.setDrawHighlightIndicators(false)
  1282. lineSuspend.setColor(NSUIColor.systemGray2, alpha: 1.0)
  1283. lineSuspend.drawCirclesEnabled = true
  1284. lineSuspend.lineWidth = 0
  1285. lineSuspend.highlightEnabled = false
  1286. lineSuspend.axisDependency = YAxis.AxisDependency.right
  1287. lineSuspend.valueFormatter = ChartYDataValueFormatter()
  1288. lineSuspend.drawValuesEnabled = false
  1289. // Resume Pump
  1290. var chartEntryResume = [ChartDataEntry]()
  1291. let lineResume = LineChartDataSet(entries:chartEntryResume, label: "")
  1292. lineResume.circleRadius = 2
  1293. lineResume.circleColors = [NSUIColor.systemTeal.withAlphaComponent(0.75)]
  1294. lineResume.drawCircleHoleEnabled = false
  1295. lineResume.setDrawHighlightIndicators(false)
  1296. lineResume.setColor(NSUIColor.systemGray4, alpha: 1.0)
  1297. lineResume.drawCirclesEnabled = true
  1298. lineResume.lineWidth = 0
  1299. lineResume.highlightEnabled = false
  1300. lineResume.axisDependency = YAxis.AxisDependency.right
  1301. lineResume.valueFormatter = ChartYDataValueFormatter()
  1302. lineResume.drawValuesEnabled = false
  1303. // Sensor Start
  1304. var chartEntrySensor = [ChartDataEntry]()
  1305. let lineSensor = LineChartDataSet(entries:chartEntrySensor, label: "")
  1306. lineSensor.circleRadius = 2
  1307. lineSensor.circleColors = [NSUIColor.systemIndigo.withAlphaComponent(0.75)]
  1308. lineSensor.drawCircleHoleEnabled = false
  1309. lineSensor.setDrawHighlightIndicators(false)
  1310. lineSensor.setColor(NSUIColor.systemGray3, alpha: 1.0)
  1311. lineSensor.drawCirclesEnabled = true
  1312. lineSensor.lineWidth = 0
  1313. lineSensor.highlightEnabled = false
  1314. lineSensor.axisDependency = YAxis.AxisDependency.right
  1315. lineSensor.valueFormatter = ChartYDataValueFormatter()
  1316. lineSensor.drawValuesEnabled = false
  1317. // Notes
  1318. var chartEntryNote = [ChartDataEntry]()
  1319. let lineNote = LineChartDataSet(entries:chartEntryNote, label: "")
  1320. lineNote.circleRadius = 2
  1321. lineNote.circleColors = [NSUIColor.systemGray.withAlphaComponent(0.75)]
  1322. lineNote.drawCircleHoleEnabled = false
  1323. lineNote.setDrawHighlightIndicators(false)
  1324. lineNote.setColor(NSUIColor.systemGray3, alpha: 1.0)
  1325. lineNote.drawCirclesEnabled = true
  1326. lineNote.lineWidth = 0
  1327. lineNote.highlightEnabled = false
  1328. lineNote.axisDependency = YAxis.AxisDependency.right
  1329. lineNote.valueFormatter = ChartYDataValueFormatter()
  1330. lineNote.drawValuesEnabled = false
  1331. // Setup COB Prediction line details
  1332. var COBpredictionChartEntry = [ChartDataEntry]()
  1333. let COBlinePrediction = LineChartDataSet(entries:COBpredictionChartEntry, label: "")
  1334. COBlinePrediction.drawCirclesEnabled = false
  1335. COBlinePrediction.setColor(NSUIColor.systemPurple)
  1336. COBlinePrediction.highlightEnabled = true
  1337. COBlinePrediction.drawHorizontalHighlightIndicatorEnabled = false
  1338. COBlinePrediction.drawVerticalHighlightIndicatorEnabled = false
  1339. COBlinePrediction.highlightColor = NSUIColor.label
  1340. COBlinePrediction.drawValuesEnabled = false
  1341. COBlinePrediction.lineWidth = 1.5
  1342. COBlinePrediction.axisDependency = YAxis.AxisDependency.right
  1343. // Setup IOB Prediction line details
  1344. var IOBpredictionChartEntry = [ChartDataEntry]()
  1345. let IOBlinePrediction = LineChartDataSet(entries:IOBpredictionChartEntry, label: "")
  1346. IOBlinePrediction.drawCirclesEnabled = false
  1347. IOBlinePrediction.setColor(NSUIColor.systemPurple)
  1348. IOBlinePrediction.highlightEnabled = true
  1349. IOBlinePrediction.drawHorizontalHighlightIndicatorEnabled = false
  1350. IOBlinePrediction.drawVerticalHighlightIndicatorEnabled = false
  1351. IOBlinePrediction.highlightColor = NSUIColor.label
  1352. IOBlinePrediction.drawValuesEnabled = false
  1353. IOBlinePrediction.lineWidth = 1.5
  1354. IOBlinePrediction.axisDependency = YAxis.AxisDependency.right
  1355. // Setup UAM Prediction line details
  1356. var UAMpredictionChartEntry = [ChartDataEntry]()
  1357. let UAMlinePrediction = LineChartDataSet(entries:UAMpredictionChartEntry, label: "")
  1358. UAMlinePrediction.drawCirclesEnabled = false
  1359. UAMlinePrediction.setColor(NSUIColor.systemPurple)
  1360. UAMlinePrediction.highlightEnabled = true
  1361. UAMlinePrediction.drawHorizontalHighlightIndicatorEnabled = false
  1362. UAMlinePrediction.drawVerticalHighlightIndicatorEnabled = false
  1363. UAMlinePrediction.highlightColor = NSUIColor.label
  1364. UAMlinePrediction.drawValuesEnabled = false
  1365. UAMlinePrediction.lineWidth = 1.5
  1366. UAMlinePrediction.axisDependency = YAxis.AxisDependency.right
  1367. // Setup ZT Prediction line details
  1368. var ZTpredictionChartEntry = [ChartDataEntry]()
  1369. let ZTlinePrediction = LineChartDataSet(entries:ZTpredictionChartEntry, label: "")
  1370. ZTlinePrediction.drawCirclesEnabled = false
  1371. ZTlinePrediction.setColor(NSUIColor.systemPurple)
  1372. ZTlinePrediction.highlightEnabled = true
  1373. ZTlinePrediction.drawHorizontalHighlightIndicatorEnabled = false
  1374. ZTlinePrediction.drawVerticalHighlightIndicatorEnabled = false
  1375. ZTlinePrediction.highlightColor = NSUIColor.label
  1376. ZTlinePrediction.drawValuesEnabled = false
  1377. ZTlinePrediction.lineWidth = 1.5
  1378. ZTlinePrediction.axisDependency = YAxis.AxisDependency.right
  1379. // SMB
  1380. var chartEntrySmb = [ChartDataEntry]()
  1381. let lineSmb = LineChartDataSet(entries:chartEntrySmb, label: "")
  1382. lineSmb.circleRadius = 2
  1383. lineSmb.circleColors = [NSUIColor.systemBlue.withAlphaComponent(0.75)]
  1384. lineSmb.drawCircleHoleEnabled = false
  1385. lineSmb.setDrawHighlightIndicators(false)
  1386. lineSmb.setColor(NSUIColor.systemBlue, alpha: 1.0)
  1387. lineSmb.lineWidth = 0
  1388. lineSmb.axisDependency = YAxis.AxisDependency.right
  1389. lineSmb.valueFormatter = ChartYDataValueFormatter()
  1390. lineSmb.valueTextColor = NSUIColor.label
  1391. lineSmb.fillColor = NSUIColor.systemBlue
  1392. lineSmb.fillAlpha = 0.6
  1393. lineSmb.drawCirclesEnabled = true
  1394. lineSmb.drawFilledEnabled = false
  1395. lineSmb.drawValuesEnabled = false
  1396. lineSmb.highlightEnabled = false
  1397. // Temp Target graph data
  1398. let chartTempTargetEntry = [ChartDataEntry]()
  1399. let lineTempTarget = LineChartDataSet(entries:chartTempTargetEntry, label: "")
  1400. lineTempTarget.setDrawHighlightIndicators(false)
  1401. lineTempTarget.lineWidth = 0
  1402. lineTempTarget.drawFilledEnabled = false
  1403. lineTempTarget.fillColor = NSUIColor.systemPurple
  1404. lineTempTarget.fillAlpha = 0.6
  1405. lineTempTarget.drawCirclesEnabled = false
  1406. lineTempTarget.axisDependency = YAxis.AxisDependency.right
  1407. lineTempTarget.highlightEnabled = true
  1408. lineTempTarget.drawValuesEnabled = false
  1409. // Setup the chart data of all lines
  1410. let data = LineChartData()
  1411. data.append(lineBG) // Dataset 0
  1412. data.append(linePrediction) // Dataset 1
  1413. data.append(lineBasal) // Dataset 2
  1414. data.append(lineBolus) // Dataset 3
  1415. data.append(lineCarbs) // Dataset 4
  1416. data.append(lineBasalScheduled) // Dataset 5
  1417. data.append(lineOverride) // Dataset 6
  1418. data.append(lineBGCheck) // Dataset 7
  1419. data.append(lineSuspend) // Dataset 8
  1420. data.append(lineResume) // Dataset 9
  1421. data.append(lineSensor) // Dataset 10
  1422. data.append(lineNote) // Dataset 11
  1423. data.append(ZTlinePrediction) // Dataset 12
  1424. data.append(IOBlinePrediction) // Dataset 13
  1425. data.append(COBlinePrediction) // Dataset 14
  1426. data.append(UAMlinePrediction) // Dataset 15
  1427. data.append(lineSmb) // Dataset 16
  1428. data.append(lineTempTarget)
  1429. BGChartFull.highlightPerDragEnabled = true
  1430. BGChartFull.leftAxis.enabled = false
  1431. BGChartFull.leftAxis.axisMaximum = maxBasal
  1432. BGChartFull.leftAxis.axisMinimum = 0
  1433. BGChartFull.rightAxis.enabled = false
  1434. BGChartFull.rightAxis.axisMinimum = 0.0
  1435. BGChartFull.rightAxis.axisMaximum = Double(maxBG)
  1436. BGChartFull.xAxis.drawLabelsEnabled = false
  1437. BGChartFull.xAxis.drawGridLinesEnabled = false
  1438. BGChartFull.xAxis.drawAxisLineEnabled = false
  1439. BGChartFull.legend.enabled = false
  1440. BGChartFull.scaleYEnabled = false
  1441. BGChartFull.scaleXEnabled = false
  1442. BGChartFull.drawGridBackgroundEnabled = false
  1443. BGChartFull.data = data
  1444. }
  1445. func updateOverrideGraph() {
  1446. var dataIndex = 6
  1447. var yTop: Double = Double(calculateMaxBgGraphValue() - 5)
  1448. var yBottom: Double = Double(calculateMaxBgGraphValue() - 25)
  1449. var chart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  1450. var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  1451. chart.clear()
  1452. smallChart.clear()
  1453. let thisData = overrideGraphData
  1454. var colors = [NSUIColor]()
  1455. for i in 0..<thisData.count{
  1456. let thisItem = thisData[i]
  1457. let multiplier = thisItem.insulNeedsScaleFactor as! Double * 100.0
  1458. var labelText = thisItem.reason + "\r\n"
  1459. labelText += String(Int(thisItem.insulNeedsScaleFactor * 100)) + "% "
  1460. if thisItem.correctionRange.count == 2 {
  1461. labelText += String(thisItem.correctionRange[0]) + "-" + String(thisItem.correctionRange[1])
  1462. }
  1463. if thisItem.enteredBy.count > 0 {
  1464. labelText += "\r\nEntered By: " + thisItem.enteredBy
  1465. }
  1466. // Start Dot
  1467. // Shift dots 30 seconds to create an empty 0 space between consecutive temps
  1468. let preStartDot = ChartDataEntry(x: Double(thisItem.date), y: yBottom, data: labelText)
  1469. BGChart.data?.dataSets[dataIndex].addEntry(preStartDot)
  1470. if UserDefaultsRepository.smallGraphTreatments.value {
  1471. BGChartFull.data?.dataSets[dataIndex].addEntry(preStartDot)
  1472. }
  1473. let startDot = ChartDataEntry(x: Double(thisItem.date + 1), y: yTop, data: labelText)
  1474. BGChart.data?.dataSets[dataIndex].addEntry(startDot)
  1475. if UserDefaultsRepository.smallGraphTreatments.value {
  1476. BGChartFull.data?.dataSets[dataIndex].addEntry(startDot)
  1477. }
  1478. // End Dot
  1479. let endDot = ChartDataEntry(x: Double(thisItem.endDate - 2), y: yTop, data: labelText)
  1480. BGChart.data?.dataSets[dataIndex].addEntry(endDot)
  1481. if UserDefaultsRepository.smallGraphTreatments.value {
  1482. BGChartFull.data?.dataSets[dataIndex].addEntry(endDot)
  1483. }
  1484. // Post end dot
  1485. let postEndDot = ChartDataEntry(x: Double(thisItem.endDate - 1), y: yBottom, data: labelText)
  1486. BGChart.data?.dataSets[dataIndex].addEntry(postEndDot)
  1487. if UserDefaultsRepository.smallGraphTreatments.value {
  1488. BGChartFull.data?.dataSets[dataIndex].addEntry(postEndDot)
  1489. }
  1490. }
  1491. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  1492. BGChart.data?.notifyDataChanged()
  1493. BGChart.notifyDataSetChanged()
  1494. if UserDefaultsRepository.smallGraphTreatments.value {
  1495. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  1496. BGChartFull.data?.notifyDataChanged()
  1497. BGChartFull.notifyDataSetChanged()
  1498. }
  1499. }
  1500. func getChartDataSets(for index: GraphDataIndex) -> (chart: LineChartDataSet?, smallChart: LineChartDataSet?) {
  1501. guard let chart = BGChart.lineData,
  1502. index.rawValue < chart.dataSets.count,
  1503. let smallChartData = BGChartFull.lineData,
  1504. index.rawValue < smallChartData.dataSets.count else {
  1505. print("Warning: Invalid GraphDataIndex \(index.description) or lineData is nil.")
  1506. return (nil, nil)
  1507. }
  1508. let chartDataSet = chart.dataSets[index.rawValue] as? LineChartDataSet
  1509. let smallChartDataSet = smallChartData.dataSets[index.rawValue] as? LineChartDataSet
  1510. return (chartDataSet, smallChartDataSet)
  1511. }
  1512. func addEntryToCharts(entry: ChartDataEntry, chart: LineChartDataSet, smallChart: LineChartDataSet?) {
  1513. chart.addEntry(entry)
  1514. if UserDefaultsRepository.smallGraphTreatments.value, let smallChart = smallChart {
  1515. smallChart.addEntry(entry)
  1516. }
  1517. }
  1518. func updateTempTargetGraph() {
  1519. let dataIndex = GraphDataIndex.tempTarget.rawValue
  1520. guard let chartData = BGChart.lineData,
  1521. chartData.dataSets.count > dataIndex,
  1522. let mainChartDataSet = chartData.dataSets[dataIndex] as? LineChartDataSet else {
  1523. print("Error: Could not retrieve temp target datasets.")
  1524. return
  1525. }
  1526. mainChartDataSet.clear()
  1527. var smallChartDataSet: LineChartDataSet?
  1528. if UserDefaultsRepository.smallGraphTreatments.value,
  1529. let smallChartData = BGChartFull.lineData,
  1530. smallChartData.dataSets.count > dataIndex,
  1531. let smallDataSet = smallChartData.dataSets[dataIndex] as? LineChartDataSet {
  1532. smallChartDataSet = smallDataSet
  1533. smallChartDataSet?.clear()
  1534. }
  1535. let thisData = tempTargetGraphData
  1536. for tempTarget in thisData {
  1537. let xStart = tempTarget.date
  1538. let xEnd = tempTarget.endDate
  1539. let yCenter = Double(tempTarget.correctionRange[0])
  1540. let yTop = yCenter + 5.0
  1541. let yBottom = yCenter - 5.0
  1542. let entry = TempTargetChartDataEntry(
  1543. xStart: xStart,
  1544. xEnd: xEnd,
  1545. yTop: yTop,
  1546. yBottom: yBottom,
  1547. data: nil
  1548. )
  1549. mainChartDataSet.addEntry(entry)
  1550. if let smallDataSet = smallChartDataSet {
  1551. smallDataSet.addEntry(entry)
  1552. }
  1553. }
  1554. BGChart.data?.notifyDataChanged()
  1555. BGChart.notifyDataSetChanged()
  1556. if let smallDataSet = smallChartDataSet {
  1557. let tempTargetRendererSmall = TempTargetRenderer(
  1558. dataProvider: BGChartFull,
  1559. animator: BGChartFull.chartAnimator,
  1560. viewPortHandler: BGChartFull.viewPortHandler,
  1561. tempTargetDataSetIndex: dataIndex
  1562. )
  1563. BGChartFull.renderer = tempTargetRendererSmall
  1564. BGChartFull.data?.notifyDataChanged()
  1565. BGChartFull.notifyDataSetChanged()
  1566. }
  1567. }
  1568. func wrapText(_ text: String, maxLineLength: Int) -> String {
  1569. var lines: [String] = []
  1570. var currentLine = ""
  1571. let words = text.components(separatedBy: .whitespacesAndNewlines)
  1572. for word in words {
  1573. if word.count > maxLineLength {
  1574. var wordToProcess = word
  1575. while !wordToProcess.isEmpty {
  1576. let spaceCount = currentLine.isEmpty ? 0 : 1
  1577. let availableSpace = maxLineLength - (currentLine.count + spaceCount)
  1578. if availableSpace <= 0 {
  1579. if !currentLine.isEmpty {
  1580. lines.append(currentLine)
  1581. currentLine = ""
  1582. }
  1583. continue
  1584. }
  1585. let takeCount = min(wordToProcess.count, availableSpace)
  1586. if takeCount <= 0 {
  1587. if !currentLine.isEmpty {
  1588. lines.append(currentLine)
  1589. currentLine = ""
  1590. }
  1591. continue
  1592. }
  1593. let index = wordToProcess.index(wordToProcess.startIndex, offsetBy: takeCount)
  1594. let substring = wordToProcess[..<index]
  1595. if currentLine.isEmpty {
  1596. currentLine = String(substring)
  1597. } else {
  1598. currentLine += " " + substring
  1599. }
  1600. wordToProcess = String(wordToProcess[index...])
  1601. if currentLine.count >= maxLineLength {
  1602. lines.append(currentLine)
  1603. currentLine = ""
  1604. }
  1605. }
  1606. } else {
  1607. let spaceNeeded = currentLine.isEmpty ? 0 : 1
  1608. if currentLine.count + spaceNeeded + word.count > maxLineLength {
  1609. lines.append(currentLine)
  1610. currentLine = word
  1611. } else {
  1612. if currentLine.isEmpty {
  1613. currentLine = word
  1614. } else {
  1615. currentLine += " " + word
  1616. }
  1617. }
  1618. }
  1619. }
  1620. if !currentLine.isEmpty {
  1621. lines.append(currentLine)
  1622. }
  1623. return lines.joined(separator: "\r\n")
  1624. }
  1625. func formatPillText(line1: String, time: TimeInterval, line2: String? = nil) -> String {
  1626. let dateFormatter = DateFormatter()
  1627. if dateTimeUtils.is24Hour() {
  1628. dateFormatter.setLocalizedDateFormatFromTemplate("HH:mm")
  1629. } else {
  1630. dateFormatter.setLocalizedDateFormatFromTemplate("hh:mm")
  1631. }
  1632. let wrappedLine1 = wrapText(line1, maxLineLength: 40)
  1633. let date = Date(timeIntervalSince1970: time)
  1634. let formattedDate = dateFormatter.string(from: date)
  1635. if let line2 = line2 {
  1636. return wrappedLine1 + "\r\n" + line2 + "\r\n" + formattedDate
  1637. } else {
  1638. return wrappedLine1 + "\r\n" + formattedDate
  1639. }
  1640. }
  1641. func updatePredictionGraphGeneric(
  1642. dataIndex: Int,
  1643. predictionData: [ShareGlucoseData],
  1644. chartLabel: String,
  1645. color: UIColor
  1646. ) {
  1647. let mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  1648. let smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  1649. mainChart.clear()
  1650. smallChart.clear()
  1651. var colors = [NSUIColor]()
  1652. let maxBGOffset: Float = 20
  1653. for i in 0..<predictionData.count {
  1654. let predictionVal = Double(predictionData[i].sgv)
  1655. if Float(predictionVal) > topPredictionBG - maxBGOffset {
  1656. topPredictionBG = Float(predictionVal) + maxBGOffset
  1657. }
  1658. if i == 0 {
  1659. if UserDefaultsRepository.showDots.value {
  1660. colors.append((color).withAlphaComponent(0.0))
  1661. } else {
  1662. colors.append((color).withAlphaComponent(1.0))
  1663. }
  1664. } else {
  1665. colors.append(color)
  1666. }
  1667. let value = ChartDataEntry(
  1668. x: predictionData[i].date,
  1669. y: predictionVal,
  1670. data: formatPillText(
  1671. line1: chartLabel,
  1672. time: predictionData[i].date,
  1673. line2: Localizer.toDisplayUnits(String(predictionVal))
  1674. )
  1675. )
  1676. mainChart.addEntry(value)
  1677. smallChart.addEntry(value)
  1678. }
  1679. smallChart.circleColors.removeAll()
  1680. smallChart.colors.removeAll()
  1681. mainChart.colors.removeAll()
  1682. mainChart.circleColors.removeAll()
  1683. if colors.count > 0 {
  1684. for color in colors {
  1685. mainChart.addColor(color)
  1686. mainChart.circleColors.append(color)
  1687. smallChart.addColor(color)
  1688. smallChart.circleColors.append(color)
  1689. }
  1690. }
  1691. BGChart.rightAxis.axisMaximum = Double(calculateMaxBgGraphValue())
  1692. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  1693. BGChart.data?.notifyDataChanged()
  1694. BGChart.notifyDataSetChanged()
  1695. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  1696. BGChartFull.data?.notifyDataChanged()
  1697. BGChartFull.notifyDataSetChanged()
  1698. }
  1699. }