当前位置: 首页 > news >正文

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 su4const 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 动态刷新,实现流畅视觉效果,符合大屏需求

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

http://www.dtcms.com/a/291894.html

相关文章:

  • AI创作系列第22篇:前端缓存与更新机制重构 - 表情包系统的全面升级
  • 贪心算法Day4学习心得
  • 当直播间告别“真人时代”:AI数字人重构商业新秩序
  • haproxy七层代理新手入门详解
  • 零事故网站重构:11步标准化流程与风险管理指南
  • 第13天 | openGauss逻辑结构:表管理1
  • zabbix“专家坐诊”第295期问答
  • SPI的收发(W25Q64外部flash 和 内部flsah)
  • 小米视觉算法面试30问全景精解
  • Android常用的adb和logcat命令
  • 【bug】ubuntu20.04 orin nx Temporary failure resolving ‘ports.ubuntu.com‘
  • 【测试开发】---Bug篇
  • kafka主题管理详解 - kafka-topics.sh
  • Claude Code Kimi K2 环境配置指南 (Windows/macOS/Ubuntu)
  • 热点leetCode题
  • AI助力临床医学科研创新与效率双提升丨临床医学日常工作、论文高效撰写与项目申报、数据分析与可视化、机器学习建模等
  • Vercel AI SDK 3.0 学习入门指南
  • Java设计模式揭秘:深入理解模板方法模式
  • 一个简单实用的 WinForm 通用开发框架
  • 替代Oracle?金仓数据库用「敢替力」重新定义国产数据库
  • Pygame开源--谷歌小恐龙游戏(附彩蛋)
  • Custom SRP - Draw Calls
  • 从零构建智能对话助手:LangGraph + ReAct 实现具备记忆功能的 AI 智能体
  • Spring Boot 整合 Redis 实现发布/订阅(含ACK机制 - 事件驱动方案)
  • 【Autosar】RTE(Runtime Environment)层详解
  • lspci/setpci用法小结
  • Day 18:推断聚类后簇的类型
  • 支付网关系统前后端鉴权方案
  • LLaMA-Mesh:语言模型驱动的3D内容生成革命
  • LLaMA-Factory相关参数说明