(未完成|草稿)微信小程序中使用canvas绘制海报的总结

357 阅读5分钟

最近在小程序中完成海报生产功能时走了一些弯路,在这里记录一下,希望能对其他人也起到一些帮助。

代码地址。

首先放上效果图。

点击分享按钮会显示下图效果。


点击保存图片会生成一张图片保存在手机里。



在组件生命周期中的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()函数。

未完待续。。。。。