// // Graphs.swift // LoopFollow // // Created by Jon Fawcett on 6/16/20. // Copyright © 2020 Jon Fawcett. All rights reserved. // import Foundation import Charts import UIKit let ScaleXMax:Float = 150.0 extension MainViewController { func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) { if chartView == BGChartFull { BGChart.moveViewToX(entry.x) } } func chartTranslated(_ chartView: ChartViewBase, dX: CGFloat, dY: CGFloat) { if chartView == BGChart { let currentMatrix = chartView.viewPortHandler.touchMatrix //BGChartFull.viewPortHandler.refresh(newMatrix: currentMatrix, chart: BGChartFull, invalidate: true) //BGChartFull.highlightValue(x: Double(currentMatrix.tx), y: Double(currentMatrix.ty), dataSetIndex: 0) } } func chartScaled(_ chartView: ChartViewBase, scaleX: CGFloat, scaleY: CGFloat) { print("Chart Scaled: \(BGChart.scaleX), \(BGChart.scaleY)") // dont store huge values var scale: Float = Float(BGChart.scaleX) if(scale > ScaleXMax ) { scale = ScaleXMax } UserDefaultsRepository.chartScaleX.value = Float(scale) } func createGraph(){ self.BGChart.clear() // Create the BG Graph Data let entries = bgData var bgChartEntry = [ChartDataEntry]() var colors = [NSUIColor]() var maxBG: Float = UserDefaultsRepository.minBGScale.value // Setup BG line details let lineBG = LineChartDataSet(entries:bgChartEntry, label: "") lineBG.circleRadius = 3 lineBG.circleColors = [NSUIColor.systemGreen] lineBG.drawCircleHoleEnabled = false lineBG.axisDependency = YAxis.AxisDependency.right lineBG.highlightEnabled = true lineBG.drawValuesEnabled = false if UserDefaultsRepository.showLines.value { lineBG.lineWidth = 2 } else { lineBG.lineWidth = 0 } if UserDefaultsRepository.showDots.value { lineBG.drawCirclesEnabled = true } else { lineBG.drawCirclesEnabled = false } lineBG.setDrawHighlightIndicators(false) lineBG.valueFont.withSize(50) // Setup Prediction line details var predictionChartEntry = [ChartDataEntry]() let linePrediction = LineChartDataSet(entries:predictionChartEntry, label: "") linePrediction.circleRadius = 3 linePrediction.circleColors = [NSUIColor.systemPurple] linePrediction.colors = [NSUIColor.systemPurple] linePrediction.drawCircleHoleEnabled = false linePrediction.axisDependency = YAxis.AxisDependency.right linePrediction.highlightEnabled = true linePrediction.drawValuesEnabled = false if UserDefaultsRepository.showLines.value { linePrediction.lineWidth = 2 } else { linePrediction.lineWidth = 0 } if UserDefaultsRepository.showDots.value { linePrediction.drawCirclesEnabled = true } else { linePrediction.drawCirclesEnabled = false } linePrediction.setDrawHighlightIndicators(false) linePrediction.valueFont.withSize(50) // create Basal graph data var chartEntry = [ChartDataEntry]() var maxBasal = UserDefaultsRepository.minBasalScale.value let lineBasal = LineChartDataSet(entries:chartEntry, label: "") lineBasal.setDrawHighlightIndicators(false) lineBasal.setColor(NSUIColor.systemBlue, alpha: 0.5) lineBasal.lineWidth = 0 lineBasal.drawFilledEnabled = true lineBasal.fillColor = NSUIColor.systemBlue.withAlphaComponent(0.8) lineBasal.drawCirclesEnabled = false lineBasal.axisDependency = YAxis.AxisDependency.left lineBasal.highlightEnabled = true lineBasal.drawValuesEnabled = false // Boluses var chartEntryBolus = [ChartDataEntry]() let lineBolus = LineChartDataSet(entries:chartEntryBolus, label: "") lineBolus.circleRadius = 7 lineBolus.circleColors = [NSUIColor.systemBlue.withAlphaComponent(0.75)] lineBolus.drawCircleHoleEnabled = false lineBolus.setDrawHighlightIndicators(false) lineBolus.setColor(NSUIColor.systemBlue, alpha: 1.0) lineBolus.drawCirclesEnabled = true lineBolus.lineWidth = 0 lineBolus.highlightEnabled = false lineBolus.axisDependency = YAxis.AxisDependency.right lineBolus.valueFormatter = ChartYDataValueFormatter() lineBolus.drawValuesEnabled = true lineBolus.valueTextColor = NSUIColor.label // Carbs var chartEntryCarbs = [ChartDataEntry]() let lineCarbs = LineChartDataSet(entries:chartEntryCarbs, label: "") lineCarbs.circleRadius = 7 lineCarbs.circleColors = [NSUIColor.systemOrange.withAlphaComponent(0.75)] lineCarbs.drawCircleHoleEnabled = false lineCarbs.setDrawHighlightIndicators(false) lineCarbs.setColor(NSUIColor.systemBlue, alpha: 1.0) lineCarbs.drawCirclesEnabled = true lineCarbs.lineWidth = 0 lineCarbs.highlightEnabled = false lineCarbs.axisDependency = YAxis.AxisDependency.right lineCarbs.valueFormatter = ChartYDataValueFormatter() lineCarbs.drawValuesEnabled = true lineCarbs.valueTextColor = NSUIColor.label // create Scheduled Basal graph data var chartBasalScheduledEntry = [ChartDataEntry]() let lineBasalScheduled = LineChartDataSet(entries:chartBasalScheduledEntry, label: "") lineBasalScheduled.setDrawHighlightIndicators(false) lineBasalScheduled.setColor(NSUIColor.systemBlue, alpha: 0.8) lineBasalScheduled.lineWidth = 2 lineBasalScheduled.drawFilledEnabled = false lineBasalScheduled.drawCirclesEnabled = false lineBasalScheduled.axisDependency = YAxis.AxisDependency.left lineBasalScheduled.highlightEnabled = false lineBasalScheduled.drawValuesEnabled = false lineBasalScheduled.lineDashLengths = [10.0, 5.0] // create Override graph data var chartOverrideEntry = [ChartDataEntry]() let lineOverride = LineChartDataSet(entries:chartOverrideEntry, label: "") lineOverride.setDrawHighlightIndicators(false) lineOverride.setColor(NSUIColor.systemTeal, alpha: 0.8 ) lineOverride.lineWidth = 10 lineOverride.drawFilledEnabled = false lineOverride.drawCirclesEnabled = false lineOverride.axisDependency = YAxis.AxisDependency.right lineOverride.highlightEnabled = true lineOverride.drawValuesEnabled = false // Setup the chart data of all lines let data = LineChartData() data.addDataSet(lineBG) // Dataset 0 data.addDataSet(linePrediction) // Dataset 1 data.addDataSet(lineBasal) // Dataset 2 data.addDataSet(lineBolus) // Dataset 3 data.addDataSet(lineCarbs) // Dataset 4 data.addDataSet(lineBasalScheduled) // Dataset 5 data.addDataSet(lineOverride) // Dataset 6 data.setValueFont(UIFont.systemFont(ofSize: 12)) // Add marker popups for bolus and carbs let marker = PillMarker(color: .secondarySystemBackground, font: UIFont.boldSystemFont(ofSize: 14), textColor: .label) BGChart.marker = marker // Clear limit lines so they don't add multiples when changing the settings BGChart.rightAxis.removeAllLimitLines() //Add lower red line based on low alert value let ll = ChartLimitLine() ll.limit = Double(UserDefaultsRepository.lowLine.value) ll.lineColor = NSUIColor.systemRed.withAlphaComponent(0.5) BGChart.rightAxis.addLimitLine(ll) //Add upper yellow line based on low alert value let ul = ChartLimitLine() ul.limit = Double(UserDefaultsRepository.highLine.value) ul.lineColor = NSUIColor.systemYellow.withAlphaComponent(0.5) BGChart.rightAxis.addLimitLine(ul) // Setup the main graph overall details BGChart.xAxis.valueFormatter = ChartXValueFormatter() BGChart.xAxis.granularity = 1800 BGChart.xAxis.labelTextColor = NSUIColor.label BGChart.xAxis.labelPosition = XAxis.LabelPosition.bottom BGChart.xAxis.drawGridLinesEnabled = false BGChart.leftAxis.enabled = true BGChart.leftAxis.labelPosition = YAxis.LabelPosition.insideChart BGChart.leftAxis.axisMaximum = maxBasal BGChart.leftAxis.axisMinimum = 0.0 BGChart.leftAxis.drawGridLinesEnabled = false BGChart.rightAxis.labelTextColor = NSUIColor.label BGChart.rightAxis.labelPosition = YAxis.LabelPosition.insideChart BGChart.rightAxis.axisMinimum = Double(UserDefaultsRepository.minBGValue.value) BGChart.rightAxis.axisMaximum = Double(maxBG) BGChart.rightAxis.gridLineDashLengths = [5.0, 5.0] BGChart.rightAxis.valueFormatter = ChartYMMOLValueFormatter() BGChart.legend.enabled = false BGChart.scaleYEnabled = false BGChart.drawGridBackgroundEnabled = false //BGChart.gridBackgroundColor = NSUIColor.secondarySystemBackground BGChart.data = data BGChart.setExtraOffsets(left: 10, top: 10, right: 10, bottom: 10) } func updateBGGraphSettings() { let dataIndex = 0 let dataIndexPrediction = 1 let lineBG = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet let linePrediction = BGChart.lineData!.dataSets[dataIndexPrediction] as! LineChartDataSet if UserDefaultsRepository.showLines.value { lineBG.lineWidth = 2 linePrediction.lineWidth = 2 } else { lineBG.lineWidth = 0 linePrediction.lineWidth = 0 } if UserDefaultsRepository.showDots.value { lineBG.drawCirclesEnabled = true linePrediction.drawCirclesEnabled = true } else { lineBG.drawCirclesEnabled = false linePrediction.drawCirclesEnabled = false } BGChart.rightAxis.axisMinimum = Double(UserDefaultsRepository.minBGValue.value) // Clear limit lines so they don't add multiples when changing the settings BGChart.rightAxis.removeAllLimitLines() //Add lower red line based on low alert value let ll = ChartLimitLine() ll.limit = Double(UserDefaultsRepository.lowLine.value) ll.lineColor = NSUIColor.systemRed.withAlphaComponent(0.5) BGChart.rightAxis.addLimitLine(ll) //Add upper yellow line based on low alert value let ul = ChartLimitLine() ul.limit = Double(UserDefaultsRepository.highLine.value) ul.lineColor = NSUIColor.systemYellow.withAlphaComponent(0.5) BGChart.rightAxis.addLimitLine(ul) BGChart.data?.dataSets[dataIndex].notifyDataSetChanged() BGChart.data?.notifyDataChanged() BGChart.notifyDataSetChanged() } func updateBGGraph() { let dataIndex = 0 let entries = bgData var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet mainChart.clear() smallChart.clear() var maxBG = UserDefaultsRepository.minBGScale.value var maxBGOffset: Float = 0.0 if UserDefaultsRepository.offsetCarbsBolus.value { maxBGOffset = 40.0 } var colors = [NSUIColor]() for i in 0.. maxBG - maxBGOffset { maxBG = Float(entries[i].sgv) + maxBGOffset } let value = ChartDataEntry(x: Double(entries[i].date), y: Double(entries[i].sgv)) mainChart.addEntry(value) smallChart.addEntry(value) if Double(entries[i].sgv) >= Double(UserDefaultsRepository.highLine.value) { colors.append(NSUIColor.systemYellow) } else if Double(entries[i].sgv) <= Double(UserDefaultsRepository.lowLine.value) { colors.append(NSUIColor.systemRed) } else { colors.append(NSUIColor.systemGreen) } } // Set Colors let lineBG = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet let lineBGSmall = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet lineBG.colors.removeAll() lineBG.circleColors.removeAll() lineBGSmall.colors.removeAll() lineBGSmall.circleColors.removeAll() if colors.count > 0 { if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Graph: colors") } for i in 0.. 18 ) { scaleX = 18 UserDefaultsRepository.chartScaleX.value = 18 } BGChart.zoom(scaleX: scaleX, scaleY: 1, x: 1, y: 1) firstGraphLoad = false } if BGChart.chartXMax > dateTimeUtils.getNowTimeIntervalUTC() { BGChart.moveViewToAnimated(xValue: dateTimeUtils.getNowTimeIntervalUTC() - (BGChart.visibleXRange * 0.7), yValue: 0.0, axis: .right, duration: 1, easingOption: .easeInBack) } } func updatePredictionGraph() { let dataIndex = 1 var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet mainChart.clear() smallChart.clear() if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Graph: print prediction") } var colors = [NSUIColor]() for i in 0.. 400 { predictionVal = 400 colors.append(NSUIColor.systemYellow) } else if predictionVal < 0 { predictionVal = 0 colors.append(NSUIColor.systemRed) } else { colors.append(NSUIColor.systemPurple) } let value = ChartDataEntry(x: predictionData[i].date, y: predictionVal) mainChart.addEntry(value) smallChart.addEntry(value) } smallChart.circleColors.removeAll() smallChart.colors.removeAll() mainChart.colors.removeAll() mainChart.circleColors.removeAll() if colors.count > 0 { if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Graph: prediction colors") } for i in 0.. maxBasal { maxBasal = basalData[i].basalRate } } BGChart.leftAxis.axisMaximum = maxBasal BGChart.data?.dataSets[dataIndex].notifyDataSetChanged() BGChart.data?.notifyDataChanged() BGChart.notifyDataSetChanged() } func updateBasalScheduledGraph() { var dataIndex = 5 BGChart.lineData?.dataSets[dataIndex].clear() for i in 0..= overrideData.count - 2 { colors.append(NSUIColor.systemGreen) } else { colors.append(NSUIColor.systemGray.withAlphaComponent(CGFloat(overrideData[i].value / 2))) } } // Set Colors let line = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet line.colors.removeAll() line.circleColors.removeAll() if colors.count > 0 { for i in 0..