2012-10-29 109 views
0

我無法嘗試使用畫布實現「獎金輪」。我正在使用類似於浮動在StackOverflow周圍的畫布「輪盤」http://jsfiddle.net/wYhvB/4/。我的困境是當你點擊旋轉,在後臺我做了一個API調用,返回一個實際應該選擇哪個獎項的ID,界面只不過是眼睛的糖果。我將所有獎品描述推入第一個數組中,我如何在每個弧中添加一個id並在特定的一個上停止,而不是在特定的隨機時間停止? I.E.如果API返回「車」,我想讓這個車輪旋轉幾次並停在車上。HTML5帆布&javascript獎輪

var colors = ["##eaeaea", "##cccccc", "##eaeaea", "##cccccc", 
        "##eaeaea", "##cccccc", "##eaeaea", "##cccccc"]; 
    // NEED to pre load this data prior 
    var prize_descriptions = ["car","house","etc..."]; // These are injected on an init call from an api 
    var current_user_status = {}; 

    var startAngle = 0; 
    var arc = Math.PI/4; 
    var spinTimeout = null; 

    var spinArcStart = 10; 
    var spinTime = 0; 
    var spinTimeTotal = 0; 

    var current_user_status = null; 
    var spin_results = null; 

    var ctx; 

    function drawSpinnerWheel() { 
     var canvas = document.getElementById("canvas"); 
     if (canvas.getContext) { 
     var outsideRadius = 200; 
     var textRadius = 160; 
     var insideRadius = 125; 

     ctx = canvas.getContext("2d"); 
     ctx.clearRect(0,0,500,500); 


     ctx.strokeStyle = "black"; 
     ctx.lineWidth = 2; 

     ctx.font = 'bold 12px Helvetica, Arial'; 

     for(var i = 0; i < 8; i++) { 
      var angle = startAngle + i * arc; 
      ctx.fillStyle = colors[i]; 

      ctx.beginPath(); 
      ctx.arc(250, 250, outsideRadius, angle, angle + arc, false); 
      ctx.arc(250, 250, insideRadius, angle + arc, angle, true); 
      ctx.stroke(); 
      ctx.fill(); 

      ctx.save(); 
      ctx.shadowOffsetX = -1; 
      ctx.shadowOffsetY = -1; 
      ctx.shadowBlur = 0; 
      ctx.shadowColor = "rgb(220,220,220)"; 
      ctx.fillStyle = "black"; 
      ctx.translate(250 + Math.cos(angle + arc/2) * textRadius, 
         250 + Math.sin(angle + arc/2) * textRadius); 
      ctx.rotate(angle + arc/2 + Math.PI/2); 
      var text = prize_descriptions[i]; 
      if (text == undefined) 
      text = "Not this time! "+i; 
      ctx.fillText(text, -ctx.measureText(text).width/2, 0); 
      ctx.restore(); 
     } 

     //Arrow 
     ctx.fillStyle = "black"; 
     ctx.beginPath(); 
     ctx.moveTo(250 - 4, 250 - (outsideRadius + 5)); 
     ctx.lineTo(250 + 4, 250 - (outsideRadius + 5)); 
     ctx.lineTo(250 + 4, 250 - (outsideRadius - 5)); 
     ctx.lineTo(250 + 9, 250 - (outsideRadius - 5)); 
     ctx.lineTo(250 + 0, 250 - (outsideRadius - 13)); 
     ctx.lineTo(250 - 9, 250 - (outsideRadius - 5)); 
     ctx.lineTo(250 - 4, 250 - (outsideRadius - 5)); 
     ctx.lineTo(250 - 4, 250 - (outsideRadius + 5)); 
     ctx.fill(); 
     } 
    } 

    function spin() { 
     spinAngleStart = Math.random() * 10 + 10; 
     spinTime = 0; 
     spinTimeTotal = Math.random() * 3 + 4 * 1000; 
     rotateWheel(); 
    } 

    function rotateWheel() { 
     spinTime += 30; 
     if(spinTime >= spinTimeTotal) { 
     stopRotateWheel(); 
     return; 
     } 
     var spinAngle = spinAngleStart - easeOut(spinTime, 0, spinAngleStart, spinTimeTotal); 
     startAngle += (spinAngle * Math.PI/180); 
     drawSpinnerWheel(); 
     spinTimeout = setTimeout('rotateWheel()', 30); 
    } 

    function stopRotateWheel() { 
     clearTimeout(spinTimeout); 
     var degrees = startAngle * 180/Math.PI + 90; 
     var arcd = arc * 180/Math.PI; 
     var index = Math.floor((360 - degrees % 360)/arcd); 
     ctx.save(); 
     ctx.font = 'bold 30px Helvetica, Arial'; 
     var text = prize_descriptions[index]; 
     ctx.fillText(text, 250 - ctx.measureText(text).width/2, 250 + 10); 
     ctx.restore(); 
    } 

    function easeOut(t, b, c, d) { 
     var ts = (t/=d)*t; 
     var tc = ts*t; 
     return b+c*(tc + -3*ts + 3*t); 
    } 


drawSpinnerWheel(); 

$("#spin").bind('click', function(e) { 
    e.preventDefault(); 
    spin(); 
});​ 

回答

1

我能想到的最簡單的方法是取出車輪的當前位置,然後計算從這一點到獎品的距離。添加一個隨機數的輪子 直徑 周長的倍數,然後你有一個距離。輪子的邊緣必須穿過這個距離才能在獎品上結束。

就像您可以使用線性或三次插值將元素從一個位置移動到另一個位置的步驟一樣,您可以使用相同的方法將輪從點0(起點)旋轉到點1(終點)從時間= 0到時間= 1

此頁Math: Ease In, ease Out a displacement using Hermite curve with time constraint是一個很好的閱讀。這是我設法圍繞基本上做同樣的事情 - 只是上/下/左/右,而不是旋轉。

這是有點波濤滔滔,而我現在只是看iot。不知道它是否是jsfiddle,缺少的圖像或我正在運行的25個瀏覽器標籤&程序。 無論如何,重點是使用非線性插值以指定的步數達到指定的距離。它應該在指定的時間到達那裏,但不能打開25個窗口..:笑:

查看上面的SO鏈接。它有一些很好的照片,可以很好地解釋。

這是當時的三次樣條插值的小提琴。 http://jsfiddle.net/enhzflep/XKzGF/

這裏是完整的代碼,因爲提交 - wizzard不喜歡我的帖子。 說:「哎呀!您的答案無法提交,因爲: 請通過內嵌相關格式化代碼來完成您的答案(不要僅鏈接到jsfiddle.net)。」

<!DOCTYPE html> 
<html> 
<head> 
<script> 
var continuePlaying = true, isPlaying=false; 

function byId(a){return document.getElementById(a)} 
function myInit() 
{ 
} 
window.addEventListener("load",myInit,!1); 

function cubicHermite(a,b,d,e,c){var g=a*a,f=g*a;return(2*f-3*g+1)*b+(f-2*g+a)*e+(-2*f+3*g)*d+(f-g)*c} 
function interp(a,b,d,e,c){var g,f;f=e/(a/2+b+d/2);g=f*a/2;f*=b;return result=c<=a?cubicHermite(c/a,0,g,0,f/b*a):c<=a+b?g+f*(c-a)/b:cubicHermite((c-a-b)/d,g+f,e,f/b*d,0)} 
function linear(a){return a} 
function cubic(a){return interp(0.35,0.3,0.35,1,a)} 
function getSize(a){return{left:a.offsetLeft,top:a.offsetTop,width:a.clientWidth,height:a.clientHeight}} 
function doAnim2(a,b,d,e){var c=a/b;setTimeout(function(){doAnimStep(0,b,c,d,e)},c)} 
function doAnimStep(a,b,d,e,c){a<=b?(setTimeout(function(){doAnimStep(a,b,d,e,c)},d),e(a/b),a++):void 0!=c&&null!=c&&c()} 


//scroll with cubic interpolation of the current scroll position 
function cubicScrollDown(b,callback) 
{ 
    var a=byId(b),c=a.scrollHeight-a.clientHeight; 
    doAnim2(500,c,function(b){a.scrollTop=c*cubic(b)},callback); 
} 
function cubicScrollUp(b,callback) 
{ 
    var a=byId(b),c=a.scrollHeight-a.clientHeight; 
    doAnim2(500,c,function(b){ a.scrollTop=c*(1-cubic(b)) },callback); 
} 

//scroll with cubic interpolation of the current scroll position 
function linearScrollDown(b, callback) 
{ 
    var a=byId(b),c=a.scrollHeight-a.clientHeight; 
    doAnim2(500,c,function(b){a.scrollTop=c*linear(b)}, callback); 
} 
function linearScrollUp(b, callback) 
{ 
    var a=byId(b),c=a.scrollHeight-a.clientHeight; 
    doAnim2(1000,c,function(b){ a.scrollTop=c*(1-linear(b)) }, callback); 
} 

function animFadeOut(elem, callback) 
{ 
    doAnim2(500,50,function(raw){elem.style.opacity=1-cubic(raw)},callback); 
} 

function animFadeIn(elem, callback) 
{ 
    doAnim2(500,50,function(raw){elem.style.opacity=cubic(raw)},callback); 
} 


function cubicBounce(b) 
{ 
    cubicScrollDown(b, downCallback); 

    function downCallback() 
    { 
     cubicScrollUp(b, upCallback); 
    } 

    function upCallback() 
    { 
     if (continuePlaying===true) 
      setTimeout(function(){cubicBounce(b);}, 0); 
     else 
      continuePlaying = true; 
    } 
} 

function linearBounce(b) 
{ 
    linearScrollDown(b, downCallback); 

    function downCallback() 
    { 
     linearScrollUp(b, upCallback); 
    } 

    function upCallback() 
    { 
     if (continuePlaying===true) 
      setTimeout(function(){linearBounce(b);}, 0); 
     else 
      continuePlaying = true; 
    } 
} 

function fadeOutIn(tgtListIdStr) 
{ 
    var tgt = byId(tgtListIdStr); 

    animFadeOut(tgt,fadedOutCallback); 

    function fadedOutCallback() 
    { 
     animFadeIn(tgt); 
    } 
} 

function prependChild(parent, element) 
{ 
    if (parent.childNodes) 
     parent.insertBefore(element, parent.childNodes[0]); 
    else 
     parent.appendChild(element) 
} 



function slideUpRemove(tgtListIdStr) 
{ 
    var tgt = byId(tgtListIdStr); 
    var listItems = tgt.getElementsByTagName('li'); 
    mHeight = listItems[0].clientHeight; 

    animFadeOut(listItems[0], slideUp); 

    function slideUp() 
    { 
     doAnim2(500, 50, slideUpStep, slideUpDone); 

     function slideUpStep(raw) 
     { 
      listItems[0].style.height = (cubic(1-raw) * mHeight) + 'px'; 
     } 

     function slideUpDone() 
     { 
      dummy = listItems[0]; 
      tgt.appendChild(dummy); 
      //dummy.removeAttribute('style'); 
      dummy.style.height = null; 
      dummy.style.opacity = null; 
     } 
    } 
} 



function slideDownInsert(tgtListIdStr) 
{ 
    // get the container, it's items and the height of the last LI item. 
    var tgt = byId(tgtListIdStr); 
    var listItems = tgt.getElementsByTagName('li'); 
    mHeight = listItems[listItems.length-1].clientHeight; 

    // create a dummy to take the place of the last item, set it's size and height. make it the first child of the containing list 
    var dummy = document.createElement('li'); 
    dummy.style.opacity = 0; 
    dummy.style.height = 0 + 'px'; 
    prependChild(tgt, dummy); 

    // animate it! 
    doAnim2(500, 50, slideDownStep,slideDownDone); 

    function slideDownStep(raw) 
    { 
     dummy.style.height = (cubic(raw) * mHeight)+'px'; 
    } 

    function slideDownDone() 
    { 
     // remove the dummy 
     var newItem = listItems[listItems.length-1]; 
     newItem.style.opacity = 0; 
     prependChild(tgt, newItem); 
     tgt.removeChild(dummy); 
     animFadeIn(newItem, function(){newItem.removeAttribute('style')}); 
    } 
} 
</script> 
<style> 
#myListDiv 
{ 
    width: 256px; 
    padding: 6px; 
    height: 128px; 
    overflow-y: hidden; /*scroll;*/ 
    border-radius: 6px; 
    border: solid 1px transparent; 
    border-color: rgba(0,0,0,0.2) rgba(255,255,255,0.4) rgba(255,255,255,0.4) rgba(0,0,0,0.2); 
/* background-image: url(img/rss128.png); */ 
    background-color: rgba(0,0,0,0.1); 
} 
h4, p 
{ 
    margin: 6px 0; 
} 

ul 
{ 
    padding: 0; 
    list-style: none; 
    margin: 0; 
} 

ul#mList li 
{ 
    padding: 0 8px; 
    margin: 0 6px; 
    display: block; 
    border: solid 1px #cccccc; 
    border-bottom-color: #000; 
    border-color: #ccc transparent #000 transparent; 
    vertical-align: middle; 
    background-color: rgba(150,150,150,0.95); 
    overflow: hidden; 
} 
.thumb 
{ 
    width: 48px; 
    height: 48px; 
    float: left; 
} 
.thumb img 
{ 
    height: 48px; 
} 
#mPanel 
{ 
    display: inline-block; 
    float: left; 
    padding: 32px; 
    background-color: hsl(80,50%,20%); 
} 
</style> 
</head> 
<body> 
    <div id='mPanel'> 
     <div id='myListDiv'> 
      <ul id='mList'> 
       <li><div class='thumb'><img src='img/opera.svg'></div><div class='itemData'><h4><a>Item #1</a></h4><p>some assorted text</p></div></li> 
       <li><div class='thumb'><img src='img/chromeEyes.svg'></div><h4><a>Item #2</a></h4><p>some assorted text</p></li> 
       <li><div class='thumb'><img src='img/girl.png'></div><h4><a>Item #3</a></h4><p>some assorted text</p></li>   
       <li><div class='thumb'><img src='img/chuck-norris.jpg'></div><h4><a>Item #1</a></h4><p>some assorted text</p></li>   
       <li><div class='thumb'><img src='img/redBaron.jpg'></div><h4><a>Item #2</a></h4><p>some assorted text</p></li> 
       <li><div class='thumb'><img src='img/default.png'></div><h4><a>Item #3</a></h4><p>some assorted text</p></li> 
      </ul> 
     </div> 
    </div> 

    <button onclick='cubicScrollDown("myListDiv")'>Cubic down</button> 
    <button onclick='cubicScrollUp("myListDiv")'>Cubic up</button><br> 
    <button onclick='cubicBounce("myListDiv")'>cubic bounce</button> 
    <button onclick='linearBounce("myListDiv")'>linear bounce</button><br> 

    <input type='button' onclick='slideUpRemove("mList")' value='newest'/> 
    <input type='button' onclick='slideDownInsert("mList")' value='Slide Down'/><br> 
    <button onclick='continuePlaying=false'>Stop Anim cycle</button> 
    <input type='button' onclick='fadeOutIn("mList");' value='fadeOutIn'/><br> 
</body> 
</html> 
4

我在創建HTML5畫布中獎輪的一些經驗,我解決了讓車輪停在在一個服務器端的過程中確定一個特定的獎金問題的方法是定義數組與輪子上顯示的內容相對應的獎品,以度爲單位指定每個獎品的開始和結束角度,然後在旋轉輪子之前將目標角度設置爲所涉獎品的開始角度和結束角度之間的隨機值, 360度的倍數,以便輪子旋轉幾次,然後在預定的獎品上減速停止。

例如,如果輪具有4個獎品則獎品陣列是...

var prizes = new Array(); 
prizes[0] = {"name" : "Prize 1", "startAngle" : 0, "endAngle" : 89}; 
prizes[1] = {"name" : "Prize 2", "startAngle" : 90, "endAngle" : 179}; 
prizes[2] = {"name" : "Prize 3", "startAngle" : 180, "endAngle" : 269}; 
prizes[3] = {"name" : "Prize 4", "startAngle" : 270, "endAngle" : 359}; 

和代碼來設置targetAngle是類似...

targetAngle = Math.floor(prizes[determinedPrize]['startAngle'] + (Math.random() * (prizes[determinedPrize]['endAngle'] - prizes[determinedPrize]['startAngle']))); 
targetAngle += (360 * 18); 

車輪的旋轉功能然後循環,直到車輪的當前角度等於目標角度。

我的獎金輪和完整評論的源代碼的工作示例可在http://www.dougtesting.net獲得。在線示例中未啓用預定義功能,但可以在下載後在源代碼(winwheel.js)中輕鬆打開。