vue实现一个转盘抽奖(奖品可配置)
主要技术
- vue2
- canvas
通过图片和canvas绘制出一个转盘
直接上代码
完成样式
html
<div class="wrap">
<div class="activcont">
<div class="rotecont">
<img src="../assets/tyhd.png" ref="tianyi" style="display: none" />
<img src="../assets/taideng.png" ref="taideng" style="display: none" />
<img
src="../assets/yinxiang.png"
ref="yinxiang"
style="display: none"
/>
<img
src="../assets/youhuiquan200.png"
ref="youhuiquan200"
style="display: none"
/>
<img
src="../assets/youhuiquan300.png"
ref="youhuiquan300"
style="display: none"
/>
<img src="../assets/hongbao.png" ref="hongbao" style="display: none" />
<img
src="../assets/wangyiyuanyinyue.png"
ref="wangyi"
style="display: none"
/>
<div class="turnplate">
<canvas
class="item"
ref="wheelcanvas"
width="422px"
height="422px"
></canvas>
<img
class="pointer"
src="../assets/turnplate-pointer.png"
@click="clickRotate"
/>
</div>
</div>
</div>
</div>
将所需要绘制的图片先放在html中,以便在canvas绘制的时候使用
css
.wrap {
width: 100%;
max-width: 640px;
margin: auto;
}
.activcont {
width: 100%;
position: relative;
}
.rotecont {
width: 80%;
position: relative;
z-index: 2;
max-width: 512px;
left: 0px;
right: 0px;
margin: auto;
overflow: hidden;
}
.rotecont .turnplate {
display: block;
width: 100%;
position: relative;
background-image: url("../assets/turnplate-bg.png");
background-size: 100% 100%;
}
.rotecont .turnplate canvas.item {
width: 100%;
margin-top: 0.2rem;
transition: all 8s;
}
.rotecont .turnplate img.pointer {
position: absolute;
width: 5rem;
height: 5rem;
left: 0px;
right: 0px;
margin: auto;
top: 32%;
}
js
转盘数据
turnplate: {
//奖品名称
restaraunts: [
"天翼高清10元",
"智能音箱",
"智能台灯",
"300元购机优惠券",
"200元购机优惠券",
"红包",
"网易云音乐",
],
//每个奖品区的背景色
colors: [
"#ffecd6",
"#ffdcc5",
"#ffecd6",
"#ffdcc5",
"#ffecd6",
"#ffdcc5",
"#ffecd6",
],
//大转盘外圆的半径
outsideRadius: 168,
//大转盘奖品位置距离圆心的距离
textRadius: 140,
//大转盘内圆的半径
insideRadius: 30,
//开始角度,此转盘开始指在200元购机券
startAngle: 7,
},
绘制奖品
drawRouletteWheel() {
let canvas = this.$refs.wheelcanvas;
if (canvas.getContext) {
//根据奖品个数计算圆周角度
let arc = Math.PI / (this.turnplate.restaraunts.length / 2); // 奖品个数 / 2
let ctx = canvas.getContext("2d");
//在给定矩形内清空一个矩形
ctx.clearRect(0, 0, 422, 422);
//strokeStyle 属性设置或返回用于笔触的颜色、渐变或模式
ctx.strokeStyle = "#f5b599";
//font 属性设置或返回画布上文本内容的当前字体属性
ctx.font = "bold 16px Helvetica";
for (let i = 0; i < this.turnplate.restaraunts.length; i++) {
// 初始角度 + 第几个奖品的圆周角度
let angle = this.turnplate.startAngle + i * arc;
// 为当前奖品填充背景色
ctx.fillStyle = this.turnplate.colors[i];
ctx.beginPath();
//arc(x,y,r,起始角,结束角,绘制方向) 方法创建弧/曲线(用于创建圆或部分圆)
//canvas创建內圆(奖品区域)
ctx.arc(
211,
211,
this.turnplate.outsideRadius,
angle,
angle + arc,
false
);
//旋转按钮的內圆
ctx.arc(
211,
211,
this.turnplate.insideRadius,
angle + arc,
angle,
true
);
//绘制以定好的路径
ctx.stroke();
//填充当前的路径
ctx.fill();
//锁画布(为了保存之前的画布状态)
ctx.save();
//----绘制奖品开始----
ctx.fillStyle = "#f3142d";
//奖品名称
let text = this.turnplate.restaraunts[i];
//translate方法重新映射画布上的 (0,0) 位置
ctx.translate(
211 + Math.cos(angle + arc / 2) * this.turnplate.textRadius,
211 + Math.sin(angle + arc / 2) * this.turnplate.textRadius
);
//rotate方法旋转当前的绘图
ctx.rotate(angle + arc / 2 + Math.PI / 2);
//在画布上绘制填色的文本。文本的默认颜色是黑色
//measureText()方法返回包含一个对象,该对象包含以像素计的指定字体宽度
ctx.fillText(text, -ctx.measureText(text).width / 2, 0);
//添加对应图标,根据奖品名称去绘制位置
if (text.indexOf("天翼") >= 0) {
let img = this.$refs.tianyi;
img.onload = function () {
ctx.drawImage(img, -25, 10);
};
ctx.drawImage(img, -25, 10);
} else if (text.indexOf("台灯") >= 0) {
let img = this.$refs.taideng;
img.onload = function () {
ctx.drawImage(img, -25, 10);
};
ctx.drawImage(img, -25, 10);
} else if (text.indexOf("音箱") >= 0) {
let img = this.$refs.yinxiang;
img.onload = function () {
ctx.drawImage(img, -25, 10);
};
ctx.drawImage(img, -25, 10);
} else if (text.indexOf("200") >= 0) {
let img = this.$refs.youhuiquan200;
img.onload = function () {
ctx.drawImage(img, -25, 10);
};
ctx.drawImage(img, -25, 10);
} else if (text.indexOf("300") >= 0) {
let img = this.$refs.youhuiquan300;
img.onload = function () {
ctx.drawImage(img, -25, 10);
};
ctx.drawImage(img, -25, 10);
} else if (text.indexOf("红包") >= 0) {
let img = this.$refs.hongbao;
img.onload = function () {
ctx.drawImage(img, -25, 10);
};
ctx.drawImage(img, -25, 10);
} else if (text.indexOf("网易") >= 0) {
let img = this.$refs.wangyi;
img.onload = function () {
ctx.drawImage(img, -25, 10);
};
ctx.drawImage(img, -25, 10);
}
//把当前画布返回(调整)到上一个save()状态之前
ctx.restore();
//----绘制奖品结束----
}
}
},
绘制奖品成功后,实现抽奖旋转
通过css实现旋转
-
给canvas元素设置过渡属性
.rotecont .turnplate canvas.item { transition: all 8s; } 转盘旋转的秒数
-
然后通过ref属性 找到canvas,让它旋转起来
this.$refs.wheelcanvas.style.transform = `rotate(${realDeg}deg)`;
-
通过随机数模拟接口抽到的奖品
getRadom(x, y) { let min = Math.ceil(x); let max = Math.floor(y); return Math.floor(Math.random() * (max - min + 1)) + min; }, // 包含最大值和最小值
-
旋转角度,抽到的奖品
getPrize(num) { switch (num) { case 0: this.rotate(210, this.turnplate.restaraunts[0]); break; case 1: this.rotate(150, this.turnplate.restaraunts[1]); break; case 2: this.rotate(97, this.turnplate.restaraunts[2]); break; case 3: this.rotate(48, this.turnplate.restaraunts[3]); break; case 4: this.rotate(355, this.turnplate.restaraunts[4]); break; case 5: this.rotate(305, this.turnplate.restaraunts[5]); break; case 6: this.rotate(255, this, this.turnplate.restaraunts[6]); break; } },
最后,绘制时机
在生命周期mounted里绘制
this.$nextTick(() => {
// 当图片都渲染完成,再调绘制
let img = this.$refs.tianyi
img.onload = () => {
this.drawRouletteWheel();
};
});