Real-time data update strategy
Real-time Data Update Strategies
ECharts, as a powerful data visualization library, offers multiple flexible update mechanisms for handling dynamic data. Whether it's scheduled refreshes, event-driven updates, or streaming data integration, choosing the right update strategy can significantly enhance chart performance and user experience.
Incremental Data Updates
For high-frequency update scenarios, full refreshes can create performance bottlenecks. ECharts' appendData
method supports incremental data appending:
// Initialize the chart
const chart = echarts.init(document.getElementById('chart'));
chart.setOption({
dataset: {
source: [
['Time', 'Value'],
['10:00', 20],
['10:01', 35]
]
},
xAxis: { type: 'category' },
yAxis: {},
series: [{ type: 'line' }]
});
// Append new data every 2 seconds
setInterval(() => {
const now = new Date();
const timeStr = `${now.getHours()}:${now.getMinutes()}`;
const newValue = Math.round(Math.random() * 50);
chart.appendData({
seriesIndex: 0,
data: [timeStr, newValue]
});
}, 2000);
Notes:
- Manually clean up old data when the volume exceeds a threshold
- Suitable for continuous charts like line/bar charts
- Requires coordination with the
dataZoom
component for viewport following
Full Data Replacement
When data structure may change, use full replacement:
function fetchData() {
return fetch('/api/data').then(res => res.json());
}
async function updateChart() {
const newData = await fetchData();
chart.setOption({
dataset: {
source: newData
}
});
}
// Use debounce to avoid frequent requests
const debouncedUpdate = _.debounce(updateChart, 300);
window.addEventListener('resize', debouncedUpdate);
Performance optimization tips:
- Use
notMerge: true
to completely clear old configurations - Enable
large: true
for large datasets - Control transition animation time with
animationDurationUpdate
WebSocket Real-time Push
For high real-time requirements like financial market data, use WebSocket:
const socket = new WebSocket('wss://market-data.example.com');
socket.onmessage = (event) => {
const payload = JSON.parse(event.data);
chart.setOption({
series: [{
data: payload.map(item => ({
name: item.symbol,
value: [item.price, item.volume]
}))
}]
});
};
// Heartbeat to maintain connection
setInterval(() => {
if (socket.readyState === WebSocket.OPEN) {
socket.send('ping');
}
}, 30000);
Exception handling points:
- Implement automatic reconnection
- Use message queues for network fluctuations
- Add data validation logic
Performance Optimization Strategies
Optimization solutions for large datasets:
// Use sampling to reduce data density
function downsample(data, factor) {
return data.filter((_, index) => index % factor === 0);
}
// Enable progressive rendering
chart.setOption({
series: [{
progressive: 1000,
progressiveThreshold: 3000
}]
});
// Use Web Worker for compute-intensive tasks
const worker = new Worker('data-processor.js');
worker.postMessage(rawData);
worker.onmessage = (e) => {
chart.setOption({ dataset: { source: e.data } });
};
Dynamic Interaction Updates
Example of interactive updates responding to user actions:
// Map drill-down example
chart.on('click', (params) => {
if (params.componentType === 'series' && params.seriesType === 'map') {
loadRegionData(params.name).then(data => {
chart.setOption({
geo: {
map: params.name + '-detail'
},
series: [{
data: data.points
}]
});
});
}
});
// Brush selection linkage
chart.on('brushSelected', (params) => {
const selectedData = params.batch[0].selected[0].dataIndex;
detailChart.setOption({
dataset: {
source: selectedData.map(idx => rawData[idx])
}
});
});
Server-Side Rendering Solution
Server-side rendering implementation in Node.js:
const echarts = require('echarts');
function renderChartToSVG(options) {
const instance = echarts.init(null, null, {
renderer: 'svg',
ssr: true,
width: 800,
height: 600
});
instance.setOption(options);
const svgStr = instance.renderToSVGString();
instance.dispose();
return svgStr;
}
// Express route example
app.get('/chart', (req, res) => {
const svg = renderChartToSVG({
title: { text: 'Server-Rendered Chart' },
series: [{ data: [120, 200, 150, 80, 70] }]
});
res.type('image/svg+xml').send(svg);
});
Cross-Framework Integration
Best practices in different frontend frameworks:
React Example
import { useRef, useEffect } from 'react';
function EChartWrapper({ options }) {
const chartRef = useRef(null);
useEffect(() => {
const chart = echarts.init(chartRef.current);
chart.setOption(options);
return () => chart.dispose();
}, [options]);
return <div ref={chartRef} style={{ width: '100%', height: 400 }} />;
}
Vue Example
<template>
<div ref="chartEl" :style="{ width, height }"></div>
</template>
<script>
export default {
props: ['options', 'width', 'height'],
mounted() {
this.chart = echarts.init(this.$refs.chartEl);
this.updateChart();
},
methods: {
updateChart() {
this.chart.setOption(this.options);
}
},
watch: {
options: {
deep: true,
handler() {
this.updateChart();
}
}
}
}
</script>
Special Scenario Handling
Multi-Chart Synchronized Updates
const charts = [chart1, chart2, chart3];
function syncUpdate(options) {
charts.forEach(chart => {
chart.setOption(options, { lazyUpdate: true });
});
echarts.getInstanceByDom(charts[0].getDom()).dispatchAction({
type: 'highlight',
seriesIndex: 0
});
}
Chunked Loading for Large Datasets
function loadChunkedData(url, chunkSize) {
let offset = 0;
function loadNextChunk() {
fetch(`${url}?offset=${offset}&limit=${chunkSize}`)
.then(res => res.json())
.then(data => {
if (data.length > 0) {
chart.appendData({ seriesIndex: 0, data });
offset += data.length;
requestAnimationFrame(loadNextChunk);
}
});
}
loadNextChunk();
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn