轻松生成小程序分享海报
作者:jasondu原文:https://segmentfault.com/a/1190000016121303小程序海报组件https://github.com/jasondu/wx... 需求小程序分享到朋友圈只能使用小程序码海报来实现,生成小程序码的方式有两种,一种是使用后端方式,一种是使用小程序自带的canvas生成;后端的方式开发难度大,由于生成图片耗用内存比较大对服务端也是不小的压力;所以使用小程序的canvas是一个不错的选择,但由于canvas水比较深,坑比较多,还有不同海报需要重现写渲染流程,导致代码冗余难以维护,加上不同设备版本的情况不一样,因此小程序海报生成组件的需求十分迫切。 在实际开发中,我发现海报中的元素无非一下几种,只要实现这几种,就可以通过一份配置文件生成各种各样的海报了。 海报中的元素分类
要解决的问题
单位问题canvas绘制使用的是px单位,但不同设备的px是需要换算的,所以在组件中统一使用rpx单位,这里就涉及到单位怎么换算问题。 通过wx.getSystemInfoSync获取设备屏幕尺寸,从而得到比例,进而做转换,代码如下: const sysInfo = wx.getSystemInfoSync();
const screenWidth = sysInfo.screenWidth;
this.factor = screenWidth / 750; // 获取比例
function toPx(rpx) { // rpx转px
return rpx * this.factor;
}
toRpx(px) { // px转rpx
return px / this.factor;
},
canvas隐藏问题在绘制海报过程时,我们不想让用户看到canvas,所以我们必须把canvas隐藏起来,一开始想到的是使用display:none; 但这样在转化成图片时会空白,所以这个是行不通的,所以只能控制canvas的绝对定位,将其移出可视界面,代码如下: .canvas.pro {
position: absolute;
bottom: 0;
left: -9999rpx;
}
圆角矩形、圆角图片由于canvas没有提供现成的圆角api,所以我们只能手工画啦,实际上圆角矩形就是由4条线(黄色)和4个圆弧(红色)组成的,如下:
圆弧可以使用canvasContext.arcTo这个api实现,这个api的入参由两个控制点一个半径组成,对应上图的示例 canvasContext.arcTo(x1,y1,x2,y2,r)
接下来我们就可以非常轻松的写出生成圆角矩形的函数啦 /**
* 画圆角矩形
*/
_drawRadiusRect(x,y,w,h,r) {
const br = r / 2;
this.ctx.beginPath();
this.ctx.moveTo(this.toPx(x + br),this.toPx(y)); // 移动到左上角的点
this.ctx.lineTo(this.toPx(x + w - br),51); font-weight: 700;">this.toPx(y)); // 画上边的线
this.ctx.arcTo(this.toPx(x + w),51); font-weight: 700;">this.toPx(y),51); font-weight: 700;">this.toPx(y + br),51); font-weight: 700;">this.toPx(br)); // 画右上角的弧
this.toPx(y + h - br)); // 画右边的线
this.toPx(y + h),51); font-weight: 700;">this.toPx(br)); // 画右下角的弧
this.toPx(y + h)); // 画下边的线
this.toPx(x),51); font-weight: 700;">this.toPx(y + h - br),136);">// 画左下角的弧
this.toPx(y + br)); // 画左边的线
// 画左上角的弧
}
如果是?画线框?就使用? 如果是?画色块?就使用? 如果是?圆角图片?就使用 this.ctx.clip();
this.ctx.drawImage(***);
clip()?方法从原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内(不能访问画布上的其他区域)。可以在使用 clip() 方法前通过使用 save() 方法对当前画布区域进行保存,并在以后的任意时间对其进行恢复(通过 restore() 方法)。 多段文字如果是连续多段不同格式的文字,如果让用户每段文字都指定坐标是不现实的,因为上一段文字的长度是不固定的,这里的解决方案是使用? 超长文字和多行文字缩略问题设置文字的宽度,通过? 矩形包含文字这个同样使用? 文字的垂直居中问题可以设置文字的基线对齐方式为middle(?
多个元素间的层级问题由于canvas没有Api可以设置绘制元素的层级,只能是根据后绘制层级高于前面绘制的方式,所以需要用户传入zIndex字段,利用数组排序(Array.prototype.sort)后再根据顺序绘制。 图片尺寸和渲染尺寸不一致问题绘制图片我们使用? 如果使用? 在基础库1.9.0起支持?
如果绘制尺寸比源图尺寸宽,那么绘制尺寸的宽度就等于源图宽度;反之,绘制尺寸比源图尺寸高,那么绘制尺寸的高度等于源图高度; 我们可以通过? canvas转图片在canvas绘制完成后调用? ,success: (res) => {
wx.hideLoading();
this.triggerEvent('success',res.tempFilePath);
},fail: (err) => {
wx.hideLoading();
'fail',err);
}
},51); font-weight: 700;">this);
});
IOS 6.6.7 clip问题在IOS 6.6.7版本中clip方法连续裁剪图片时,只有第一张有效,这是微信的bug,官方也证实了(?https://developers.weixin.qq....?) 关于获取canvas实例我们可以使用? 如何使用组件 |