关于微信小程序:微信小程序小程序-拼图海报制作功能-思路与问题解决

1次阅读

共计 4344 个字符,预计需要花费 11 分钟才能阅读完成。

应用小程序生成分享海报图,是很常见的性能了,很多的小程序都有相似的性能。尤其是浏览类、学习类的,总能看到朋友圈有人分享“我明天背会了 ** 单词,快来一起学习吧”这种。然而这种海报,都是主动排版生成的,用户是无奈手动参加的。

为了加强用户参与性,咱们模拟一些图片解决 App,实现可能本人拼图生成海报的性能。

1. 整体思路

将整个页面分为 绘制区域 与 操作区域。

  1. 抉择背景图。
  2. 减少要绘制的图片、文字等元素(以下简称拼图元素)。减少的拼图元素在绘制区域中展现。
  3. 在绘制区域中,触控操作拼图元素,获取操作后的后果(地位、缩放等)。
  4. 在管制区域,对拼图元素进行其它操作,如层叠程序扭转、旋转、缩放等。
  5. 依据每一个拼图元素的地位、缩放等信息,应用 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. 完结

至此,整体思路与开发时呈现的问题介绍结束。欢送各位探讨交换。

正文完
 0