| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- //
- // IOBChart.swift
- // LoopUI
- //
- // Copyright © 2019 LoopKit Authors. All rights reserved.
- //
- import Foundation
- import LoopKit
- import SwiftCharts
- import HealthKit
- import UIKit
- public class IOBChart: ChartProviding {
- static let chartUnit = HKUnit.internationalUnit()
- public init() {
- }
- /// The chart points for IOB
- public private(set) var iobPoints: [ChartPoint] = [] {
- didSet {
- if let lastDate = iobPoints.last?.x as? ChartAxisValueDate {
- endDate = lastDate.date
- }
- }
- }
- /// The minimum range to display for insulin values.
- private let iobDisplayRangePoints: [ChartPoint] = [0, 1].map {
- return ChartPoint(
- x: ChartAxisValue(scalar: 0),
- y: ChartAxisValueInt($0)
- )
- }
- public private(set) var endDate: Date?
- private var iobChartCache: ChartPointsTouchHighlightLayerViewCache?
- }
- public extension IOBChart {
- func didReceiveMemoryWarning() {
- iobPoints = []
- iobChartCache = nil
- }
- func generate(withFrame frame: CGRect, xAxisModel: ChartAxisModel, xAxisValues: [ChartAxisValue], axisLabelSettings: ChartLabelSettings, guideLinesLayerSettings: ChartGuideLinesLayerSettings, colors: ChartColorPalette, chartSettings: ChartSettings, labelsWidthY: CGFloat, gestureRecognizer: UIGestureRecognizer?, traitCollection: UITraitCollection) -> Chart
- {
- let yAxisValues = ChartAxisValuesStaticGenerator.generateYAxisValuesWithChartPoints(iobPoints + iobDisplayRangePoints, minSegmentCount: 2, maxSegmentCount: 3, multiple: 0.5, axisValueGenerator: { ChartAxisValueDouble($0, labelSettings: axisLabelSettings) }, addPaddingSegmentIfEdge: false)
- let yAxisModel = ChartAxisModel(axisValues: yAxisValues, lineColor: colors.axisLine, labelSpaceReservationMode: .fixed(labelsWidthY))
- let coordsSpace = ChartCoordsSpaceLeftBottomSingleAxis(chartSettings: chartSettings, chartFrame: frame, xModel: xAxisModel, yModel: yAxisModel)
- let (xAxisLayer, yAxisLayer, innerFrame) = (coordsSpace.xAxisLayer, coordsSpace.yAxisLayer, coordsSpace.chartInnerFrame)
- // The IOB area
- let lineModel = ChartLineModel(chartPoints: iobPoints, lineColor: colors.insulinTint, lineWidth: 2, animDuration: 0, animDelay: 0)
- let iobLine = ChartPointsLineLayer(xAxis: xAxisLayer.axis, yAxis: yAxisLayer.axis, lineModels: [lineModel])
- let iobArea = ChartPointsFillsLayer(xAxis: xAxisLayer.axis, yAxis: yAxisLayer.axis, fills: [ChartPointsFill(chartPoints: iobPoints, fillColor: colors.insulinTint.withAlphaComponent(0.5))])
- // Grid lines
- let gridLayer = ChartGuideLinesForValuesLayer(xAxis: xAxisLayer.axis, yAxis: yAxisLayer.axis, settings: guideLinesLayerSettings, axisValuesX: Array(xAxisValues.dropFirst().dropLast()), axisValuesY: yAxisValues)
- // 0-line
- let dummyZeroChartPoint = ChartPoint(x: ChartAxisValueDouble(0), y: ChartAxisValueDouble(0))
- let zeroGuidelineLayer = ChartPointsViewsLayer(xAxis: xAxisLayer.axis, yAxis: yAxisLayer.axis, chartPoints: [dummyZeroChartPoint], viewGenerator: {(chartPointModel, layer, chart) -> UIView? in
- let width: CGFloat = 0.5
- let viewFrame = CGRect(x: chart.contentView.bounds.minX, y: chartPointModel.screenLoc.y - width / 2, width: chart.contentView.bounds.size.width, height: width)
- let v = UIView(frame: viewFrame)
- v.layer.backgroundColor = colors.insulinTint.cgColor
- return v
- })
- if gestureRecognizer != nil {
- iobChartCache = ChartPointsTouchHighlightLayerViewCache(
- xAxisLayer: xAxisLayer,
- yAxisLayer: yAxisLayer,
- axisLabelSettings: axisLabelSettings,
- chartPoints: iobPoints,
- tintColor: colors.insulinTint,
- gestureRecognizer: gestureRecognizer
- )
- }
- let layers: [ChartLayer?] = [
- gridLayer,
- xAxisLayer,
- yAxisLayer,
- zeroGuidelineLayer,
- iobChartCache?.highlightLayer,
- iobArea,
- iobLine,
- ]
- return Chart(frame: frame, innerFrame: innerFrame, settings: chartSettings, layers: layers.compactMap { $0 })
- }
- }
- public extension IOBChart {
- func setIOBValues(_ iobValues: [InsulinValue]) {
- let dateFormatter = DateFormatter(timeStyle: .short)
- let doseFormatter = NumberFormatter.dose
- iobPoints = iobValues.map {
- return ChartPoint(
- x: ChartAxisValueDate(date: $0.startDate, formatter: dateFormatter),
- y: ChartAxisValueDoubleUnit($0.value, unitString: Self.chartUnit.shortLocalizedUnitString(), formatter: doseFormatter)
- )
- }
- }
- }
|