关于小程序:小程序canvas大转盘

35次阅读

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

// luckRoll.wxml
<view class="canvas-container" style="transform: rotate({{isRotate}}deg)">
    <canvas disable-scroll="true" canvas-id='canvas' id="canvas-bg" class='canvas'></canvas>
    <image src="{{tempFilePath}}"></image>
</view>

须要定义的数据

// luckRoll.js
data: {
    trunBtn: false,// 抽奖按钮是否能够点击
    itemsNum: 3, // 大转盘等分数, 可依据后盾配置加载
    itemsArc: 0, // 大转盘每等分角度
    coupons: [],// 每个扇形中的文字填充
    isRotate: -180, // 初始旋转角度
}

创立一个 canvas 对象, 因为它是个组件,所以在传入转盘数据的时候,初始化 canvas

properties: {
    rollOptions: {
        type: Array,
        observer(val) {if(val.length > 0) {
                this.setData({
                    coupons: val,
                    itemsNum: val.length
                })
                const ctx = wx.createCanvasContext("canvas", this); // 创立 id 为 canvas 的绘图
                this.getGiftList(ctx)
            }
        }
    }
},
getGiftList(ctx) {
    let that = this;
    let itemsArc = 360/that.data.itemsNum
    that.setData({itemsArc}, function () {const query = wx.createSelectorQuery().in(that)
        query.select('#canvas-bg').boundingClientRect()
        query.exec(function (rect) {w1 = parseInt(rect[0].width / 2);
            h1 = parseInt(rect[0].height / 2);
            that.drawRegion(itemsArc, ctx);// 每一份扇形的外部绘制。})
    })
}

绘制扇形

drawRegion(e, ctx) {
    let that = this;
    let itemsArc = e;// 每一份扇形的角度
    let num = that.data.itemsNum;// 等分数量
    let itemArr = that.data.coupons.map(item=>item.name);// 放文字的数组
    for (let i = 0; i < num; i++) {ctx.beginPath();
        ctx.moveTo(w1, h1);
        ctx.arc(w1, h1, w1 - 2, itemsArc * i * Math.PI / 180, (itemsArc + itemsArc * i) * Math.PI / 180);// 绘制扇形,默认从第四象限开始画,所以区域编号 1 的中央为三点钟开始地位
        ctx.closePath();
        const colorList = ['#7cd8e3', '#ffffff']
        ctx.setFillStyle(colorList[i % 2]);
        ctx.fill();
        ctx.save();
        ctx.beginPath();
        ctx.translate(w1, h1);// 将原点移至圆形圆心地位
        ctx.rotate((itemsArc * (i + 1 + (num - 2) * 0.25)) * Math.PI / 180);// 旋转文字
        if (num >= 6) {ctx.setFontSize(18);// 设置文字字号大小
        } else {ctx.setFontSize(20);// 设置文字字号大小
        }
        if (i % 2 == 0) {ctx.setFillStyle("#ffffff");// 设置文字色彩
        } else {ctx.setFillStyle("#7cd8e3");// 设置文字色彩
        }
        ctx.setTextAlign("center");// 使文字垂直居中显示
        ctx.setTextBaseline("middle");// 使文字水平居中显示
        if (itemArr[i].length < 7) {ctx.setFontSize(12);// 设置文字字号大小
            ctx.fillText(itemArr[i], 0, -(h1 * 0.75));
        } else if (itemArr[i].length >= 7 && itemArr[i].length <= 10) {let len = Math.ceil(itemArr[i].length / 2)
            ctx.fillText(itemArr[i].slice(0, len), 0, -(h1 * 0.80));
            ctx.fillText(itemArr[i].slice(len), 0, -(h1 * 0.65));
            ctx.setFontSize(20);// 设置文字字号大小
        } else {let mainInfo = itemArr[i].slice(0, 10) + '...'
            ctx.fillText(mainInfo.slice(0, 6), 0, -(h1 * 0.80));
            ctx.fillText(mainInfo.slice(6, 13), 0, -(h1 * 0.65));
            ctx.setFontSize(20);// 设置文字字号大小
        }
        ctx.restore();// 保留绘图上下文,使上一个绘制的扇形保留住。}
    ctx.draw();
    setTimeout(()=>{
        wx.canvasToTempFilePath({
            x: 0,
            y: 0,
            width: 2 * w1,
            height: 2 * h1,
            destWidth: 8 * w1,
            destHeight: 8 * h1,
            fileType: 'jpg', 
            quality: 1,// 图片的品质,目前仅对 jpg 无效。取值范畴为 (0, 1],不在范畴内时当作 1.0 解决。canvasId: 'canvas',
            success: function (res) {
                var tempFilePath = res.tempFilePath;
                that.setData({tempFilePath: res.tempFilePath})

            },
            fail: function (res) {console.log('----------', res)
            }
        }, that)
    },1000)
    ctx.draw(true);// 参数为 true 的时候,保留以后画布的内容,持续绘制
}

wx.canvasToTempFilePath 特地重要,必须将 canvas 转换为图片在页面上渲染,不然会呈现各种问题,canvas 用 translateY 移出页面显示

另外 wx.canvasToTempFilePath 必须写在 setTimeout 外面,不然安卓机的图片是黑屏

下面转盘曾经画成,上面就要转动起来

startRoll(index) {
    let that = this;
    let turntableRegionId = index+1
    let rotate = that.data.isRotate - that.data.isRotate % 360 + (720 - Number(turntableRegionId - 1) * that.data.itemsArc - 0.5 * that.data.itemsArc - 90)
    // 转动过程写在 css 动画外面,时长 3s
    that.setData({isRotate: rotate + 2160})
    let cur = that.data.coupons[index]
    let isBingo = !!cur.isPrize
    let award = cur.name
    that.setData({
        isBingo: isBingo, // 是否中奖
        award: award // 奖品
    })
    setTimeout(()=>{
        //3S 后显示最终后果弹窗
        that.setData({dialogShow: true})
    },3000)
}

其余细节,我的项目不同再另外写
外围 css

.canvas-container {
    width: 550rpx;
    height: 550rpx;
    transition:all 3s ease;
    position: absolute;
    top: 45rpx;
    left: 110rpx;
    z-index: 1;
    border-radius: 50%;
    overflow: hidden;
}
.canvas{
    width: 550rpx;
    height: 550rpx;
    display: block;
    position: fixed;
    left: -5000px;
}

正文完
 0