摸鱼摸鱼,闲来无事就是摸鱼
搞个营销类的转盘抽奖活动
转盘抽奖
先看一下效果图
思路
做完项目Google一下发现还可以通过css 的方式去做,这边主要通过canvas的方法去绘制
先生成一个基础的canvas
<canvas id="canvas" width="600" height="600"></canvas>
首先绘制一个圆的背景(也可以通过图片来设置背景)
js
const drawBall = (beginPointX,beginPointY,radius,startAngle,endAngle,backgroudColor) =>{
const ctx = canvasOptions.ctx
ctx.beginPath();
ctx.arc(beginPointX,beginPointY,radius,startAngle,endAngle);
ctx.fillStyle = backgroudColor;
ctx.fill();
}
// 设置背景为图片 获取最小值 通过半径来判断 缩放值
const drawRoundImage = (beginPointX,beginPointY,radius,startAngle,endAngle,backImage) =>{
const ctx = canvasOptions.ctx
let temp = Math.min(backImage.width,backImage.height);
let scale = radius / temp;
ctx.rect(beginPointX-backImage.width*scale, beginPointX-backImage.height*scale, beginPointX+radius, beginPointY+backImage.width*scale.height*scale);
ctx.drawImage(backImage, beginPointX-backImage.width*scale/2, beginPointY-backImage.height*scale/2,backImage.width*scale,backImage.height*scale);
}
画完背景就里面抽奖的内容了
js
// 根据抽奖的内容列表来判断每次分配所占的角度
for (const [index,item] of ballOptions.entries()){
let startAngle = 0;
let endAngle = 0;
if(index){
startAngle = 2*Math.PI*(index/ballOptions.length);
}
if(index !=ballOptions.length-1){
endAngle = 2*Math.PI*((index+1)/ballOptions.length);
}
await drawArc(300,300,200,startAngle+angle.value,endAngle+angle.value,item.color,item)
}
// 转盘里面的内容 包括图片 背景颜色 和 字体内容
const drawArc=(beginPointX,beginPointY,radius,startAngle,endAngle,backgroudColor,item)=>{
const centerX = 300;
const centerY = 300;
const orbitRadius = 200
const ctx = canvasOptions.ctx
ctx.beginPath();
ctx.arc(beginPointX,beginPointY,radius,startAngle,endAngle);
if(backgroudColor){
ctx.fillStyle = backgroudColor;
ctx.strokeStyle ="white";
}else{
ctx.fillStyle = "rgba(0,0,0,0)";
}
ctx.fill();
ctx.beginPath()
ctx.moveTo(300,300)
const startX = centerX + orbitRadius * Math.cos(startAngle);
const startY = centerY + orbitRadius * Math.sin(startAngle);
const endX = centerX + orbitRadius * Math.cos(endAngle);
const endY = centerY + orbitRadius * Math.sin(endAngle);
ctx.lineTo(startX,startY)
ctx.lineTo(endX,endY);
ctx.closePath();
ctx.fillStyle = backgroudColor;
ctx.strokeStyle = backgroudColor
ctx.stroke();
ctx.fill();
// 保存字体样式
ctx.save();
ctx.translate((startX+endX)/2, (startY+endY)/2);
// 根据圆的弧度计算文字旋转角度
let angle = 0
let index = ballOptions.findIndex(ite =>ite.label == item.label);
if(index != ballOptions.length-1){
angle = (startAngle + endAngle) / 2 + Math.PI/2;
}else{
angle = (startAngle + endAngle) / 2 - Math.PI/2;
}
// 旋转画布
ctx.rotate(angle);
ctx.font = '24px Arial bold';
ctx.fillStyle = '#AA625B';
ctx.textAlign = "center"
ctx.fillText(item.label, 0,0);
ctx.restore();
if("backImage" in item){
let img = new Image();
img.src = item.backImage;
img.onload=()=>{
ctx.save();
ctx.translate(((startX+endX)/2+300)/2, ((startY+endY)/2+300)/2);
let angle = 0
let index = ballOptions.findIndex(ite =>ite.label == item.label);
if(index != ballOptions.length-1){
angle = (startAngle + endAngle) / 2 + Math.PI/2;
}else{
angle = (startAngle + endAngle) / 2 - Math.PI/2;
}
// 旋转画布
ctx.rotate(angle);
drawRoundImage(0,0,60,0,Math.PI*2,img)
ctx.restore();
}
}
}
最后就是转盘的动画内容了 包括旋转角速度的变化 以及一些后门的逻辑
js
if(isAnimal.value){
speed.value += 0.0005;
angle.value += speed.value;
// console.log(angle.value);
animateFlag.value = requestAnimationFrame(animate);
}
if(speed.value > 0.32){
stopAnimate();
}
const stopAnimate = () =>{
// 计算减缓速度 设置减缓的时间
// 设置一个延时暂停然后
// 后门计算说谁谁必中
if(mustIndex.value){
if(!startAngle.value){
mustIndex.value = ballOptions.length-mustIndex.value-2
}
startAngle.value = ((mustIndex.value)*Math.PI*2)/ballOptions.length; // 指针应该停的位置
endAngle.value = ((mustIndex.value+1)*Math.PI*2)/ballOptions.length; // 指针应该挺的位置
let startAngle1 = startAngle.value;
let endAngle1 = endAngle.value
let stopAngle = (startAngle1+endAngle1)/2; // 暂停的中间值
let baseAngle = angle.value % (2*Math.PI) // 当前的旋转的所在的位置
// console.log(stopAngle);
downSpeed.value = stopAngle<baseAngle?(2*Math.PI-baseAngle+stopAngle)/1000:(stopAngle-baseAngle)/1000;
subSpeed();
}else{
// console.log(startAngle.value);
// console.log("6");
subSpeed();
}
}
const subSpeed=()=>{
speed.value -= downSpeed.value;
if(mustIndex.value){
if(!(angle.value % (2*Math.PI)>startAngle.value
&&
angle.value % (2*Math.PI)<endAngle.value)){
speedFlag.value = requestAnimationFrame(subSpeed);
}else if(speed.value<0){
// console.log("6");
cancelAnimationFrame(animateFlag.value)
cancelAnimationFrame(speedFlag.value)
}
else{
// angle.value = startAngle.value;
cancelAnimationFrame(animateFlag.value)
cancelAnimationFrame(speedFlag.value)
}
}else{
if(speed.value<0){
cancelAnimationFrame(animateFlag.value)
cancelAnimationFrame(speedFlag.value)
// console.log("6");
}else{
speedFlag.value = requestAnimationFrame(subSpeed);
}
}
}
const startAnimate = ()=>{
isAnimal.value = true
animate();
speed.value = 0.1
}
具体代码在 github.com/chenchuchun... 感觉是想复杂也写复杂了 damn