1 Star 2 Fork 1

YanGo/ygEcg

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

harmonyOS 基于 ArkUI(ETS) 实现的心电图组件

前言

随着大家生活水平的提升,越来越多的人注重自身身心健康,养生成了目前比较热门的活动。心电图是检测心脏活动状态的直观表现,可以通过心电图来观察人提的健康状况。 响应鸿蒙万物互联的口号,肯定少不了智能设备和心电检测设备的互联。所以本文实现了简单的心电图功能UI展示。

效果图

img

组件API

ygEcg

属性名 类型 默认值 描述
ecgData EcgDataType - 配置心电图的信息

接口 EcgDataType

参数名 参数类型 必填 默认值 参数描述
data Array - 心电数据源
timeStep number 40 每一小格代表时间(毫秒),x轴方向
mvStep number 0.1 每小格表示电压(毫伏/mv),y轴方向
waveLineColor string - 波线颜色
gridColor Array - 网格颜色,第一个为小网格,第二个为大网格
maxTime number - 图标显示最大时间区域(毫秒)
width number - 画布宽度
height number - 画布高度
backgroundColor string - 画布背景色

组件调用

// import 引入接口和组件
import ygEcg,{EcgDataType} from './../common/compontents/ygEcg'

@Entry
@Component
struct Index {
    @State ecgData:EcgDataType = {
        data: [
        0, 0, 0, 0.1, 0, 0, 0, -0.2, 1.5, -0.4, 0, 0, 0, 0.1, 0.2, 0.1, 0, 0, 0,
        0, 0, 0, 0.1, 0, 0, 0, -0.2, 1.0, -0.4, 0, 0, 0, 0.1, 0.2, 0.1, 0, 0, 0,
        0, 0, 0, 0.1, 0, 0, 0, -0.2, 1.0, -0.4, 0, 0.1, 0, 0.1, 0.2, 0.1, 0, 0, 0,
        0, 0, 0, 0.1, 0, 0, 0, -0.2, 2.0, -0.3, 0, 0, 0, 0.1, 0.2, 0.1, 0, 0, 0,
        0, 0, 0, 0.1, 0, 0, 0, -0.2, 1.0, -0.4, 0, 0, -0.1, 0.1, 0.2, 0.4, 0, 0, 0,
        0, 0, 0, 0.1, 0, 0, 0, -0.2, 1.0, -0.4, 0, 0, 0, 0.1, 0.2, 0.2, 0, 0, 0,
        0, 0, 0, 0.1, 0, 0, 0, -0.2, 1.0, -0.4, 0, 0.1, 0, 0.1, 0.2, 0.1, 0, 0, 0,
        0, 0, 0, 0.1, 0, 0, 0, -0.2, 1.0, -0.4, 0, 0, 0, 0.1, 0.2, 0.1, 0, 0, 0,
        0, 0, 0, 0.1, 0, 0, 0, -0.2, 1.0, -0.4, 0, 0, 0, 0.1, 0.2, 0.1, 0, 0, 0,
        ],
        timeStep: 40, // 每一小格表示40毫秒,x轴方向
        mvStep: 0.1, // 每小格表示0.1mv,y轴方向
        waveLineColor: '#181818', // 波线颜色
        gridColor: ['#ffa5a5','#dd0000'], // 网格颜色,第一个为小网格,第二个为大网格
        maxTime: 6000,
        width: 700,
        height: 300,
        backgroundColor: '#fff'
    }
    build() {
        Row(){
          ygEcg({ecgData: $ecgData})
        }
        .justifyContent(FlexAlign.Center)
        .alignItems(VerticalAlign.Center)
        .width('100%')
        .height('100%')
        //    .backgroundColor('#151515')
    }
}

实现前的准备

在写这个demo之前,以为心电图应该就是现在简单的上下波动的折线图 以为是这样的(图片来源于网络) img 实际上医学上心电图是这样的(图片来源于网络) img 最后上网补了一下相关知识,大概了解到的对应的波形和走纸速度的关系(图片来源于网络) img

因为没有见过真实的数据结构,所以参考了上图的波形和走纸速度,自己模拟了一组数据

实现原理

通过使用canvas组件,绘制一个类似医学上的心电图纸网格,然后通过心电源数据,绘制对应的折线形成心电波形

实现过程

一、 创建canvas画布

@Component
struct ygEcg {
  private settings: RenderingContextSettings = new RenderingContextSettings(true);
  private ctx: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  @Link ecgData: EcgDataType;
  build() {
    Canvas(this.ctx)
      .onReady(()=>{
      })
      .width(this.ecgData.width)
      .height(this.ecgData.height)
      .backgroundColor(this.ecgData.backgroundColor)
  }
}

二、 绘制小网格

因为通上面的心电波形图解得知,默认一个小网格的走纸速度是0.04秒,也就是40毫秒,通过传入的数据timeStep字段控制 那么要绘制多少个小格呢?通过画布宽度,和maxTime字段(最大的显示时间,上面代码案例是6000毫秒)可以计算得知,将要绘制 6000/40=150小格

  // 组件生命周期
  aboutToAppear() {
    // 计算每1小格需要绘制的宽度
    this.littleGridSize = Math.floor(this.ecgData.width / (this.ecgData.maxTime / this.ecgData.timeStep))
    // 计算每1大格需要绘制的宽度(每5小格是1大格)
    this.LargeGridSize = this.littleGridSize * 5
  }
//   绘制小格
  drawLittleGrid = ():void => {
    let c = this.ctx;
    let {width:w, height: h} = this.ecgData;
    c.strokeStyle = this.ecgData.gridColor[0];
    c.lineWidth = 0.5;
    c.beginPath();
    for(let x = 0; x <= w; x += this.littleGridSize){
      c.moveTo(x, 0)
      c.lineTo(x, h)
      c.stroke()
    }
    for(let y = 0; y <= h; y += this.littleGridSize){
      c.moveTo(0, y)
      c.lineTo(w, y)
      c.stroke()
    }
    c.closePath();
  }

三、 绘制大网格

每1大格等于5小格

//  绘制大格
  drawLargeGrid = ():void => {
    let c = this.ctx;
    let {width:w, height: h} = this.ecgData;
    let lg = this.LargeGridSize;
    c.strokeStyle = this.ecgData.gridColor[1];
    c.lineWidth = 0.5;
    c.beginPath();
    for(let x = 0; x <= w; x += lg){
      c.moveTo(x, 0);
      c.lineTo(x, h);
      c.stroke();
    }
    for(let y = 0; y <= h; y += lg){
      c.moveTo(0, y);
      c.lineTo(w, y);
      c.stroke();
    }
    c.closePath();
  }

最后绘制的结果如图 img

四、 绘制心电波形

获取画布高度的一半位置,作为心电波形的基线,在基线的基础上,通过心电数据源,将每个数据在基线上通过对数据的偏于来绘制点线,最后形成一个折线状态的心电波形线

// 数据视图更新
  update = (data?: Array<number>):void => {
    let c = this.ctx;
//    c.clearRect(0, 0, this.ecgData.width, this.ecgData.height)
    c.beginPath();
    c.strokeStyle = this.ecgData.waveLineColor;
    c.lineWidth = 1.2;
    c.lineJoin = 'round'
    c.lineCap = 'round'
    let point = data || this.ecgData.data;
    if(point.length === 0) return;

    //开始遍历输出数据
    c.moveTo(0, Math.floor(this.ecgData.height / 2))
    for (let i = 0; i < point.length; i++) {
      let x = i * this.littleGridSize;
      let y = Math.floor(this.ecgData.height / 2) + point[i] * this.LargeGridSize * -1
      c.lineTo(x, y);
      c.stroke();
    }
    c.closePath();

  }

刷新预览器看看效果 img

五、 最后一步实现心跳的动画效果

这里的动画刷新时间是根据配置的心电图步长来做定时器的时间,默认是40毫秒,也就是每一小格走纸的时间。这样就可以保持跟实际时间对应,不会出现心跳快慢的问题。 当然,这里还是有写误差的,因为代码执行的过程也是消耗时间的,会比实际时间多一丢丢

//  获取心律数据
  getEcgData = ():void => {
    let points = this.ecgData.data;
    //最后传递出去的数据
    let pointsLast = [];
    //当前取到了第几个数据了
    let currInedx = 0;
    let timer = null;
    clearInterval(timer)
    timer = setInterval( ()=> {
      if(currInedx < points.length){
        currInedx ++;
        pointsLast = points.slice(0,currInedx)
        this.update(pointsLast)
      } else {
        clearInterval(timer)
      }
    },this.ecgData.timeStep)
  }

最后再来看一下心电图的动画效果 img

代码地址

https://gitee.com/yango520/yg-ecg2

总结

绘制这个心电图没有用到重绘机制,动画效果是每次绘制的时候覆盖在原有的波形线上的,但是这样会比重绘整个画布性能更好一些。 通过实现这个demo之后,对心电图上的信息有了全新的了解,我觉得大家都可以去学会看心电图来分析心脏状况,自己理解了总比别人告知更有说服力。

避坑小技巧

  1. 当代码大变更的时候(一般复制出来单独做一个文件的时候),需要在build选项卡里清理项目,不然也不报错,也不刷新,但是样式就是错乱。
  2. 预览器开久了之后,当一段时间不动了,再次刷新开启都一直卡着开启中进不去,需要关闭IDE重新打开才可以用。

空文件

简介

基于harmonyOS(eTS)实现的心电图功能 展开 收起
TypeScript 等 2 种语言
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/yango520/yg-ecg.git
git@gitee.com:yango520/yg-ecg.git
yango520
yg-ecg
ygEcg
master

搜索帮助

Cb406eda 1850385 E526c682 1850385