React+Chart.js绘制网格纸风格PQRST心电图波形技术求助
解决Chart.js实现心电图网格纸波形的问题
核心思路
要实现1mm×1mm的网格纸效果,关键是完成物理单位与画布像素的映射、刻度与网格的精准对齐,以及波形数据的单位转换。以下是具体实现方案:
一、Chart.js 具体配置实现
import React, { useEffect, useRef } from 'react'; import Chart from 'chart.js/auto'; const ECGChart = () => { const canvasRef = useRef(null); useEffect(() => { if (!canvasRef.current) return; const ctx = canvasRef.current.getContext('2d'); // 清除旧实例避免内存泄漏 window.ecgChartInstance?.destroy(); // 心电图标准映射:1mV=10mm,速度25mm/s(1mm对应0.04秒) const mVPerMm = 0.1; const secondsPerMm = 0.04; // 模拟PQRST波形数据 [时间(秒), 电压(mV)] const ecgRawData = [ [0, 0], [0.02, 0.1], [0.04, 0.2], [0.06, 0.1], // P波 [0.08, 0], [0.1, -0.1], [0.12, -0.2], [0.14, 1.5], // QRS波 [0.16, 0], [0.18, -0.1], [0.2, 0.1], [0.22, 0], // ST段 [0.24, 0.05], [0.26, 0.1], [0.28, 0.05], [0.3, 0], // T波 [0.32, 0], [0.34, 0], [0.36, 0], [0.38, 0], [0.4, 0] ]; // 转换数据为网格坐标:X=时间/秒转mm,Y=电压/mV转mm const chartData = { labels: ecgRawData.map(item => item[0] / secondsPerMm), datasets: [{ data: ecgRawData.map(item => item[1] / mVPerMm), borderColor: '#000', borderWidth: 2, fill: false, tension: 0.1, // 轻微平滑贴近真实心电图 pointRadius: 0 // 隐藏冗余数据点 }] }; const chartOptions = { responsive: true, maintainAspectRatio: false, scales: { x: { type: 'linear', min: 0, max: 40, // 显示40mm宽度(对应1.6秒) ticks: { stepSize: 10, // 每10mm显示刻度(对应0.4秒) color: '#666' }, grid: { color: '#ddd', lineWidth: 1, stepSize: 1, // 每1mm绘制一条网格线 drawBorder: true, tickLength: 0 }, title: { display: true, text: '距离(mm) | 速度:25mm/s' } }, y: { type: 'linear', min: -10, // 向下10mm(对应-1mV) max: 10, // 向上10mm(对应1mV) ticks: { stepSize: 10, // 每10mm显示刻度(对应1mV) color: '#666' }, grid: { color: '#ddd', lineWidth: 1, stepSize: 1, // 每1mm绘制一条网格线 drawBorder: true, tickLength: 0 }, title: { display: true, text: '电压(mm) | 10mm=1mV' } } }, plugins: { legend: { display: false } } }; window.ecgChartInstance = new Chart(ctx, { type: 'line', data: chartData, options: chartOptions }); return () => window.ecgChartInstance?.destroy(); }, []); // 适配屏幕DPI:96DPI下1mm≈3.78像素,设置画布实际像素与物理尺寸对应 return ( <div style={{ width: '400mm', height: '200mm', maxWidth: '100%' }}> <canvas ref={canvasRef} style={{ width: '100%', height: '100%' }} width={Math.floor(400 * 3.78)} height={Math.floor(200 * 3.78)} /> </div> ); }; export default ECGChart;
二、关键配置说明
单位映射
- 将原始的时间(秒)、电压(mV)数据转换为mm单位,确保波形与1mm网格完全对齐。
- 画布通过
width/height属性设置实际像素数,CSS设置物理尺寸,解决不同屏幕DPI导致的网格大小偏差。
网格与刻度对齐
grid.stepSize:1确保每1mm绘制一条网格线;ticks.stepSize:10对应心电图标准的1mV/0.4秒刻度。- 关闭刻度线长度(
tickLength:0),让网格线直接作为刻度参考。
波形优化
- 设置
tension:0.1让波形轻微平滑,更贴近真实心电图形态;隐藏数据点避免干扰视觉。
- 设置
三、备选库推荐
如果Chart.js的配置仍无法满足需求,可以考虑专门的医学可视化库:
- ECG.js:专为心电图设计,内置标准网格、波形渲染逻辑,无需手动配置单位映射。
- D3.js:灵活性极强,可完全自定义网格样式、波形动画,适合高度定制场景。
- Plotly.js:提供现成的心电图模板,支持交互功能,配置成本低。
内容的提问来源于stack exchange,提问作者Bhushan wagh
相关产品推荐
相关产品推荐

