了解更多开源请访问:开源基础软件社区https://ost.51cto.com前言随着大家生活水平的提高,越来越多的人关注自己的身心健康,养生保健成为一项比较普及的活动。心电图是检测心脏活动状态的直观表现,通过心电图可以观察到一个人的健康状况。应鸿蒙万物互联的口号,智能设备和心电检测设备的互联肯定少不了。所以本文实现了一个简单的心电图功能UI展示。效果图组件APIygEcg属性名称类型默认值说明ecgDataEcgDataType-配置ECG信息接口EcgDataType参数名称参数类型必填默认值参数说明dataArrayyes-ECG数据源timeStepnumber为每个cell40代表时间(毫秒),x轴方向的mvStepnumber为0.1,每个小格子代表电压(毫伏/mv),y轴方向的waveLineColorstring为-波浪线颜色gridColorArray为-格子颜色,第一个为a小网格,第二个是大网格maxTimenumberis-图标显示最大时区(毫秒)widthnumberis-canvas宽度heightnumberis-canvas高度backgroundColorstringis-canvas背景颜色组件调用//importinterfaceandcomponentsimportygEcg,{EcgDataType}来自'./../common/components/ygEcg'@Entry@ComponentstructIndex{@StateecgData:EcgDataType={数据:[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毫秒,mvStep在x轴方向: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之前,我以为心电图应该是一个简单的上下波动的折线图。虚线形成ECG波形。实现过程1.创建canvascanvas@ComponentstructygEcg{privatesettings:RenderingContextSettings=newRenderingContextSettings(true);privatectx:CanvasRenderingContext2D=newCanvasRenderingContext2D(this.settings)@LinkecgData:EcgDataType;build(){Canvas(this.ctx).onReady(()=>{}).width(this.ecgData.width).height(this.ecgData.height).backgroundColor(this.ecgData.backgroundColor)}}2.画一个小格子因为心在上面根据电波图,小格子的默认纸速是0.04秒,也就是40毫秒。通过传入数据的timeStep字段的控制,绘制多少个小格子?通过canvas的宽度和maxTime字段(最大显示时间,上面的代码案例是6000毫秒)可以计算出会被绘制。6000/40=150个小基站。//组件生命周期aboutToAppear(){//计算每个小格子需要绘制的宽度this.littleGridSize=Math.floor(this.ecgData.width/(this.ecgData.maxTime/this.ecgData.timeStep))//计算每个大格子需要绘制的宽度(每5个小格子为1个大格子)this.LargeGridSize=this.littleGridSize*5}//绘制一个小格子drawLittleGrid=():void=>{让c=this.ctx;让{width:w,height:h}=this.ecgData;c.strokeStyle=this.ecgData.gridColor[0];c.lineWidth=0.5;c.beginPath();for(letx=0;x<=w;x+=this.littleGridSize){c.moveTo(x,0)c.lineTo(x,h)c.stroke()}for(lety=0;y<=h;y+=this.littleGridSize){c.moveTo(0,y)c.lineTo(w,y)c.stroke()}c.closePath();}3.绘制大格子时,每1个大格子等于5个小格子。//绘制大网格drawLargeGrid=():void=>{letc=this.ctx;让{width:w,height:h}=this.ecgData;让lg=this.LargeGridSize;c.strokeStyle=this.ecgData.gridColor[1];c.lineWidth=0.5;c.beginPath();for(letx=0;x<=w;x+=lg){c.moveTo(x,0);c.lineTo(x,h);c.中风();}for(让y=0;y<=h;y+=lg){c.moveTo(0,y);c.lineTo(w,y);c.stroke();}c.closePath();}最终的绘制结果如图:4.绘制心电波形,得到画布高度的一半作为心电波形的基线。在基线的基础上,通过心电数据源,通过对数据进行偏置绘制虚线,在基线上绘制每条数据,最终形成折线状态的心电波形线。//数据视图更新update=(data?:Array):void=>{letc=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'letpoint=data||这个.ecgData.数据;如果(点。长度===0)返回;//开始遍历输出数据c.moveTo(0,Math.floor(this.ecgData.height/2))for(leti=0;i{letpoints=this.ecgData.data;//最后传出的数据letpointsLast=[];//当前获取的数据条数letcurrInedx=0;让定时器=空;clearInterval(timer)timer=setInterval(()=>{if(currInedx