#2023盲盒+码# 鸿蒙下动态心电波形的模拟 - 基于STAGE模型下ArkTS语言 原创

droidzxy
发布于 2023-8-28 16:12
浏览
1收藏

【本文正在参加 2023「盲盒」+码有奖征文活动】,活动链接 https://ost.51cto.com/posts/25284

简要介绍

本实践主要测试一下在新版本鸿蒙3.1,支持STAGE模型ArkTS语言的环境中,如何实现心电波形的绘制,动态刷新以及多个波形的绘制过程,这里使用的是本地的模拟数据,不包括从物理设备上的数据采集过程。

效果预览

#2023盲盒+码# 鸿蒙下动态心电波形的模拟 - 基于STAGE模型下ArkTS语言-鸿蒙开发者社区

功能分析

整个页面是按照Column进行布局,顶部放置一个Row容器组件,里面包含刷新时间和心率的Text组件,中间和底部分别是Canvas组件,负责绘制心电波形图。
现在的方法是单个波形绘制在单一的Canvas中,如果需要展现更多的波形,按这种方法就需要增加对应数量的Canvas组件。不同的Canvas,需要设置不同的CanvasRenderingContext2D,不能共用同一个。
在Canvas的onReady函数中,我们设置波形曲线的粗细、颜色和端点样式,把起始点moveTo到最左端。
在整个页面的aboutToAppear函数中,我们设置一个定时器,在定时回调中,我们更新时间、心率和波形数据。当波形从左往右画还没有到最右端时,先是通过clearRect清空画线区域历史图像,然后通过lineTo连接到下一个点,并调用stroke进行绘制。当到达最右端时,重新beginPath,并moveTo到屏幕最左端。

实现代码

Index.ets,声明式开发语言文件,布局逻辑放在同一个文件中。


let yPosArray: number[] = [45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 46, 46, 46, 46, 46, 46, 45, 45, 45, 44, 44, 45, 49, 73, 94, 97, 80, 51, 43, 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 47, 47, 48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 55, 54, 53, 52, 50, 48, 47, 45, 44, 44, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47];
let heartData: number[] =  [60, 78, 80, 89, 90, 85, 95, 99, 101, 106, 118]

// xxx.ets
@Entry
@Component
struct Index {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  private context2: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)

  private arrayIndex: number = 0;
  private xPos: number = 1;

  @State timeValue: string = "14:40:32";
  @State heartBeatValue: string = "68";

  aboutToAppear() {

    let that = this;
    let count = 0;

    setInterval(function() {
      console.log('do every 1s.');


      // calc time
      let date = new Date()
      let hh = date.getHours().toString()
      if(date.getHours() < 10) {
        hh = '0' + hh;
      }
      let mm = date.getMinutes().toString()
      if(date.getMinutes() < 10) {
        mm = '0' + mm;
      }
      let ss = date.getSeconds().toString()
      if(date.getSeconds() < 10) {
        ss = '0' + ss;
      }
      that.timeValue = hh + ":" + mm + ":" + ss;


      // heartbeat
      count++;
      if(count > 30) {
        count = 0;
        that.heartBeatValue = heartData[Math.round(10 * Math.random())].toString()

      }


      that.xPos++;
      if(that.xPos > 360) {
        that.xPos = 0

        that.context.beginPath()
        that.context.moveTo(0, 200 - yPosArray[that.arrayIndex])


        that.context2.beginPath()
        that.context2.moveTo(0, 200 - yPosArray[that.arrayIndex])

      }
      that.arrayIndex++;
      if(that.arrayIndex > 99) {
        that.arrayIndex = 0
      }
      that.context.clearRect(that.xPos, 0, 10, 200)
      that.context.lineTo(that.xPos, 200 - yPosArray[that.arrayIndex])
      that.context.stroke()


      that.context2.clearRect(that.xPos, 0, 10, 200)
      that.context2.lineTo(that.xPos, 200 - yPosArray[that.arrayIndex])
      that.context2.stroke()

    }, 50);
  }

  build() {
    Column() {
      Row() {
        Text(this.timeValue)
          .fontColor(Color.White)
          .fontSize(25)

        Row(){
          Text(this.heartBeatValue)
            .fontColor(Color.White)
            .fontSize(38)
          Text(' 次/分')
            .fontColor(Color.White)
            .fontSize(20)
        }
        .alignItems(VerticalAlign.Bottom)
      }
      .width('100%')
      .margin({top: 20})
      .backgroundColor(Color.Black)
      .justifyContent(FlexAlign.SpaceBetween)
      .alignItems(VerticalAlign.Center)
      .padding(10)

      Canvas(this.context)
        .width('100%')
        .height('30%')
        .backgroundColor('#000000')
        .onReady(() =>{

          this.context.lineWidth = 2
          this.context.strokeStyle = 'rgb(0,255,0)'
          this.context.lineCap = 'round'

          this.context.beginPath()
          this.context.moveTo(1, 200 - yPosArray[0])
          this.context.stroke()

        })


      Canvas(this.context2)
        .width('100%')
        .height('30%')
        .backgroundColor('#000000')
        .onReady(() =>{

          this.context2.lineWidth = 2
          this.context2.strokeStyle = 'rgb(0,255,0)'
          this.context2.lineCap = 'round'

          this.context2.beginPath()
          this.context2.moveTo(1, 200 - yPosArray[0])
          this.context2.stroke()

        })
    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.Black)
    .justifyContent(FlexAlign.Start)
    .alignItems(HorizontalAlign.Center)
  }
}

实践总结

在ArkTS中实现波形绘制,还是比较方便的,而且布局和逻辑在一个文件中,源码管理上对开发者来说方便了不少,但逻辑上对波形数据的管理要比js下chart组件复杂些。通过测试发现,当波形数量增加时,整体页面刷新率下降,出现卡顿现象,如果以后在产品中实现动态刷新多波形的情况,可能还需要好好优化一下。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
已于2023-8-28 16:47:10修改
1
收藏 1
回复
举报
1条回复
按时间正序
/
按时间倒序
wx656d869fca5c9
wx656d869fca5c9

博主这篇文章代码有个隐藏bug,有个划线问题,就是每次Canvas 都是从1开始画,正确的方法改为

this.context.moveTo(this.xPos, 200 - yPosArray[0])
1
回复
2023-12-4 16:49:35
回复
    相关推荐