最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用JavaScript+HTML實(shí)現(xiàn)一個(gè)可交互的幸運(yùn)大轉(zhuǎn)盤(pán)

 更新時(shí)間:2026年02月07日 10:09:50   作者:bjzhang75  
互動(dòng)元素在各類(lèi)數(shù)字化應(yīng)用中都是提升用戶(hù)體驗(yàn)的重要手段,抽獎(jiǎng)轉(zhuǎn)盤(pán)作為一種經(jīng)典且富有吸引力的互動(dòng)形式,廣泛應(yīng)用于各種場(chǎng)景,本文將詳細(xì)介紹如何使用 HTML、CSS 和 JavaScript 來(lái)實(shí)現(xiàn)一個(gè)可交互的幸運(yùn)大轉(zhuǎn)盤(pán),需要的朋友可以參考下

一、幸運(yùn)大轉(zhuǎn)盤(pán)

互動(dòng)元素在各類(lèi)數(shù)字化應(yīng)用中都是提升用戶(hù)體驗(yàn)的重要手段。抽獎(jiǎng)轉(zhuǎn)盤(pán)作為一種經(jīng)典且富有吸引力的互動(dòng)形式,廣泛應(yīng)用于各種場(chǎng)景。無(wú)論是電商平臺(tái)的促銷(xiāo)活動(dòng),還是企業(yè)年會(huì)的抽獎(jiǎng)程序、商場(chǎng)導(dǎo)購(gòu)的互動(dòng)展示,一個(gè)生動(dòng)有趣的轉(zhuǎn)盤(pán)都能有效吸引參與者的注意力,增加活動(dòng)的趣味性和參與度。本文將詳細(xì)介紹如何使用 HTML、CSS 和 JavaScript 來(lái)實(shí)現(xiàn)一個(gè)可交互的幸運(yùn)大轉(zhuǎn)盤(pán)。

二、效果演示

這個(gè)幸運(yùn)大轉(zhuǎn)盤(pán)的彩色扇形區(qū)域代表不同的獎(jiǎng)項(xiàng),中央有一個(gè)明顯的指針指示抽獎(jiǎng)結(jié)果,用戶(hù)點(diǎn)擊轉(zhuǎn)盤(pán)中心區(qū)域可觸發(fā)動(dòng)畫(huà)旋轉(zhuǎn),旋轉(zhuǎn)結(jié)束后會(huì)顯示抽中的獎(jiǎng)項(xiàng),使用緩動(dòng)函數(shù)使旋轉(zhuǎn)更加自然流暢。

三、系統(tǒng)分析

1、頁(yè)面結(jié)構(gòu)

頁(yè)面主體部分由2部分組成。其中 canvas 是整個(gè)轉(zhuǎn)盤(pán)繪制的核心載體,通過(guò) JavaScript 獲取該元素的繪圖上下文后,我們可以使用 Canvas API 進(jìn)行圖形繪制和動(dòng)畫(huà)控制。result 中顯示抽獎(jiǎng)結(jié)果。

<div class="main">
  <canvas id="canvas" width="400" height="400"></canvas>
  <div class="result" id="result"></div>
</div>

2、核心功能實(shí)現(xiàn)

2.1 初始化參數(shù)與數(shù)據(jù)

首先定義了一些基礎(chǔ)參數(shù)和數(shù)據(jù),這些變量分別表示獎(jiǎng)項(xiàng)列表、對(duì)應(yīng)的顏色、當(dāng)前旋轉(zhuǎn)角度、旋轉(zhuǎn)狀態(tài)標(biāo)志以及轉(zhuǎn)盤(pán)中心坐標(biāo)和半徑等。

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var prizes = ['一等獎(jiǎng)', '二等獎(jiǎng)', '三等獎(jiǎng)', '四等獎(jiǎng)', '五等獎(jiǎng)', '六等獎(jiǎng)'];
var colors = ['#FFADAD', '#FFD6A5', '#FDFFB6', '#CAFFBF', '#9BF6FF', '#A0C4FF'];
var currentRotation = 0, isSpinning = false;
var cx = canvas.width / 2, cy = canvas.height / 2, r = 200;

2.2 繪制轉(zhuǎn)盤(pán)

繪制轉(zhuǎn)盤(pán)的過(guò)程主要是遍歷所有獎(jiǎng)項(xiàng),計(jì)算每個(gè)扇形的角度范圍并依次繪制,每一塊扇形都根據(jù)當(dāng)前旋轉(zhuǎn)角度進(jìn)行調(diào)整,確保動(dòng)畫(huà)過(guò)程中扇形位置正確更新。

function drawWheel() {
  var angle = 2 * Math.PI / prizes.length;
  prizes.forEach((p, i) => {
    ctx.beginPath();
    ctx.moveTo(cx, cy);
    ctx.arc(cx, cy, r, i * angle + currentRotation, (i + 1) * angle + currentRotation);
    ctx.closePath();
    ctx.fillStyle = colors[i];
    ctx.fill();
    ctx.strokeStyle = '#fff';
    ctx.lineWidth = 2;
    ctx.stroke();
    ctx.save();
    ctx.translate(cx, cy);
    ctx.rotate(i * angle + angle / 2 + currentRotation);
    ctx.fillStyle = '#B14113';
    ctx.font = 'bold 16px Arial';
    ctx.textAlign = 'center';
    ctx.fillText(p, r * 0.7, 5);
    ctx.restore();
  });
}

2.3 繪制指針

指針由三角形和圓形組合而成,使用漸變填充增加視覺(jué)層次感。

function drawPointer() {
  var len = 80;
  ctx.save();
  ctx.translate(cx, cy);
  ctx.beginPath();
  ctx.moveTo(0, -len);
  ctx.lineTo(-8, 0);
  ctx.lineTo(8, 0);
  ctx.closePath();
  var g = ctx.createLinearGradient(0, 0, 0, -len);
  g.addColorStop(0, '#ff4757');
  g.addColorStop(1, '#ff3838');
  ctx.fillStyle = g;
  ctx.fill();
  ctx.strokeStyle = '#c44569';
  ctx.lineWidth = 2;
  ctx.stroke();

  ctx.beginPath();
  ctx.arc(0, 0, 12, 0, Math.PI * 2);
  var cg = ctx.createRadialGradient(0, 0, 0, 0, 0, 10);
  cg.addColorStop(0, '#fff');
  cg.addColorStop(1, '#ff6b6b');
  ctx.fillStyle = cg;
  ctx.fill();
  ctx.strokeStyle = '#c44569';
  ctx.lineWidth = 2;
  ctx.stroke();
  ctx.restore();
}

2.4 動(dòng)畫(huà)旋轉(zhuǎn)與抽獎(jiǎng)邏輯

當(dāng)用戶(hù)點(diǎn)擊轉(zhuǎn)盤(pán)中心時(shí),觸發(fā)抽獎(jiǎng)動(dòng)畫(huà),這里實(shí)現(xiàn)了平滑減速的旋轉(zhuǎn)動(dòng)畫(huà),通過(guò)三次貝塞爾曲線模擬 “ease-out” 緩動(dòng)效果,讓旋轉(zhuǎn)看起來(lái)更自然。旋轉(zhuǎn)結(jié)束時(shí),通過(guò)角度計(jì)算確定指針指向的具體獎(jiǎng)項(xiàng)。

function spin() {
  if (isSpinning) return;
  isSpinning = true;
  document.getElementById('result').textContent = '';

  var minRot = 3 * 2 * Math.PI, maxRot = 6 * 2 * Math.PI;
  var addRot = Math.random() * (maxRot - minRot) + minRot;
  var targetRotation = currentRotation + addRot;

  var duration = 4000;
  var start = performance.now();

  function frame(t) {
    var elapsed = t - start;
    var progress = Math.min(elapsed / duration, 1);
    // ease-out 緩動(dòng)
    var eased = 1 - Math.pow(1 - progress, 3);
    currentRotation = startRotation + (targetRotation - startRotation) * eased;
    draw();
    if (progress < 1) {
      requestAnimationFrame(frame);
    } else {
      var pointerAngle = 3 * Math.PI / 2;
      var norm = (2 * Math.PI - currentRotation % (2 * Math.PI)) % (2 * Math.PI);
      var hit = (norm + pointerAngle) % (2 * Math.PI);
      var anglePer = 2 * Math.PI / prizes.length;
      var idx = Math.floor(hit / anglePer) % prizes.length;
      document.getElementById('result').textContent = `恭喜獲得:${prizes[idx]}!`;
      isSpinning = false;
    }
  }

  var startRotation = currentRotation;
  requestAnimationFrame(frame);
}

四、擴(kuò)展建議

  • 增加音效:可以在旋轉(zhuǎn)開(kāi)始和結(jié)束時(shí)播放音效,增強(qiáng)體驗(yàn)感受
  • 自定義獎(jiǎng)項(xiàng):提供配置面板讓用戶(hù)自定義獎(jiǎng)項(xiàng)名稱(chēng)和數(shù)量
  • 記錄抽獎(jiǎng)歷史:保存每次抽獎(jiǎng)的結(jié)果,方便統(tǒng)計(jì)分析
  • 限制抽獎(jiǎng)次數(shù):加入每日抽獎(jiǎng)次數(shù)限制或積分兌換機(jī)制

五、完整代碼

git地址:https://gitee.com/ironpro/hjdemo/blob/master/wheel/index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>幸運(yùn)大轉(zhuǎn)盤(pán)</title>
  <style>
      * {
          margin: 0;
          padding: 0;
          box-sizing: border-box;
      }

      body {
          background-color: #f5f5f5;
          min-height: 100vh;
          padding: 20px;
      }
      .container {
          max-width: 800px;
          margin: 0 auto;
          background: white;
          border-radius: 15px;
          box-shadow: 0 20px 40px rgba(0,0,0,0.1);
          overflow: hidden;
      }

      .header {
          background: #FF6B35;
          color: white;
          padding: 20px;
          text-align: center;
      }

      .header h1 {
          font-size: 28px;
          font-weight: 500;
      }
      .main {
          padding: 20px;
          display: flex;
          flex-direction: column;
          align-items: center;
          height: 500px;
      }
      #canvas {
          width: 400px;
          height: 400px;
          border-radius: 50%;
          box-shadow: 0 0 30px rgba(0, 0, 0, .3);
      }
      .result {
          text-align: center;
          font-size: 24px;
          font-weight: bold;
          margin-top: 20px;
          color: #333;
      }
  </style>
</head>
<body>
<div class="container">
  <div class="header">
    <h1>幸運(yùn)大轉(zhuǎn)盤(pán)</h1>
  </div>
  <div class="main">
    <canvas id="canvas" width="400" height="400"></canvas>
    <div class="result" id="result"></div>
  </div>
</div>
<script>
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  var prizes = ['一等獎(jiǎng)', '二等獎(jiǎng)', '三等獎(jiǎng)', '四等獎(jiǎng)', '五等獎(jiǎng)', '六等獎(jiǎng)'];
  var colors = ['#FFADAD', '#FFD6A5', '#FDFFB6', '#CAFFBF', '#9BF6FF', '#A0C4FF'];
  var currentRotation = 0, isSpinning = false;
  var cx = canvas.width / 2, cy = canvas.height / 2, r = 200;

  // 繪制轉(zhuǎn)盤(pán)
  function drawWheel() {
    var angle = 2 * Math.PI / prizes.length;
    prizes.forEach((p, i) => {
      ctx.beginPath();
      ctx.moveTo(cx, cy);
      ctx.arc(cx, cy, r, i * angle + currentRotation, (i + 1) * angle + currentRotation);
      ctx.closePath();
      ctx.fillStyle = colors[i];
      ctx.fill();
      ctx.strokeStyle = '#fff';
      ctx.lineWidth = 2;
      ctx.stroke();
      ctx.save();
      ctx.translate(cx, cy);
      ctx.rotate(i * angle + angle / 2 + currentRotation);
      ctx.fillStyle = '#B14113';
      ctx.font = 'bold 16px Arial';
      ctx.textAlign = 'center';
      ctx.fillText(p, r * 0.7, 5);
      ctx.restore();
    });
  }

  // 繪制指針
  function drawPointer() {
    var len = 80;
    ctx.save();
    ctx.translate(cx, cy);
    ctx.beginPath();
    ctx.moveTo(0, -len);
    ctx.lineTo(-8, 0);
    ctx.lineTo(8, 0);
    ctx.closePath();
    var g = ctx.createLinearGradient(0, 0, 0, -len);
    g.addColorStop(0, '#ff4757');
    g.addColorStop(1, '#ff3838');
    ctx.fillStyle = g;
    ctx.fill();
    ctx.strokeStyle = '#c44569';
    ctx.lineWidth = 2;
    ctx.stroke();

    ctx.beginPath();
    ctx.arc(0, 0, 12, 0, Math.PI * 2);
    var cg = ctx.createRadialGradient(0, 0, 0, 0, 0, 10);
    cg.addColorStop(0, '#fff');
    cg.addColorStop(1, '#ff6b6b');
    ctx.fillStyle = cg;
    ctx.fill();
    ctx.strokeStyle = '#c44569';
    ctx.lineWidth = 2;
    ctx.stroke();
    ctx.restore();
  }

  // 繪制
  function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawWheel();
    drawPointer();
  }

  // 抽獎(jiǎng)
  function spin() {
    if (isSpinning) return;
    isSpinning = true;
    document.getElementById('result').textContent = '';

    var minRot = 3 * 2 * Math.PI, maxRot = 6 * 2 * Math.PI;
    var addRot = Math.random() * (maxRot - minRot) + minRot;
    var targetRotation = currentRotation + addRot;

    var duration = 4000;
    var start = performance.now();

    function frame(t) {
      var elapsed = t - start;
      var progress = Math.min(elapsed / duration, 1);
      // ease-out 緩動(dòng)
      var eased = 1 - Math.pow(1 - progress, 3);
      currentRotation = startRotation + (targetRotation - startRotation) * eased;
      draw();
      if (progress < 1) {
        requestAnimationFrame(frame);
      } else {
        var pointerAngle = 3 * Math.PI / 2;
        var norm = (2 * Math.PI - currentRotation % (2 * Math.PI)) % (2 * Math.PI);
        var hit = (norm + pointerAngle) % (2 * Math.PI);
        var anglePer = 2 * Math.PI / prizes.length;
        var idx = Math.floor(hit / anglePer) % prizes.length;
        document.getElementById('result').textContent = `恭喜獲得:${prizes[idx]}!`;
        isSpinning = false;
      }
    }

    var startRotation = currentRotation;
    requestAnimationFrame(frame);
  }

  // 添加點(diǎn)擊事件
  canvas.addEventListener('click', function (e) {
    var rect = canvas.getBoundingClientRect();
    var x = e.clientX - rect.left - cx;
    var y = e.clientY - rect.top - cy;
    var distance = Math.sqrt(x * x + y * y);
    if (distance < 30) {
      spin();
    }
  });
  draw();
</script>
</body>
</html>

到此這篇關(guān)于使用JavaScript+HTML實(shí)現(xiàn)一個(gè)可交互的幸運(yùn)大轉(zhuǎn)盤(pán)的文章就介紹到這了,更多相關(guān)JavaScript HTML幸運(yùn)大轉(zhuǎn)盤(pán)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaScript如何從listbox里同時(shí)刪除多個(gè)項(xiàng)目

    JavaScript如何從listbox里同時(shí)刪除多個(gè)項(xiàng)目

    要從列表框同時(shí)刪除多個(gè)項(xiàng)目只能從下向上刪除,這樣就不會(huì)出現(xiàn)索引號(hào)亂變的問(wèn)題了,下面有個(gè)不錯(cuò)的示例,大家可以感受下
    2013-10-10
  • 一個(gè)頁(yè)面元素appendchild追加到另一個(gè)頁(yè)面元素的問(wèn)題

    一個(gè)頁(yè)面元素appendchild追加到另一個(gè)頁(yè)面元素的問(wèn)題

    一般都是自己創(chuàng)建元素然后append到頁(yè)面的但是如果是頁(yè)面本身有的元素append到另一個(gè)頁(yè)面元素呢,很多的新手朋友對(duì)此問(wèn)題比較好奇,本人也是如此啊,好了不多說(shuō),切入主題,感興趣的朋友可以了解下哦
    2013-01-01
  • JavaScript中確定值的類(lèi)型的三種方法

    JavaScript中確定值的類(lèi)型的三種方法

    JavaScript是一種弱類(lèi)型語(yǔ)言,當(dāng)你給一個(gè)變量賦了一個(gè)值,該值是什么類(lèi)型的,那么該變量就是什么類(lèi)型的,那么當(dāng)我們?cè)谑褂靡恍┓椒ǖ臅r(shí)候,必須知道該變量是什么類(lèi)型的,才能調(diào)用該變量對(duì)應(yīng)的一些方法,本文介紹了JavaScript中確定值的類(lèi)型的三種方法,需要的朋友可以參考下
    2025-08-08
  • javascript獲取網(wǎng)頁(yè)寬高方法匯總

    javascript獲取網(wǎng)頁(yè)寬高方法匯總

    本文給大家匯總介紹了下javascript獲取網(wǎng)頁(yè)寬高的方法,以及各個(gè)瀏覽器下不同方法獲取到的值的對(duì)比,有需要的小伙伴可以參考下。
    2015-07-07
  • javascript實(shí)現(xiàn)簡(jiǎn)單計(jì)算器效果【推薦】

    javascript實(shí)現(xiàn)簡(jiǎn)單計(jì)算器效果【推薦】

    下面小編就為大家?guī)?lái)一篇javascript實(shí)現(xiàn)簡(jiǎn)單計(jì)算器效果【推薦】。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考
    2016-04-04
  • 頁(yè)面右下角彈出提示框示例代碼js版

    頁(yè)面右下角彈出提示框示例代碼js版

    右下角彈出提示框想必大家不會(huì)陌生吧,本文簡(jiǎn)單的為大家實(shí)現(xiàn)一個(gè),具體代碼如下,有需求的朋友可以參考下
    2013-08-08
  • 用innerHTML &符號(hào)副值給文本框后會(huì)變成&amp;的方法

    用innerHTML?。Ψ?hào)副值給文本框后會(huì)變成&amp;的方法

    用innerHTML?。Ψ?hào)副值給文本框后會(huì)變成&amp;的方法...
    2007-07-07
  • JS瀏覽器BOM常見(jiàn)操作實(shí)例詳解

    JS瀏覽器BOM常見(jiàn)操作實(shí)例詳解

    這篇文章主要介紹了JS瀏覽器BOM常見(jiàn)操作,結(jié)合實(shí)例形式詳細(xì)分析了JS瀏覽器BOM模型元素常見(jiàn)操作技巧與使用注意事項(xiàng),需要的朋友可以參考下
    2020-04-04
  • 最新評(píng)論

    延庆县| 璧山县| 习水县| 晋江市| 遵义市| 黄大仙区| 铜陵市| 石嘴山市| 延津县| 利津县| 山东省| 台北市| 鄯善县| 贵阳市| 政和县| 邵阳市| 合肥市| 盘锦市| 乃东县| 郸城县| 满洲里市| 土默特右旗| 黔江区| 桓仁| 海丰县| 苏尼特左旗| 安塞县| 阿城市| 新建县| 石城县| 铜陵市| 临江市| 方正县| 铁岭市| 大关县| 天水市| 平定县| 汽车| 广西| 和田县| 集贤县|