美文网首页
小程序canvas绘制序列祯

小程序canvas绘制序列祯

作者: RadishHuang | 来源:发表于2021-06-16 21:09 被阅读0次

小程序下绘制序列祯,没有H5那么简单和便利。目前小程序的画布推出了2D,可以提高画布的渲染效率和内存的消耗。实际上用起来却没那么好用。本文仍然是以传统的小程序画布的方式去实现。

  • 通过wx.downloadFile方法下载网络图片,转为本地的临时文件tempfilepath
  • 一次性加载全部的序列祯,然后清除,防止播放序列祯出现闪屏。
  • 通过定时器播放序列祯。

wxml的代码

创建普通的画布,注意不是2d的即刻。还是传统的画布api

<!--index.wxml-->
<view class="container">
    <canvas 
        style="width:{{config.width}}px;height:{{config.height}}px;position:absolute;top:0px;left:0px;"
        canvas-id="firstCanvas"
        disable-scroll="true" 
        bindtouchstart="canvasStart" 
        bindtouchmove="canvasMove" 
        bindtouchend="canvasEnd" 
        touchcancel="canvasEnd" 
        binderror="canvasIdErrorCallback"
        ></canvas>
</view>

JS画布的逻辑实现

这边先把代码全部都贴出来,再分步解释。


// 画布绘制序列帧

const store = getApp().store;
const create = getApp().create;
const regeneratorRuntime = getApp().regeneratorRuntime;

create(store, {
    data: {
        config: {
            width: 375,
            height: 375,
        }
    },
    onLoad() {

        const result = wx.getSystemInfoSync();
        if (result) {
            const config = {
                width: result.windowWidth,
                height: result.windowHeight,
            }
            this.setData({ config })
        }

        this.createDownLoadList();
    },
    begainAnimate(params) {
        const context = wx.createCanvasContext('firstCanvas');
        // 第一帧
        const width = this.data.config.width;
        const height = this.data.config.height;
        // 播放序列帧会出现闪屏。
        // 猜测可能是画布初始化的时候,就没有图片资源。
        // 所以用了一个很粗暴的方法
        // 在刚开始把所有的图片全部都加载到画布里面去。
        for (var i = params.length - 1; i >= 0; i--) {
            context.drawImage(params[i].tempFilePath, 0, 0, width, height);
        }
        context.draw();
        let index = 0;
        // 网上说需要 requestAnimationFrame 来刷新,其实只要控制在 16ms刷一次就可以。刷的频率不能太高。
        // setInterval(()=>{
        // }, 16)
        const timer = setInterval(() => {
            index++;
            if (index > (params.length - 1)) {
                clearInterval(timer);
                return;
            }
            context.clearRect(0, 0, width, height);
            context.drawImage(params[index].tempFilePath, 0, 0, width, height);
            context.draw();
        }, 100)

    },
    async createDownLoadList() {
        const count = 85;
        var pathList = [];
        for (var i = 0; i < count; i++) {
            const name = `00000${i}`.substr(-5);
            const imagePath = `https://wx.sephora.cn/h5/flawless/flawless6/img/index/sy2_${name}.jpg`;
            pathList.push({
                index: i,
                imagePath: imagePath
            });
        }
        let loadList = [];
        for (var i = 0; i < count; i++) {
            loadList.push(this.preLoad(pathList[i]));
        }
        const fileList = await Promise.all(loadList);
        this.begainAnimate(fileList);
    },

    preLoad(params) {
        return new Promise((resolve) => {
            wx.downloadFile({
                url: params.imagePath,
                success(res) {
                    if (res.statusCode === 200) {
                        params.tempFilePath = res.tempFilePath
                        resolve(params);
                    } else {
                        console.log('下载图片出错');
                    }
                }
            })
        })
    },
}); 

小程序骨架使用的是westore的创建形式,这边不用太过于在意。首先这边用promise包了一个下载的方法。通过for循环,创建出promise的下载队列出来。然后在await整个下载的过程回调。从而保证所有的图片都下载完毕,并且都拿到了临时路径。

preLoad(params) {
        return new Promise((resolve) => {
            wx.downloadFile({
                url: params.imagePath,
                success(res) {
                    if (res.statusCode === 200) {
                        params.tempFilePath = res.tempFilePath
                        resolve(params);
                    } else {
                        console.log('下载图片出错');
                    }
                }
            })
        })
    },

接下来就是播放序列的问题。这边遇到一个很神奇,画布在绘制序列帧的时候,会出现闪烁闪屏。也没找到合适的办法,这边只能粗暴的先把所有的序列祯本地路径全部都绘制到画布上去。然后在清空画布。猜测可能是画布还没有缓存到序列祯的资源,从而导致的闪屏。

for (var i = params.length - 1; i >= 0; i--) {
            context.drawImage(params[i].tempFilePath, 0, 0, width, height);
        }
        context.draw();

最后的步骤就是通过定时器,或者是通过requestAnimationFrame去做序列祯的播放都可以。如果是通过定时器的话,需要注意间隔时间不要小于16ms一下,测试过效果不佳。

    const timer = setInterval(() => {
            index++;
            if (index > (params.length - 1)) {
                clearInterval(timer);
                return;
            }
            context.clearRect(0, 0, width, height);
            context.drawImage(params[index].tempFilePath, 0, 0, width, height);
            context.draw();
        }, 100)

相关文章

网友评论

      本文标题:小程序canvas绘制序列祯

      本文链接:https://www.haomeiwen.com/subject/yrifyltx.html