H5 Canvas抽奖大转盘代码实现及总结

2018-09-14  本文已影响0人  辣瓜瓜

最近项目上写了一个签到页面,放在h5、ios和安卓中一起用 ,其中有一个功能是抽奖大转盘,这是一个很常用的功能,现在总结记录一下:

效果gif

需求

1、每种奖品的中奖概率由后台确定,非随机。
2、页面上大转盘中的奖品图品和名称有后台提供,灵活非静态。

技术栈

1、HTML5 Canvas
2、引用Jquery插件jQueryRotate.js

踩坑和注意

1、绘制后的画布文字模糊,画布设置尺寸后,css将其设置为一半大小,如此就相当于画了一张200*400的图片,然后设置他显示成100*200的大小,这样一来就变得清晰了。需要注意的是,这样将画布放大之后,绘制的过程中对应的那些坐标,长度等等都要相应的放大

<canvas width="200" height="400" style="width: 100px;height: 200px;"></canvas>

2、canvas加载奖品图片,全都堆叠在左上角,原因是绘制画布时图片还没加载出来,需要使用onload解决

//注意需要等图片加载完成后绘制
window.onload = function() {
    drawWheelCanvas();
};

3、ios的Webview ajax不兼容,因为当时是本地作为服务器测试的,部署在服务器上就行了。参考

4、save()与restore()区别</br>
save表示保存save函数之前的状态;</br>restore表示获取save保存的状态

5、canvas是从水平位置开始绘制的


6、实现转盘四周闪烁效果,其实就是两张图片的切换,如图


两张图片的切换
四周闪烁效果.gif

具体代码

第一步:HTML布局
<div class="wheel">
    <canvas class="item" id="wheelCanvas" width="422px" height="422px"></canvas>
    <img class="pointer" src="images/wheel-pointer.png"/><!--大转盘指针图片-->
</div>

第二部:绘制大转盘

做一些画布的基础设置,此处预先假设抽奖奖项为6项

//获取canvas画布
var canvas = document.getElementById("wheelCanvas");
var ctx = canvas.getContext("2d");
var canvasW = canvas.width; // 画板的高度
var canvasH = canvas.height; // 画板的宽度
//计算每个奖项所占角度数
var baseAngle = Math.PI * 2 / 6;
ctx.clearRect(0,0,canvasW,canvasH);//去掉背景默认的黑色
console.log(canvasW);
ctx.strokeStyle = "#199301"; //设置画图线的颜色
ctx.font = '26px Microsoft YaHei';//设置字号字体

循环绘制6个60度的扇形,canvas是从水平位置开始绘制的,效果如图

colors = ["#AE3EFF","#4D3FFF","#FC262C","#3A8BFF","#EE7602","#FE339F"];
for(var index = 0; index < 6; index++) {
    var angle = index * baseAngle;       
    ctx.fillStyle = colors[index];//设置每个扇形区域的颜色
    ctx.beginPath();//开始绘制
    ctx.arc(canvasW * 0.5, canvasH * 0.5, 170, angle, angle + baseAngle, false);
    ctx.arc(canvasW * 0.5, canvasH * 0.5, 68, angle + baseAngle, angle, true);
    //context.arc(x,y,r,sAngle,eAngle,counterclockwise);创建弧/曲线
    ctx.stroke();//开始链线
    ctx.fill();//填充颜色
    ctx.save();//保存当前环境的状态
}

循环绘制6个60度的扇形,并放上文字图片

colors = ["#AE3EFF","#4D3FFF","#FC262C","#3A8BFF","#EE7602","#FE339F"];
rewardUrl =[]//从服务器请求回来的imgurl
prizeId =[]//从服务器请求回来的奖项
// 图片信息
var imgUrl1 = new Image();
imgUrl1.src = turnWheel.rewardUrl[0];
var imgUrl2 = new Image();
imgUrl2.src = turnWheel.rewardUrl[1];
var imgUrl3 = new Image();
imgUrl3.src = turnWheel.rewardUrl[2];
var imgUrl4 = new Image();
imgUrl4.src = turnWheel.rewardUrl[3];
var imgUrl5 = new Image();
imgUrl5.src = turnWheel.rewardUrl[4];
var imgUrl6 = new Image();
imgUrl6.src = turnWheel.rewardUrl[5];
//注意需要等图片加载完成后绘制
window.onload = function() {
    drawWheelCanvas();
};

for(var index = 0; index < 6; index++) {
    var angle = index * baseAngle;       
    ctx.fillStyle = colors[index];//设置每个扇形区域的颜色
    ctx.beginPath();//开始绘制
    ctx.arc(canvasW * 0.5, canvasH * 0.5, 170, angle, angle + baseAngle, false);
    ctx.arc(canvasW * 0.5, canvasH * 0.5, 68, angle + baseAngle, angle, true);
    //context.arc(x,y,r,sAngle,eAngle,counterclockwise);创建弧/曲线
    ctx.stroke();//开始链线
    ctx.fill();//填充颜色
    ctx.save();//保存当前环境的状态
    ctx.fillStyle = "#fff000";
    var rewardName = prizeId[index];
    var line_height = 24;
    // translate方法重新映射画布上的 (0,0) 位置
    var translateX = canvasW * 0.5 + Math.cos(angle + baseAngle / 2) * turnWheel.textRadius;
    var translateY = canvasH * 0.5 + Math.sin(angle + baseAngle / 2) * turnWheel.textRadius;
    ctx.translate(translateX, translateY);
    // rotate方法旋转当前的绘图,因为文字适合当前扇形中心线垂直的!
    // angle,当前扇形自身旋转的角度 +  baseAngle / 2 中心线多旋转的角度  + 垂直的角度90°
    ctx.rotate(angle + baseAngle / 2 + Math.PI / 2);
    //设置文本位置,居中显示 
    ctx.fillText(rewardName, -ctx.measureText(rewardName).width / 2, 100);
    //添加对应图标
    if(index == 0){
        ctx.drawImage(imgUrl1,-35,0,60,60);
    }else if(index == 1){
        ctx.drawImage(imgUrl2,-35,0,60,60);
    }else if(index == 2){
        ctx.drawImage(imgUrl3,-35,0,60,60);
    }else if(index == 3){
        ctx.drawImage(imgUrl4,-35,0,60,60);
    }else if(index == 4){
        ctx.drawImage(imgUrl5,-35,0,60,60);
    }else{
        ctx.drawImage(imgUrl6,-35,0,60,60);
    }
    ctx.restore(); //很关键,还原画板的状态到上一个save()状态之前
}

第三部:设置旋转转盘配置
//旋转转盘 item:奖品序号,从0开始的; txt:提示语 ,count 奖品的总数量;
var rotateFunc = function(item, tip, count) {
    // 应该旋转的角度,旋转插件角度参数是角度制。
    var baseAngle = 360 / count;
    // 旋转角度 == 270°(当前第一个角度和指针位置的偏移量) - 奖品的位置 * 每块所占的角度 - 每块所占的角度的一半(指针指向区域的中间)
    angles = 360 * 3 / 4 - (item * baseAngle) - baseAngle / 2; // 因为第一个奖品是从0°开始的,即水平向右方向
    $('#wheelCanvas').stopRotate();
    // 注意,jqueryrotate 插件传递的角度不是弧度制。
    // 哪个标签调用方法,旋转哪个控件
    $('#wheelCanvas').rotate({
        angle: 0,
        animateTo: angles + 360 * 5, // 这里多旋转了5圈,圈数越多,转的越快
        duration: 8000,
        callback: function() { // 回调
            //弹出中奖提示
            turnWheel.bRotate = !turnWheel.bRotate;
        }
    });
};
第四部:点击抽奖事件

此处需要做的是,在用户点击时向后台发送请求,接收中奖信息,开始旋转...

// 抽取按钮按钮点击触发事件
$('.pointer').click(function() {
    // 正在转动,直接返回
    if(turnWheel.bRotate) return;

    turnWheel.bRotate = !turnWheel.bRotate;
    var count = turnWheel.rewardNames.length;

    $.ajax({
        type: "POST",
        url: "./drawPrize.htm",
        data: {
            customerId: $(".customerId").val()
        },
        async: false,
        dataType: "json", // 返回数据类型
        success: function(data) {
            console.log(data);
            if(data.type == 1) { //积分不足
                
            } else if(data.type == 2) { //抽奖次数已经用完
            
            } else { //抽奖次数已经用完
                turnWheel.prizeId.forEach(function(currentValue, index) {
                    if(currentValue == data.prize.id) {
                        var item = index;
                        $(".award-warp .content").html(data.prize.name);
                        // 开始抽奖
                        rotateFunc(item, turnWheel.rewardNames[item], count);
                    }
                })
            }
        },
        error: function(data) {

            console.log("网络错误,请检查您的网络设置!");
        }
    });

});
文章借鉴参考:http://www.cnblogs.com/bingwei/p/4830932.html
完整代码:https://github.com/MiuMiu-S/Draw-a-iottery
上一篇下一篇

猜你喜欢

热点阅读