应用小程序生成分享海报图,是很常见的性能了,很多的小程序都有相似的性能。尤其是浏览类、学习类的,总能看到朋友圈有人分享 “我明天背会了**单词,快来一起学习吧”这种。然而这种海报,都是主动排版生成的,用户是无奈手动参加的。
为了加强用户参与性,咱们模拟一些图片解决App,实现可能本人拼图生成海报的性能。
1. 整体思路
将整个页面分为 绘制区域 与 操作区域。
- 抉择背景图。
- 减少要绘制的图片、文字等元素(以下简称拼图元素)。减少的拼图元素在绘制区域中展现。
- 在绘制区域中,触控操作拼图元素,获取操作后的后果(地位、缩放等)。
- 在管制区域,对拼图元素进行其它操作,如层叠程序扭转、旋转、缩放等。
- 依据每一个拼图元素的地位、缩放等信息,应用canvas进行绘制,并生成图片。
思路确立了,就开始实操。
2. 素材局部
因为小程序有对包大小的限度,所以咱们的图片素材是不能间接扔在小程序里的。
我是间接将素材依照肯定的命名规定间接传到了云存储服务中,小程序中通过规定进行拼接获取所有素材的地址。
初始开发时,能够先把图片素材放在小程序文件夹里。不影响开发者工具内的开发与测试,只不过无奈真机调试与预览。
为了便于操作与计算,所有的图片素材都采纳的对立大小的png格局(最好是正方形)。
3. 绘制区域
1. 组件抉择
选用小程序组件 <movable-area>
与 <movable-view>
。
应用上述组件,能够实现拼图元素在绘制区域内的挪动、缩放,监听事件还能够回传触控操作后拼图元素的地位。
具体的应用形式请参考文档。
https://developers.weixin.qq....
留神:
<movable-view>
容许双指缩放后,呈现了bug,比方挪动拼图元素时会产生图片放大、挪动时产生惯性动画(即便没有设置)等。因而放弃,采纳其余办法实现。*- 通过列表渲染,渲染
<movable-view>
时,肯定要谨严的给出惟一key作为wx:key
,不要应用诸如wx:key="index"
。否则,在删除拼图元素、批改拼图元素层叠程序时,会呈现bug。
2. 单位与比例换算
<movable-area>
元素自身在页面的高宽、定位能够应用 rpx。
其外部的拼图元素宽高、地位等,我集体倡议应用 px 单位。
- 首先,rpx不是相对单位,是比例单位,最终生成的图片不能应用rpx作为宽高单位,否则大家生成的图片大小不统一,为此拼图元素的相干数据也应该间接应用px为单位,便于后边的换算。
- 其次,
<movable-view>
的监听事件返回的定位信息也是以px为单位的。
比例换算就没什么好说的了,拿到绘制区域的实在宽度,晓得输入指标宽度,算就完了~
4. 操作区域
1. 文字拼图元素的新增
图片拼图元素的减少没什么特地的中央,比拟容易解决,设置好 <movable-view>
的宽、高、x、y等属性,再在其外部减少 <image>
即可。文字拼图元素的减少绝对麻烦一点。
文字拼图元素能够分成 横排文字 和 竖排文字。
抛开字号、字体、初始的x、y、等共性的款式/属性:
- 横排文字只需为
<movable-view>
设置足够的宽度就好了,否则汉字会换行。 - 竖排文字需为
<movable-view>
设置1倍字号的宽度,好让每一个文字刚好占据一行。也因而,要思考line-height
。咱们须要为竖排文字设置一个适合的line-height
。我这里间接设置为了 1.5倍字号。
2. 缩放与旋转
之前咱们提到过,应用 <movable-view>
自带的缩放性能,呈现了bug,因而这里通过 <slider>
手动设置缩放倍数。缩放倍数间接反馈在 <movable-view>
的宽高款式上。通过间接批改宽高款式实现缩放倍数,一个益处就是缩放时不会影响拼图元素的地位(由左上缩放,而不是核心缩放)。
旋转角度也通过 <slider>
手动设置(0 - 360)。
留神:
咱们在<movable-area>
中触控滑动拼图元素,本质上是实时批改所选<movable-view>
的transform
款式(translate
)。因而,拼图元素的旋转(transform: rotate(*deg)
),应该加在<movable-view>
的子元素上。
因为比拟麻烦,我这里只为图片拼图元素的缩放与旋转。文字拼图元素的pass掉了。
3. 层叠程序的批改
<movable-view>
是采纳 相对定位 的,因而渲染的程序就能代表层叠程序。
5. 应用canvas绘制海报图
1. canvas组件
canvas组件的大小,设置成为最终海报图输入大小即可。
canvas组件能够设置相对定位,搁置在屏幕区域外即可。
2. 不同根底库版本,获取上下文对象的办法/绘制办法
1. 在根底库2.9.0以下版本
应用 wx.createCanvasContext()
办法获取上下文对象。
而后应用小程序的 CanvasContext
API进行绘制操作。
详情请参考文档:https://developers.weixin.qq....
留神:
- drawImage办法第一个参数为图片资源的本地地址,如果应用网络图片,须要通过
getImageInfo / downloadFile
获取本地地址。- 应用
wx.canvasToTempFilePath
办法生成图片,须要将其放在draw
函数的回调里,来保障图片胜利导出。
2. 根底库2.9及以上(我用的本办法,后边介绍的留神状况中,有些基于此)
在 canvas
组件中设置 type = "2d"
, 通过 SelectorQuery
获取canvas实例,进而获取上下文对象。
上下文对象的相干API与Web原生统一。
query.select('#myCanvas').fields({node: true, size: true}).exec(res => { const canvas = res[0].node; const ctx = canvas.getContext('2d'); canvas.width = 1000; canvas.height = 1500; //其它操作...})
留神:
- 获取canvas实例后,须要显示的设置画布的宽高。画布宽高最大值为 1365 * 1365。
- drawImage办法在这里与Web原生办法统一,第一个参数须要为HTMLImageElement(这里咱们只探讨HTMLImageElement的状况),因而须要先应用
canvas.createImage
办法创立图片对象,设置src,并期待加载结束。- 应用
canvas.toDataURL
返回一个蕴含图片展现的 data URI (data:<mediatype>;base64,<data>)。
3. 一些要留神的中央
1. 所有的原始间隔数据都要通过比例校对到canvas的尺寸比例上。
2. 竖排文字的绘制
通过逐字绘制的形式实现。
用 y + n * line-height - (line-height - font-size) / 2
的形式确定第n个汉字的的垂直绘制地位 y'。
肯定要记住减去 line-height
带来的空白。
3. 绘制文字时,设置字体属性
ctx.font = "字号 字体"
必须采纳残缺格局,否则会生效。
4. 文字绘制时,垂直地位 y
会多出1倍字号左右的间隔
不晓得什么起因导致的,反正我这里呈现了。
呈现了的话,记得补上。
5. 绘制图片的旋转时
ctx.save();ctx.translate(图片中心点x,y);ctx.rotate(度数);//(负的图片宽高的一半)drawImage(img, -x, -y);ctx.restore();
ctx.rotate()的度数是 弧度 。
6. 网络图片加载问题
应用 drawImage
办法绘制图片时,须要先应用 canvas.createImage
办法创立图片对象,设置src,并期待加载结束。
而所有的拼图素材都是网络图片,异步加载,因而会呈现 因为加载速度不同导致绘制程序错乱、 返回dataURI时图片加载未实现导致局部素材绘制未实现 等问题。
因而须要期待所有要用的素材加载结束之后,再进行绘制。
这里我将图片的加载封装为 Promise
对象,通过 Promise.all()
实现。
addImagePromise(canvas, temp){ return new Promise((resolve, reject) => { let imgEle = canvas.createImage(); imgEle.src = temp.image; imgEle.onload = function(){ //!!!很多人在这里都会习惯写 imgEle.onload = null; 然而小程序内会报错 resolve(imgEle); } })}...let eleImagePromiseList = [];for(let i = 0; i < eles.length; i++){ let temp = eles[i]; if(temp.type == 1){ //文字 eleImagePromiseList.push(null); } if(temp.type == 2){ //图片 eleImagePromiseList.push(this.addImagePromise(canvas, temp)); }}Promise.all(eleImagePromiseList).then(res => { //加载结束,开始绘制})
6. 把返回的 data URI 存入零碎相册
通过 小程序的文件管理器 将 data URI 中base64编码的图片局部存储到本地,再保留至相册。
let fs = wx.getFileSystemManager();let imagePath = wx.env.USER_DATA_PATH + '/myPost.png';let imageSrc = this.data.drawImageSrc.replace(/^data:image\/\w+;base64,/, '');fs.writeFile({ filePath: imagePath, data: imageSrc, encoding: "base64", success(res){ wx.saveImageToPhotosAlbum({ filePath: imagePath, success(res) { //... } }) }})
7. 真机调试问题
在 canvas
组件中设置 type = "2d"
的形式进行canvas绘制时,进行真机调试时,会报错,报错来源于 通过createSelectorQuery
获取canvas实例。
能够间接通过 预览 查看成果。如果的确须要调试,请更新开发工具,应用 真机调试 2.0 进行。
相干材料:
https://developers.weixin.qq....
https://developers.weixin.qq....
8. 完结
至此,整体思路与开发时呈现的问题介绍结束。欢送各位探讨交换。