You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

二、关键配置说明

  1. 单位映射

    • 将原始的时间(秒)、电压(mV)数据转换为mm单位,确保波形与1mm网格完全对齐。
    • 画布通过width/height属性设置实际像素数,CSS设置物理尺寸,解决不同屏幕DPI导致的网格大小偏差。
  2. 网格与刻度对齐

    • grid.stepSize:1 确保每1mm绘制一条网格线;ticks.stepSize:10 对应心电图标准的1mV/0.4秒刻度。
    • 关闭刻度线长度(tickLength:0),让网格线直接作为刻度参考。
  3. 波形优化

    • 设置tension:0.1 让波形轻微平滑,更贴近真实心电图形态;隐藏数据点避免干扰视觉。

三、备选库推荐

如果Chart.js的配置仍无法满足需求,可以考虑专门的医学可视化库:

  • ECG.js:专为心电图设计,内置标准网格、波形渲染逻辑,无需手动配置单位映射。
  • D3.js:灵活性极强,可完全自定义网格样式、波形动画,适合高度定制场景。
  • Plotly.js:提供现成的心电图模板,支持交互功能,配置成本低。

内容的提问来源于stack exchange,提问作者Bhushan wagh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 20:40:59