10

小程序canvas大转盘

 3 years ago
source link: https://segmentfault.com/a/1190000038840851
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

小程序canvas大转盘

发布于 16 分钟前
// 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;
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK