0

I am trying to play around with the SwiftUI Charts framework to make a bar graph, where the x axis is a date, and the y axis is the number of seconds.

As the number of seconds grows, at some point, the data starts to loose value, as the seconds start to get too large. I was looking to convert it to the next largest date component.

As an example: 90s->1.5 min 20,000s->5.5hr

Is there a way to do this within the .ChartYAxis{} that is available

import Foundation
import SwiftUI
import Charts

public struct BarChartData: Identifiable, Equatable {
    
    public let id = UUID()
    let date: Date
    let count: Double
    let runningTotal: Double
    
    
    init(date: Date, count: Double, runningTotal: Double) {
        self.date = date
        self.count = count
        self.runningTotal = runningTotal
    }
}

struct BarChart: View {
    
    @Binding public var barChartData: [BarChartData]
    @Binding public var selectedInterval: TimeManager.TimeIntervalOption
    
    var body: some View {
        GroupBox ("History"){
            Chart {
                ForEach(barChartData) { datum in
                    BarMark(
                        x: .value("Date", datum.date, unit: getGraphUnit(selectedInterval)),
                        y: .value("Count", datum.count)
                    )
                    .foregroundStyle(by: .value("Value", "Time"))
                    
                    LineMark(
                        x: .value("Date", datum.date, unit: getGraphUnit(selectedInterval)),
                        y: .value("Total", datum.runningTotal)
                    )
                    .foregroundStyle(by: .value("Value", "Total"))
                }
            }
            .padding()
            .frame(maxWidth: .infinity, maxHeight: 300)
            .chartForegroundStyleScale([
                "Time": Color.purple,
                "Total": Color.rewindsRed
            ])
            .chartXAxis {
                AxisMarks(position: .bottom, values: .stride(by: getGraphUnit(selectedInterval), count: getStrideByUnit(selectedInterval))) {
                    _ in
                    AxisTick()
                    AxisGridLine()
                    AxisValueLabel(format: getAxisUnit(selectedInterval), centered: false)
                }
            }
        }
    }
    
    private func getAxisUnit(_ selectedInterval: TimeManager.TimeIntervalOption) -> Date.FormatStyle {
        switch selectedInterval {
        case .Day:
            return .dateTime.hour(.twoDigits(amPM: .abbreviated))
        case .Week:
            return .dateTime.weekday(.abbreviated)
        case .Month:
            return .dateTime.day(.defaultDigits)
        case .Year:
            return .dateTime.month(.abbreviated)
        case .Lifetime:
            return .dateTime.year(.extended(minimumLength: 4))
        }
    }
    
    private func getGraphUnit(_ selectedInterval: TimeManager.TimeIntervalOption) -> Calendar.Component {
        switch selectedInterval {
        case .Day:
            return .hour
        case .Week:
            return .day
        case .Month:
            return .day
        case .Year:
            return .month
        case .Lifetime:
            return .year
        }
    }
    
    private func getStrideByUnit(_ selectedInterval: TimeManager.TimeIntervalOption) -> Int {
        switch selectedInterval {
        case .Day:
            return 4
        case .Week:
            return 1
        case .Month:
            return 7
        case .Year:
            return 12
        case .Lifetime:
            return 1
        }
    }
}

struct BarChart_Previews: PreviewProvider {
    
    static let testData: [BarChartData] = [
        BarChartData(date: Date(dateString: "2023-07-18 16:00:00 +0000", format: "yyyy-MM-dd HH:mm:ss Z"), count: 200.0, runningTotal: 200),
        BarChartData(date: Date(dateString: "2023-07-18 17:00:00 +0000", format: "yyyy-MM-dd HH:mm:ss Z"), count: 300.0, runningTotal: 500),
        BarChartData(date: Date(dateString: "2023-07-18 18:00:00 +0000", format: "yyyy-MM-dd HH:mm:ss Z"), count: 200.0, runningTotal: 700),
        BarChartData(date: Date(dateString: "2023-07-18 19:00:00 +0000", format: "yyyy-MM-dd HH:mm:ss Z"), count: 200.0, runningTotal: 900),
        BarChartData(date: Date(dateString: "2023-07-18 20:00:00 +0000", format: "yyyy-MM-dd HH:mm:ss Z"), count: 200.0, runningTotal: 1100),
        BarChartData(date: Date(dateString: "2023-07-18 21:00:00 +0000", format: "yyyy-MM-dd HH:mm:ss Z"), count: 200.0, runningTotal: 1300),
        BarChartData(date: Date(dateString: "2023-07-18 22:00:00 +0000", format: "yyyy-MM-dd HH:mm:ss Z"), count: 200.0, runningTotal: 1500),
    ]
    
    static var previews: some View {
        BarChart(barChartData: .constant(testData), selectedInterval: .constant(.Day))
    }
}

I explored trying to use the ChartAxisLabel, as a way to convert the value, as it has a format method of .timeDuration, that I found, but it was unavailable for use. I’m

Mickey223
  • 1
  • 1

0 Answers0