Vue实现实时ApexChart:数据滚动与定时更新问题求助
Vue3 + ApexCharts 实时数据流图表实现问题
问题背景
尝试参考ApexCharts的实时折线图示例,但示例组件结构不实用且缺失部分方法,想要实现每1秒推送一个1秒数据块的实时图表,现有代码如下:
<template> <VueApexCharts type="line" height="350" width="100%" :options="chartOptions" :series="series" ref="chart" /> </template> <script> import { ref } from "vue"; import VueApexCharts from "vue3-apexcharts"; import { useStore } from "vuex"; export default { name: "ChartApex", components: { VueApexCharts }, props: ["session"], setup(/* props */) { let store = useStore(); let chartStream = undefined; let series = [ { name: "data1", data: ref([]), }, { name: "data2", data: [], }, ]; let chartOptions = { chart: { // id: "realtime", width: "100%", height: 350, type: "line", animations: { enabled: true, easing: "linear", dynamicAnimation: { speed: 1000, }, }, toolbar: { show: true, }, zoom: { enabled: true, }, }, dataLabels: { enabled: true, }, stroke: { curve: "straight", }, title: { text: "Chart", align: "left", }, grid: { row: { colors: ["#f3f3f3", "transparent"], opacity: 0.5, }, }, xaxis: { type: "numeric", show: true, range: 3, }, yaxis: { min: -32768, show: true, max: 32768, }, }; return { chartOptions, series, store, chartStream, }; }, watch: { "session.device.isDataStream"(newVal) { if (newVal) this.startStream(); else this.endStream(); }, }, methods: { startStream() { console.log("starting chart stream"); this.chartStream = setInterval(() => { // Push data this.series[0].data.value.push( ...this.store.state.session.samples[0].at(-1) ); }, 1000); }, endStream() { console.log("end chart srtrem"); clearInterval(this.chartStream); }, }, }; </script>
具体需求与疑问
- X轴固定显示10秒的数据范围
- 新增1秒数据块时,图表自动滚动X轴,始终保持显示10秒的数据
- 目前从Vuex Store获取分块更新的数据,但图表数据堆叠且不滚动,希望每1秒推送一个数据块
- 更倾向于直接绑定Store变量,但担心使用computed方法会降低性能
Store数据结构
store.state.samples[0]是包含多个1秒数据块的数组,格式如下:
// samples[0] [ // Chunk 1 of almost a second [ [8.75, 0], [17.5, -1], [26.25, -2], [35, -3],... ], [ // Chunk 2 of almost a second. [958.6875, -12747], [962.375, -12808], [966.0625, -12789],... ] ]
解决方案
1. 修正数据推送逻辑,避免重复堆叠
当前定时器会重复推送最后一个数据块,需要新增索引记录已处理的块:
在setup函数中添加响应式变量:
let processedChunkIndex = ref(-1);
然后修改startStream方法:
startStream() { console.log("starting chart stream"); this.chartStream = setInterval(() => { const latestChunks = this.store.state.session.samples[0]; const newChunkIndex = latestChunks.length - 1; // 只推送未处理过的最新块 if (newChunkIndex > processedChunkIndex.value) { this.series[0].data.value.push(...latestChunks[newChunkIndex]); processedChunkIndex.value = newChunkIndex; // 更新X轴范围实现滚动 this.updateXAxisRange(); } }, 1000); }
2. 实现X轴固定10秒范围与自动滚动
首先修改chartOptions中的xaxis配置,移除固定range:
xaxis: { type: "numeric", show: true, min: undefined, max: undefined },
然后新增updateXAxisRange方法:
updateXAxisRange() { const chartInstance = this.$refs.chart; if (!chartInstance) return; const data = this.series[0].data.value; if (data.length === 0) return; // 获取最新数据点的X值(时间) const latestX = data[data.length - 1][0]; // 计算10秒范围的X轴区间 const minX = latestX - 10; // 更新X轴范围并触发重绘 chartInstance.updateOptions({ xaxis: { min: minX, max: latestX } }, false, true); }
3. 优化Store数据绑定与性能问题
- 用
watch监听Store数据变化替代定时器轮询,更高效:
在setup函数中添加watch:
import { ref, watch } from "vue"; // ... 其他代码 watch( () => this.store.state.session.samples[0], (newChunks) => { if (!this.session.device.isDataStream) return; const newChunkIndex = newChunks.length - 1; if (newChunkIndex > processedChunkIndex.value) { this.series[0].data.value.push(...newChunks[newChunkIndex]); processedChunkIndex.value = newChunkIndex; this.updateXAxisRange(); } }, { deep: true } );
- 关于computed性能:如果只是映射Store数据到series,computed的开销极小,Vue会缓存计算结果,仅在依赖变化时重新计算。如果担心性能,用上述watch方式手动更新series即可,两者性能差异可以忽略。
4. 修复响应式问题
series中的data2未用ref包裹,改为响应式:
let series = [ { name: "data1", data: ref([]), }, { name: "data2", data: ref([]), }, ];
内容的提问来源于stack exchange,提问作者Imnotapotato
相关产品推荐
相关产品推荐

