使用canvas绘制转盘
根据每次抽奖的随机索引计算出对应奖励的角度,再使用transform: rotate实现动画效果
html文件
<!DOCTYPE html>
<html lang="en">
<link>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./index.css">
<title>转盘抽奖Demo</title>
<style>
body {
margin: 0;
}
</style>
</head>
<body>
<div class="turntable">
<div class="route">
<canvas id="canvas" width="500" height="500"></canvas>
<ul class="reward-list">
</ul>
</div>
<div class="point"></div>
</div>
<div class="reward-num"></div>
<div class="reward-type"></div>
<ul>
<li class="select-type">谢谢参与</li>
<li class="select-type">公仔</li>
<li class="select-type">保温杯</li>
<li class="select-type">鼠标垫</li>
<li class="select-type">口罩</li>
<li class="select-type">200积分</li>
</ul>
<script src="./main.js"></script>
</body>
</html>
css文件
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
body {
background-color: rgba(0, 0, 0, 0.17);
}
.turntable {
margin: 0 auto;
width: 500px;
height: 500px;
background-color: gray;
border-radius: 50%;
margin-top: 100px;
position: relative;
}
.route {
width: 100%;
height: 100%;
position: relative;
perspective: 1px;
}
#canvas {
width: 500px;
height: 500px;
}
.point {
width: 80px;
height: 80px;
position: absolute;
top: calc(50% - 40px);
left: calc(50% - 40px);
background-color: #515151;
border-radius: 50%;
}
.reward-list {
position: absolute;
left: 0;
top: 0;
width: 500px;
height: 500px;
}
.reward-item {
position: absolute;
left: calc(50% - 100px);
top: 0;
width: 200px;
height: 250px;
padding: 20px 10px;
text-align: center;
box-sizing: border-box;
}
.point::after {
position: absolute;
content: "";
width: 20px;
height: 20px;
left: calc(50% - 10px);
top: -7.5px;
transform: rotate(45deg);
background-color: #515151;
}
.reward-num,
.reward-type {
text-align: center;
margin-top: 50px;
margin-bottom: 50px;
}
ul {
width: 600px;
margin: 0 auto;
display: flex;
justify-content: space-evenly;
}
.select-type {
display: inline-block;
padding: 0 10px;
cursor: pointer;
text-align: center;
height:30px;
background-color: #515151;
color: #fff;
line-height: 30px;
border-radius: 5px;
}
main.js文件
let rewardList = ["谢谢参与", "公仔", "保温杯", "鼠标垫", "口罩", "200积分"];
//奖励个数(包括谢谢参与)
// const num = random(2, 5) + 1;
const num = 6;
//每一份角度
const angle = (Math.PI * 2) / num;
//初始化转盘
function initTurntable() {
let textEl = document.querySelector(".reward-num");
textEl.innerHTML = `奖励个数:${num}`;
drawGird(num);
initReward();
initDraw();
}
// 生产一圈的点坐标
function initPolygon(num = 3, r = 250, center = { x: 250, y: 250 }) {
// 生成多边形的点
let points = [];
//偏移量
let baseAngle = angle - Math.PI / 2;
for (let i = 0; i < num; i++) {
// 当前点对应的角度
let currenAngle = i * angle + baseAngle;
let point = {
x: r * Math.cos(currenAngle) + center.x,
y: r * Math.sin(currenAngle) + center.y,
};
points.push(point);
}
return points;
}
//绘制转盘内容
function drawGird(num) {
let canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, 500, 500);
ctx.beginPath();
ctx.arc(250, 250, 249, 0, 4 * Math.PI);
ctx.stroke();
ctx.closePath();
initPolygon(num).map((item, index) => {
ctx.beginPath();
ctx.moveTo(250, 250);
ctx.lineTo(item.x, item.y);
ctx.strokeStyle = `rgb(${Math.floor(Math.random() * 255)},${Math.floor(
Math.random() * 255
)},${Math.floor(Math.random() * 255)})`;
ctx.stroke();
ctx.closePath();
});
}
//高亮中奖区域
function highlight(num) {
let canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
let fix = -Math.PI / 2;
let sub = Math.PI / 720;
//计算高亮位置
let start = angle * num + fix + sub;
let end = angle * (num + 1) + fix - sub;
/**绘制扇形 */
ctx.beginPath();
ctx.moveTo(250, 250);
ctx.arc(250, 250, 248, start, end);
ctx.fillStyle = "rgb(255, 210, 247)";
ctx.fill();
ctx.closePath();
}
//初始化奖励位置
function initReward() {
let rewardBox = document.querySelector(".reward-list");
rewardList.slice(0, num).map((reward, index) => {
let el = document.createElement("li");
el.classList.add("reward-item");
el.innerHTML = reward;
el.style["transform-origin"] = `100px 250px`;
el.style["transform"] = `rotate(${(360 / num) * index + 180 / num}deg)`;
rewardBox.appendChild(el);
});
}
//初始化抽奖功能
function initDraw() {
let el = document.querySelector(".point");
el.addEventListener("click", () => {
console.log("抽奖");
luckDraw();
});
}
/**抽奖 */
function luckDraw(which = -1) {
// 随机中奖
which = which == -1 ? random(num - 1) : which;
console.log(which);
let msgEl = document.querySelector(".reward-type");
msgEl.innerHTML = `中奖内容:${rewardList[which]}`;
let el = document.querySelector(".route");
//旋转角度 = 固定圈数 + index * (每一份角度) + 中心偏移
el.style["transform"] = `rotate(-${36000 + (360 / num) * which + 180 / num
}deg)`;
el.style["transition"] = "transform 5s cubic-bezier(0, 1, 0.2, 1)";
setTimeout(() => {
highlight(which);
setTimeout(() => {
el.style["transition"] = "none";
el.style["transform"] = "none";
drawGird(num);
}, 2000);
}, 4000);
}
// 初始化点击事件
function initSelect() {
let selectList = document.querySelectorAll(".select-type");
for (let i = 0; i < selectList.length; i++) {
selectList[i].addEventListener("click", () => {
luckDraw(i);
});
}
}
function random(num) {
return Math.floor(Math.random() * 10) % num + 1
}
initTurntable();
initSelect();