微信小程序-canvas2D-海报-安卓适配
前言
官方文档一言难尽,本文记录在canvas2D实际体验中遇到的各种问题及解决方案
canvas2D
使用原因:官方宣布:2.9.0 起支持一套新 Canvas 2D 接口(需指定 type 属性),同时支持同层渲染,原有接口不再维护。 使用:
<canvas type="2d" id="myCanvas"></canvas>
注意点:
id而不是canvas-id- 注意声明
type="2d" - wx.canvasToTempFilePath 真机调试失效,暂无具体解决办法,官方维护人员:走预览调试,真机无效,具体原因:官方就是这么屌
- 在使用```canvasToTempFilePath``将cavnas转换成图片时,canvas一定要出现在页面结构中,否则会出现fail no image报错情况,另外一定要赋予其宽度和高度,不要使用%写法,如下:(使用vw,vh,px都行)
<!-- BAD -->
<canvas type="2d" id="myCanvas" style="width:100%;height:100%;"></canvas>
<!-- GOOD -->
<canvas type="2d" id="myCanvas" style="with:100vw;height:100vh;"></canvas>
- ctx.drawImage()使用如下:
const img = canvas.createImage()
img.src = that.data.erCodeImage.path
img.onload = () => {
ctx.drawImage(img, 540 * unit, 860 * unit, 165 * unit, 165 * unit)
}
- 注意网络图片需为https,并且需将图片下载到本地,方法如下:
/**
* @description: 封装的下载图片函数
* @params:
* @return {type}
*/
downLoadImage(url) {
return new Promise((resolve, reject) => {
// console.log("要下载的图片", url)
wx.getImageInfo({
src: url,
success(res) {
// console.log("下载好的", res.path)
// resolve(res.path)
resolve(res)
},
fail(err) {
reject(err)
}
})
})
},
/**
* @description: 封装的下载云存储文件函数
* @params:
* @return {type}
*/
downLoadCloudFile(id) {
return new Promise((resolve, reject) => {
wx.cloud.downloadFile({
fileID: id,
success: res => {
// 返回临时文件路径
console.log(1231312312, res)
resolve(res.tempFilePath)
},
fail: err => {
console.log('err', err)
}
})
})
},
- 一些setFillStyle的使用方法有修改,具体使用百度即可
生成海报项目开始
构建画布
<canvas type="2d" id="myCanvas" style="width: 750px;height: 1125px;border:1px solid blue;;margin:auto;"></canvas>
canvas元素,同html中的canvas
初始化canvas
- 创建一个dom元素节点查询器
// 页面中
const query = wx.createSelectorQuery()
// 组件中
const query = wx.createSelectorQuery().in(this)
- 选择我们的canvas节点
query.select('#myCanvas')
- 初始化canvas画布的基础参数
这里着重注意:dpr设备像素比,为了适配各种各样的安卓机,这里推荐使用dpr=1,否则,会出现如下类似报错 canvasToTempFilePath:fail:convert native buffer parameter fail. native buffer exceed size limit,
initCanvas() {
const query = wx.createSelectorQuery().in(this) // 创建一个dom元素节点查询器
query.select('#myCanvas') // 选择我们的canvas节点
.fields({ // 需要获取的节点相关信息
node: true, // 是否返回节点对应的 Node 实例
size: true // 是否返回节点尺寸(width height)
}).exec((res) => { // 执行针对这个节点的所有请求,exec((res) => {alpiny}) 这里是一个回调函数
const dom = res[0] // 因为页面只存在一个画布,所以我们要的dom数据就是 res数组的第一个元素
const canvas = dom.node // canvas就是我们要操作的画布节点
const ctx = canvas.getContext('2d') // 以2d模式,获取一个画布节点的上下文对象
// const dpr = wx.getSystemInfoSync().pixelRatio // 获取设备的像素比,未来整体画布根据像素比扩大
const dpr = 1
// dpr大小影响图片的显示分辨度,可以理解为影响像素的大小,值越大,越高清,但个人猜测过大会影响渲染效率或者加重小程序运行负担
// const unit = 2
canvas.width = 750 * dpr
canvas.height = 750 * 1.5 * dpr
ctx.scale(dpr,dpr)
this.setData({
canvasDom: dom, // 把canvas的dom对象放到全局
canvas: canvas, // 把canvas的节点放到全局
ctx: ctx, // 把canvas 2d的上下文放到全局
dpr: dpr // 屏幕像素比
}, function () {
console.log('开始绘图')
this.drawWork() // 开始绘图
})
})
},
关于canvas.width和canvas.height设置,主要是为了能方便控制画出图像的大小,canvas的width和height并不是style中的width和height,换句话说就是前者是==画布宽高==后者是==css元素宽高== ctx:指2d上下文,通俗点理解可以理解为画图的画笔
- 绘制文本时特别要注意,字体一定要是系统中有的字体,否则文字绘制不上,部分安卓机型可能会闪退,这里推荐如下代码操作,推荐字体:Arial,如果文字出现真机中变小问题,可能原因如下:
- 注意font中的属性值设置顺序,错误的顺序可能会带来不一样的结果
- 有些可能是因为未设置字体导致,具体不详
ctx.font = '56px Arial';
// BAD
// 设置粗体文字
ctx.font = '56px bold Arial';
// GOOD
// 设置粗体文字
ctx.font = 'bold 56px Arial';
- 在使用
canvasToTempFilePath将图片转成临时文件保存到手机时注意设置输出宽度(destWidth),输出高度(destWidth),否则在手机上查看时,你会发现图片被拉伸了或者某方向被裁剪了,具体可详见canvas文档中的canvasToTempFilePath
setData()设置canvas,ctx
关于在安卓机中将canvas,ctx对象赋值给data时使用setData()报错 推荐如下设置(直接赋值给this对象,js中一样可以全局使用)
// BAD
query.select('#myCanvas') // 选择我们的canvas节点
.fields({ // 需要获取的节点相关信息
node: true, // 是否返回节点对应的 Node 实例
size: true // 是否返回节点尺寸(width height)
}).exec((res) => {
const dom = res[0] // 因为页面只存在一个画布,所以我们要的dom数
const canvas = dom.node // canvas就是我们要操作的画布节点
const ctx = canvas.getContext('2d') // 以2d模式,获取一个画布
// 这种操作会报错
that.setData({
canvasDom:dom
canvas:canvas
ctx: ctx
})
// this.drawWork()
})
// GOOD
query.select('#myCanvas') // 选择我们的canvas节点
.fields({ // 需要获取的节点相关信息
node: true, // 是否返回节点对应的 Node 实例
size: true // 是否返回节点尺寸(width height)
}).exec((res) => {
const dom = res[0] // 因为页面只存在一个画布,所以我们要的dom数
const canvas = dom.node // canvas就是我们要操作的画布节点
const ctx = canvas.getContext('2d') // 以2d模式,获取一个画布
// 安卓机用setData会出现报错,所以直接保存在that中
that.canvasDom = dom
that.canvas = canvas
that.ctx = ctx
// this.drawWork()
})
drawImage绘制很多图片
canvas绘制过多图片时,在保存到手机的图片中可能会有部分图片不显示,具体原因是因为图片未全部绘制完成就开始生成图片,这里需要进行异步处理,在图片全部绘制完成后再进行生成和保存