最近在小程序中完成海报生产功能时走了一些弯路,在这里记录一下,希望能对其他人也起到一些帮助。
首先放上效果图。
点击分享按钮会显示下图效果。
点击保存图片会生成一张图片保存在手机里。
在组件生命周期中的attached钩子中,增加上权限检查。根据当前用户的权限,来判断显示“保存图片”按钮还是“授权并保存图片”按钮。
检查完权限后,去计算当前画布的缩放比例。unit = 设备宽度 / 750 * 0.8(其中0.8为绘制后的图片的显示大小占屏幕总大小的百分比)。
接着执行this.drwCanvas()函数进行画布操作。
在methods方法中封装下载图片和云存储文件的函数,由于项目中将静态图片放在了云服务中,所以封装了云存储文件函数,如果实际开发中未使用云开发,只封装一个下载图片函数即可。
使用canvas绘制线上图片需要先将图片缓存在本地中,否则会出现图片绘制不到画布上的问题。所以使用使用Promise.all在获取到所有图片的tempFilePath/path之后再执行绘制操作。
现在我们去看一下wxml
可以看出这个组件由两部分组成。
<v-mask>是我实现的一个遮罩层组件,实现起来很简单,此处我就不展开讲了,如果需要组件源码的话我会把gitee的地址贴出来。
v-mask中类名为shareImage的图片,为通过canvas绘制后缓存在手机中的图片。
我们将canvas组件放置在view.hideCanvas容器中,然后将view.hideCanvas容器浮动到屏幕外的位置,并将它隐藏掉。可以看到在canvas组件上,为他设置了width:750px;height: 1125px。zoom为动态的unit。给canvas设置750px的宽度和1125px的高度,目的是让canvas容器和设计稿上的尺寸一致,这样在后续生成图片时,就不会出现图片模糊的问题。
image.shareImage为显示在用户窗口上的绘制结果。
下面我们开始绘制。
首先开始绘制白色的背景。
然后开始绘制顶部的“发现一个好产品,邀请您一起前往游玩”标题图片。
titleOffLeft是标题图片在canvas画布中居中时的左偏移量。
titleOffTop为标题图片距离画布顶部的距离。
titleWidth和titleHeight分别为标题图片的宽度和高度。
配置完标题图片的相关信息后就可以通过ctx.drawImage将标题图片绘制到画布上。
同理,绘制产品图片不再赘述。
下面绘制产品图外的灰色边框。
接下来绘制主标题。关于主标题的需求是当文字超出两行时只显示两行,最后一个字符显示成"省略号"。
此处的做法是判断主标题的字数是否大于40个字符,如果大于40个字符,就将第21到39个字符截取出来作为title2,并在title2的末尾增加省略号。
然后将主标题的第1到20个字符截取出来作为title1。
注:如果文字小于20个字符时title1为主标题的全部内容,title2为空字符。
接下来进行排版。首先通过ctx.measureText(title1).width计算title1的字符所占的宽度。
然后通过ctx.fillText(title1, 56, 595)和ctx.fillText(title2, 56, 630)分别绘制第一行主标题和第二行主标题。(其中,56是文字距离画布左侧的距离。其实这个距离的数值并不太严格,但是为了节省开发时间所以采取了该方式)。
副标题同理不再赘述。
因为字体的大小和颜色不同,所以我们可以把价格的绘制分成三部分,分别为"¥","99999"和"/人起"。
首先设置好"¥"的颜色和字号后,将"¥"绘制到画布上(距离画布左边的距离仍为56),然后获取"¥"字符所占的宽度offsetPriceIcon。
接着设置金额的颜色和字号,将金额绘制到画布上(距离画布左边的距离为56 加上"¥"字符所占的宽度offsetPriceIcon),然后获取金额字符所占宽度offsetPrice。
最后设置"/人起"的颜色和字号,将其绘制到画布上(距离画布左边的距离为56 加上"¥"字符所占的宽度offsetPriceIcon加上"金额"字符所占宽度offsetPrice)。
绘制供应商
该部分简单说一下,主要思路是获取供应商字体所占的宽度后再加上文字两旁的间距,计算出供应商边框的宽度;然后调用roundRect函数将边框绘制在画布上。
绘制
画布上的内容绘制完后,就需要通过ctx.draw()将绘图上下文绘制到画布上。
当绘制成功后,需要在ctx.draw()的回调中执行wx.canvasToTempFilePath()将画布内容导出成图片。
注意:如果在组件中使用wx.canvasToTempFIlePath()时,需要把上下文this作为第二个参数传入。
当生成图片失败、用户主动点击右上角的关闭按钮时,均会通过this.triggerEvent('complete')发送complete事件。在组件外部会监听complete方法,监听到complete处罚后将组件销毁掉。
当图片绘制成功后,如果用户已授权,则执行saveImage()函数。
未完待续。。。。。