Trying to implement a chart into my app where it tracks your profit of a game over time. The idea is very simple, a line chart that shows your progress over the course of a year. I'm using dummy data for now while I style the chart, with dates in Jan, Feb, March, May, and December but for some reason the chart is skewing oddly because the data points are not spaced evenly across the X axis.
Does anyone know how I can fix this?
Code with dummy data below, as well as the image:

let dummyData: [dummySession] = [
    .init(date: Date.from(year: 2023, month: 1, day: 1), profit: 0),
    .init(date: Date.from(year: 2023, month: 2, day: 12), profit: 55),
    .init(date: Date.from(year: 2023, month: 3, day: 20), profit: 376),
    .init(date: Date.from(year: 2023, month: 5, day: 2), profit: 120),
    .init(date: Date.from(year: 2023, month: 5, day: 18), profit: 500),
    .init(date: Date.from(year: 2023, month: 12, day: 11), profit: 222)
]

VStack {
    Chart {
        ForEach(dummyData) { session in
            LineMark(x: .value("Date", session.date, unit: .month),
                     y: .value("Profit", session.profit))
            .lineStyle(.init(lineWidth: 3, lineCap: .round, lineJoin: .round))
        }
        .interpolationMethod(.cardinal)
    }
    .chartXAxis {
        AxisMarks(stroke: StrokeStyle(lineWidth: 0))
    }
    .chartYAxis {
        AxisMarks(position: .trailing, values: .automatic) { value in
            AxisGridLine()
            AxisValueLabel() {
                if let intValue = value.as(Int.self) {
                    Text(intValue.asCurrency())
                        .padding(.leading, 25)
                }
            }
        }
    }
}
.frame(maxHeight: 300)

chart result

推荐答案

与其使用Date,不如创建自己的Plottable类型,它的行为类似于String(即primitivePlottable返回String).SwiftData将字符串视为分类数据,并以相等的间距绘制它们.

struct YearMonthDay: Plottable, Hashable {
    init(year: Int, month: Int, day: Int) {
        self.year = year
        self.month = month
        self.day = day
    }
    
    init?(primitivePlottable: String) {
        guard let date = try? Date.ISO8601FormatStyle.iso8601.parse(primitivePlottable) else {
            return nil
        }
        let components = Calendar.current.dateComponents([.year, .month, .day], from: date)
        guard let day = components.day, let month = components.month, let year = components.year else {
            return nil
        }
        self.day = day
        self.month = month
        self.year = year
    }
    
    let year: Int
    let month: Int
    let day: Int
    
    var primitivePlottable: String {
        date.formatted(.iso8601)
    }
    
    // this will be useful later
    var date: Date {
        Calendar.current.date(from: DateComponents(year: year, month: month, day: day))!
    }
}

然后,DummySession struct 将声明为:

struct Session: Identifiable {
    let date: YearMonthDay
    let profit: Int
    
    var id: YearMonthDay {
        date
    }
}

创建图表时,应按所需格式设置X轴标签的格式:

Chart {
    ForEach(data) { session in
        LineMark(x: .value("Date", session.date),
                 y: .value("Profit", session.profit))
        .lineStyle(.init(lineWidth: 3, lineCap: .round, lineJoin: .round))
    }
    .interpolationMethod(.cardinal)
}
.chartXAxis {
    AxisMarks { value in
        if let yearMonthDay = value.as(YearMonthDay.self) {
            AxisValueLabel {
                Text(yearMonthDay.date, format: .dateTime.month().day())
            }
        }
    }
}
.chartYAxis {
    AxisMarks(position: .trailing, values: .automatic) { value in
        AxisGridLine()
        AxisValueLabel {
            if let intValue = value.as(Int.self) {
                Text(intValue, format: .currency(code: "USD"))
                    .padding(.leading, 25)
            }
        }
    }
}

输出:

enter image description here

Ios相关问答推荐

第三方框架的iOS隐私声明

删除领域中的cartItem时出现问题

如何删除NavigationView中的默认透明标头?

SwiftData共享扩展阻止应用程序打开SQLite文件

从包含 5 个以上项目的自定义选项卡栏的导航视图中删除更多按钮

如何制作支持不同语言的iOS应用

uikit中如何触发swiftui功能

SwiftUI 每秒从 Timer 更新单个 @State 属性,每秒也重绘整个视图

@MainActor 类的扩展是主要演员吗?

UIView 倒置旋转时的zoom 问题

使用 @MainActor 更新 UI 的适当策略是什么?

如何快速设置条形按钮的图像?

使用 Vim 代替(或与)Xcode 进行 iOS 开发

检测 iPhone/iPad/iPod touch 的 colored颜色 ?

iOS 10 / Xcode 8 设备上的 NSLog 似乎被截断了?为什么?

由于 NSInvalidUnarchiveOperationException 导致 iOS11 WKWebview 崩溃

Xcode 4.2 如何将一个项目包含到另一个项目中?

自动布局:是什么创建了名为 UIView-Encapsulated-Layout-Width & Height 的约束?

使用 swift 从应用程序委托打开视图控制器

打开 XIB 文件后 Xcode 6.3 冻结/挂起