在现代交通大屏项目中,实时数据的采集和可视化尤为重要。本文结合 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 动态刷新,实现流畅视觉效果,符合大屏需求
如果你正在做交通、工业或监控领域的实时可视化,这个方案值得借鉴。