js实现抽奖大圆盘
实现思路
通过HTML5 Canvas绘制圆盘,使用JavaScript控制旋转动画和结果判定。核心逻辑包括绘制扇形区域、添加文字、旋转动画及停止后的结果回调。
HTML结构
<div class="wheel-container">
<canvas id="wheelCanvas" width="400" height="400"></canvas>
<button id="spinBtn">开始抽奖</button>
</div>
CSS样式
.wheel-container {
position: relative;
width: 400px;
margin: 0 auto;
}
#wheelCanvas {
display: block;
margin: 20px auto;
}
#spinBtn {
display: block;
margin: 10px auto;
padding: 10px 20px;
background: #ff4757;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
JavaScript实现
const canvas = document.getElementById('wheelCanvas');
const ctx = canvas.getContext('2d');
const spinBtn = document.getElementById('spinBtn');
const prizes = ['一等奖', '二等奖', '三等奖', '谢谢参与', '再来一次', '优惠券'];
const colors = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40'];
let currentRotation = 0;
let isSpinning = false;
// 绘制圆盘
function drawWheel() {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = Math.min(centerX, centerY) - 10;
const arcAngle = (2 * Math.PI) / prizes.length;
prizes.forEach((prize, index) => {
ctx.beginPath();
ctx.fillStyle = colors[index % colors.length];
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, radius, index * arcAngle, (index + 1) * arcAngle);
ctx.fill();
// 添加文字
ctx.save();
ctx.translate(centerX, centerY);
ctx.rotate(index * arcAngle + arcAngle / 2);
ctx.textAlign = 'right';
ctx.fillStyle = '#fff';
ctx.font = '16px Arial';
ctx.fillText(prize, radius - 20, 10);
ctx.restore();
});
}
// 旋转动画
function spin() {
if (isSpinning) return;
isSpinning = true;
const spinDuration = 3000 + Math.random() * 2000;
const startTime = Date.now();
const startRotation = currentRotation;
const targetRotation = startRotation + 10 + Math.random() * 20;
function animate() {
const now = Date.now();
const progress = Math.min((now - startTime) / spinDuration, 1);
const easeProgress = easeOut(progress);
currentRotation = startRotation + (targetRotation - startRotation) * easeProgress;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(currentRotation);
ctx.translate(-canvas.width / 2, -canvas.height / 2);
drawWheel();
ctx.restore();
if (progress < 1) {
requestAnimationFrame(animate);
} else {
isSpinning = false;
const prizeIndex = determinePrize();
alert(`恭喜获得: ${prizes[prizeIndex]}`);
}
}
requestAnimationFrame(animate);
}
// 缓动函数
function easeOut(t) {
return 1 - Math.pow(1 - t, 3);
}
// 确定获奖结果
function determinePrize() {
const normalizedRotation = ((currentRotation % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI);
const arcAngle = (2 * Math.PI) / prizes.length;
return Math.floor((2 * Math.PI - normalizedRotation) / arcAngle) % prizes.length;
}
// 初始化
drawWheel();
spinBtn.addEventListener('click', spin);
功能扩展建议
- 添加指针元素:在圆盘中心绘制固定指针
- 音效支持:旋转时添加音效,停止时播放提示音
- 结果高亮:停止后高亮显示获奖区域
- 数据动态配置:通过API获取奖品列表
- 移动端适配:添加触摸事件支持
注意事项
- 旋转动画使用requestAnimationFrame实现流畅效果
- 通过缓动函数使旋转呈现先快后慢的效果
- 角度计算需处理2π的周期性
- 文字绘制时需要进行坐标系变换
- 禁止重复点击防止动画冲突







