forked from LoopKit/LoopKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChartPoint.swift
More file actions
144 lines (118 loc) · 5.91 KB
/
ChartPoint.swift
File metadata and controls
144 lines (118 loc) · 5.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//
// ChartPoint.swift
// Naterade
//
// Created by Nathan Racklyeft on 2/19/16.
// Copyright © 2016 Nathan Racklyeft. All rights reserved.
//
import Foundation
import HealthKit
import LoopKit
import SwiftCharts
struct TargetChartBar {
let points: [ChartPoint]
let isOverride: Bool
}
extension ChartPoint {
static func barsForGlucoseRangeSchedule(_ glucoseRangeSchedule: GlucoseRangeSchedule, unit: HKUnit, xAxisValues: [ChartAxisValue], considering potentialOverride: TemporaryScheduleOverride? = nil) -> [TargetChartBar] {
let targetRanges = glucoseRangeSchedule.quantityBetween(
start: ChartAxisValueDate.dateFromScalar(xAxisValues.first!.scalar),
end: ChartAxisValueDate.dateFromScalar(xAxisValues.last!.scalar)
)
let dateFormatter = DateFormatter()
var result = [TargetChartBar?]()
for (index, range) in targetRanges.enumerated() {
var startDate = ChartAxisValueDate(date: range.startDate, formatter: dateFormatter)
var endDate: ChartAxisValueDate
if index == targetRanges.startIndex, let firstDate = xAxisValues.first as? ChartAxisValueDate {
startDate = firstDate
}
if index == targetRanges.endIndex - 1, let lastDate = xAxisValues.last as? ChartAxisValueDate {
endDate = lastDate
} else {
endDate = ChartAxisValueDate(date: targetRanges[index + 1].startDate, formatter: dateFormatter)
}
if let override = potentialOverride,
startDate.date < endDate.date,
(override.startDate...override.scheduledEndDate).overlaps(startDate.date...endDate.date)
{
result.append(createBar(value: range.value, unit: unit, startDate: startDate, endDate: ChartAxisValueDate(date: override.startDate, formatter: dateFormatter), isOverride: false))
let targetDuringOverride = override.settings.targetRange ?? range.value
result.append(createBar(
value: targetDuringOverride,
unit: unit,
startDate: ChartAxisValueDate(date: max(override.startDate, startDate.date), formatter: dateFormatter),
endDate: ChartAxisValueDate(date: min(override.scheduledEndDate, endDate.date), formatter: dateFormatter),
isOverride: true))
result.append(createBar(value: range.value, unit: unit, startDate: ChartAxisValueDate(date: override.scheduledEndDate, formatter: dateFormatter), endDate: endDate, isOverride: false))
} else {
result.append(createBar(value: range.value, unit: unit, startDate: startDate, endDate: endDate, isOverride: false))
}
}
return result.compactMap { $0 }
}
static fileprivate func createBar(value: ClosedRange<HKQuantity>, unit: HKUnit, startDate: ChartAxisValueDate, endDate: ChartAxisValueDate, isOverride: Bool) -> TargetChartBar? {
guard startDate.date < endDate.date else { return nil }
let value = value.doubleRangeWithMinimumIncrement(in: unit)
let minValue = ChartAxisValueDouble(value.minValue)
let maxValue = ChartAxisValueDouble(value.maxValue)
return TargetChartBar(
points: [
ChartPoint(x: startDate, y: maxValue),
ChartPoint(x: endDate, y: maxValue),
ChartPoint(x: endDate, y: minValue),
ChartPoint(x: startDate, y: minValue)
],
isOverride: isOverride)
}
static func pointsForGlucoseRangeScheduleOverride(_ override: TemporaryScheduleOverride, unit: HKUnit, xAxisValues: [ChartAxisValue], extendEndDateToChart: Bool = false) -> [ChartPoint] {
guard let targetRange = override.settings.targetRange else {
return []
}
return pointsForGlucoseRangeScheduleOverride(
range: targetRange.doubleRangeWithMinimumIncrement(in: unit),
activeInterval: override.activeInterval,
unit: unit,
xAxisValues: xAxisValues,
extendEndDateToChart: extendEndDateToChart
)
}
private static func pointsForGlucoseRangeScheduleOverride(range: DoubleRange, activeInterval: DateInterval, unit: HKUnit, xAxisValues: [ChartAxisValue], extendEndDateToChart: Bool) -> [ChartPoint] {
guard let lastXAxisValue = xAxisValues.last as? ChartAxisValueDate else {
return []
}
let dateFormatter = DateFormatter()
let startDateAxisValue = ChartAxisValueDate(date: activeInterval.start, formatter: dateFormatter)
let displayEndDate = min(lastXAxisValue.date, extendEndDateToChart ? .distantFuture : activeInterval.end)
let endDateAxisValue = ChartAxisValueDate(date: displayEndDate, formatter: dateFormatter)
let minValue = ChartAxisValueDouble(range.minValue)
let maxValue = ChartAxisValueDouble(range.maxValue)
return [
ChartPoint(x: startDateAxisValue, y: maxValue),
ChartPoint(x: endDateAxisValue, y: maxValue),
ChartPoint(x: endDateAxisValue, y: minValue),
ChartPoint(x: startDateAxisValue, y: minValue)
]
}
}
extension ChartPoint: TimelineValue {
public var startDate: Date {
if let dateValue = x as? ChartAxisValueDate {
return dateValue.date
} else {
return Date.distantPast
}
}
}
private extension ClosedRange where Bound == HKQuantity {
func doubleRangeWithMinimumIncrement(in unit: HKUnit) -> DoubleRange {
let increment = unit.chartableIncrement
var minValue = self.lowerBound.doubleValue(for: unit)
var maxValue = self.upperBound.doubleValue(for: unit)
if (maxValue - minValue) < .ulpOfOne {
minValue -= increment
maxValue += increment
}
return DoubleRange(minValue: minValue, maxValue: maxValue)
}
}