下面实现抽奖算法及中奖通知的功能。
首先定义指针转动时中奖的角度和未中奖的角度,以便判断用户是否中奖,图中有6个奖项,相应有6个未中奖区域。奖项角度及其他变量定义如下。
1 var totalAngle = 0;2 var steps = ;3 var loseAngle = [36, 96, 156, 216, 276, 336];4 var winAngle = [6, 66, 126, 186, 246, 306];5 var prizeLevel;6 var now = 0;7 var count = 0;8 var a = 0.01;9 var outter, inner, timer, running = false;
用户进入抽奖界面后,点击抽奖指针,相应的代码处理如下。
1 $("#inner").click(function { 2 if (running) return; 3 if (count >= 3) { 4 alert("达到最大抽奖次数!"); 5 return 6 } 7 $.ajax({ 8 url: "data.php", 9 dataType: "json",10 data: {11 openid: "<?php echo $_GET["openid"];?>",12 time: (new Date).valueOf13 },14 beforeSend: function {15 running = true;16 timer = setInterval(function {17 i += 518 },19 1)20 },21 success: function(data) {22 // 达到最大抽奖次数23 if (data.status == "MAX") {24 alert("您已达到最大抽奖次数!");25 count = 3;26 clearInterval(timer);27 return28 }29 // 有中奖时转盘转到相应位置30 if (data.status == "WIN") {31 $("#prizename").text(data.prizename);32 count = 3;33 clearInterval(timer);34 prizeLevel = data.prizelevel;35 start(winAngle[data.prizelevel - 1]);36 return37 }38 // 未中奖则再给机会39 running = false;40 count++41 prizeLevel = null;42 start43 },44 // 未获取JSON返回,前台处理45 error: function {46 prizeLevel = null;47 start;48 running = false;49 count++50 },51 timeout: 400052 })53 })
点击事件发生时,页面将向data.php文件发送POST请求,将当前用户的OpenID和时间传递过去。data.php中在收到数据后将需要进行一系列的复杂处理,这些在24.5.6节中有详细的讲述下面是一个中奖情形的返回结果。
echo '{"status": "WIN", "prizename": "iPhone 5S", "prizelevel": "2"}';
该情形表示当前已中奖,奖品等级是2,奖品为iPhone 5S。data.php将该JSON数据返回给请求页面,原页面收到数据后,第29~37行代码将进行处理,它将抽奖次数直接置为最大抽奖次数3,并且计算转盘将要旋转的角度,而这个旋转角度也就是奖项的角度,以此确保转盘停止后,指针落点无误。
当中奖数据返回中没有要中奖的标记(第38~42行)或者没有接收到返回的JSON数据时(第44~50行),转盘也需要计算旋转角度,页面将在前台累加抽奖次数,直到达到最大抽奖次数,然后提示用户抽奖次数已经用完。如果返回的JSON数据中显示已经达到最大抽奖次数,则以JSON数据优先作为判断依据(第22~28行)。
当启动转盘转动时,本次抽奖结果已经被旋转角度确定下来了,这是通过start方法实现的。该方法带有一个参数deg。如果中奖,则deg传输进来时就已经是某奖项的角度;如果没有中奖,deg直接传空,这时将随机计算出一个非奖项的角度并赋给它。start方法的实现如下。
1 function start(deg) { 2 deg = deg || loseAngle[parseInt(loseAngle.length * Math.random)]; 3 running = true; 4 clearInterval(timer); 5 totalAngle = 360 * 5 + deg; 6 steps = ; 7 now = 0; 8 countSteps; 9 requestAnimFrame(step)
在start函数中,需要根据旋转角度生成本次转动的步骤,这时往往需要添加N个360°,以便在旋转N圈后落到真正的奖项区域。而这个旋转角度以数组的方式保存。其角度差需要逐渐变小,以实现减速旋转最终停下来的效果。该数组的生成代码如下。
1 function countSteps {2 var t = Math.sqrt(2 * totalAngle / a);3 var v = a * t;4 for (var i = 0; i < t; i++) {5 steps.push((2 * v * i - a * i * i) / 2)6 }7 steps.push(totalAngle)8 }
上面代码将生成一个元素个数非常大的角度列表数组,数组存储到steps中。这里为了简便,生成了一个简化版本,如表24-9所示。
表24-9 旋转角度数组
从表24-9中可以看到,转盘将从0旋转到624.9°,每一步的旋转角度差将越来越小,直到为0,这时将停留到预先生成好的角度上。
而实现旋转的动画效果,是使用HTML5中的window.requestAnimFrame方法实现的,代码如下。
1 window.requestAnimFrame = (function { 2 return window.requestAnimationFrame || 3 window.webkitRequestAnimationFrame || 4 window.mozRequestAnimationFrame || 5 window.oRequestAnimationFrame || 6 window.msRequestAnimationFrame || 7 function(callback) { 8 window.setTimeout(callback, 1000 / 60) 9 }10 });
当动画将每个旋转角度走完以后,需要将中奖结果提示给用户。没有中奖时只需要弹出一个消息框即可,而中奖时需要隐藏转盘、显示中奖区域、显示中奖结果。该部分代码如下。
1 function step { 2 outter.style.webkitTransform = 'rotate(' + steps[now++] + 'deg)'; 3 outter.style.MozTransform = 'rotate(' + steps[now++] + 'deg)'; 4 outter.style.oTransform = 'rotate(' + steps[now++] + 'deg)'; 5 outter.style.msTransform = 'rotate(' + steps[now++] + 'deg)'; 6 if (now < steps.length) { 7 requestAnimFrame(step) 8 } else { 9 running = false;10 setTimeout(function {11 if (prizeLevel != null) {12 var levelName= new Array("", "一等奖", "二等奖", "三等奖", "四等奖", "五等奖", "六等奖")13 $("#prizelevel").text(levelName[prizeLevel]);14 $("#result").slideToggle(500); // 显示中奖区域15 $("#outercont").slideUp(500) // 隐藏转盘16 } else {17 alert("亲,继续努力哦!")18 }19 },20 200)21 }
最终的中奖结果页面如图24-22所示。
图24-22 大转盘中奖页面