Reputation: 415
I want to do a chart animation of where 2 paths present each other from left to right. I have the following code:
GeometryReader { geometry in
let height = geometry.size.height
let width = geometry.size.width
Path { path in
path.move(to: CGPoint(x: 0, y: -height * self.ratio(for: 0)))
for index in 1..<dataPoints.count {
path.addLine(to: CGPoint(
x: CGFloat(index) * width / CGFloat(dataPoints.count - 1),
y: -height * self.ratio(for: index)))
}
}
.trim(from: 0, to: end)
.stroke(Color.accentColor, style: StrokeStyle(lineWidth: 5, lineJoin: .round))
.animation(.linear(duration: 2))
.onAppear(perform: {
end = 1
})
}
The animation is trimming from left to right which looks good. Problem is the starting point of Path. The chart moves from "behind the scenes" top-left position. I don't know how to set this before the animation starts. If I create a var path: Path
how do I initialise with, e.g., CGRect if this is inside a subview and I just the width and height inside the GeometryReader ViewBuilder? Please help. Thank you in advance.
Edit: I was suspicious on the timing of rendering the screen of the .onAppear closure. I got it working using DispatchQueue. Solution:
.onAppear {
DispatchQueue.main.async {
end = 1
}
}
Upvotes: 0
Views: 2011
Reputation: 12125
The problem lies in this line:
-height * self.ratio(for: index)))
I don't know what you self.ratio(for:)
func does, and I don't understand why you use -height
... this seems to lead to the line starting at the upper left corner of your view. As points are added the view grows larger into negative values and gets pushed down.
You should instead start at y: height (of GeometryReader) and grow smaller but not negative.
struct ContentView: View {
@State private var end = 0.0
let dataPoints: [Double] = [3, 4, 7, 17, 11, 15, 4]
var body: some View {
VStack {
GeometryReader { geometry in
let height = geometry.size.height
let width = geometry.size.width
let maxValue = dataPoints.max(by: <) ?? 1
Path { path in
path.move(to: CGPoint(
x: 0,
y: height - dataPoints[0] / maxValue * height ) )
for index in 1..<dataPoints.count {
path.addLine(to: CGPoint(
x: CGFloat(index) * width / CGFloat(dataPoints.count - 1),
y: height - dataPoints[index] / maxValue * height ))
}
}
.trim(from: 0, to: end)
.stroke(Color.accentColor, style: StrokeStyle(lineWidth: 5, lineJoin: .round))
.animation(.linear(duration: 2), value: end)
}
Button("Start") { end = 1 }
}
.frame(height: 300)
}
}
Upvotes: 1