小程序H5实现canvas设定底图绘制功能以及闪退问题处理
前言
嗨~ 友友们,最近由于业务需要开始转战小程序开发,有一个业务需求就是使用canvas进行渲染底图,并在底图上进行绘制,数据来源主要是第三方提供的数据点坐标。这里会分别对小程序和H5进行区别实现,希望可以对友友们有帮助哦~
思路分析
因为业务需要就是在底图上绘制数据点坐标,实现步骤如下:
-
初始化canvas对象
小程序版:参照微信开放文档Canvas画布,进行画布初始化,注意哦,这里的ctx对象是在异步回调中返回的,需要处理异步的问题。
小程序调试时需注意,canvas不支持真机调试,想要在真机调试模式调试画布需要开启调试模式(亲测可以,官方没有说明)。
小程序开发工具中定位在
画布
上的元素会被画布
遮挡,但是在预览时可以看到定位元素的效果哦~
<canvas id="myCanvas" disable-scroll="false" type="2d"></canvas>
const query = wx.createSelectorQuery();
query.select('#myCanvas')
.fields({ node: true, size: true })
.exec((res) => {
let canvasDom = res[0].node;
const ctx = canvasDom.getContext('2d');
// 初始化画布大小:注意哦!此处可能引起闪退,屏幕像素比越大,canvas就会越大哦
const dpr = wx.getSystemInfoSync().pixelRatio;
canvasDom.width = canvasW * dpr;
canvasDom.height = canvasH * dpr;
ctx.scale(dpr, dpr);
});
H5版:参照MDN web docs 以下代码基于Vue3.0,友友们在使用时可根据自己的开发框架参照文档进行调整。
<canvas ref="canvas" class="canvas" type="2d"></canvas>
const canvas = ref(null) // canvas 的 dom节点
const ctx = canvas.value.getContext('2d')
const dpr = window.devicePixelRatio // 像素比
// 初始化画布大小
this.canvasDom.width = canvasW * dpr
// canvasW指的是canvas需要渲染的宽度,canvasH是需要渲染的高度
this.canvasDom.height = canvasH * dpr
ctx.scale(dpr, dpr)
this.canvasContext = ctx
注意事项:因为使用动态图片作为canvas的底图,所以为了更好的适配图片,可能需要进行等比计算,计算出图片使用的最佳尺寸,如需要适配平板也需要跟产品和设计沟通具体事宜哦~
-
绘制底图
小程序版:使用文档提供canvas加载图片的
createImage
结合drawImage
进行绘制。文档上说明小程序绘制的
网图
需通过getImageInfo / downloadFile先下载得出本地临时路径
// 绘制底图
ctx.beginPath();
const img = canvasDom.createImage();
img.src = url;
img.onload = function (e) {
ctx.drawImage(this, 0, 0, canvasW, canvasH);
};
H5版:使用Image对象进行访问图片,使用drawImage
进行绘制图片。
ctx.beginPath()
const img = new Image()
img.src = image
img.onload = function (e) {
ctx.drawImage(this, 0, 0, canvasW, canvasH)
}
-
遍历点坐标数据列表,绘制点坐标
绘制坐标点,这里就是挪动到起始点,开始绘制的过程,中间的临界值条件需要友友们根据需求进行处理哦~
这里在小程序 安卓机运行时出现了闪退的问题,并没有报错,最后经过调试,发现是频繁调用了
ctx.save()
导致的,小程序的Canvas组件使用的是GPU加速,但是其内存限制较为严格,而使用ctx.save()
在绘制时占用了过多的内存,就可能导致闪退。
for (let i = 0; i < points.length; i++) {
const obj = lp[i];
ctx.moveTo(this.lastPoint.x, this.lastPoint.y); // 移动坐标
ctx.lineTo(pointX, pointY); //连线
ctx.stroke(); // 绘制空心
// ctx.save(); // 保存绘制状态 导致闪退的原因
}
完整代码:
const real_Width = 500; // 这里另一个参照的实际尺寸
const real_height = 500; // 这里另一个参照的实际尺寸
const systemInfo = wx.getSystemInfoSync();
const screenW = systemInfo.windowWidth; // 屏幕可视宽
const screenH = systemInfo.windowHeight; // 屏幕可视高
let canvasW = null, canvasH = null; // 画布宽高
const wh = screenW / screenH;
if (wh < real_Width / real_height) {
canvasW = screenW;
canvasH = (screenW * real_height) / real_Width;
} else {
canvasW = (screenH * real_Width) / real_height;
canvasH = screenH;
}
export default class Draw {
lastPoint = { x: null, y: null } // 上一个点
canvasContext = null
url = null // 底图本地地址
async constructor(url) {
this.url = url
const { ctx } = await this.init()
this.canvasContext = ctx
}
init() {
return new Promise((resolve, reject) => {
const query = wx.createSelectorQuery();
query.select('#myCanvas')
.fields({ node: true, size: true })
.exec((res) => {
let canvasDom = res[0].node;
const ctx = canvasDom.getContext('2d');
const dpr = wx.getSystemInfoSync().pixelRatio;
// 初始化画布大小
canvasDom.width = canvasW * dpr;
canvasDom.height = canvasH * dpr;
ctx.scale(dpr, dpr);
// 开始绘制
ctx.beginPath();
ctx.strokeStyle = '#000000';
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
const img = canvasDom.createImage();
img.src = this.url;
img.onload = function (e) {
// 底图
ctx.drawImage(this, 0, 0, canvasW, canvasH);
};
resolve(ctx);
});
});
}
draw(points) {
for (let i = 0; i < points.length; i++) {
const obj = points[i];
this.drawPoints(obj);
}
}
drawPoints(point) {
const ctx = this.canvasContext;
const x = point.x;
const y = point.y;
const pointX = (x * canvasW) / real_Width;
const pointY = (y * canvasH) / real_height;
if (条件) {
ctx.moveTo(this.lastPoint.x, this.lastPoint.y);
ctx.lineTo(pointX, pointY);
} else {
ctx.moveTo(pointX, pointY);
}
this.lastPoint.x = pointX;
this.lastPoint.y = pointY;
ctx.stroke();
// ctx.save();
}
}
结语
友友们,今天也是收获满满的一天呀!以上代码纯属脑电波运行,如有bug,请自行解决或下方留言哦~ 如果你看到这里了,那就请用你发财
的小手给作者点个小赞赞
吧~
转载自:https://juejin.cn/post/7216213764776738873