返回搜索
Chart.js 时间轴与数据时间戳不匹配导致图表不显示的问题
5次浏览1/8/2026
Chart.jsVue 3TypeScriptTime SeriesData VisualizationElectron

问题描述

在使用 Chart.js 绘制时间序列图表时,虽然数据已经成功查询并映射到图表数据结构中,但图表仍然不显示任何数据。日志显示数据映射成功(`validDataCount: 249`),但生成的图表数据中所有值都是 `null`。 具体表现: - 数据查询成功,返回 249 条记录 - 数据映射到 `dataMap` 成功 - 但生成的图表数据数组中所有值都是 `null` - 图表渲染后没有任何数据点显示

根本原因

图表时间轴的生成逻辑与数据时间戳不匹配。具体原因: 1. **固定时间轴生成**:图表从 `now - HISTORY_DURATION` 开始,每秒生成一个时间点(共 300 个点) 2. **数据时间戳不对齐**:数据库中的时间戳是实际保存时间,与固定生成的时间轴不完全对齐 3. **时间戳匹配失败**:数据映射时使用向下取整到秒的方式匹配,但由于时间轴起始点与数据时间戳存在差异(如 588ms),导致无法匹配 4. **复杂的映射逻辑**:虽然添加了最近匹配逻辑,但在某些情况下仍然无法正确匹配 根本原因是试图将实际数据时间戳映射到固定生成的时间轴上,而不是直接使用数据的时间戳作为横轴。

解决方案

简化图表逻辑,直接使用数据库中的时间戳作为横轴,不做任何时间对齐或映射处理: ```typescript // 在 createChart 函数中 const createChart = ( canvas: HTMLCanvasElement, label: string, dataKey: keyof PerformanceDataPoint, yAxisLabel: string, range: { min: number; max: number }, formatValue?: (value: number) => string ): Chart<'line', number[], string> => { // 直接使用数据库中的时间戳作为横轴,不做任何处理 // 按时间戳排序 const sortedData = [...performanceData.value].sort((a, b) => a.timestamp - b.timestamp); // 生成时间标签(横轴) const labels: string[] = sortedData.map((point) => { const date = new Date(point.timestamp); return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}`; }); // 直接使用数据值,不做任何映射或对齐 const data: number[] = sortedData.map((point) => { let value = point[dataKey] as number; // 对于码率稳定性,计算相对值(相对于平均值) if (dataKey === 'bitrate') { const avgBitrate = sortedData.reduce((sum, p) => sum + p.bitrate, 0) / sortedData.length; const bitrateBaseline = avgBitrate > 0 ? avgBitrate : 1; value = bitrateBaseline > 0 ? (value / bitrateBaseline) : 1; } return value; }); // 创建标记线数据(合理范围) const minLineData = new Array(sortedData.length).fill(range.min); const maxLineData = new Array(sortedData.length).fill(range.max); // 创建图表... }; ``` 同样修改 `updateChartData` 函数: ```typescript const updateChartData = (chart: Chart<'line', number[], string> | null, ...) => { if (!chart) return; // 直接使用数据库中的时间戳作为横轴,不做任何处理 const sortedData = [...performanceData.value].sort((a, b) => a.timestamp - b.timestamp); // 生成时间标签和数据... // 更新图表... }; ``` 关键修改点: 1. **移除固定时间轴生成**:不再生成固定的时间点数组 2. **直接使用数据时间戳**:使用实际数据的时间戳作为横轴标签 3. **简化数据映射**:直接使用数据值,不做任何时间对齐或映射 4. **保持数据完整性**:显示所有数据点,按时间戳排序

背景信息

这是一个基于 Electron + Vue 3 + TypeScript 的推流监控应用。使用 Chart.js 绘制性能监控图表,显示 FPS、丢帧率、丢包率和码率稳定性等指标。 技术栈: - **前端框架**:Vue 3 + TypeScript - **图表库**:Chart.js - **数据库**:SQLite (通过 sql.js) - **数据格式**:时间序列数据,每个数据点包含时间戳和多个指标值 原始设计: - 图表显示最近 5 分钟的数据 - 横轴固定为 300 个时间点(每秒一个点) - 将实际数据映射到固定时间轴上 问题发现过程: 1. 数据查询成功,但图表不显示 2. 日志显示数据映射成功,但生成的图表数据都是 `null` 3. 检查时间戳发现数据时间戳与时间轴时间戳存在差异(如 588ms) 4. 尝试添加最近匹配逻辑,但问题仍然存在 5. 最终改为直接使用数据时间戳,问题解决 相关文件: - `src/renderer/components/StreamPerformanceViewer.vue` - 图表组件 - `createChart()` 函数 - `updateChartData()` 函数