Graphs.swift 82 KB

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