FireStore数据填充Charts图表重叠及按时间排序需求
Swift Charts图表重叠+FireStore数据按时间排序填充问题
问题描述
我用Swift语言,借助Charts库绘制图表时,从FireStore读取数据填充出现图表重叠问题。同时希望能按时间顺序填充图表数据,当前FireStore数据结构如图(注:原提问提及有图但未提供)。作为新手寻求帮助,我的代码如下:
func LiveChart() { db.collection("Admin").document("AiSmartRobot").collection("AiDailyProfit").addSnapshotListener({ [self] (querySnapShot, error) in for document in querySnapShot!.documents{ if let quantity = document.data()["quantity"] as? Double{ if let datetime = document.data()["date"] as? String{ let barChartView = BarChartView(frame: live.bounds) barChartView.delegate = self barChartView.xAxis.labelPosition = .bottom let xValues = [datetime] barChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: xValues) self.live.addSubview(barChartView) var values = [BarChartDataEntry]() let numbers : [Double] = [quantity] for i in 0..<numbers.count { let value = BarChartDataEntry(x: Double(i), y: numbers[i]) values.append(value) } let ds = BarChartDataSet(values: values, label: "") let data = BarChartData(dataSets: [ds]) ds.valueColors = [UIColor(red: 57.0/255.0, green: 176.0/255.0, blue: 158.0/255.0, alpha: 1)] barChartView.data = data barChartView.chartDescription?.text = "" barChartView.animate(yAxisDuration: 2) barChartView.notifyDataSetChanged() } } } }) }
解决方案
1. 解决图表重叠问题
你当前代码的核心问题是在每个FireStore文档的循环里都创建了新的BarChartView并添加到live容器中,导致每次数据更新都会叠加一个新图表,最终出现重叠。正确做法是提前创建一次图表视图,后续只更新数据。
2. 解决按时间顺序填充问题
FireStore查询默认不排序,需要给查询添加排序规则;同时要先收集所有有效数据,确保顺序正确后再转换为图表数据,避免逐个文档处理导致的顺序混乱。
修改后的完整代码示例
首先在视图控制器类中声明图表属性:
var barChartView: BarChartView!
然后在viewDidLoad中初始化图表视图并添加到容器:
override func viewDidLoad() { super.viewDidLoad() // 初始化图表视图,一次性创建 barChartView = BarChartView(frame: live.bounds) barChartView.delegate = self barChartView.xAxis.labelPosition = .bottom barChartView.chartDescription?.text = "" live.addSubview(barChartView) // 启动数据监听 LiveChart() }
最后修改LiveChart函数:
func LiveChart() { db.collection("Admin").document("AiSmartRobot").collection("AiDailyProfit") .order(by: "date") // 关键:让FireStore按date字段排序返回数据 .addSnapshotListener({ [self] (querySnapShot, error) in // 安全解包数据,处理错误 guard let documents = querySnapShot?.documents else { print("获取数据失败: \(error?.localizedDescription ?? "未知错误")") return } // 收集所有有效数据 var chartItems = [(date: String, quantity: Double)]() for document in documents { if let quantity = document.data()["quantity"] as? Double, let dateStr = document.data()["date"] as? String { chartItems.append((date: dateStr, quantity: quantity)) } } // 如果FireStore的排序不满足需求(比如date是自定义格式),可以在客户端二次排序 // chartItems.sort { $0.date < $1.date } // 根据实际日期格式调整排序逻辑 // 转换为图表需要的Entry和X轴标签 var chartEntries = [BarChartDataEntry]() var xLabels = [String]() for (index, item) in chartItems.enumerated() { chartEntries.append(BarChartDataEntry(x: Double(index), y: item.quantity)) xLabels.append(item.date) } // 更新图表数据 let dataSet = BarChartDataSet(values: chartEntries, label: "") dataSet.valueColors = [UIColor(red: 57.0/255.0, green: 176.0/255.0, blue: 158.0/255.0, alpha: 1)] let chartData = BarChartData(dataSets: [dataSet]) barChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: xLabels) barChartView.data = chartData barChartView.animate(yAxisDuration: 2) barChartView.notifyDataSetChanged() }) }
关键修改说明
- 移除循环内创建
BarChartView的代码,改为在viewDidLoad中一次性创建,避免重复添加视图导致重叠 - 添加
order(by: "date")让FireStore直接返回排序后的数据,减少客户端处理压力 - 先收集所有有效数据再统一处理,确保数据顺序正确后再更新图表
- 安全解包数据,增加错误处理,避免强制解包
querySnapShot导致崩溃
内容的提问来源于stack exchange,提问作者lin lin
相关产品推荐
相关产品推荐

