背景图+标题+内容+专属头像、昵称+引流二维码是构成海报设计的基本要素。这些基本要素,即是我们需要在代码上实现的功能。可以简单的理解为,要绘制(块、图片)元素、单、多行文字到Canvas中并生成一张海报图片。
分析了要实现的功能,我的脑海浮现出了三种实现的方法:
Talkischeap,Showmethedemo.
小程序的实现,和在web端操作css差别可大了。主要的问题/方法是下面三个:
canvas并没有提供绘制圆角矩形的方法,因此我们需要以另一种方法来实现它。方法的核心是一个叫CanvasContext.arcTo的方法,我们先来看看它的使用的用法:
CanvasRenderingContext2D.arcTo()是Canvas2DAPI根据控制点和半径绘制圆弧路径,使用当前的描点(前一个moveTo或lineTo等函数的止点)。根据当前描点与给定的控制点1连接的直线,和控制点1与控制点2连接的直线,作为使用指定半径的圆的切线,画出两条切线之间的弧线路径。
你可以想象成,一个圆拼命地往一个死角∠挤,挤到极限时,就是我们要的弧线了。控制点1与控制点2连接的直线,作为使用指定半径的圆的切线,所以这条线也是会被无线延长的。千言万语不如一图:
那么,一个矩形的圆角就显得如此的理所当然:
当图片既有背景又有边框又有圆角时,我们就需要以一种取巧的方法来实现:“叠罗汉”。
因为canvas的"图层"遵循先来后来居上原则,后绘制的会盖在先绘制的"图层"上。所以,我们要按顺序的:
CanvasContext.strokeRect能更好得达到绘制边框功能,但它无法设置圆角,所以不使用。
绘制出来的效果如图:
//绘制块元素canvasToDrawBlock(ctx,params){returnnewPromise(async(resolve)=>{const{x,y,url,width,height,radius,border,borderColor,backgroundColor}=paramsif(border){ctx.setFillStyle(borderColor'#fff')this.canvasToDrawArcRectPath(ctx,x-border,y-border,width+border*2,height+border*2,radius )ctx.fill()}if(backgroundColor){ctx.setFillStyle(backgroundColor)this.canvasToDrawArcRectPath(ctx,x,y,width,height,radius)ctx.fill()}if(url){ctx.save()this.canvasToDrawArcRectPath(ctx,x,y,width,height,radius)ctx.clip()const{path:tempImageUrl}=awaitthis.uniGetImageInfoSync(url)ctx.drawImage(tempImageUrl,x,y,width,height)}ctx.restore()resolve()})}绘制单、多行文字通常来说,海报会出现多行的文字。但canvas对文字排版的支持很弱,使我们没办法像使用CSS排版一样愉快的使用canvas进行文字排版。canvas绘制文字时,只会一股脑的在单行上一直画下去而不会根据容器宽度自动换行。
好在canvas中提供了CanvasContext.measureText(stringtext)返回文本宽度的接口。因此,我们只需要把文字逐个计算宽度并绘制,主要步骤如下:
CanvasContext.draw绘制完后,我们再调用uni.canvasToTempFilePath把当前画布指定区域的内容导出海报图片临时地址。需要注意的是,在自定义组件下,需要在第三个参数上绑定当前组件实例的this,以操作组件内canvas组件
既然生成的海报可能几个月都不会更换,那我们完全可以在第一次绘制完海报后,就把文件存入用户本地缓存下次直接使用就好。具体的步骤如下:
constfs=wx.getFileSystemManager()fs.saveFile({tempFilePath:tempCanvasFilePaths,//传入一个本地临时文件路径success:(res)=>{storage.set(this.cacheKey,res.savedFilePath,86400000)this.posterImage=res.savedFilePath}})因此,我们完整的步骤如下:
当然了,你也可以选择把生成海报的途径,转移到web-view上,那你想怎么弄就怎么弄了(滑稽.jpg)。但缺点也很明显:web-view容器会自动铺满整个小程序页面,个人类型的小程序暂不支持使用。
功能暂时就这些了,如果有什么觉得重要的功能需求,可以在issue中提出。后续也可能加入一个可视化操作海报参数的页面。什么时候?下次一定!