从原始采样到可缩放心电图:用 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 一下。我会持续把实际项目里遇到的性能、交互与数据适配问题沉淀到这个仓库里。

相关推荐
冰心孤城1 小时前
Excel: xls与xlsx格式转换排坑指南
java·前端·excel
程序员黑豆2 小时前
鸿蒙应用开发之跨组件传参:@Provide 与 @Consume 跨层级数据同步详解
前端·harmonyos
C++、Java和Python的菜鸟3 小时前
第9章 后端Web进阶(AOP)
java·开发语言·前端
我星期八休息3 小时前
扩展— TCP 全连接队列与 tcpdump 抓包
linux·服务器·开发语言·前端·网络·tcp/ip·tcpdump
AC赳赳老秦4 小时前
CSDN 技术社区数据采集:OpenClaw 抓取公开技术热帖,生成领域技术热点周报
java·大数据·前端·数据库·python·php·openclaw
结网的兔子4 小时前
【前端开发】Web端迁移至 uni-app 及鸿蒙扩展方案对比
前端·uni-app·harmonyos
黄泉路醉s5 小时前
在Vant+Vue+TypeScript的H移动前端使用UnoCSS
前端·vue.js·typescript
水瓶夜之5 小时前
.NET 中的新增功能系列文章——.NET SDK中的新增功能
前端·chrome·.net
笨笨狗吞噬者5 小时前
VS Code 内置浏览器打开网页
前端