目录
前言
想象一下,你正置身于一个充满惊喜与刺激的世界,手中的转盘仿佛掌握着无尽的财富与好运。而今天,我们将为你揭秘如何用Canvas打造三种不同玩法的转盘,让你在每一次旋转中都能感受到不同的乐趣与期待!
效果图展示
一、 转盘的三重玩法
1、玩法一:等分转盘
首先,我们来看看等分转盘。这种转盘的特点是每个区域都均等划分,每个区域的面积、形状都完全相同。无论是红色区域、蓝色区域还是绿色区域,它们都有着相同的概率被选中。当你轻轻一点,转盘飞速旋转,最终停留在哪个区域,完全取决于你的运气。这种等分转盘,简单直接,公平公正,是初学者们的最爱。
2、玩法二:不等分转盘
然而,如果你觉得等分转盘太过单调,那么不等分转盘或许能满足你的需求。在这种玩法中,每个区域的面积、形状都不尽相同。有些区域占据了大半个转盘,而有些区域则只有小小的一角。这样的设计,让每个区域被选中的概率也各不相同。旋转转盘时,你或许会期待那些大面积的区域能够停下来,但也可能被那些小巧玲珑的区域所惊艳。不等分转盘,充满了未知与惊喜,让你在每一次旋转中都能体验到不同的刺激感。
3、玩法三:等分转盘与概率不相等
除了区域大小的不同,我们还可以在等分上进行调整。有些转盘虽然区域相等,但每个区域被选中的概率却是不相等的。这是通过复杂的算法和计算实现的,让转盘在旋转时能够自动调整速度和角度,确保每个区域被选中的机会不完全相等。而另一些转盘则直接让概率与区域大小挂钩,大区域有着更高的被选中概率。这样的转盘,既考验玩家的运气,也考验设计者的智慧。
二、svg绘制转盘指针
- 通过iconfont官网下载svg指针代码:iconfont官网链接
<svg t="1713059543990" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="1835" width="200" height="200">
<path
d="M263.577601 776.630449a242.559588 242.559588 0 0 1 138.417007-218.124973L483.818959 23.36268a27.485506
27.485506 0 0 1 54.283873 0l81.824351 535.142796a242.559588 242.559588 0 0 1 138.417006 218.124973
247.369551 247.369551 0 0 1-494.739102 0z"
p-id="1836" fill="#f4ad13"></path>
</svg>
三、Canvas绘制转盘
-
html、css部分内容
#css
<style>
.box {
width: 100%;
height: 550px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
}
canvas {
display: block;
margin: 20px auto;
}
svg {
position: absolute;
left: 50%;
top: 50%;
width: 70px;
height: 70px;
margin-left: -35px;
margin-top: -65px;
}
</style>
#html
<div class="box">
<canvas id="rouletteCanvas" width="302" height="302"></canvas>
<svg t="1713059543990" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="1835" width="200" height="200">
<path
d="M263.577601 776.630449a242.559588 242.559588 0 0 1 138.417007-218.124973L483.818959 23.36268a27.485506
27.485506 0 0 1 54.283873 0l81.824351 535.142796a242.559588 242.559588 0 0 1 138.417006 218.124973
247.369551 247.369551 0 0 1-494.739102 0z"
p-id="1836" fill="#f4ad13"></path>
</svg>
<button onclick="startSpinning()">开始抽奖</button>
</div>
2、JavaScript实现
①、获取canvas的dom并通过getContext 方法用于获取canvas 元素上的渲染上下文
const canvas = document.getElementById('rouletteCanvas');
const ctx = canvas.getContext('2d');
②、转盘参数所用到的参数
对于转盘的前期准备工作,首先我们需要考虑到需要的转盘参数,参数内容分别有: 奖项数量、 每个奖项的角度、转盘半径、转盘中心X坐标 、转盘中心Y坐标 、中奖内容、和每个奖项的背景颜色。
// 转盘参数
const numSegments = 8; // 奖项数量
const anglePerSegment = Math.PI * 2 / numSegments; // 每个奖项的角度 Math.PI=π
const radius = 150; // 转盘半径
const centerX = canvas.width / 2; // 转盘中心X坐标
const centerY = canvas.height / 2; // 转盘中心Y坐标
const prizeText = ['奖品1', '奖品2', '奖品3', '奖品4', '奖品5', '奖品6', '奖品7', '奖品8'];// 各奖项内容
const prizeColors = ['#ff0000', '#8e44ad', '#0000ff', '#32cd32', '#f0f', '#ff5733', '#90ee90', '#888888']; // 各奖项背景颜色
③、绘制转盘背景方法
// ctx.arc(centerX, centerY, radius, startAngle, endAngle, false);
// centerX 和 centerY:圆弧所在圆的圆心坐标。
// radius:圆弧所在圆的半径。
// startAngle 和 endAngle:圆弧的起始角度和结束角度,以弧度为单位。
// 这个参数表示绘制的是逆时针方向的圆弧。如果设置为true,则会绘制顺时针方向的圆弧。
function drawRoulette() {
//清除整个 <canvas> 元素上的所有内容,将画布恢复到初始的空白状态。
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < numSegments; i++) {
const startAngle = (i ) * anglePerSegment;//起始角度
const endAngle = (i+1 ) * anglePerSegment;//结尾角度
const x = centerX + Math.cos(startAngle) * radius;// 输出startAngle的余弦值
const y = centerY + Math.sin(startAngle) * radius;// 输出startAngle的正弦值
ctx.beginPath();
// 开始绘制圆盘
ctx.arc(centerX, centerY, radius, startAngle, endAngle, false);
ctx.closePath();
ctx.fillStyle = prizeColors[i];// 填充扇形区域
ctx.fill();
ctx.save();//保存当前的Canvas状态
ctx.restore();
}
}
④、初始化转盘和指针的调用
// 初始化转盘和指针
drawRoulette();
效果图展示
四、Canvas扩展
/*
arc()方法绘制的圆弧不会自动连接到圆心,因此如果你想要一个完整的扇形效果
(包括从圆弧到圆心的线段),你需要手动绘制这些线段。但是,对于填充操作,
你不需要手动闭合路径,因为fill()会自动处理这个问题。
*/
1、每个奖项内容的填充
// 绘制文本
const textAngle = startAngle + (endAngle - startAngle) / 2;
const textX = centerX + Math.cos(textAngle) * (radius - 40);//x轴上的坐标值,基于圆的半径和指定的角度Angle
const textY = centerY + Math.sin(textAngle) * (radius - 40);//y轴上的坐标值,基于圆的半径和指定的角度Angle
ctx.translate(textX, textY);// 将Canvas的原点移动到(textX, textY)位置
ctx.rotate(textAngle);// 旋转Canvas沿着指定的textAngle方向排列
ctx.textAlign = 'center';// 设置文本的对齐方式为居中
ctx.textBaseline = 'middle';// 设置文本垂直居中
ctx.fillStyle = '#fff';// 设置文本填充颜色为白色
ctx.fillText(prizeText[i], 0, 0);//指定位置绘制文本
ctx.rotate(textAngle),这个坐标是基于平移和旋转后的新坐标系。
2、 绘制连接圆心的线段(可选,如果填充的话不需要,因为fill()会自动闭合路径)
ctx.lineTo(centerX, centerY);
3、如果需要,也可以绘制扇形的边框
// 如果需要,也可以绘制扇形的边框
ctx.lineWidth = 1; // 设置边框宽度
ctx.strokeStyle = '#666'; // 设置边框颜色
ctx.stroke();
五、完整代码
本章为绘制转盘,完整代码供学习参考,扩展已详细进行注解。Canvas三重玩法请关注下一章。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>转盘抽奖</title>
<style>
.box {
width: 100%;
height: 550px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
}
canvas {
display: block;
margin: 20px auto;
}
svg {
position: absolute;
left: 50%;
top: 50%;
width: 70px;
height: 70px;
margin-left: -35px;
margin-top: -65px;
}
</style>
</head>
<body>
<div class="box">
<canvas id="rouletteCanvas" width="302" height="302"></canvas>
<svg t="1713059543990" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="1835" width="200" height="200">
<path
d="M263.577601 776.630449a242.559588 242.559588 0 0 1 138.417007-218.124973L483.818959 23.36268a27.485506 27.485506 0 0 1 54.283873 0l81.824351 535.142796a242.559588 242.559588 0 0 1 138.417006 218.124973 247.369551 247.369551 0 0 1-494.739102 0z"
p-id="1836" fill="#f4ad13"></path>
</svg>
<button onclick="startSpinning()">开始抽奖</button>
</div>
<script>
const canvas = document.getElementById('rouletteCanvas');
const ctx = canvas.getContext('2d');
// 转盘参数
const numSegments = 8; // 奖项数量
const anglePerSegment = Math.PI * 2 / numSegments; // 每个奖项的角度 Math.PI=π
const radius = 150; // 转盘半径
const centerX = canvas.width / 2; // 转盘中心X坐标
const centerY = canvas.height / 2; // 转盘中心Y坐标
const pointerLength = 50; // 指针长度
const prizeText = ['奖品1', '奖品2', '奖品3', '奖品4', '奖品5', '奖品6', '奖品7', '奖品8'];// 各奖项内容
const prizeColors = ['#ff0000', '#8e44ad', '#0000ff', '#32cd32', '#f0f', '#ff5733', '#90ee90', '#888888']; // 各奖项背景颜色
// 绘制转盘背景
function drawRoulette() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < numSegments; i++) {
const startAngle = (i + 6) * anglePerSegment;
const endAngle = (i + 7) * anglePerSegment;
const x = centerX + Math.cos(startAngle) * radius;
const y = centerY + Math.sin(startAngle) * radius;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, startAngle, endAngle, false);
ctx.lineTo(centerX, centerY);
ctx.closePath();
ctx.fillStyle = prizeColors[i];
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = '#666';
ctx.stroke();
const textAngle = startAngle + (endAngle - startAngle) / 2;
const textX = centerX + Math.cos(textAngle) * (radius - 40);
const textY = centerY + Math.sin(textAngle) * (radius - 40);
ctx.save();
ctx.translate(textX, textY);
ctx.rotate(textAngle);
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = '#fff';
ctx.fillText(prizeText[i], 0, 0);
ctx.restore();
}
}
// 初始化转盘和指针
drawRoulette();
</script>
</body>
</html>