context.drawImage('/static/poster.png',0,0,320,410);//绘制背景图片constavatarLeft=185;constavatarTop=18;constavatarWidth=16;constavatarHeight=16;context.drawImage('/static/avatar.png',avatarLeft,avatarTop,avatarWidth,avatarHeight);从设计上来看头像和昵称是对齐的。
直接按照设计稿距离来设定看看效果
constnickName='墙头草中的顶尖的';constnameLeft=avatarLeft+avatarWidth+7;context.setFillStyle('#ffffff');context.setFontSize(12);context.fillText(nickName,nameLeft,21,96);实际效果如下:
发现与预期效果对应不上,思考下这是为什么?文字设置距离偏移的参考基线不是文字的顶部。
怎么验证我的说法呢?可以x值设置为0。
constnickName='墙头草中的顶尖的';constnameLeft=avatarLeft+avatarWidth+7;context.setFillStyle('#ffffff');context.setFontSize(12);context.fillText(nickName,nameLeft,0,96);//修改为0再看看效果:
发现参考点几乎是文字的底部,这就验证了上面的结论。
怎么解决这个问题呢?
通常知道文本行实际占用的高度,需要知道其line-height,上面并不知道其line-height值。canvas本身并不直接支持line-height属性,显然没办法获得相对准确的行高。
只能采用第二种方式,从canvas提供API来看,可以更改文本相行对齐的点。
constnickName='墙头草中的顶尖的';constnameLeft=avatarLeft+avatarWidth+7;context.setFillStyle('#ffffff');context.setFontSize(12);context.setTextBaseline('top');//更改基线对齐点context.fillText(nickName,nameLeft,21,96);再来看看效果如下:
接下来实现二维码区域,主要白色背景+二维码+文案
constrectWidth=300;constrectHeight=89;constrectLeft=10;constrectTop=311;context.setFillStyle('#ffffff');context.fillRect(rectLeft,rectTop,rectWidth,rectHeight);效果如下:
constqrcodeLeft=20;constqrcodeTop=rectTop+10;constqrcodeWidth=68;constqrcodeHeight=68;context.drawImage('/static/qrcode.png',qrcodeLeft,qrcodeTop,qrcodeWidth,qrcodeHeight);二维码这里直接采用现成图片。实际上前端可以通过weapp.qrcode.esm.js在前端生成二维码,再把它绘制上去。
conststartX=qrcodeLeft+qrcodeWidth+15;consttext1='与志同道合的,他们一起成长';context.setFillStyle('#161413');context.setFontSize(14);context.setTextBaseline('top');context.fillText(text1,startX,rectTop+29);consttext2='扫码即可进入“Get一下”社区';context.font='bold14pxArial';context.fillText(text2,startX,rectTop+51);看看最后的效果:
左上角的部分没有绘制,思路同头像和昵称一样。接下来只要把图片保存到相册即可。
在小程序中,提供方法支持如下:
constonSave=()=>{//转换为临时路径uni.canvasToTempFilePath({canvasId:'posterId',success:(res)=>{//保存图片到相册uni.saveImageToPhotosAlbum({filePath:res.tempFilePath,success:()=>{uni.showToast({title:'保存成功',icon:'none',});},fail:()=>{uni.showToast({title:'保存失败',icon:'none',});},});},});};这里基本上把一个海报绘制
constnickName='墙头草中的顶尖的墙头草中的顶尖的';constnameLeft=avatarLeft+avatarWidth+7;context.setFillStyle('#ffffff');context.setFontSize(12);context.fillText(nickName,nameLeft,21,96);
从效果来看,发现文字直接重叠。如果希望超出的部分能够通过省略号来省略,是可以的
constnickName='墙头草中的顶尖的墙头草中的顶尖的';constnameLeft=avatarLeft+avatarWidth+7;context.setFillStyle('#ffffff');context.setFontSize(12);context.fillText(nickName,nameLeft,21,96);lettext='';consttextArr=nickName.split('');constellipsisWidth=context.measureText('...').width;//省略号的宽度for(leti=0;i
处理后效果如下:
默认采用圆角头像,如果用户上传的头像没有进行裁剪处理,导致图片出现非圆角情况,那么在海报上呈现的效果可能会有所差异。
先使用一个非圆角的图片,代码修改如下:
constavatarLeft=185;constavatarTop=18;constavatarWidth=16;constavatarHeight=16;context.drawImage('/static/avatar-rect.png',avatarLeft,avatarTop,avatarWidth,avatarHeight);效果如下:
现在对图片处理一下:
constavatarLeft=185;constavatarTop=18;constavatarWidth=16;constavatarHeight=16;context.beginPath();context.arc(avatarLeft+avatarWidth/2,avatarTop+avatarHeight/2,avatarWidth/2,0,2*Math.PI);context.closePath();context.clip();//绘制圆形头像context.drawImage('/static/avatar-rect.png',avatarLeft,avatarTop,avatarWidth,avatarHeight);效果如下:
圆角是实现了,发现其他区域内容都被裁剪了。这是为什么?clip()改变了绘画环境。ctx()调用后,所裁剪的区域就是clip()后的绘制环境,clip()之后的绘画只能在裁剪区域中渲染,不能访问画布上的其他区域。
怎么处理这个问题呢?通过save()和restore().
context.save();//暂存context.beginPath();context.arc(avatarLeft+avatarWidth/2,avatarTop+avatarHeight/2,avatarWidth/2,0,2*Math.PI);context.closePath();context.clip();//绘制圆形头像context.drawImage('/static/avatar-rect.png',avatarLeft,avatarTop,avatarWidth,avatarHeight);context.restore();//恢复