最近项目上写了一个签到页面,放在h5、ios和安卓中一起用 ,其中有一个功能是抽奖大转盘,这是一个很常用的功能,现在总结记录一下:
需求
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、实现转盘四周闪烁效果,其实就是两张图片的切换,如图
具体代码
第一步: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("网络错误,请检查您的网络设置!");
}
});
});