now it is possible to add background lines precisely as charts are displayed at correct size also rewrote basics to conform with Shapes and Animatable protocol
101 lines
4.0 KiB
Swift
101 lines
4.0 KiB
Swift
import SwiftUI
|
|
|
|
/// A single line of data, a view in a `LineChart`
|
|
public struct Line: View {
|
|
@EnvironmentObject var chartValue: ChartValue
|
|
@ObservedObject var chartData: ChartData
|
|
|
|
var style: ChartStyle
|
|
|
|
@State private var showIndicator: Bool = false
|
|
@State private var touchLocation: CGPoint = .zero
|
|
@State private var showBackground: Bool = true
|
|
@State private var didCellAppear: Bool = false
|
|
|
|
var curvedLines: Bool = true
|
|
|
|
/// The content and behavior of the `Line`.
|
|
/// Draw the background if showing the full line (?) and the `showBackground` option is set. Above that draw the line, and then the data indicator if the graph is currently being touched.
|
|
/// On appear, set the frame so that the data graph metrics can be calculated. On a drag (touch) gesture, highlight the closest touched data point.
|
|
/// TODO: explain rotation
|
|
public var body: some View {
|
|
GeometryReader { geometry in
|
|
ZStack {
|
|
if self.didCellAppear && self.showBackground {
|
|
LineBackgroundShapeView(chartData: chartData,
|
|
geometry: geometry,
|
|
style: style)
|
|
}
|
|
LineShapeView(chartData: chartData,
|
|
geometry: geometry,
|
|
style: style,
|
|
trimTo: didCellAppear ? 1.0 : 0.0)
|
|
.animation(.easeIn)
|
|
// if self.showIndicator {
|
|
// IndicatorPoint()
|
|
// .position(self.getClosestPointOnPath(touchLocation: self.touchLocation))
|
|
// .rotationEffect(.degrees(180), anchor: .center)
|
|
// .rotation3DEffect(.degrees(180), axis: (x: 0, y: 1, z: 0))
|
|
// }
|
|
}
|
|
.onAppear {
|
|
didCellAppear = true
|
|
}
|
|
.onDisappear() {
|
|
didCellAppear = false
|
|
}
|
|
|
|
.gesture(DragGesture()
|
|
.onChanged({ value in
|
|
self.touchLocation = value.location
|
|
self.showIndicator = true
|
|
// self.getClosestDataPoint(point: self.getClosestPointOnPath(touchLocation: value.location))
|
|
self.chartValue.interactionInProgress = true
|
|
})
|
|
.onEnded({ value in
|
|
self.touchLocation = .zero
|
|
self.showIndicator = false
|
|
self.chartValue.interactionInProgress = false
|
|
})
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Private functions
|
|
|
|
//extension Line {
|
|
// /// Calculate point closest to where the user touched
|
|
// /// - Parameter touchLocation: location in view where touched
|
|
// /// - Returns: `CGPoint` of data point on chart
|
|
// private func getClosestPointOnPath(touchLocation: CGPoint) -> CGPoint {
|
|
// let closest = self.path.point(to: touchLocation.x)
|
|
// return closest
|
|
// }
|
|
//
|
|
// /// Figure out where closest touch point was
|
|
// /// - Parameter point: location of data point on graph, near touch location
|
|
// private func getClosestDataPoint(point: CGPoint) {
|
|
// let index = Int(round((point.x)/step.x))
|
|
// if (index >= 0 && index < self.chartData.data.count){
|
|
// self.chartValue.currentValue = self.chartData.points[index]
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
struct Line_Previews: PreviewProvider {
|
|
/// Predefined style, black over white, for preview
|
|
static let blackLineStyle = ChartStyle(backgroundColor: ColorGradient(.white), foregroundColor: ColorGradient(.black))
|
|
|
|
/// Predefined style red over white, for preview
|
|
static let redLineStyle = ChartStyle(backgroundColor: .whiteBlack, foregroundColor: ColorGradient(.red))
|
|
|
|
static var previews: some View {
|
|
Group {
|
|
Line(chartData: ChartData([8, 23, 32, 7, 23, -4]), style: blackLineStyle)
|
|
Line(chartData: ChartData([8, 23, 32, 7, 23, 43]), style: redLineStyle)
|
|
}
|
|
}
|
|
}
|
|
|