You could try this approach, using an .chartOverlay
and .onContinuousHover
.
You will have to adjust the location calculations to suit your purpose.
struct ContentView: View {
let measurement: [Measurement] = [
Measurement(id: "1", val: 11.2),
Measurement(id: "2", val: 22.2),
Measurement(id: "3", val: 38.2)
]
@State var select = "0"
@State var isHovering = false
var body: some View {
Chart {
ForEach(measurement) { data in
BarMark(x: .value("Time", data.id), y: .value("val", data.val))
.foregroundStyle(select == data.id ? .blue : .red)
}
}
.chartOverlay { proxy in
GeometryReader { geometry in
ZStack(alignment: .top) {
Rectangle().fill(.clear).contentShape(Rectangle())
.onContinuousHover { phase in
switch phase {
case .active(let location):
bar(at: location, proxy: proxy, geometry: geometry)
isHovering = true
case .ended:
isHovering = false
}
}
}
}
}
}
func bar(at location: CGPoint, proxy: ChartProxy, geometry: GeometryProxy) {
let xPosition = location.x - geometry[proxy.plotAreaFrame].origin.x
let yPosition = location.y - geometry[proxy.plotAreaFrame].origin.y
guard let month: String = proxy.value(atX: xPosition) else { return }
guard let measure: Double = proxy.value(atY: yPosition) else { return }
// more logic here ....
select = month
}
}
struct Measurement: Identifiable {
var id: String
var val: Double
}
If you want to just tap on the BarMarks
, see my other answer at: How to change the color of BarView in SwiftUI charts when we tap on it