canvas画抽奖转盘

HTML部分
<div class="round">
      <div class="wheel_bg">
        <div class="bg">
          <img v-show="bg" class="bg1" src="@/assets/image/bg1.png" alt />
          <img v-show="!bg" class="bg2" src="@/assets/image/bg2.png" alt />
        </div>
        <canvas
          id="wheelCanvas"
          width="400px"
          height="400px"
          class="lottery_bg"
          :style="`transform: rotate(${wheelDeg}deg)`"
        ></canvas>
        <img @click="lottery" class="center" src="@/assets/image/center.png" alt />
      </div>
    </div>
JS部分
getLottery() {
      this.list = [];

      let tag = JSON.parse(localStorage.getItem("country_i") || 1);
      draw_get_list(res => {
        console.log(res);
        if (res.code == 0) {
          this.num_rule.rule =
            tag == 1 ? res.data.list.data.en_rule : res.data.list.data.sa_rule;
          if (res.data.list.list) {
            res.data.list.list.forEach(ite => {
              let list = {
                id: ite.id,
                name: "",
                ratio: ite.ratio,
                img: {
                  resource_url: ite.image,
                  horizontal_resolution: 300, //水平分辨率
                  vertical_resolution: 300 //垂直分辨率
                },
                lucky_image: ite.lucky_image
              };
              this.list.push(list);
            });
          }
          // 循环一下,将图片渲染到页面上
          this.list.forEach(function(item) {
            if (item.img) {
              var img = new Image();
              img.src = item.img.resource_url;
              // console.log(img);
              item.imgEl = img;
            }
          });
        } else {
          Toast({ message: res.msg, time: 2000, i: 1 });
        }
        console.log(this.list);
        // 请求会数据后,就可以开始将奖品之类的,画到转盘上了
        this.draw();
      });
    },
    checkImgComplete() {
      let complete = true;
      this.list.forEach(function(item) {
        if (item.imgEl && !item.imgEl.complete) {
          complete = false;
        }
      });
      return complete;
    },
    draw() {
      const _this = this;
      // 先判断,图片是否加载完成
      if (!_this.checkImgComplete()) {
        setTimeout(function() {
          _this.draw();
        }, 50);
        return;
      }
      //获取canvas画布
      // this.list 是通过后台获取回来的奖品列表
      let len = this.list.length;
      let canvas = document.getElementById("wheelCanvas");
      let ctx = canvas.getContext("2d");
      let canvasW = canvas.width; // 画板的高度
      let canvasH = canvas.height; // 画板的宽度
      //计算每个奖项所占角度数
      let baseAngle = (Math.PI * 2) / len;
      // ctx.clearRect(0, 0, canvasW, canvasH); //去掉背景默认的黑色
      ctx.strokeStyle = "#FEA801"; //设置画图线的颜色
      console.log(ctx);
      // 开始循环绘制每个奖品
      for (let i = 0; i < len; i++) {
        // 每个扇形的起始角度
        let angle = i * baseAngle;
        ctx.font = "16px Microsoft YaHei"; //设置字号字体
        let bgc = i % 2 === 0 ? "#FEA801" : "#FBDF74"; //设置每个扇形区域的颜色
        let bgc1 = i % 2 === 0 ? "#FBDF74" : "#FEA801";
        console.log(canvasW, canvasH);
        let grd = ctx.createRadialGradient(
          canvasW * 0.5,
          canvasW * 0.5,
          100,
          canvasW * 0.5,
          canvasW * 0.5,
          200
        );
        grd.addColorStop(0.83, bgc);
        grd.addColorStop(0.84, bgc1);
        grd.addColorStop(0.97, bgc1);
        grd.addColorStop(1, "#F2BB41");
        ctx.fillStyle = grd;
        ctx.beginPath(); //开始绘制
        ctx.arc(
          canvasW * 0.5,
          canvasH * 0.5,
          200,
          angle,
          angle + baseAngle,
          false
        );
        // 中心点的小圆,这样会形成一个环形图案
        ctx.arc(
          canvasW * 0.5,
          canvasH * 0.5,
          10,
          angle + baseAngle,
          angle,
          true
        );
        ctx.stroke(); //开始链线
        ctx.fill(); //填充颜色
        ctx.save(); //保存当前环境的状态
        ctx.fillStyle = "#017ec2"; // 设置文字颜色
        let item = this.list[i];
        // 计算文字的偏移量
        let translateX = canvasW * 0.5 + Math.cos(angle + baseAngle / 2) * 260;
        let translateY = canvasH * 0.5 + Math.sin(angle + baseAngle / 2) * 260;
        // 如果奖品无图,则文字相应改大,并且偏移变小
        if (!item.img) {
          ctx.font = "20px Microsoft YaHei"; //设置字号字体
          translateX = canvasW * 0.5 + Math.cos(angle + baseAngle / 2) * 220;
          translateY = canvasH * 0.5 + Math.sin(angle + baseAngle / 2) * 220;
        }
        ctx.translate(translateX, translateY);
        // rotate方法旋转当前的绘图,因为文字适合当前扇形中心线垂直的!
        // angle,当前扇形自身旋转的角度 +  baseAngle / 2 中心线多旋转的角度  + 垂直的角度90°
        ctx.rotate(angle + baseAngle / 2 + Math.PI / 2);
        //设置文本位置,居中显示
        ctx.fillText(item.name, -ctx.measureText(item.name).width / 2, 100);
        //添加对应缩略图
        let triangleEdge = canvasH * 0.25;
        // 根据角度不同,计算图片最大宽度
        let imgMaxWidth = Math.sqrt(
          2 * triangleEdge * triangleEdge * (1 - Math.cos(baseAngle))
        );
        if (item.imgEl) {
          ctx.drawImage(
            item.imgEl,
            -imgMaxWidth * 0.5,
            canvasH * 0.23,
            imgMaxWidth,
            (item.img.vertical_resolution * imgMaxWidth) /
              item.img.horizontal_resolution
          );
        }
        ctx.restore(); //很关键,还原画板的状态到上一个save()状态之前
      }
    },
    lottery() {
      if (this.showResult) {
        this.showResult = false;
        this.$router.go(-1);
        return;
      }
      if (this.rolling) {
        return;
      }
      if (!this.$store.state.status.token)
        this.$router.push({ path: "/account/login" });
      let data = this.$store.state.status.token
        ? this.$store.state.status.token
        : "";
      lucky_draw({ token: data }, res => {
        console.log(res);
        if (res.code == 0) {
          this.lucky_d(res.data.id);
        } 
      });
    },
    lucky_d(id) {
      if (this.num_rule.num > 0) {
        this.num_rule.num--;
      }
      this.rolling = true;
      // 这里应该从后台获取中奖结果,我们随便模拟一下中奖结果
      let winIndex = 0;
      this.list.some((item, i) => {
        if (item.id == id) {
          this.result = item;
          winIndex = i;
          return true;
        }
      });
      console.log(winIndex, this.result);
      let prize_angle = 360 - (360 / this.list.length) * winIndex; //转动到每个奖项的偏移的角度
      let area_angle = 180 - 360 / this.list.length; //初始指针角度
      console.log(prize_angle, area_angle, this.wheelDeg, this.wheelDeg % 360);
      // 计算中奖的旋转角度
      this.wheelDeg =
        this.wheelDeg - (this.wheelDeg % 360) + 3600 + prize_angle - area_angle;
      console.log(this.wheelDeg);
      // 关闭中奖结果
      setTimeout(() => {
        this.showResult = true;
        this.rolling = false;
        window.history.pushState(null, null, "#");
      }, 5500);
    },
CSS部分
.round {
  width: 100vw;
  position: relative;
  .wheel_bg {
    margin: 0 0.35rem;
    position: absolute;
    top: 0rem;
    left: 0%;
    width: calc(100vw - 0.7rem);
    height: calc(100vw - 0.7rem);
    background-color: #fbdf74;
    border-radius: 50%;
    overflow: hidden;
    transition: transform 8s ease-in-out;
    z-index: 1;
    border: 2px solid #ffeea5;
    box-sizing: border-box;
  }
  .lottery_bg {
    position: absolute;
    top: 0.4rem;
    left: 0.4rem;
    width: calc(100% - 0.8rem);
    height: calc(100% - 0.8rem);
    background-color: #fea801;
    border-radius: 50%;
    overflow: hidden;
    transition: transform 5s ease-in-out;
    z-index: 2;
  }
  .center {
    position: absolute;
    top: 51%;
    left: 50%;
    width: 1.4rem;
    transform: translate(-50%, -50%);
    margin-top: -0.2rem;
    z-index: 4;
  }
  .bg {
    position: absolute;
    top: 0rem;
    left: 0rem;
    width: 100%;
    height: 100%;
    z-index: 3;
    .bg1,
    .bg2 {
      width: 100%;
      height: 100%;
    }
  }
}

posted on 2020-04-28 15:22  |小乌龟|  阅读(398)  评论(0)    收藏  举报

导航