从原始采样到可缩放心电图:用 h5ECG 绘制自己的 ECG

很多前端项目都能"画一条曲线",但要把真实的 ECG 采样画成一张可读、可缩放、比例正确的心电图纸,细节远比一条 canvas.lineTo() 多。

我把这个过程整理成了 h5ECG:一个框架无关的 ECG Canvas 渲染库,提供原生、React 和 Vue 三种入口。它把网格、波形、缩放、拖拽、12 导联排版和测量尺都封装好;你只需要准备自己的采样数据。

本文讨论的是数据可视化与前端实现,不用于医疗诊断。实际临床使用还需要合规的数据处理、设备标定与专业审核。

先说最容易踩坑的:你的"数值"到底是什么?

不同采集设备输出的数据并不相同。有的直接给 mV,有的给 ADC 整数,有的还带着偏移量。h5ECG 默认按本仓库示例的标定理解输入:

  • 基线 adcBaseline: 2048
  • 换算系数 adcUnitsPerMv: 1000,即 1000 个 ADC units = 1mV

因此,一串类似 2025, 2025, 2038 的数据不是直接拿来当像素高度,而是先换算为 mV,再按增益绘制。若你的设备参数不同,务必覆盖这两个选项;比例错了,波形看似正常,时间和电压含义却已经不对了。

安装:npm、GitHub 都可以

优先使用 npm:

复制代码
npm install h5ecg

如果你希望直接依赖源码仓库,也可以固定到已发布版本:

bash 复制代码
npm install github:dongweiq/h5ecg#v0.1.1

固定 tag 而不是分支名,是为了让团队构建更稳定、结果更可复现。

最小可用示例:在页面上画出一条自己的波形

页面里准备一个有高度的容器:

bash 复制代码
<div id="viewer" style="height: 520px"></div>

再把你自己的单导联数据传入:

ini 复制代码
import { EcgCanvas } from 'h5ecg';

const samples = '2025\n2025\n2038\n2040';

const viewer = new EcgCanvas(document.getElementById('viewer')!, {
  mode: '12x1',
  speed: 25,
  gain: 10,
  pixelsPerMillimeter: 8,
  adcBaseline: 2048,
  adcUnitsPerMv: 1000,
});

viewer.setData(samples);

这里有三个真正决定"心电图纸感"的参数:

  • speed: 25:25 mm 对应 1 秒,所以 1 mm 小格为 40 ms。
  • gain: 10:10 mm 对应 1 mV。
  • pixelsPerMillimeter:只决定屏幕显示密度,不改变上述医学比例。

想看更细的局部时,可以直接调用:

ini 复制代码
viewer.zoomBy(1.2);
viewer.setOptions({ speed: 50, gain: 20 });
viewer.resetViewport();

用户也能用鼠标拖动、滚轮或双指缩放。网格与波形会分层绘制,且只处理可见样本;高密度数据缩小时会保留每个像素桶的峰谷,而不是把尖峰"抹平"。

你的数据是 12 导联?直接传数组或对象

h5ECG 支持 12x1、6x2-sync、6x2-continuous、3x4-sync 和 3x4-continuous 等布局。可以传入 12 条导联的数组,也可以传一个带导联名的对象:

php 复制代码
viewer.setOptions({ mode: '3x4-continuous' });

viewer.setData({
  I: leadI,
  II: leadII,
  III: leadIII,
  aVR: leadAVR,
  aVL: leadAVL,
  aVF: leadAVF,
  V1: leadV1,
  V2: leadV2,
  V3: leadV3,
  V4: leadV4,
  V5: leadV5,
  V6: leadV6,
});

这比在业务代码里手动切 12 个 Canvas、算每个导联的起止坐标要省心得多。

React 和 Vue:包装组件直接上

React:

javascript 复制代码
import { EcgCanvas } from 'h5ecg/react';

export function ReportView({ samples }: { samples: number[] }) {
  return (
    <EcgCanvas
      data={samples}
      mode="6x2-sync"
      speed={25}
      gain={10}
      style={{ height: 520 }}
    />
  );
}

Vue:

ini 复制代码
<script setup lang="ts">
import { EcgCanvas } from 'h5ecg/vue';
const samples = '2025\n2025\n2038';
</script>

<template>
  <EcgCanvas
    :data="samples"
    :options="{ mode: '3x4-continuous', speed: 25, gain: 10 }"
    style="height: 520px"
  />
</template>

加上测量尺,让"看图"变成可交互查看

除了展示,组件还支持可拖拽的测量尺,可返回时长、电压和心率估算:

javascript 复制代码
const viewer = new EcgCanvas(container, {
  onRulerChange(measurement) {
    console.log(measurement.durationMs);
    console.log(measurement.voltageMv);
    console.log(measurement.heartRateBpm);
  },
});

viewer.setRulerVisible(true);

这些结果建立在 speed、gain、设备标定和缩放比例正确的前提上。也正因为如此,先把数据单位搞清楚,比先调颜色和线宽更重要。

试试看,也欢迎一起完善

在线示例在这里:h5ECG Demo。

项目源码、Issue 和贡献入口在这里:github.com/dongweiq/h5...。

如果这个库帮你少写了一堆 Canvas 坐标计算,欢迎点一个 Star ;如果你也在做医疗可视化、波形渲染或前端组件库,欢迎 Follow 一下。我会持续把实际项目里遇到的性能、交互与数据适配问题沉淀到这个仓库里。

相关推荐
故七月2 小时前
GEO 信源评估体系:如何判断一条网页信源能否被大模型采信
前端·网络·人工智能
liangshanbo12152 小时前
Webpack 常见 Plugin 面试题
前端·webpack·node.js
xxwl5852 小时前
vue3的入门学习
前端·vue.js·学习
用户847172102842 小时前
.shot 文件格式规范
前端·后端
web打印社区2 小时前
政务办事大厅:叫号小票、办理回执网页怎么静默出纸
前端·javascript·vue.js·pdf·html·政务
C++ 老炮儿的技术栈2 小时前
有符号变量与无符号变量的区别
服务器·开发语言·前端·数据结构·c++·算法·c
aixingpan2 小时前
aixingpan.cn API开发文档:api_docs_bichart_natalvssecondary2接口指南
前端·php
liangshanbo12152 小时前
Webpack Tree Shaking 面试题整理
前端·webpack·node.js
去伪存真3 小时前
从乱码到高精度检索:探矿业务中 TXT、Word、PDF 与网页的 RAG 清洗之道
前端·agent
两个西柚呀3 小时前
JS事件总结
前端·javascript·css