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

实现图表末尾追加数据点不重绘及X轴动态更新需求

Highcharts iOS 图表优化:批量追加数据不重绘+无数据时自动更新X轴

问题背景

使用Highcharts开发iOS图表时,每次添加数据点都会触发图表重绘,引发性能问题。需实现两个核心需求:

  • 在图表末尾批量追加新数据点,不立即触发重绘
  • 当无新数据更新时,每秒自动更新X轴并展示当前数值

解决方案代码

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 liveContainer: UIView! // 改用普通UIView作为容器,规避与Charts库类名冲突
    @IBOutlet weak var Number: UILabel!
    
    let db = Firestore.firestore()
    var number: Int = 0 {
        didSet {
            Number.text = "#" + String(number)
        }
    }

    var quantityArray: [Double] = []
    private var chartView: HIChartView!
    private var chartOptions: HIOptions!
    private var updateTimer: Timer?
    private var lastUpdateTimestamp: Int = 0 // 记录最后一次数据更新时间戳

    override func awakeFromNib() {
        super.awakeFromNib()
        // 仅初始化一次图表配置
        setupChart()
        // 启动无数据时的自动更新定时器
        startAutoUpdateTimer()
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

    // 初始化图表基础配置
    private func setupChart() {
        chartView = HIChartView(frame: liveContainer.bounds)
        liveContainer.addSubview(chartView)
        
        chartOptions = HIOptions()
        
        let chart = HIChart()
        chart.type = "spline"
        chart.marginRight = 10
        chartOptions.chart = chart
        
        let time = HITime()
        time.useUTC = true
        chartOptions.time = time
        
        let title = HITitle()
        title.text = "Live random data"
        chartOptions.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; }")
        chartOptions.accessibility = accessibility
        
        let xAxis = HIXAxis()
        xAxis.type = "datetime"
        xAxis.tickPixelInterval = 150
        chartOptions.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]
        chartOptions.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}"
        chartOptions.tooltip = tooltip
        
        let legend = HILegend()
        legend.enabled = false
        chartOptions.legend = legend
        
        let exporting = HIExporting()
        exporting.enabled = false
        chartOptions.exporting = exporting
        
        let spline = HISpline()
        spline.name = "Random data"
        spline.data = []
        chartOptions.series = [spline]
        
        chartView.options = chartOptions
    }

    // 追加数据点(不立即触发重绘)
    func appendDataPoint(quantity: Double, timestamp: Int) {
        quantityArray.append(quantity)
        lastUpdateTimestamp = timestamp
        
        // 添加数据点时设置redraw为false,避免立即重绘
        let point = ["x": timestamp, "y": quantity]
        chartView.options.series.first?.addPoint(point, redraw: false)
        
        // 可在批量添加完成后手动调用以下代码触发一次重绘
        // chartView.redraw()
    }

    // 启动无数据时的自动更新定时器
    private func startAutoUpdateTimer() {
        updateTimer?.invalidate()
        updateTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            guard let self = self else { return }
            
            // 若最近1秒内有数据更新,跳过本次自动更新
            let currentTimestamp = Int(Date().timeIntervalSince1970)
            if currentTimestamp - self.lastUpdateTimestamp < 1 {
                return
            }
            
            // 更新X轴范围,保持展示最近60秒数据
            if let xAxis = self.chartOptions.xAxis.first as? HIXAxis {
                let now = Int(Date().timeIntervalSince1970) * 1000 // Highcharts使用毫秒时间戳
                xAxis.max = now
                xAxis.min = now - 60000
            }
            
            // 展示最后一个数据点的数值
            if let lastValue = self.quantityArray.last {
                self.nowusdt.text = String(format: "%.2f", lastValue)
            }
            
            // 触发重绘更新X轴
            self.chartView.redraw()
        }
    }

    // 手动触发图表重绘(批量添加数据后调用)
    func triggerChartRedraw() {
        chartView.redraw()
    }

    deinit {
        updateTimer?.invalidate()
    }
}

关键优化说明

  1. 复用图表实例:将HIChartView和HIOptions设为类属性,仅在awakeFromNib中初始化一次,避免重复创建图表导致的频繁重绘。
  2. 无重绘追加数据:使用Highcharts原生的addPoint(_:redraw:)方法,设置redraw: false实现批量添加数据后统一重绘,减少重绘次数。
  3. 无数据自动更新:通过定时器每秒检查数据状态,无新数据时自动更新X轴时间范围,同时刷新数值展示,保持图表活跃性。
  4. 规避命名冲突:将原LineChartView类型的控件改为普通UIView容器,避免与Charts库类名冲突。

内容的提问来源于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.04 09:00:56