Issue #943

In this tutorial, we’ll learn how to use Swift Charts to visualize ranking data.

Screenshot 2023-08-18 at 11 48 28

We use default AxisMarks and AxisMarks to let Swift Charts interpolate x and y grid lines. For y axis, I want to have finer grain control over the grid, so I specify an arrayLiteral

Note that for rank, the lower value the better ranking, so we make use of chartYScale with reversed automatic domain to flip from 0 -> 100 to 100 -> 0

Finally, to handle hover, we place an invisible view Color.clear with onContinuousHover. Note that the x axis value are in Date values, so we need to cast to Date type

struct ContentView: View {
    @State private var selectedDate: Date?
    var body: some View {
        Chart {
            ForEach(items) { item in
                lineMark(for: item)
        .chartXAxisLabel("Last 30 days")
        .chartXAxis {
        .chartYAxis {
            AxisMarks(values: .init(arrayLiteral: 1, 25, 50, 75, 100))
        .chartYScale(domain: .automatic(reversed: true))
        .chartLegend(spacing: 16)
        .chartOverlay { proxy in
                .onContinuousHover { phase in
                    switch phase {
                    case let .active(location):
                        selectedDate = proxy.value(atX: location.x, as: Date.self)
                    case .ended:
                        selectedDate = nil

For our mark, we can move it to another method marked with @ChartContentBuilder. As we get hovered date value, we can find the item for that and place an annotation

private func lineMark(for item: RankTrends.DailyItem) -> some ChartContent {
        x: .value("Date",,
        y: .value("Rank", item.rank)
    if let selectedDate,
       let item = items.first(where: { $ selectedDate) }) {
            x: .value("Date", selectedDate)
        .annotation {