JavaScript实践:用Canvas开发一个可配置的大转盘抽奖功能

news2024/9/23 3:20:34

在这里插入图片描述

🏆作者简介,黑夜开发者,全栈领域新星创作者✌,阿里云社区专家博主,2023年6月csdn上海赛道top4。
🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。
🏆本文已收录于专栏:100个JavaScript的小应用。
🎉欢迎 👍点赞✍评论⭐收藏

文章目录

  • 🚀一、引言
  • 🚀二、开发思路
  • 🚀三、代码实现
    • 🔎3.1 HTML结构(index.html)
    • 🔎3.2 CSS样式(style.css)
    • 🔎3.3 JavaScript代码(script.css)
      • 🍁3.3.1 配置中奖概率
      • 🍁3.3.2 开发圆盘效果
      • 🍁3.3.3 开发指针样式
      • 🍁3.3.4 开发点击抽奖事件
  • 🚀四、测试效果
  • 🚀五、完整代码
    • 🔎5.1 index.html
    • 🔎5.2 style.css
    • 🔎5.3 script.js
  • 🚀六、总结


🚀一、引言

大转盘抽奖是一种常见的游戏方式,用户可以通过点击按钮让指针开始旋转,在经过一段时间后指针会停下来,显示用户中奖的奖项。本文将用JavascriptHTML实现一个简单的大转盘抽奖功能。详细介绍实现思路和代码。

⭐⭐文末附完整代码⭐⭐

🚀二、开发思路

本文将使用JavaScriptHTML来实现一个简单的大转盘抽奖功能。具体步骤如下:

  1. 创建HTML结构:使用HTML创建一个大转盘容器,包括转盘、指针和抽奖按钮。
  2. 使用CSS样式:使用CSS样式来美化大转盘的外观,包括颜色、字体等。
  3. 使用JavaScript编写抽奖逻辑:根据配置的奖项和概率,计算中奖结果,并设置指针的旋转动画效果。
  4. 绑定点击事件:为抽奖按钮绑定点击事件,点击按钮后开始抽奖逻辑。
  5. 弹出中奖内容:抽奖结束后,使用alert弹窗显示中奖结果。

🚀三、代码实现

🔎3.1 HTML结构(index.html)

<div id="canvas">
   <canvas id="wheel" width="600" height="600"></canvas></div>
<button onclick="startSpin()">抽奖</button>

🔎3.2 CSS样式(style.css)

css样式主要定义圆盘和按钮的显示效果,核心代码如下:

#canvas {
    position: relative;
}

.block {
    width: 200px;
    height: 200px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 20px;
    font-weight: bold;
}

🔎3.3 JavaScript代码(script.css)

🍁3.3.1 配置中奖概率

先定义一个配置数组,用于配置奖项的名称抽奖背景色以及中奖的概率,后面圆盘会根据这个显示出对应的效果。

const prizes = [
   { text: '奖品1', color: '#f44336', probability: 0.2 },
   { text: '奖品2', color: '#9c27b0', probability: 0.1 },
   { text: '奖品3', color: '#3f51b5', probability: 0.15 },
   { text: '奖品4', color: '#00bcd4', probability: 0.25 },
   { text: '奖品5', color: '#4caf50', probability: 0.2 },
   { text: '奖品6', color: '#000000', probability: 0.1 }
];

🍁3.3.2 开发圆盘效果

根据上面的配置,来开发出圆盘,主要用到Javascript进行编码。

function drawWheel() {
   ctx.clearRect(0, 0, canvas.width, canvas.height);

    let startAngle = 0;
    let endAngle = 0;

    for (let i = 0; i < prizes.length; i++) {
        startAngle = endAngle;
        endAngle = startAngle + (Math.PI * 2 * prizes[i].probability);

        ctx.beginPath();
        ctx.arc(centerX, centerY, radius, startAngle, endAngle, false);
        ctx.lineTo(centerX, centerY);
        ctx.fillStyle = prizes[i].color;
        ctx.fill();

        ctx.save();
        ctx.translate(centerX, centerY);
        ctx.rotate((startAngle + endAngle) / 2);
        ctx.fillStyle = 'white';
        ctx.font = '20px Arial';
        ctx.fillText(prizes[i].text, radius / 2, 0);
        ctx.restore();
    }
}

现在来预览一下圆盘效果,是不是还挺好看的。接下来继续开发指针及旋转中奖效果。
在这里插入图片描述

🍁3.3.3 开发指针样式

首先来一段css样式来安排一下指针效果:

#pointer {
    position: absolute;
    top: calc(50% - 5px);
    left: calc(50% - 2.5px);
    width: 5px;
    height: 30%;
    background-color: red;
    transform-origin: bottom center;
    transition: transform 5s ease-in-out;
    left: 300px;
    top: 120px;
}

把下面的div放到index.html里面去,显示效果如下图。

<div id="pointer"></div>

在这里插入图片描述

🍁3.3.4 开发点击抽奖事件

我们通过点击按钮来触发抽奖动作。当用户点击按钮时。开始旋转抽奖指针,并且在5秒后停止并显示中奖内容。主要js代码如下。

function spinWheel() {
    if (!spinning) {
        angle = angle % (Math.PI * 2);

        ctx.clearRect(centerX - 10, centerY - radius - 10, 20, radius + 20);
        ctx.save();
        ctx.translate(centerX, centerY);
        ctx.rotate(angle);

        ctx.beginPath();
        ctx.moveTo(-5, -radius - 5);
        ctx.lineTo(5, -radius - 5);
        ctx.lineTo(0, -radius - 15);
        ctx.closePath();
        ctx.fillStyle = 'red';
        ctx.fill();

        ctx.restore();

        angle += 0.1;
        requestAnimationFrame(spinWheel);
    }
}
// 开始抽奖逻辑
function startSpin() {
    if (!spinning) {
        genRandom()
        spinning = true;
        spinWheel();
        pointerRotate()
        setTimeout(stopSpin, 5000);
    }
}
// 指针开始旋转
function pointerRotate() {
   const pointer = document.getElementById('pointer');
   const rotation = 360 * random + 720;
    // 设置动画
    pointer.style.transform = 'rotateZ(' + rotation + 'deg)';
    pointer.style.pointerEvents = 'none';
    // 停止旋转并弹出中奖内容
    setTimeout(() => {
        pointer.style.pointerEvents = 'auto';
    }, 5000);
}
// 指针停止事件
function stopSpin() {
    spinning = false;

    const selectedPrize = getSelectedPrize();
    alert('中奖内容:' + selectedPrize.text);
}
// 根据旋转角度获取中奖内容
function getSelectedPrize() {
    let startAngle = 0;
    let endAngle = prizes[0].probability;

    for (let i = 0; i < prizes.length; i++) {
        if (random >= startAngle && random < endAngle) {
            return prizes[i];
        }

        startAngle = endAngle;
        endAngle += prizes[i + 1].probability;
    }
}

🚀四、测试效果

在实际场景中假设我们设计如下5个奖项。点击抽奖按钮,可以看到指针转动,5秒后停止并弹出中奖内容。

  1. macbook 14pro,中奖概率10%。
  2. iPhone13,中奖概率30%。
  3. xiaomi手机,中奖概率20%。
  4. 100元商城优惠券,中奖概率20%。
  5. 感谢参与,中奖概率20%。
const prizes = [
   { text: 'macbook14pro', color: '#f44336', probability: 0.1 },
   { text: 'iPhone13', color: '#9c27b0', probability: 0.3 },
   { text: 'xiaomi', color: '#3f51b5', probability: 0.2 },
   { text: '100元优惠券', color: '#00bcd4', probability: 0.2 },
   { text: '感谢参与', color: '#4caf50', probability: 0.2 },
];

在这里插入图片描述

🚀五、完整代码

🔎5.1 index.html

<!DOCTYPE html>
<html>
<head>
    <title>大转盘抽奖</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <div id="canvas">
        <canvas id="wheel" width="600" height="600"></canvas>
        <div id="pointer"></div>
    </div>
    <button onclick="startSpin()">抽奖</button>

    <script type="text/javascript" src="script.js"></script>
</body>
</html>

🔎5.2 style.css

#canvas {
    position: relative;
    width: 600px;
    height: 600px;
}
#pointer {
    position: absolute;
    top: calc(50% - 5px);
    left: calc(50% - 2.5px);
    width: 5px;
    height: 30%;
    background-color: red;
    transform-origin: bottom center;
    transition: transform 5s ease-in-out;
    left: 300px;
    top: 120px;
}

.block {
    width: 200px;
    height: 200px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 20px;
    font-weight: bold;
}

🔎5.3 script.js

const prizes = [
    { text: 'macbook14pro', color: '#f44336', probability: 0.1 },
    { text: 'iPhone13', color: '#9c27b0', probability: 0.3 },
    { text: 'xiaomi', color: '#3f51b5', probability: 0.2 },
    { text: '100元优惠券', color: '#00bcd4', probability: 0.2 },
    { text: '感谢参与', color: '#4caf50', probability: 0.2 },
];

const canvas = document.getElementById('wheel');
const ctx = canvas.getContext('2d');
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = Math.min(canvas.width, canvas.height) / 2;
let angle = 0;
let spinning = false;

function drawWheel() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    let startAngle = 0;
    let endAngle = 0;

    for (let i = 0; i < prizes.length; i++) {
        startAngle = endAngle;
        endAngle = startAngle + (Math.PI * 2 * prizes[i].probability);

        ctx.beginPath();
        ctx.arc(centerX, centerY, radius, startAngle, endAngle, false);
        ctx.lineTo(centerX, centerY);
        ctx.fillStyle = prizes[i].color;
        ctx.fill();

        ctx.save();
        ctx.translate(centerX, centerY);
        ctx.rotate((startAngle + endAngle) / 2);
        ctx.fillStyle = 'white';
        ctx.font = '20px Arial';
        ctx.fillText(prizes[i].text, radius / 2, 0);
        ctx.restore();
    }
}

function spinWheel() {
    if (!spinning) {
        angle = angle % (Math.PI * 2);

        ctx.clearRect(centerX - 10, centerY - radius - 10, 20, radius + 20);
        ctx.save();
        ctx.translate(centerX, centerY);
        ctx.rotate(angle);

        ctx.beginPath();
        ctx.moveTo(-5, -radius - 5);
        ctx.lineTo(5, -radius - 5);
        ctx.lineTo(0, -radius - 15);
        ctx.closePath();
        ctx.fillStyle = 'red';
        ctx.fill();

        ctx.restore();

        angle += 0.1;
        requestAnimationFrame(spinWheel);
    }
}

function startSpin() {
    if (!spinning) {
        genRandom()
        spinning = true;
        spinWheel();
        pointerRotate()
        setTimeout(stopSpin, 5000);
    }
}

function pointerRotate() {

   const pointer = document.getElementById('pointer');
   const rotation = 360 * random + 720;
    // 设置动画
    pointer.style.transform = 'rotateZ(' + rotation + 'deg)';
    pointer.style.pointerEvents = 'none';
    // 停止旋转并弹出中奖内容
    setTimeout(() => {
        pointer.style.pointerEvents = 'auto';
    }, 5000);
}

function stopSpin() {
    spinning = false;

    const selectedPrize = getSelectedPrize();
    alert('中奖内容:' + selectedPrize.text);
}

function getSelectedPrize() {
    let startAngle = 0;
    let endAngle = prizes[0].probability;

    for (let i = 0; i < prizes.length; i++) {
        if (random >= startAngle && random < endAngle) {
            return prizes[i];
        }

        startAngle = endAngle;
        endAngle += prizes[i + 1].probability;
    }
}

var random = Math.random()

function genRandom() {
    random = Math.random()
}

drawWheel();

🚀六、总结

本文使用JavaScriptHTML实现了一个的大转盘抽奖功能。通过配置奖项和概率,用户可以根据自己的需要来设置抽奖的规则。点击抽奖按钮后,指针开始旋转,经过5秒后停止,并弹出中奖内容。

以上就是本文的具体思路和代码实现,通过这个示例,你可以了解到如何使用JavaScriptHTML来实现大转盘抽奖功能。希望对你有所帮助!实际的应用中,可以基于上面的内容修改。

在这里插入图片描述

今天的内容就到这里,我们下次见。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/855283.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Qlearning强化学习的路径规划算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 Q值更新规则 4.2 基于Q-learning的路径规划算法设计 4.3 Q-learning路径规划流程 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022A 3.部分核心程序 ..…

leetcode870. 优势洗牌(java)

优势洗牌 leetcode870. 优势洗牌题目描述双指针 排序代码 滑动窗口 leetcode870. 优势洗牌 难度 - 中等 leetcode870. 优势洗牌 题目描述 给定两个长度相等的数组 nums1 和 nums2&#xff0c;nums1 相对于 nums2 的优势可以用满足 nums1[i] > nums2[i] 的索引 i 的数目来描…

SecOC基础原理详解1

1、SecOC是什么&#xff1f; SecOC官方说法叫安全通讯模块。通俗一点就是发送CAN原始数据的时候进行加密&#xff0c;解析CAN原始数据的时候进行解密。 车上实施SecOC机制数据的ECU&#xff08;ECU是啥&#xff1f;可以百度一下&#xff09;&#xff0c;即使接收到了攻击性的…

如何将NAS空间变为本地磁盘,并拥有与实体硬盘所有常用功能

1.前言 作为一个垃圾佬&#xff0c;用自己的双路E5板子&#xff0c;加持PCIE拆分&#xff0c;4块PM983A齐上阵&#xff0c;气势可嘉。作为一个家庭NAS&#xff0c;如果仅仅用他当作一个普通的存储区存储数据那未免太过于浪费了&#xff1b;另一边&#xff0c;由于工作机硬盘太…

leetcode 子序列问题

718 最长重复子数组 此处求的是连续的子序列&#xff0c;使用动态规划进行求解。 使用dp[i][j]表示第1个序列前i个数字和第2个序列前j个数字的最大的重复子数组长度。 class Solution(object):def findLength(self, nums1, nums2):""":type nums1: List[int]:t…

Kotlin语法

整理关键语法列表如下&#xff1a; https://developer.android.com/kotlin/interop?hlzh-cn官方指导链接 语法形式 说明 println("count ${countnum}")字符串里取值运算 val count 2 var sum 0 类型自动推导 val 定义只读变量&#xff0c;优先 var定义可变变量…

Visual Studio在Release模式下设置代码的调试

Visual Studio在Release模式下设置代码的调试 Debug 模式下模型的加载速度、打开速度会降低很多&#xff0c;这里不推荐使用 Debug 模式进行调试。 Release 模式下可进行调试&#xff0c;使用 Release 模式调试&#xff0c;会提高模型打开速度、 加载速度、编译速度&#xff0c…

ChatGPT 6 月流量下滑 10%大模型遇到增长停滞,背后原因是什么?

近期数据显示&#xff0c;ChatGPT在过去的6个月中流量下滑了10%。这引发了对大模型发展是否达到瓶颈的疑问。我们对此进行了分析&#xff0c;并得出以下观点。首先&#xff0c;ChatGPT在实用性方面存在一些问题。它生成的文本内容往往过于模板化&#xff0c;句式和结构的同质性…

【计算机视觉 | Kaggle】保姆级教程:入门 Kaggle 的步骤详细介绍

文章目录 一、Overview二、Evaluation三、Timeline四、Code Requirements五、Data5.1 数据的可视化5.2 文件 六、Discussion七、Code 一、Overview 当进入到一场比赛的 Overview 页面后&#xff0c;先读完 Description&#xff0c;了解比赛讲了一件什么事情。 我们以一场比赛…

无涯教程-Perl - getprotobynumber函数

描述 此函数在标量context中将协议NUMBER转换为其对应的名称,在列表context中将其名称和相关信息转换为:($name,$aliases,$protocol_number)。 语法 以下是此函数的简单语法- getprotobynumber NUMBER返回值 此函数针对错误返回undef,否则返回标量context中的协议编号,并在…

Metamask登录方式集成

Metamask登录 https://www.toptal.com/ethereum/one-click-login-flows-a-metamask-tutorial#how-the-login-flow-works 参考&#xff1a; https://zh.socialgekon.com/one-click-login-with-blockchain 后端需要在用户表中增加address和nonce字段。兼容其他登录方式&#xff0…

添加@Transactional事务

1. 在启动类上新增开启注解功能 EnableTransactionManagement EnableTransactionManagement //开启事务注解功能 SpringBootApplication public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);} } 2. 方法上…

【Linux】gdb 的使用

目录 1. 使用 gdb 的前置工作 2. 如何使用 gdb 进行调试 1、如何看到我的代码 2、如何打断点 3、怎么运行程序 4、如何进行逐过程调试 5、如何进行逐语句调试 6、如何监视变量值 7、如何跳到指定位置 8、运行完一个函数 9、怎么跳到下一个断点 10、如何禁用/开启…

[OnWork.Tools]系列 04-快捷启动

简介 主要功能是将常用的软件拖动到软件中,实现快速点击启动,结合软件设置中的设置的快捷键,可以快速呼出对应的面板,使用快捷键快速启动应用 拖拽内容 拖拽快捷方式到面板,双击快速打开 拖拽文件方式到面板,双击快速打开 拖拽文件夹到面板双击快速打开 拖拽项目调整顺序 右…

python编程求出介于这两个数 之间的所有质数并打印输出。显示格式为“*数是质数

这里写自定义目录标题 练习 &#xff1a;提示用户输入两个正整数&#xff0c;编程求出介于这两个数之间的所有质数并打印输出。显示格式为“*数是质数。”代码打印效果 练习 &#xff1a;提示用户输入两个正整数&#xff0c;编程求出介于这两个数之间的所有质数并打印输出。显示…

在时间和频率域中准确地测量太阳黑子活动及使用信号处理工具箱(TM)生成广泛的波形,如正弦波、方波等研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

英信翻译为世界动力电池大会提供同传服务

2023年6月8日-11日&#xff0c;世界动力电池大会在四川宜宾举行。作为世界级动力电池行业盛会&#xff0c;以“绿色新动力世界新动能”为主题&#xff0c;2023世界动力电池大会积极服务全球碳中和愿景&#xff0c;致力于推动全球动力电池产业高质量可持续发展&#xff0c;得到了…

web安全漏洞

1.什么是Web漏洞 WEB漏洞通常是指网站程序上的漏洞&#xff0c;可能是由于代码编写者在编写代码时考虑不周全等原因而造成的漏洞。如果网站存在WEB漏洞并被黑客攻击者利用&#xff0c;攻击者可以轻易控制整个网站&#xff0c;并可进一步提前获取网站服务器权限&#xff0c;控制…

外资的“噩梦”,特斯拉不惧挑战,租赁印度办公楼,入驻当地市场

根据8月9日《印度时报》的报道&#xff0c;特斯拉近期在印度正式成立了名为“特斯拉印度汽车与能源公司”的子公司。 据可靠消息人士透露&#xff0c;特斯拉已在印度浦那维曼纳加尔地区的Panchshil商业园总部租下了面积为5850平方英尺的办公空间&#xff0c;该商业园被认为是印…

Cobalt Strike(cs)下载及使用

下载地址 https://pan.baidu.com/s/1OzsPz8vzEunZW35Oqdq2aw?pwdraf2 提取码&#xff1a;raf2 使用 1、启动服务 2、客户端连接服务&#xff0c;可以是linux\windows 3.新建监听器 4、生成反弹shell 5、在目标机器上执行生成的exe文件&#xff0c;靶机可以ping同攻击机&…