CoreJava Linxu磁盘 USB串口通信 oracle authentication mobile tcp module vue请求 ddos压力测试 css获取最后一个元素 jquery解析json base64转16进制 java解析json数组 matlab图像滤波 pyhton中异常和模块 docker启动命令 mysql 导入数据 python环境搭建 python类和对象 java中继承 java搭建 java类的继承 java基础代码 java实现多线程 java入门课程 学java基础 java中instanceof java正则匹配数字 java获取数据类型 java学习流程 linux内核编程 microkms comsol软件下载 eml文件阅读器下载 野德天赋 批处理if 电子商城系统 碧桂园园宝 爱奇艺无法投屏
当前位置: 首页 > 学习教程  > 编程语言

vue幸运抽奖大转盘的丑绝实现

2020/7/24 10:51:50 文章标签:

自己通过canvas+vue(vue不是必备的可以)实现的一个抽奖转盘,重点在实现逻辑,所以样式丑绝。
基本效果图,中间指针可以替换为图片
基本效果图,中间指针可以替换为图片

数据格式

转盘的分块由传入的数组长度确定,分为4,6,8块还是能看的

 {
          id: 1, // 奖品标识,可按需设置
          content: "谢谢参与", // 奖品文本
          prize: "111", //奖品内容
          probability: 0.75, // 中奖概率,也可以不设,由后台决定是否中奖及中了什么奖
          img: "https://img.stringon.com/dd4cffa524bf46f790520a46fefd1726-S375",// 奖品图片,按需设置
        },
        {
          id: 2,
          content: "现金红包2元",
          prize: "222",
          probability: 0.05,
          img: "https://img.stringon.com/c0f57be115e541fd90b8df5ef163110b-S375",
        },
        {
          id: 3,
          content: "现金红包10元",
          prize: "333",
          probability: 0.02,
          img: "https://img.stringon.com/c0f57be115e541fd90b8df5ef163110b-S375",
        },
        {
          id: 4,
          content: "现金红包3元",
          prize: "444",
          probability: 0.04,
          img: "https://img.stringon.com/c0f57be115e541fd90b8df5ef163110b-S375",
        },

html部分

第一个canvas绘制大转盘
在这里插入图片描述
第二个canvas绘制中间转盘,可替换为图片(用drawImage绘制)
在这里插入图片描述

<div class="turn-box">
    <canvas id="chart" ref="turnBox" height="400" width="600">
      你的浏览器不支持HTML5 canvas
    </canvas>
    <canvas id="centerChart" ref="centerChart" height="400" width="600">
      你的浏览器不支持HTML5 canvas
    </canvas>
  </div>

css部分

css部分比较简单,主要用来定位两个canvas之间的位置

.turn-box {
  position: relative;
}
canvas {
  position: absolute;
  left: 0;
  right: 0;
  margin: auto;
  top: 0;
}
#centerChart {
  top: 50px;
}

js部分

重点的总是留在最后,下面是实现代码,注释我会尽量写的清楚一点

// data初始化
data(){
	return{
		canvas: null,
        ctx: null,
        width: 262, // 宽
        height: 262, // 高
        count: 12,//抽奖次数,也是从后台请求
        running: null,//是否正在抽奖
        turnInfo:[] //奖品信息,一般从后台请求
	}
},
computed: {
   //为了方便比较,这里是中奖区域,如果由后台返回中奖信息,那这里就是不需要的
    randList() {
      let start = 0;
      return this.turnInfo.map((item) => {
        start = item.probability + start;
        return Number(start.toFixed(2));
      });
    },
  },
mounted() {
   // 获得canvas上下文
   this.canvas = document.getElementById("chart");
   if (this.canvas && this.canvas.getContext) {
     this.ctx = this.canvas.getContext("2d");
   }
   this.drawCharts(); //绘制
    const that = this;
    // 点击抽奖
    this.canvas.onclick = async function () {
      if (that.count === 0) return; //没有抽奖次数处理逻辑
      if (that.running) return; //正在抽奖中处理逻辑
      const rand = that.getPrize();//获取中奖信息
      that.$refs.turnBox.style.transform = "unset";
      that.$refs.turnBox.style.transition = "all 0s";//先将之前旋转状态重置
      await setTimeout(() => {
        let deg = 1800 + 360 - (360 / that.turnInfo.length) * rand;//计算旋转角度,1800(360*5)为多旋转的角度
        that.$refs.turnBox.style.transform = `rotate(${deg}deg)`;
        that.$refs.turnBox.style.transition = "all 3s ease-in-out";//开始旋转
      });
      console.log(that.turnInfo[rand].content);//输出中奖信息
      that.running = setTimeout(() => {
        clearTimeout(that.running);
        that.running = null;正在抽奖状态重置
        that.count -= 1;//中奖次数减一
      }, 3000);//延迟时间为转盘旋转动画时间
    };
  },
methods:{
// 图表初始化
    initChart() {
      //   这里是对高清屏幕的处理,
      // 方法:先将canvas的width 和height设置成本来的两倍
      //     然后将style.height 和 style.width设置成本来的宽高
      //     这样相当于把两倍的东西缩放到原来的 1/2,这样在高清屏幕上 一个像素的位置就可以有两个像素的值
      //     这样需要注意的是所有的宽高间距,文字大小等都得设置成原来的两倍才可以。
      this.canvas.width = this.width * 2;
      this.canvas.height = this.height * 2;
      this.canvas.style.height = `${this.height}px`;
      this.canvas.style.width = `${this.width}px`;

      this.ctx.translate(0.5, 0.5); // 当只绘制1像素的线的时候,坐标点需要偏移,这样才能画出1像素实线
    },
    //绘制大转盘
    drawTurnBox() {
      let num = this.turnInfo.length;
      this.ctx.font = "bold 18px Microsoft YaHei";
      for (let i = 0; i < num; i++) {
        //根据奖品参数 绘制扇形填充颜色,按需设置
        // ctx.fillStyle = this.turnInfo.colors[i];
        //开始绘制扇形
        this.ctx.save();
        this.ctx.beginPath();
        this.ctx.translate(this.width, this.width);
        // // 从(0, 0)坐标开始定义一条新的子路径
        this.ctx.moveTo(0, 0);
        this.ctx.rotate(((360 / num) * (i + 1) * Math.PI) / 180);
        //arc(x,y,r,起始角,结束角,绘制方向) 方法创建弧/曲线(用于创建圆或部分圆)
        this.ctx.arc(0, 0, this.width, 0, (2 * Math.PI) / num, false);
        this.ctx.arc(0, 0, this.width / 2 - 50, (2 * Math.PI) / num, 0, true);
        if ((i + 1) % 2 == 0) {
          this.ctx.fillStyle = "#ffb820";
        } else {
          this.ctx.fillStyle = "#ffcb3f";
        }
        // this.ctx.lineWidth = 0.5;
        this.ctx.strokeStyle = "transparent";
        this.ctx.stroke();
        this.ctx.fill();
        this.ctx.restore();
      }
    },
    // 绘制文本
    drawText() {
      let num = this.turnInfo.length;
      this.ctx.font = "24px Arial";
      let arc = Math.PI / (num / 2);
      for (let i = 0; i < num; i++) {
        let angle = 0 + i * arc;
        this.ctx.save();
        //奖品默认字体颜色
        // this.ctx.fillStyle = "#fff";
        let text = this.turnInfo[i].content;
        this.ctx.translate(
          this.width + Math.cos(angle + arc / 2) * (this.width - 40),
          this.width + Math.sin(angle + arc / 2) * (this.width - 40)
        );
        this.ctx.rotate(angle + arc / 2 + Math.PI / 2);
        //由于设计的转盘色块是交错的,所以这样可以实现相邻奖品区域字体颜色不同
        // if (i % 2 == 0) {
        //   this.ctx.fillStyle = "#fff";
        // }
        //将字体绘制在对应坐标
        this.ctx.fillText(text, -this.ctx.measureText(text).width / 2, 20);
        //设置字体
        // this.ctx.font = " 14px Microsoft YaHei";
        //把当前画布返回(插入)到上一个save()状态之前
        this.ctx.restore();
        //绘制奖品图片
        if (this.turnInfo[i].img) {
          this.ctx.save();
          this.ctx.translate(
            this.width + Math.cos(angle + arc / 2) * this.width,
            this.width + Math.sin(angle + arc / 2) * this.width
          );
          this.ctx.rotate(angle + arc / 2);

          let img = new Image();
          img.src = this.turnInfo[i].img;
          this.ctx.drawImage(img, -this.width / 2 + 10, -50, 42, 94);
          this.ctx.restore();
        }
      }
    },
    // 绘制中间圆盘
    drawCenter() {
      const canvas = document.getElementById("centerChart");
      canvas.style.top = `${63}px`;// 位置自己定啦
      let ctx = null;
      if (canvas && canvas.getContext) {
        ctx = canvas.getContext("2d");
      }
      let arc = Math.PI / (this.turnInfo.length / 2);
      canvas.width = this.width;
      canvas.height = this.height;
      canvas.style.height = `${this.height / 2}px`;
      canvas.style.width = `${this.width / 2}px`;
      ctx.translate(0.5, 0.5);
      ctx.save();
      ctx.fillStyle = "#ffcb3f";
      ctx.beginPath();
      ctx.translate(this.width / 2, this.width / 2);
      ctx.rotate(arc / this.turnInfo.length + Math.PI / 180);
      //这一部分可以通过drawImage直接绘制成图片,保留中心点设置与旋转角度即可,其他的都随意
      ctx.moveTo(0, 40);
      ctx.lineTo(this.width / 2, 40); //绘制指针
      ctx.arc(0, 0, this.width / 2 - 40, 2 * Math.PI, 0, true);//绘制圆
      ctx.lineWidth = 1;
      ctx.strokeStyle = "rgba(0,0,0,0.45)";
      ctx.stroke();
      ctx.fill();
      ctx.restore();
    },
    // 开始绘制
    drawCharts() {
      this.drawCenter(); //绘制中心圆
      this.initChart(); // 图表初始化
      this.drawTurnBox(); // 绘制转盘
      this.drawText(); // 绘制文字
    },
    //获取中将信息,中奖信息由后台返回会比较安全,这里只需要返回中奖的索引就可以
    getPrize() {
      let rand = Number(Math.random().toFixed(2));//中奖随机数
      let prizeIndex = -1;//中奖索引
      let index = 0;
      while (prizeIndex === -1 && index < this.randList.length) {
        prizeIndex = this.randList[index] >= rand ? index : -1;
        index++;
      }
      return prizeIndex;
    },
}

写在最后

以上就是我实现抽奖大转盘的全部代码,写得比较急,代码粗糙(canvas中图片加载还有问题,考虑在图片加载完之后再绘制canvas),样式我自己都不忍直视,如果我记得并且有时间的话,我还会进行优化的。


本文链接: http://www.dtmao.cc/news_show_50343.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?