iOS实现每秒更新动态折线图:X轴起始异常及需求调整
问题描述
- 在iOS中使用Highcharts实现每秒更新的折线图,当前存在两个问题:
- 图表初始渲染正常,但几秒内折线显示异常,之后恢复每秒更新
- X轴初始显示1975年左右的时间,需要让X轴从传入的
lastQuatityTimestamp参数开始,后续基于当前时间每秒更新
问题分析
- 无效初始数据:代码中
spline.data包含两个仅设置x未设置y的点,Highcharts会将这类点解析为y=0;同时Date().timeIntervalSince1970返回秒级时间戳,而Highcharts的datetime轴要求毫秒级时间戳,单位不匹配导致X轴显示异常(1975年是秒级转毫秒级后的错误时间) - 时间戳单位不统一:
lastQuatityTimestamp是秒级参数,而定时器中(new Date()).getTime()是毫秒级,两者混用导致X轴刻度混乱 - 重复添加视图:每次调用
LiveChart都会创建新的HIChartView并添加到live上,可能导致视图层级混乱,影响渲染
修复方案
- 统一时间戳单位:将所有时间戳转为毫秒级,
lastQuatityTimestamp乘以1000,Date().timeIntervalSince1970也乘以1000得到毫秒值 - 修复初始数据:移除无效的初始点,基于
lastQuatityTimestamp创建有效初始数据,确保每个点都有x和y - 设置X轴起始范围:通过
xAxis.min将X轴最小值设为lastQuatityTimestamp对应的毫秒值,确保X轴从指定时间开始显示 - 避免重复添加视图:先移除
live上已有的HIChartView,再添加新的,防止视图叠加
修改后的完整代码
import UIKit import Highcharts import Firebase import FirebaseFirestore import Charts class LiveTableViewCell: UITableViewCell { @IBOutlet weak var Aitime: UILabel! @IBOutlet weak var time: UILabel! @IBOutlet weak var nowusdt: UILabel! @IBOutlet weak var nowq8: UILabel! @IBOutlet weak var inusdt: UILabel! @IBOutlet weak var live: LineChartView! @IBOutlet weak var Number: UILabel! let db = Firestore.firestore() var number: Int = 0 { didSet { Number.text = "#"+String(number) } } override func awakeFromNib() { super.awakeFromNib() } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) } func LiveChart(quantity: Double, lastQuatityTimestamp: Int){ // 移除已存在的HIChartView,避免重复添加 live.subviews.forEach { subview in if subview is HIChartView { subview.removeFromSuperview() } } let chartView = HIChartView(frame: live.bounds) let options = HIOptions() let chart = HIChart() chart.type = "spline" chart.marginRight = 10 chart.events = HIEvents() // 定时器中使用当前时间的毫秒级时间戳,y值保持传入的quantity(如需动态值可修改) chart.events.load = HIFunction(jsFunction: "function () { var series = this.series[0]; setInterval(function () { var x = (new Date()).getTime(), y = \(quantity); series.addPoint([x, y], true, true); }, 1000); }") options.chart = chart let time = HITime() time.useUTC = true options.time = time let title = HITitle() title.text = "Live random data" options.title = title let accessibility = HIAccessibility() accessibility.announceNewData = HIAnnounceNewData() accessibility.announceNewData.enabled = true accessibility.announceNewData.minAnnounceInterval = 15000 accessibility.announceNewData.announcementFormatter = HIFunction(jsFunction: "function (allSeries, newSeries, newPoint) { if (newPoint) { return 'New point added. Value: ' + newPoint.y; } return false; }") options.accessibility = accessibility let xAxis = HIXAxis() xAxis.type = "datetime" xAxis.tickPixelInterval = 150 // 设置X轴最小值为传入的lastQuatityTimestamp(秒转毫秒) xAxis.min = Double(lastQuatityTimestamp * 1000) options.xAxis = [xAxis] let yAxis = HIYAxis() yAxis.title = HITitle() yAxis.title.text = "Value" let plotLines = HIPlotLines() plotLines.value = 0 plotLines.width = 1 plotLines.color = HIColor(hexValue: "808080") yAxis.plotLines = [plotLines] options.yAxis = [yAxis] let tooltip = HITooltip() tooltip.headerFormat = "<b>{series.name}</b><br/>" tooltip.pointFormat = "{point.x:%Y-%m-%d %H:%M:%S}<br/>{point.y:.2f}" options.tooltip = tooltip let legend = HILegend() legend.enabled = false options.legend = legend let exporting = HIExporting() exporting.enabled = false options.exporting = exporting let spline = HISpline() spline.name = "Random data" // 基于lastQuatityTimestamp创建有效初始数据(秒转毫秒) let startTimestampMs = Double(lastQuatityTimestamp * 1000) spline.data = [ ["x": startTimestampMs, "y": quantity], // 可选:添加前几秒的历史点,让初始折线更连贯 ["x": startTimestampMs - 1000, "y": quantity], ["x": startTimestampMs - 2000, "y": quantity] ] options.series = [spline] chartView.options = options self.live.addSubview(chartView) } }
关键修改点说明
- 时间戳统一:将
lastQuatityTimestamp乘以1000转为毫秒级,初始数据和X轴最小值都使用该值 - 修复初始数据:移除无效的无y值点,替换为基于起始时间的有效点,避免图表渲染异常
- 视图清理:添加了移除旧
HIChartView的逻辑,防止重复添加导致的渲染问题 - X轴起始控制:通过
xAxis.min强制X轴从指定时间开始显示,解决初始显示1975年的问题
内容的提问来源于stack exchange,提问作者Saurabh Pathak
相关产品推荐
相关产品推荐

