如何在Charts中创建仅显示有数据日期的连续日期柱状图
SwiftUI Charts 实现仅显示有数据日期的连续柱状图
当训练会话数据存在日期缺失时(如下示例),SwiftUI Charts默认会按时间轴填充无数据的日期位置,导致柱状图出现空白。
// 示例缺失日期的训练数据 TrainingSession(date: formatter.date(from: "2024-05-12 07:37:30 +0000")!, maxRM: 10.0, totalVolume: 0.0), TrainingSession(date: formatter.date(from: "2024-06-01 15:00:00 +0000")!, maxRM: 10.5, totalVolume: 105.0), TrainingSession(date: formatter.date(from: "2024-06-03 15:00:00 +0000")!, maxRM: 10.0, totalVolume: 100.0)
要实现仅展示有数据日期的连续柱状图,核心是把X轴从时间轴类型改为类别类型,让Charts只根据现有数据生成轴标记。
修改方案
- 新增日期格式化逻辑,将
Date转换为固定格式的字符串(如yyyy-MM-dd) - 修改
Chart的X轴绑定为日期字符串(类别值),而非原始Date类型 - 调整X轴标记,直接使用数据中的所有日期字符串,避免自动填充空白
修改后的完整代码
import SwiftUI import Charts struct TrainingSession { var date: Date var maxRM: Double var totalVolume: Double // 新增:格式化日期字符串,作为类别标识 var formattedDate: String { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd" return formatter.string(from: date) } } struct GraphView: View { var sessions: [TrainingSession] // 提取所有有数据的日期字符串 private var sessionDates: [String] { sessions.map { $0.formattedDate } } var body: some View { ScrollView { VStack(alignment: .leading) { // 最大RM的图表 VStack(alignment: .leading) { Text("最大RM") .font(.headline) .padding() Chart(sessions, id: \.formattedDate) { session in BarMark( // 修改X轴为类别值(日期字符串) x: .value("日期", session.formattedDate), y: .value("Max RM", session.maxRM) ) } .chartXAxis { // 使用现有数据的日期生成轴标记,不自动填充空白 AxisMarks(values: sessionDates) { value in AxisGridLine() AxisTick() AxisLabel(content: { Text(value.as(String.self)!) .rotationEffect(.degrees(45)) // 旋转标签避免重叠 }) } } .chartScrollableAxes(.horizontal) .padding([.leading, .trailing, .bottom]) } // 总负荷量的图表 VStack(alignment: .leading) { Text("总负荷量") .font(.headline) .padding() Chart(sessions, id: \.formattedDate) { session in BarMark( x: .value("日期", session.formattedDate), y: .value("总负荷量", session.totalVolume) ) } .chartXAxis { AxisMarks(values: sessionDates) { value in AxisGridLine() AxisTick() AxisLabel(content: { Text(value.as(String.self)!) .rotationEffect(.degrees(45)) }) } } .chartScrollableAxes(.horizontal) .padding([.leading, .trailing, .bottom]) } } } } } struct ContentView: View { var body: some View { GraphView(sessions: sampleData) } var sampleData: [TrainingSession] { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z" return [ TrainingSession(date: formatter.date(from: "2024-05-12 07:37:30 +0000")!, maxRM: 10.0, totalVolume: 0.0), TrainingSession(date: formatter.date(from: "2024-06-01 15:00:00 +0000")!, maxRM: 10.5, totalVolume: 105.0), TrainingSession(date: formatter.date(from: "2024-06-03 15:00:00 +0000")!, maxRM: 10.0, totalVolume: 100.0) ] } } struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } }
关键修改点说明
- 在
TrainingSession中新增formattedDate计算属性,将日期转换为固定格式的字符串,作为类别标识 - 把
BarMark的x参数从.value("Date", session.date)改为.value("日期", session.formattedDate),将X轴从时间轴转为类别轴 chartXAxis部分使用sessionDates(现有数据的日期字符串数组)生成轴标记,避免Charts自动填充无数据的日期间隔- 对X轴标签添加旋转效果,防止日期字符串过长导致重叠
内容的提问来源于stack exchange,提问作者takuma
相关产品推荐
相关产品推荐

