> 技术文档 > Vue + WebSocket 实时数据可视化实战:多源融合与模拟数据双模式设计_vue 通过websocket实时接收数据

Vue + WebSocket 实时数据可视化实战:多源融合与模拟数据双模式设计_vue 通过websocket实时接收数据

在现代交通大屏项目中,实时数据的采集和可视化尤为重要。本文结合 Vue3 和 ECharts,分享一个支持多 WebSocket 数据源实时合并、模拟数据调试、自动重连的完整设计方案,帮助你快速搭建健壮的数据可视化组件。


一、项目背景与核心需求

  • 实时接收多个 WebSocket 数据源(不同服务器或端口)

  • 设计模拟数据接口,方便本地开发调试

  • 支持数据的自动合并(如车流总量、车辆类型分布)

  • 使用 ECharts 动态展示统计数据

  • 保证 WebSocket 断线自动重连,提高稳定性


二、项目架构与核心状态管理

定义一个全局响应式对象 sources,分别存储四个数据源的数据,支持真实数据和模拟数据统一写入。


const USE_MOCK = true; // 是否启用模拟数据 const sources = reactive({ su1: {}, su2: {}, su3: {}, su4: {}, });

三、WebSocket 连接与模拟数据设计

1. 真实 WebSocket 连接实现

使用原生 WebSocket 连接服务器,设置事件监听,支持断线自动重连。


function createRealWS(url, setTarget) { const ws = new WebSocket(url); ws.onopen = () => console.log(`🟢 WebSocket ${url} 已连接`); ws.onmessage = (event) => { const data = JSON.parse(event.data); setTarget(JSON.parse(data.data)); }; ws.onerror = () => console.error(`WebSocket ${url} 出错`); ws.onclose = () => { console.warn(`WebSocket ${url} 关闭,3秒后重连...`); setTimeout(() => createRealWS(url, setTarget), 3000); };}

2. 模拟数据接口

为了方便本地开发,使用定时器生成结构一致的模拟数据,模拟数据每3秒刷新一次。


function createMockSource(setTarget) { setInterval(() => { const mock = { timestamp: Date.now(), globalTime: new Date().toLocaleString(), totalVehiCount: Math.floor(Math.random() * 1000), aveSpeed: +(30 + Math.random() * 10).toFixed(2), numVehiByType: Object.fromEntries( [1, 2, 3, 7, 8, 10, 11, 15, 100].map(k => [k, Math.floor(Math.random() * 100)]) ), }; setTarget(mock); }, 3000);}

3. 初始化所有数据源

根据 WebSocket URL 端口号映射到对应数据源,启用模拟或真实数据。

function initAllSources() { const urls = [ \"ws://xx/wsStatisJd\", \"ws://xx/wsStatisJd\", \"ws://xx/wsStatisJd\", \"ws://xx/wsStatisJd\", ]; urls.forEach((url) => { const key = getSourceKeyByPort(url); // su1 su2 su3 su4 const setFn = (data) => (sources[key] = data); if (USE_MOCK) { createMockSource(setFn); } else { createRealWS(url, setFn); } });}

四、数据合并与格式化

合并车流总量

将四个数据源的车辆总数相加,确保数值准确。


function mergeTotal(...totals) { return totals.reduce((sum, val) => sum + Number(val || 0), 0);}

合并车辆类型分布

对每种车辆类型进行累加。


格式化合并后的车辆类型数据,固定顺序输出并计算百分比


function formatVehicleTypeData(numVehiByType, total = 0) { const fixedOrder = [8, 3, 2, 1, 15, 7, 10, 11, 100]; return fixedOrder.map(key => { const value = numVehiByType[key] || 0; const name = vehicleTypeMap[key] || `类型${key}`; const percent = total > 0 ? ((value / total) * 100).toFixed(1) : \"0.0\"; return { name, value, percent: Number(percent), color: vehicleColorMap[name] || \"#999999\", }; });}

五、响应式数据更新与图表刷新

通过 watchEffect 监听数据变化,自动计算合并数据并刷新 ECharts 饼图。


watchEffect(() => { const { su1, su2, su3, su4 } = sources; const mergedTotal = mergeTotal( su1.totalVehiCount, su2.totalVehiCount, su3.totalVehiCount, su4.totalVehiCount ); const mergedType = mergeVehicleType( su1.numVehiByType || {}, su2.numVehiByType || {}, su3.numVehiByType || {}, su4.numVehiByType || {} ); chartData.value = formatVehicleTypeData(mergedType, mergedTotal); realtimeTime.value = new Date().toLocaleString(); totalVehiCount.value = mergedTotal; aveSpeed.value = { su1: su1.aveSpeed || 0, su2: su2.aveSpeed || 0, su3: su3.aveSpeed || 0, su4: su4.aveSpeed || 0, }; InitEchart2(chartData.value);});

六、ECharts 饼图动态渲染

初始化并动态更新饼图,颜色对应车辆类型,关闭标签和提示框保证大屏美观。


const InitEchart2 = (data) => { const chartDom = document.getElementById(\"map-left-4-1-echarts\"); if (!chartDom) return; if (!myChart) { myChart = echarts.init(chartDom); } const colorList = data.map(item => item.color || \"#ccc\"); myChart.setOption({ color: colorList, tooltip: { show: false }, series: [{ name: \"车辆类型占比\", type: \"pie\", radius: [\"55%\", \"80%\"], avoidLabelOverlap: false, itemStyle: { borderRadius: 1, borderColor: \"#2c3950\", borderWidth: 2, }, label: { show: false }, emphasis: { scale: false, label: { show: false } }, labelLine: { show: false }, data: data.map(({ name, value }) => ({ name, value })), }], });};

七、启动与定时刷新逻辑

在组件挂载时,初始化数据接口和数据源,并设置定时器周期刷新相关统计数据。


onMounted(() => { curDayCountData(); // 获取今日车流初始数据 initAllSources(); // 启动 WebSocket / 模拟数据 getDeviceOnlineData(); // 设备在线率数据 curDayEventCountData(); // 今日事件统计 eventHistoryCountData(); // 事件历史统计 dataRefreshTimer = setInterval(() => { curDayCountData(); getDeviceOnlineData(); curDayEventCountData(); eventHistoryCountData(); }, 30000);});onUnmounted(() => { if (dataRefreshTimer) clearInterval(dataRefreshTimer);});

八、总结

  • 多数据源实时管理,灵活切换模拟/真实数据,提升开发效率

  • 自动重连机制,保证 WebSocket 长连接稳定可靠

  • 响应式合并处理,统一计算统计数据,确保展示准确

  • ECharts 动态刷新,实现流畅视觉效果,符合大屏需求

如果你正在做交通、工业或监控领域的实时可视化,这个方案值得借鉴。