下面實現抽獎算法及中獎通知的功能。
首先定義指針轉動時中獎的角度和未中獎的角度,以便判斷用戶是否中獎,圖中有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).valueOf 13 }, 14 beforeSend: function { 15 running = true; 16 timer = setInterval(function { 17 i += 5 18 }, 19 1) 20 }, 21 success: function(data) { 22 // 達到最大抽獎次數 23 if (data.status == "MAX") { 24 alert("您已達到最大抽獎次數!"); 25 count = 3; 26 clearInterval(timer); 27 return 28 } 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 return 37 } 38 // 未中獎則再給機會 39 running = false; 40 count++ 41 prizeLevel = null; 42 start 43 }, 44 // 未獲取JSON返回,前台處理 45 error: function { 46 prizeLevel = null; 47 start; 48 running = false; 49 count++ 50 }, 51 timeout: 4000 52 }) 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 大轉盤中獎頁面