Search code examples
swiftswiftuiswiftui-charts

Using Swift Charts, in a BarMark, how can I change the color of single date in the x axis to blue?


Using Swift Charts, I have a bar chart that has dates on the x-axis and points on the y-axis. This data comes from the property chartData which contains the integer points for each date. The data point representing today's date and points could be anywhere in the chartData.

So, I'd like to change the color of the x-axis label to blue for the date that matches today's date. All other dates should remain in their default color. This gives the user a visual indication of which date is today's date.

I know how to change the color of all x-axis labels, but this is not what I want. I want to change the color of the one x-axis label that matches todays date. Thank you!

struct DailyPointsChart: View {
    @Binding var scrollPosition: Date
    let chartData: [(Date, Int)]
    
    var body: some View {
        Chart {
            ForEach(chartData, id: \.0) { data in
                BarMark(
                    x: .value("Day", data.0, unit: .day),
                    y: .value("Points", data.1)
                )
            }
            .cornerRadius(10)
            .foregroundStyle(Color(UIColor.purple))

        }
        .chartScrollableAxes(.horizontal)
        .chartXVisibleDomain(length: 3600 * 24 * 7) // 7 visible days on chart
        .chartScrollPosition(x: $scrollPosition)
        
        .chartXAxis {
            AxisMarks(values: .stride(by: .day, count: 1)) {
                AxisTick()
                AxisValueLabel(format: .dateTime.month().day())
                    .foregroundStyle(Color.blue) // This changes the color of all x-axis labels, which is not what we want
            }
        }
    }
}



Solution

  • This solution works best, for my project:

    .chartXAxis {
        AxisMarks(values: .stride(by: .day, count: 1)) { value in
              AxisTick()
              AxisValueLabel(format: .dateTime.month().day())
                  .foregroundStyle(value.as(Date.self)?.isSameDay(as: todayDate) ?? false ? Color.blue : .secondary)
        }
    }
    
    extension Date {
        func isSameDay(as otherDate: Date) -> Bool {
            let calendar = Calendar.current
            return calendar.isDate(self, inSameDayAs: otherDate)
        }
    }