I'm trying to get the LinePlot
feature from Xcode 16 to work. I tried the example code and it works, but I'm struggling to make it work interactively and animated.
The answer has been taken from this blogpost about creating a spiral with LinePlot and animating it:
https://lucasvandongen.dev/recreating_ovo_timer_in_swiftui.php
The result looks something like this:
import Charts
import SwiftUI
struct PlotPoint: Identifiable {
let id: Int
let x, y: Double
}
public struct Counter: View {
private static let minimumAngle: CGFloat = 60
private static let maximumAngle: CGFloat = 75
@State private var beginAngle: CGFloat = Self.minimumAngle
@State private var endAngle: CGFloat = Self.maximumAngle
@State private var points: [PlotPoint] = [
PlotPoint(
id: 1,
x: 0,
y: 0
),
PlotPoint(
id: 2,
x: 1,
y: 3
)
]
public init() { }
public var body: some View {
Chart(points) {
LinePlot(
x: "x",
y: "y",
t: "t",
domain: beginAngle...endAngle
) { t in
spiral(t: t)
}
PointMark(
x: .value("Wing Length", $0.x),
y: .value("Wing Width", $0.y)
).symbol {
Circle()
.fill(.white)
.stroke(
.blue,
lineWidth: 2
)
.frame(
width: 8,
height: 8
)
}
}
.chartXScale(domain: -8...8)
.chartYScale(domain: -8...8)
.chartXAxis(.hidden)
.chartYAxis(.hidden)
.aspectRatio(
1,
contentMode: .fit
)
Slider(
value: $beginAngle,
in: Self.minimumAngle...endAngle
)
.onChange(
of: beginAngle,
perform: updateBeginPoint(to:)
)
.onAppear {
updateBeginPoint(to: beginAngle)
}
Slider(
value: $endAngle,
in: beginAngle...Self.maximumAngle
)
.onChange(
of: endAngle,
perform: updateEndPoint(to:)
)
.onAppear {
updateEndPoint(to: endAngle)
}
}
private func updateBeginPoint(to newValue: Double) {
let endPoint = spiral(t: newValue)
points[0] = PlotPoint(
id: 2,
x: endPoint.0,
y: endPoint.1
)
}
private func updateEndPoint(to newValue: Double) {
let endPoint = spiral(t: newValue)
points[1] = PlotPoint(
id: 2,
x: endPoint.0,
y: endPoint.1
)
}
private func spiral(t: Double) -> (Double, Double) {
let a: CGFloat = 0.1
let b: CGFloat = 0.1
let r = a + b * t
let x = r * cos(t)
let y = r * sin(t)
return (x, y)
}
}