Graphs.swift 81 KB

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