You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS实现每秒更新动态折线图:X轴起始异常及需求调整

问题描述
  • 在iOS中使用Highcharts实现每秒更新的折线图,当前存在两个问题:
    1. 图表初始渲染正常,但几秒内折线显示异常,之后恢复每秒更新
    2. X轴初始显示1975年左右的时间,需要让X轴从传入的lastQuatityTimestamp参数开始,后续基于当前时间每秒更新
问题分析
  1. 无效初始数据:代码中spline.data包含两个仅设置x未设置y的点,Highcharts会将这类点解析为y=0;同时Date().timeIntervalSince1970返回秒级时间戳,而Highcharts的datetime轴要求毫秒级时间戳,单位不匹配导致X轴显示异常(1975年是秒级转毫秒级后的错误时间)
  2. 时间戳单位不统一:lastQuatityTimestamp是秒级参数,而定时器中(new Date()).getTime()是毫秒级,两者混用导致X轴刻度混乱
  3. 重复添加视图:每次调用LiveChart都会创建新的HIChartView并添加到live上,可能导致视图层级混乱,影响渲染
修复方案
  1. 统一时间戳单位:将所有时间戳转为毫秒级,lastQuatityTimestamp乘以1000,Date().timeIntervalSince1970也乘以1000得到毫秒值
  2. 修复初始数据:移除无效的初始点,基于lastQuatityTimestamp创建有效初始数据,确保每个点都有x和y
  3. 设置X轴起始范围:通过xAxis.min将X轴最小值设为lastQuatityTimestamp对应的毫秒值,确保X轴从指定时间开始显示
  4. 避免重复添加视图:先移除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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 21:35:17