I also tried using the .chartOverlay modifier and used the .onTapGesture modifier to get the point and the value. But the view, as expected, blocked the chart and thereby restricted the chart scroll behavior.
.chartOverlay(content: { proxy in
GeometryReader { geometry in
Rectangle()
.fill(.red.opacity(0.4))
.frame(width: 100, height: 100)
.onTapGesture(count: 1, coordinateSpace: .global) { value in
guard let plotFrame = proxy.plotFrame else { return }
let origin = geometry[plotFrame].origin
let location = CGPoint(
x: value.x - origin.x,
y: value.y - origin.y
)
// Get the x (date) and y (price) value from the location.
let (date, price) = proxy.value(at: location, as: (String, Double).self) ?? ("x", 10)
print("Location: \(date), \(price)")
}
}
})
A drag gesture on a Chart also counts as "selecting" the chart - for every bit of distance the finger moves, you are selecting a new value in the chart. This obviously interferes with scrolling.
It seems like you only want taps to count as "selecting" the chart. You can use a chartGesture. Here is a complete example:
struct Point: Hashable {
let x: Double
let y: Double
}
let data = (0..<100).map { Point(x: Double($0), y: .random(in: 0..<100)) }
struct ContentView: View {
@State private var selection: Double = 0
var body: some View {
VStack {
Text("Selected: \(selection)")
Chart {
LinePlot(data, x: .value("X", \.x), y: .value("Y", \.y))
}
.chartScrollableAxes(.horizontal)
.chartXVisibleDomain(length: 10)
.chartGesture { proxy in
SpatialTapGesture().onEnded { value in
if let newSelection = proxy.value(atX: value.location.x, as: Double.self) {
selection = newSelection
}
}
}
}
}
}