大家好,我是雄雄。

内容先知

  • 前言
  • 效果图
  • 实现代码

前言

近期,接了个项目,三端(小程序、PC、公众号)同步开发,PC端没的问题,以前一直做的就是PC端,但是小程序和公众号之前没有做过,只能通过这个项目,边做边学了。

人家都说小程序用原生的特别难,大部分都用uniapp开发,说是这个方便快捷,还能写app呢,因为我们的项目,需要用到蓝牙采集数据、画布画仪表盘以及心电图等,所以我们不太敢用uniapp开发,硬着头皮开始用原生开发。开发的过程中,也遇到过很多问题,但是好在经过我们团队的不懈努力,问题基本都解决了。

下面我就来分享一下,在小程序中,如何通过canvas实现心电图的绘制,包括背景方格,R波等~

效果图

下面我们先来看看效果图:

由于电脑显示有误差,所以有的线粗有的线细,在手机上没有任何问题。

这个是按照标准来做的,两个大格1cm,一个大格有5个小格,每个小格有10个数据,绘制的进度为:20ms就传递来5个数,随机绘制在图中。

实现代码

首先在wxml中的代码为:

<!-- 心电图 --><view class="tab-middle-ecg"><view class="tab-middle-line"><canvas type="2d" id="ecgGridCanvas" style="width: 100%;height: 255px;margin:-10px auto 0;"></canvas></view><view class="tab-middle-grid" style="width: 290px;margin: -280px auto 0;overflow: hidden;"><canvas type="2d" id="ecgCanvas" style="width: 100%;height: 260px;margin: 0 auto;display: inline-flex;"></canvas></view></view>

然后就是index.js文件的相关代码了:
找到onReady(),在内部添加代码:

//心电图的背景const queryLine = wx.createSelectorQuery();queryLine.select('#ecgGridCanvas').fields({node: true,size: true}).exec((res) => {//为什么要加25?不知道。const width = 500;const height = 330;const canvas = res[0].node;const ctx = canvas.getContext('2d');//获取设备的像素比const dpr = wx.getSystemInfoSync().pixelRatio;canvas.width = width * dpr;canvas.height = height * dpr;ctx.scale(dpr, dpr)//调用画图的方法this.setEcgLineCharts(res[0]);})//心电图的线const query = wx.createSelectorQuery();query.select('#ecgCanvas').fields({node: true,size: true}).exec((res) => {const canvas = res[0].nodeconst ctx = canvas.getContext('2d')const dpr = wx.getSystemInfoSync().pixelRatiocanvas.width = 290 * dprcanvas.height = 160 * dprctx.scale(dpr, dpr)//this.setEcgCharts(res[0])})

methods中的方法如下:

  /*画图*/setEcgLineCharts(canvas) {//构建画布const options = {//背景颜色backgroundColor: '#FFFFFF',//网格颜色gridColor: ['#34a0fb', '#c7dff5', '#63b3f8'],//网格颜色// gridColor:['#34a0fb','#e0acbd','#ea0808'],//控制的是最下面左下角文字的颜色lineColor: '#070606',//这两个可以整体控制方格的大小h: 325,w: 475,data: [],start: true,bgline: true,ampTime: true};//调用画布的方法heartChart(canvas, options);//加载数据this.getEcgData();//heartChart.prototype.drawFun()},//心电数据getEcgData() {//950个数据,理论上是一整屏幕let data = "2043,2045,2049,2044,2042,2054,2055,2053,2045,2045";//测试数据 100个数据,也就是占用两个大格//let data = "2043,2045,2049";//封装的数据let points = [];//最后传递出去的数据let pointsLast = [];//将数据拆分下来放在这个数组里面data.split(',').forEach((res) => {points.push(res);});//当前取到了第几个数据了let currInedx = 0;//当前是第几组数据let currGroupData = 0;//20毫秒传递一次var timer = setInterval(function () {var count = 1;pointsLast = [];for (let i = currInedx; ; i++) {if (count > 5) {break;}pointsLast.push(points[i]);count++;}//一波五个数,下一波的索引就需要加5currInedx += 5;if (currInedx >= points.length) {//clearInterval(timer);//console.log("currIndex的值是:",currInedx);}//调用划线的方法heartChart.prototype.update({data: pointsLast,//传递的这一组数据开始的第一个数据currentData: pointsLast[0],//当前是第几组currGroupData: currGroupData})//组数加1currGroupData++;if (currGroupData >= points.length / 5) {clearInterval(timer);}}, 20);},

需要注意的是:data 变量中的数据应该是有950个,在手机上正好是一个屏幕的数据。

最后一步,在ecg.js文件中,写如下代码:

//画布的属性
let chartOption = null;
//页面dom元素
let domCavas = null;
//Canvas的属性
let ctx = null;
//重新封装的画布属性
let options = null;
//是否是第一次进来
let isFrist = false;
//上一波最后一个y轴的数
let lastY = 0;let heartChart = function (dom, option) {//拿到传递过来的画布的属性,进行构造chartOption = Object.assign({}, option);ctx = dom.node.getContext('2d');domCavas = dom;domCavas.width = chartOption.w;domCavas.height = chartOption.h;//绘制背景方格heartChart.prototype.drawBackground();//左下角文字heartChart.prototype.drawTxt();//调用更新绘制的方法heartChart.prototype.update(option);//定标符号heartChart.prototype.GongLink();}
/*画方格*/
heartChart.prototype.drawBackground = function () {if (chartOption.bgline) {heartChart.prototype.drawMd()//小格heartChart.prototype.drawLg()//大格}
}
/*小格*/
heartChart.prototype.drawMd = function () {ctx.strokeStyle = chartOption.gridColor[1];ctx.strokeWidth=1;ctx.beginPath();var w = chartOption.w, h = chartOption.h;for (var x = 0.5; x < w; x += 5) {ctx.moveTo(x, 0);ctx.lineTo(x, h);ctx.stroke();}for (var y = 0.5; y < h; y +=  5) {ctx.moveTo(0, y);ctx.lineTo(w, y);ctx.stroke();}ctx.closePath();return;
}
/*大格*/
heartChart.prototype.drawLg = function () {ctx.strokeStyle = chartOption.gridColor[2];ctx.strokeWidth = 1;ctx.beginPath();let w = chartOption.w + 0.5, h = chartOption.h + 0.5;let hl = 0;let wl = 0;for (let x = 0.5; x < w; x += 25) {ctx.moveTo(x, 0);ctx.lineTo(x, h);ctx.stroke();wl = x;}for (let y = 0.5; y < h; y += 25) {ctx.moveTo(0, y);ctx.lineTo(w, y);ctx.stroke();hl = y;}ctx.moveTo(wl + 25, 0);ctx.lineTo(wl + 25, hl + 25);ctx.lineTo(0, hl + 25);ctx.stroke();ctx.closePath();
}
/*左下角文字*/
heartChart.prototype.drawTxt = function () {let color = chartOption.lineColor;if (chartOption.ampTime) {ctx.font = '10px Arial';ctx.fontWeight = '300';ctx.fillStyle = color;ctx.fillText("Amp: 10mm/mv  Time: 25mm/sec", 10, 320);}
}
/*定标符号*/
heartChart.prototype.GongLink = function () {ctx.moveTo(0, 175);ctx.lineTo(0, 125);//绘制已定义的路径ctx.stroke();//创建从当前点回到起始点的路径。ctx.closePath();
}
/*** 画线的方法* 1.一共有19个大格子* 2.一个大格子有5个小格子,一共就是19*5=95个小格子* 3.一个小格子放10个数据,一页就是95*10=950个数据* 4.拿过来的数据,需要拆分一下,950个一波,再950个一波,不能都一起画完* 5.先按照逗号截取,截取出来了之后重新赋值到变量里面*/
heartChart.prototype.update = function (option) {//起始一条路径,或重置当前路径。ctx.beginPath();//设置或返回用于笔触的颜色、渐变或模式ctx.strokeStyle = chartOption.lineColor;ctx.lineWidth = '1';//合并对象options = Object.assign({}, chartOption, option);chartOption = options;let point = [];//拿到传递过来的数据point = chartOption.data;//拿到传递的这一组数据开始的第一个数据let currentX = chartOption.currentData;//拿到组数(相当于x轴的坐标)let currGroupData = parseFloat(chartOption.currGroupData) * 2.5;//第一次进来的时候,处理这些if (!isFrist) {//在给定的矩形内清除指定的像素。ctx.clearRect(0, 0, 0, 0);// 把路径移动到画布中的指定点,不创建线条。ctx.moveTo(currentX, 150);//修改这个值,让变成第二次isFrist = true;}else{//将点移动到上一波最后一个点上ctx.moveTo(currGroupData-0.5, lastY);//console.log("当前坐标",currGroupData-0.5, lastY)}//如果没有传来数据,直接出去,别画了if (point.length <= 0) {return false;}//开始遍历输出数据for (let i = 0; i < point.length; i++) {let obj = {//x轴x: currGroupData + i * 0.5,//y轴y: 175 - parseInt((parseInt(point[i]) - 2048) * 0.32),};//判断心电是否有值if (!isNaN(obj.y)) {//y轴有值的时候在画ctx.lineTo(obj.x, obj.y);//记录上一波最后一个y轴lastY = obj.y;}}//绘制已定义的路径ctx.stroke();//创建从当前点回到起始点的路径。ctx.closePath();// console.log("最后一个y",lastY)
}
export {heartChart};

其实,网上也有类似的canvas画布画心电图,但是,没有达到我想要的效果,所以就研究了好几天,自己画了这么一套,要是觉得本文能帮助你的话,还望收藏下来,以便后续使用。

微信小程序中使用画布canvas实现动态心电图绘制相关推荐

  1. 在H5、微信小程序中使用canvas绘制二维码、分享海报

    在H5.微信小程序中使用canvas绘制二维码.分享海报 文章目录 在H5.微信小程序中使用canvas绘制二维码.分享海报 前言 一.canvas绘制二维码 1.H5中使用canvas 2.微信小程 ...

  2. Canvas绘图在微信小程序中的应用:生成个性化海报

    Canvas绘图在微信小程序中的应用:生成个性化海报 如极客时间的一些实现案例: 基础语法 Canvas本质是一个可以使用脚本(通常为JavaScript)来绘制图形的 HTML 元素,默认大小为30 ...

  3. Canvas 动画引擎解析与微信小程序中的应用

    点击观看大咖分享 抗击疫情,腾讯云在行动.在开发微信小程序的过程中,我们经常需要展现一些图形和图表.目前市面上有好几款常用的图形库,在这些图形库的底层都有渲染引擎在支撑. ZRender 是其中一款非 ...

  4. Canvas绘图在微信小程序中的应用:生成个性化海报 1

    一.Canvas应用的背景(个人理解)及基础语法 背景 从2012年开始,微信那个时候用户的积累的量已经非常大了,推出公众号,当然大屏智能手机在那个时候也流行,传统的大众媒体逐步消亡,像微信公众号这样 ...

  5. 在微信小程序中绘制图表(part2)

    本期大纲 1.确定纵坐标的范围并绘制 2.根据真实数据绘制折线 相关阅读: 在微信小程序中绘制图表(part1) 在微信小程序中绘制图表(part3) 关注我的 github 项目 查看完整代码. 确 ...

  6. 微信小程序中裁剪图片以及压缩到指定尺寸并上传

    本文分为两个内容,分别是裁剪图片和压缩 引出问题 1.为何要裁剪图片 因为需要上传头像,但是每个型号的手机拍出来的照片尺寸都不太一样,不能统一,所以,希望在上传之前进行自主裁剪,保证上传到服务器上的尺 ...

  7. 微信小程序中的页面文件和组件

    页面文件 页面构造器 JS文件 页面的JS文件,用于书写当前页面所需要的脚本代码以及生命周期函数. Page() : 注册了一个页面 接收一个对象,该对象用于配置当前页面所需内容. 该对象拥有的属性: ...

  8. 微信小程序中使用async/await

    在之前写了微信小程序中如何使用promise,其实使用promise的最终目的是要能使用async/await. 同时要使用async/await也必须在promise的基础之上. 1.下载regen ...

  9. 微信小程序中进行图片压缩

    微信小程序中进行图片压缩 问题: 一般情况下,小程序在进行拍照识别的时候,上传图片的大小会使小程序出现冗余,这个时候,为了减少小程序的冗余 并且使上传的图片可以分辨出该图片中的内容是那些内容,我们就需 ...

最新文章

  1. 黄聪:C# 反射入门知识
  2. 【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 amp; 纹理混合...
  3. 毕业三年,贷款40万创业之后我又做回了程序员
  4. windows消息处理机制
  5. mysql udf limit_锁定服务UDF接口
  6. 自动化运维之–Cobbler
  7. yum 安装没有公钥_window 安装docker
  8. Oracle中修改sysman和dbsnmp密码正确流程
  9. 《一》Android 数据库 SQlite SQLiteOpenHelper
  10. Spark内存空间分配机制
  11. Vue全家桶+koa2+MySql(sequelize)重构“零食商贩”项目
  12. centos安装nginx 编译时报错_树莓派centos-arm安装k8s编译
  13. 新型智慧城市的技术诠释
  14. MySQL基础学习_第016章节_简单的查询语句
  15. 《花开半夏》--9 远去
  16. Matlab保留工作区变量教程
  17. ISCC 2019 逆向rev02
  18. 微信公众平台教程--素材编辑
  19. 报表服务器组件,开发者手册概述:Power BI 报表服务器
  20. Echarts 实现动态地图

热门文章

  1. OJ每日一练——乘方计算
  2. Java实现 四舍五入取整到百位 四舍五入取整到千位 数字取整到千位 数字取值到千位 数字取整到百位 数字取值到百位
  3. 史上首例!程序员写的代码,被国家博物馆收藏了!
  4. Android 实现人脸识别检测时的扫描动画效果(二维码扫描动画效果同理)
  5. 在市场买一个小鸡都要20多块,为什么加工好的童子鸡才19块?
  6. python作图之plt.contour详解
  7. 中文分词与关键词提取概述
  8. 苹果自带的APP下载分析统计工具
  9. BTC钱包(wallet.dat 文件密码与私钥的区别)
  10. 关于bitcoin core钱包api