SwiftUI chart annotation not working when using chartScrollableAxes

When using the new iOS “chartScrollableAxes” feature annotation that should show on top of the chart view no longer work. When disabling “chartScrollableAxes” everything works again.

Filed as FB12584128

import SwiftUI
import Charts

class ChartDataEntry:Identifiable {
	var date:Date
	var value:Double
	
	init(date:Date, value: Double) {
		self.date=date
		self.value=value
	}
}

struct ContentView: View {
	@State var rawSelectedDate: Date?

	var chartData = [ChartDataEntry(date: Date().yesterday.yesterday.yesterday.yesterday.startOfDay, value: 10.0),
									 ChartDataEntry(date: Date().yesterday.yesterday.yesterday.startOfDay, value: 20.0),
									 ChartDataEntry(date: Date().yesterday.yesterday.startOfDay, value: 30.0),
									 ChartDataEntry(date: Date().yesterday.startOfDay, value: 40.0),
									 ChartDataEntry(date: Date().startOfDay, value: 50.0)]
	
	var body: some View {
		VStack {
			Chart(chartData) { entry in
				BarMark(
					x: .value("Day", entry.date, unit: .day),
					y: .value("Values", entry.value)
				)
				
				if let selectedDate {
					RuleMark( x: .value("Selected", selectedDate, unit: .day))
						.foregroundStyle(Color.gray.opacity(0.3))
						.offset(yStart: -10)
						.zIndex(-1)
						.annotation(position: .top, spacing: -10,
												overflowResolution: .init(
													x: .fit(to: .chart),
													y: .disabled
												)
						) {
							Text("Longer Sample Text")
						}
				}

			}
			.chartScrollableAxes(.horizontal) // <<--- when this is disabled the annotation will be shown correctly
			.chartXSelection(value: $rawSelectedDate)
			.frame(height: 300)
		}
		.padding()
	}
	
	var selectedDate: Date? {
		guard let rawSelectedDate else { return nil }
		return chartData.first(where: {
			let endOfDay = $0.date.endOfDay
			return ($0.date ... endOfDay).contains(rawSelectedDate)
		})?.date
	}

}

#Preview {
    ContentView()
}

extension Date {
	var yesterday: Date {
		return Calendar.current.date(byAdding: .day, value: -1, to: self)!
	}
	
	var startOfDay: Date {
		return Calendar.current.startOfDay(for: self)
	}

	var endOfDay: Date {
		var components = DateComponents()
		components.day = 1
		components.second = -1
		return Calendar.current.date(byAdding: components, to: startOfDay)!
	}

}
Post not yet marked as solved Up vote post of Besti Down vote post of Besti
1.5k views
  • I have the same issue on my side resolved by disabling “chartScrollableAxes”

  • Same issue here!

  • Xcode Beta 15.1 the issue is still here.

Replies

@Besti did you ever get feedback answered from Apple on this. I discovered the same issue when trying to implement an annotation on a RuleMark for a horizontal scrolling bar chart. It seems like the annotations don't respect the overflow modifier when contained using the new chartScrollableAxis modifier. Any help would be great.

Still an issue on Xcode 15.0.1 and Swift 5.9. I've tried all the .fit options but to no avail. Space is cleared for the annotation but no view result is displayed. I tried a chartOverlay proxy but this hasn't worked as I can't get gestures to work on my Mac in the simulator.

I've found the issue is still present. A workaround is to use a ZStack to overlay two charts with identical scales and axes. The first chart (background) is non-scrollable, allowing us to draw the selection RuleMark and an annotation popover. The second chart (foreground) is scrollable and enables data drawing and selection.