不依赖任何库:实现推广转盘三连中
一个乱写的推广转盘,很乱但是效果还行
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
}
.container {
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: scroll;
}
.canvas-wrapper {
position: relative;
}
.button {
background: transparent;
outline: none;
border: none;
display: block;
position: absolute;
left: 0;
right: 0;
top: 56vh;
border-radius: 50%;
margin: 0 auto;
width: 100px;
height: 100px;
}
#canvas {
display: block;
}
style>
head>
<body>
<div class="container">
<div class="canvas-wrapper">
<button class="button">button>
<canvas id="canvas">canvas>
div>
<div>信息div>
div>
body>
<script>
// 获取像素比 高清cavas
function getPixelRatio(context) {
var backingStore = context.backingStorePixelRatio ||
context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1;
return (window.devicePixelRatio || 1) / backingStore;
};
var wheel = new Wheel();
// 公共类
function Wheel() {
let cav = document.getElementById('canvas');
this.pointerRange = [];
this.pointerIndex = 0;
this.turned = []; //已经转中的下标数组
this.turnTargetRotate = []; //要转的目的数组
this.turnedCount = 0; // 转盘次数
this.startTurn = false; // 开始抽
this.delay = 20;
this.speed = 1; //转速
this.ctx = cav.getContext('2d');
this.ratio = getPixelRatio(this.ctx);
this.w = window.innerWidth;
this.h = window.innerHeight;
cav.style.width = this.w + 'px';
cav.style.height = this.h + 'px';
cav.width = this.w * this.ratio;
cav.height = this.h * this.ratio;
}
Wheel.prototype.updatePointerIndex = function (rotate) {
let rotateV = rotate % 360;
let index = this.pointerRange.findIndex(d => rotateV < d);
this.pointerIndex = index == -1 ? 0 : index;
}
// 转盘类
function AwardRound({
cx,
cy,
cr = 100,
data = []
}) {
let angleStore = 0;
let sum = 0;
this.cx = cx * wheel.ratio;
this.cy = cy * wheel.ratio;
this.cr = cr * wheel.ratio;
this.count = data.length;
this.data = data.map((d, i) => {
sum += d.angle;
let prevData = data[i - 1];
angleStore += d.angle + (i - 1 > 0 ? prevData.angle : 0);
let startAngle = - 90 - (d.angle / 2);
d.beginAngle = startAngle / 180 * Math.PI;
d.endAngle = (startAngle + d.angle) / 180 * Math.PI;
if (i == 0) {
d.rotateAngle = 0;
} else {
d.rotateAngle = angleStore;
}
wheel.pointerRange.push(sum - (data[0].angle / 2));
if (d.isTurn) {
let prevItem = wheel.pointerRange[i - 1];
wheel.turnTargetRotate.push({
rotate: ((wheel.pointerRange[i] - prevItem) / 2 + prevItem) + 3 * 360,
index: i
})
}
return d;
});
}
AwardRound.prototype.render = function () {
let iconW = 36 * wheel.ratio;
this.data.forEach((d, i) => {
wheel.ctx.save();
wheel.ctx.translate(this.cx, this.cy);
wheel.ctx.rotate((d.rotateAngle) * Math.PI / 360);
wheel.ctx.beginPath();
// 画底盘
wheel.ctx.fillStyle = d.background || '#fdf1e7';
wheel.ctx.arc(0, 0, this.cr, d.beginAngle, d.endAngle);
wheel.ctx.lineTo(0, 0);
wheel.ctx.fill()
// 名字
wheel.ctx.fillStyle = d.color || '#000';
wheel.ctx.font = `${d.fontSize ? d.fontSize * wheel.ratio : 16}px 微软雅黑`;
wheel.ctx.textAlign = 'center';
wheel.ctx.fillText(d.name || '', 0, - this.cr + 20 * wheel.ratio);
// 图片
if (d.icon) {
wheel.ctx.drawImage(d.icon, -iconW / 2, -this.cr + 40 * wheel.ratio, iconW, iconW);
}
// 浮层
wheel.ctx.fillStyle = '#000';
wheel.ctx.globalAlpha = i == wheel.pointerIndex || wheel.turned.includes(i) ? 0 : 0.5;
wheel.ctx.arc(0, 0, this.cr, d.beginAngle, d.endAngle);
wheel.ctx.lineTo(0, 0);
wheel.ctx.fill();
wheel.ctx.restore();
})
}
// 按钮类
function Button({
cx,
cy
}) {
this.cx = cx * wheel.ratio;
this.cy = cy * wheel.ratio;
this.rotate = 0;
}
Button.prototype.render = function () {
let tmpW = 25 * wheel.ratio;
wheel.ctx.save()
wheel.ctx.translate(this.cx, this.cy);
wheel.ctx.rotate(this.rotate * Math.PI / 180);
wheel.ctx.beginPath()
wheel.ctx.fillStyle = '#FF910B';
wheel.ctx.arc(0, 0, 50 * wheel.ratio, 0, Math.PI * 2);
wheel.ctx.fill();
wheel.ctx.moveTo(0, 0);
wheel.ctx.lineTo(tmpW, 0);
wheel.ctx.lineTo(0, -80 * wheel.ratio);
wheel.ctx.lineTo(-tmpW, 0);
wheel.ctx.fill();
wheel.ctx.restore();
}
Button.prototype.update = function () {
this.rotate += wheel.speed;
if (wheel.startTurn) { // 开始转了
if (this.rotate >= wheel.turnTargetRotate[wheel.turnedCount].rotate) { // 达到阈值
wheel.delay--; //延时器
if (wheel.delay > 0) {
// 休息一下
this.rotate = wheel.turnTargetRotate[wheel.turnedCount].rotate; // 保持抽到位置
wheel.speed = 0; //停止转动
} else {
// 转下一次
wheel.turnedCount++; // 中次+1
wheel.turned.push(wheel.turnTargetRotate[wheel.turnedCount - 1].index);
wheel.speed = 20;
wheel.delay = 20;
if (wheel.turnedCount < 3) {
this.rotate = 0;
}
}
}
}
wheel.updatePointerIndex(this.rotate);
}
// 背景类
function Background() {
let img = new Image()
img.src = './bg.png';
this.bgImg = img;
}
Background.prototype.render = function () {
let iconW = (wheel.w - 10) * wheel.ratio;
let iconH = iconW * (846 / 720);
wheel.ctx.drawImage(this.bgImg, 5 * wheel.ratio, wheel.h * wheel.ratio - iconH, iconW, iconH)
}
var awardData = [
{
icon: 'http://mdhw.oss-cn-hangzhou.aliyuncs.com/goods/1652065297220_maYiZc27.jpg',
name: '感谢参与',
background: '#fdf1e7',
color: '#C24603',
fontSize: '13',
angle: 45,
},
{
icon: '',
name: 'AirJordan1',
background: '#FFB876',
color: '#C24603',
fontSize: '11',
angle: 25
},
{
icon: 'http://mdhw.oss-cn-hangzhou.aliyuncs.com/goods/1652065313260_JDMZ2GTW.jpg',
name: 'iPhone手机',
background: '#BD1600',
color: '#FEE28A',
fontSize: '11',
angle: 25,
isTurn: true,
},
{
icon: '',
name: '蓝牙音箱',
background: '#FFDAB2',
color: '#C24603',
fontSize: '11',
angle: 25
},
{
icon: 'http://mdhw.oss-cn-hangzhou.aliyuncs.com/goods/1652065297220_maYiZc27.jpg',
name: '感谢参与',
background: '#fdf1e7',
color: '#C24603',
fontSize: '13',
angle: 45,
},
{
icon: '',
name: 'AirJordan1',
background: '#FFB876',
color: '#C24603',
fontSize: '11',
angle: 25
},
{
icon: 'http://mdhw.oss-cn-hangzhou.aliyuncs.com/goods/1652065313260_JDMZ2GTW.jpg',
name: 'iPhone手机',
background: '#BD1600',
color: '#FEE28A',
fontSize: '11',
angle: 25,
isTurn: true,
},
{
icon: '',
name: '蓝牙音箱',
background: '#FFDAB2',
color: '#C24603',
fontSize: '11',
angle: 25
},
{
icon: 'http://mdhw.oss-cn-hangzhou.aliyuncs.com/goods/1652065297220_maYiZc27.jpg',
name: '感谢参与',
background: '#fdf1e7',
color: '#C24603',
fontSize: '13',
angle: 45,
},
{
icon: '',
name: 'AirJordan1',
background: '#FFB876',
color: '#C24603',
fontSize: '11',
angle: 25
},
{
icon: 'http://mdhw.oss-cn-hangzhou.aliyuncs.com/goods/1652065313260_JDMZ2GTW.jpg',
name: 'iPhone手机',
background: '#BD1600',
color: '#FEE28A',
fontSize: '11',
angle: 25,
isTurn: true,
},
{
icon: '',
name: '蓝牙音箱',
background: '#FFDAB2',
color: '#C24603',
fontSize: '11',
angle: 25
},
];
awardData = awardData.map(d => {
if (d.icon) {
let img = new Image();
img.src = d.icon;
d.icon = img
}
return d
})
window.onload = function () {
let iconH = (wheel.w - 10) * (846 / 720);
let cx = wheel.w / 2;
let cr = cx - 30;
let cy = wheel.h - iconH + cr + 25;
var btnDom = document.querySelector('.button')
var background = new Background();
var awardRound = new AwardRound({
cx: cx,
cy: cy,
cr: cr,
data: awardData
});
var button = new Button({
cx,
cy,
});
const clickDown = function () {
if (wheel.startTurn) {
btnDom.removeEventListener('click', clickDown);
return;
}
button.rotate = 0;
wheel.startTurn = true;
wheel.speed = 20;
}
btnDom.addEventListener('click', clickDown)
function doAnimate() {
// 清除画布
wheel.ctx.clearRect(0, 0, 10000, 10000)
// 渲染转盘背景
background.render();
// 渲染转盘
awardRound.render();
// 渲染按钮
button.update();
button.render();
if (wheel.turnedCount < 3) {
requestAnimationFrame(() => {
doAnimate();
})
}
}
doAnimate();
}
script>
html>