Bootstrap

模拟ECG心电图

最近项目中遇到实现ECG心电图效果,此示例只是模拟效果,还不能对接真实数据。

展现的效果图

本示例使用 ES6class 语法糖,结合 canvas 画布标签实现。

class ECGCanvas {}
  • 首先创建类名 ECGCanvas

构造函数

constructor(options={}){
  this.element = options.element || 'canvas'; // canvas元素id
  this.canvas = document.getElementById(this.element);  // canvas对象
  this.context = this.canvas.getContext("2d");  // canvas上下文
  this.context.width = options.width || 250; // canvas宽
  this.context.height = options.height || 100; // canvas高
  this.context.lineWidth = options.lineWidth || 1;  // canvas 绘制线粗细
  this.context.strokeStyle = options.strokeStyle || '#396'; // canvas 绘制线颜色
  this.speed = options.speed || 20; // 绘制速度
  this.point = { x : 0, y : this.context.height / 2 }; // 绘制当前坐标位置
  this.counter = 0; // 计数,为累加用
  this.distance = 10; //  波动间隔
  this.interval = null; // 定时器
}

接着实现 ECGCanvas 类的构造函数,对应属性已给出注释,下面几个说明一下

  • point 是要画线的坐标位置,{ x : 0 } 表示横向从画布的最左端开始, { y : this.context.height / 2 } 是纵向从画布的最中间开始。
  • counter 绘制线时做累加用
  • distance 波动间隔,数值越大,波动越不明显
  • interval 做定时器用,绘制动画用 setInterval 实现。

绘制方法draw()

draw(){
  let x = (this.counter += 0.1) * this.distance;
  let y = this.context.height / 2 - Math.tan((Math.cos(this.counter) * Math.random() * 2));
  this.context.beginPath();
  this.context.moveTo(this.point.x, this.point.y)
  this.context.lineTo(x, y);
  this.context.closePath();
  this.context.stroke();
  this.point = { x, y };
  if( this.point.x >= this.context.width ){
    this.reset();
  }
}

实现 ECGCanvas 类的绘制线的 draw() 方法

  • x 算法是 counter 累加0.1的结果再与 distance 求乘积。
  • y 的算法是模拟绘制图线上下波动的关键。随机数 Math.random 生成0到1之间的小数,再与 Math.cos 余弦函数的乘积使其波动的概率减小。与 context.height / 2 取差值是为了绘制点的纵向坐标始终在纵向的中心上下波动。正切函数 Math.tan 在某一个间断区间内是递增函数,它的值小概率会接近正负∞,也就是绘制曲线时波动会小概率出现陡增陡降的情况。

reset() 方法

reset(){
  clearInterval(this.interval);
  this.counter = 0;
  this.point = { x : 0, y : this.context.height / 2 };
}
  • 停止计时器
  • 重置 counterpoint

clear() 方法

clear(){
  this.context.clearRect(0, 0, this.context.width, this.context.height);
}
  • context.clearRect 清空画布

最后写一个 start() 方法

start(){
  this.reset();
  this.clear();
  clearInterval(this.interval);
  this.interval = setInterval(this.draw.bind(this),this.speed);
}
  • 注意 setInterval 中的 this.draw.bind(this)。 ( this 本身的坑,不然现在都推崇 hooks )

现在可以开始测试了

<canvas id="canvas" width="250" height="100"></canvas>
<button onclick="onDraw()">绘制</button>
  • 准备一个 canvas 标签,和一个触发绘制功能的按钮。
let ecg = new ECGCanvas();
function onDraw(){
  ecg.start();
}
  • 实例化对象,并调用 start 方法绘制心电图。
;