Post

Replies

Boosts

Views

Activity

Reply to Interactive Charts
I figured it out. It doesn't come out of the box, some coding is needed. (The algorithm is simple, get the X value for the tap/drag, convert it to chart X and Y, use Point and Rule markers. The example is for (Date, Double) chart values.)   @State var position: ChartPosition?       var body: some View {     Chart {       ForEach(session!.heightData) { height in         AreaMark(           x: .value("Time", height.time.start),           y: .value("Height", height.height.doubleValue(for: diveManager.heightUnit))         )       }       if let position = position {         RuleMark(x: .value("Time", position.x))           .foregroundStyle(.orange.opacity(0.5))         RuleMark(y: .value("Height", position.y))           .foregroundStyle(.orange.opacity(0.5))         PointMark(x: .value("Time", position.x), y: .value("Height", position.y))           .foregroundStyle(.orange)           .symbol(BasicChartSymbolShape.circle.strokeBorder(lineWidth: 3.0))           .symbolSize(250)       }     }     .chartOverlay { proxy in       GeometryReader { geometry in         Rectangle().fill(.clear).contentShape(Rectangle())           .gesture(DragGesture().onChanged { value in updateCursorPosition(at: value.location, geometry: geometry, proxy: proxy) })           .onTapGesture { location in updateCursorPosition(at: location, geometry: geometry, proxy: proxy) }       }     }   }       func updateCursorPosition(at: CGPoint, geometry: GeometryProxy, proxy: ChartProxy) {     let data = session!.heightData     let origin = geometry[proxy.plotAreaFrame].origin     let datePos = proxy.value(atX: at.x - origin.x, as: Date.self)     let firstGreater = data.lastIndex(where: { $0.time.start < datePos! })     if let index = firstGreater {       let time = data[index].time.start       let height = data[index].height.doubleValue(for: diveManager.heightUnit)       position = ChartPosition(x: time, y: height)     }   }
Oct ’22