美文网首页
react实现抽奖大转盘

react实现抽奖大转盘

作者: 李大公子 | 来源:发表于2019-06-24 10:13 被阅读0次

先看一下实现的效果(这样才有动力)


01.gif

1、html代码

   <canvas className="item" id="wheelcanvas" height={422} width={422}/>

2、绘制圆盘

    let canvas = document.getElementById("wheelcanvas");
    // 获取canvas的上下文,context含有各种api用来操作canvas
    let context = canvas.getContext('2d');
    this.setState({canvas: canvas, context: context});
    context.save();
    // 新建一个路径,画笔的位置回到默认的坐标(0,0)的位置
    // 保证了当前的绘制不会影响到之前的绘制
    context.beginPath();
    // 设置填充转盘用的颜色,fill是填充而不是绘制
    context.fillStyle = '#fff';
    // 绘制一个圆,有六个参数,分别表示:圆心的x坐标,圆心的y坐标,圆的半径,开始绘制的角度,结束的角度,绘制方向(false表示顺时针)
    context.arc(211, 211, 211, startRadian, Math.PI * 2 + startRadian, false);
    // 将设置的颜色填充到圆中,这里不用closePath是因为closePath对fill无效.
    context.fill();
    // 将画布的状态恢复到上一次save()时的状态
    context.restore();
02.jpg

2、绘制奖品
canvas绘制都是从水平出开始绘制,所以这里我调整了初始弧度

    let awards = [
        {id: 1, name: '一等奖', level: '1', color:"#FFC200"},
       {id: 2, name: '二等奖', level: '2', color:"#FFE122"},
       {id: 3, name: '三等奖', level: '3', color:"#FFC200"},
        {id: 4, name: '四等奖', level: '4', color:"#FFE122"},
        {id: 5, name: '五等奖', level: '5', color:"#FFC200"},
        {id: 6, name: '六等奖', level: '6', color:"#FFE122"},
    ],//大转盘要绘制的奖品
    let startRadian = -90 * Math.PI / 180,//大转盘的开始弧度(canvas绘制圆从水平方向开始,所以这里调整为垂直方向) 弧度计算公式:角度*Math.PI/180
    // 第一个奖品色块开始绘制时开始的弧度及结束的弧度
    let RadianGap = Math.PI * 2 / awards.length, endRadian = startRadian + RadianGap;
    for (let i = 0; i < awards.length; i++) {
      context.save();
      context.beginPath();
      // 为了区分不同的色块,使用随机生成的颜色作为色块的填充色
      context.fillStyle = awards[i].color;
      // 这里需要使用moveTo方法将初始位置定位在圆点处,这样绘制的圆弧都会以圆点作为闭合点
      context.moveTo(211, 211);
      // 画圆弧时,每次都会自动调用moveTo,将画笔移动到圆弧的起点,半径设置的比转盘稍小一点
      context.arc(211, 211, 201, startRadian, endRadian, false);
      context.fill();
      context.restore();
      // 开始绘制文字
      context.save();
      //设置文字颜色
      context.fillStyle = '#f00';
      //设置文字样式
      context.font = "18px Arial";
      // 改变canvas原点的位置,简单来说,translate到哪个坐标点,那么那个坐标点就将变为坐标(0, 0)
      context.translate(
        211 + Math.cos(startRadian + RadianGap / 2) * 201,
        211 + Math.sin(startRadian + RadianGap / 2) * 201
      );
      // 旋转角度,这个旋转是相对于原点进行旋转的.
      context.rotate(startRadian + RadianGap / 2 + Math.PI / 2);
      // 这里就是根据获取的各行的文字进行绘制,maxLineWidth取70,相当与一行最多展示5个文字
      this.getLineTextList(context, awards[i].name, 70).forEach((line, index) => {
        // 绘制文字的方法,三个参数分别带:要绘制的文字,开始绘制的x坐标,开始绘制的y坐标
        context.fillText(line, -context.measureText(line).width / 2, ++index * 25)
      });
      context.restore();
      // 每个奖品色块绘制完后,下个奖品的弧度会递增
      startRadian += RadianGap;
      endRadian += RadianGap;
    }
//绘制文字,文字过长进行换行,防止文字溢出
  getLineTextList(context, text, maxLineWidth) {
    let wordList = text.split(''), tempLine = '', lineList = [];
    for (let i = 0; i < wordList.length; i++) {
      if (context.measureText(tempLine).width >= maxLineWidth) {
        lineList.push(tempLine);
        maxLineWidth -= context.measureText(text[0]).width;
        tempLine = ''
      }
      tempLine += wordList[i]
    }
    lineList.push(tempLine);
    return lineList
  }
03.jpg

3、绘制中间的小圆

    //下面是画中间的小圆
    context.save();
    // 新建一个路径,画笔的位置回到默认的坐标(0,0)的位置
    // 保证了当前的绘制不会影响到之前的绘制
    context.beginPath();
    // 设置填充转盘用的颜色,fill是填充而不是绘制
    context.fillStyle = '#fff';
    // 绘制一个圆,有六个参数,分别表示:圆心的x坐标,圆心的y坐标,圆的半径,开始绘制的角度,结束的角度,绘制方向(false表示顺时针)
    context.arc(211, 211, 70, startRadian, Math.PI * 2 + startRadian, false);
    // 将设置的颜色填充到圆中,这里不用closePath是因为closePath对fill无效.
    context.fill();
    // 将画布的状态恢复到上一次save()时的状态
    context.restore();
04.jpg

4、添加中间的按钮和转盘边框

//html
<img className="wheel-circle" src="https://wp.touty.io/api/file/5d0c51ff2ab79c000897ecac.image"/>
          <canvas className="item" id="wheelcanvas" height={422} width={422}/>
          <img onClick={this.draw.bind(this)} className="pointer" src="https://wp.touty.io/api/file/5d0c51c02ab79c000897ecaa.image"/>

这样一个静态的大转盘就完成了,下面是让转盘转动起来


05.jpg

5、点击抽奖让转盘转起来

  //点击抽奖让转盘转起来
  draw(e) {
    const {canvas, context} = this.state;
    // 只要抽奖没有结束,就不让再次抽奖
    if (!this.state.canBeClick) return;
    this.state.canBeClick = false;
    // 每次点击抽奖,都将初始化角度重置
    this.state.startRadian = 0;
    const distance = this.distanceToStop();
    this.rotatePanel(distance);//调用处理旋转的方法
  }

得出最后停留的地方

distanceToStop() {
    // middleDegrees为奖品块的中间角度(最终停留都是以中间角度进行计算的)距离初始的startRadian的距离,distance就是当前奖品跑到指针位置要转动的距离。
    let middleDegrees = 0, distance = 0;
    // 映射出每个奖品的middleDegrees
    let awardsToDegreesList = this.state.awards.map((data, index) => {
      let awardRadian = (Math.PI * 2) / this.state.awards.length;
      return awardRadian * index + (awardRadian * (index + 1) - awardRadian * index) / 2
    });
    // 随机生成一个索引值,来表示此次抽奖应该中的奖品
    const currentPrizeIndex = Math.floor(Math.random() * this.state.awards.length);
    console.log('当前奖品应该中的奖品是:' + this.state.awards[currentPrizeIndex].name);
    middleDegrees = awardsToDegreesList[currentPrizeIndex];
    // 因为指针是垂直向上的,相当坐标系的Math.PI/2,所以这里要进行判断来移动角度
    distance = Math.PI * 3 / 2 - middleDegrees;
    distance = distance > 0 ? distance : Math.PI * 2 + distance;
    // 这里额外加上后面的值,是为了让转盘多转动几圈,看上去更像是在抽奖
    return distance + Math.PI * 10;
  }

让转盘转动

// 处理旋转的关键方法
  rotatePanel(distance) {
    // 这里用一个很简单的缓动函数来计算每次绘制需要改变的角度,这样可以达到一个转盘从块到慢的渐变的过程
    let changeRadian = (distance - this.state.startRadian) / 20;
    this.state.startRadian += changeRadian;
    // 当最后的目标距离与startRadian之间的差距低于0.0001时,就默认奖品抽完了,可以继续抽下一个了。
    if (distance - this.state.startRadian <= 0.001) {
      this.state.canBeClick = true;
      return
    } ;
    // 初始角度改变后,需要重新绘制
    this.onLoadPage(this.state.awards);
    // 循环调用rotatePanel函数,使得转盘的绘制连续,造成旋转的视觉效果
    window.requestAnimationFrame(this.rotatePanel.bind(this, distance));
  }

这样我们就得到了最终的效果图

01.gif
完整代码查看:codePen

相关文章

  • react实现抽奖大转盘

    先看一下实现的效果(这样才有动力) 1、html代码 2、绘制圆盘 2、绘制奖品canvas绘制都是从水平出开始绘...

  • php实现刮刮卡大转盘抽奖概率

    php实现刮刮卡大转盘抽奖概率 本文实例为大家分享了php中奖概率算法,可用于刮刮卡,大转盘等抽奖算法,用法很简单...

  • 小程序实现大转盘,九宫格抽奖,带跑马灯效果

    基本实现功能 1,小程序仿天猫超市大转盘 2,九宫格转盘抽奖 3,积分抽奖 4,抽到的积分随机生成 5,抽奖结果可...

  • 小程序的大转盘活动怎么做?

    日常生活中最常见的抽奖活动莫过于大转盘抽奖了吧,无论线上线下。大转盘抽奖活动具有多样性、并可开展基于粘性维护的活动...

  • 【Java 实战】实现大转盘抽奖

    项目场景 实现一个大转盘抽奖的功能,能后台自定义奖项,各奖项中奖概率,奖品数量,当日抽奖最大次数等。 一、设计思路...

  • 微信小程序幸运大转盘制作教程

    幸运大转盘抽奖方式是我见过最常用的抽奖方式了,这种方式简单,直接,让人看着兴奋。那么,幸运大转盘微信小程序怎么制作...

  • canvas大转盘

    下面再介绍一个canvas实例,使用canvas技术实现一个大转盘,在抽奖中用的比较多,实现后的效果如果所示: 第...

  • 连中三元

    幸运大转盘,抽奖领红包,雨露来听歌,胜利哒凯旋。

  • 微信小程序大转盘抽奖

    微信小程序大转盘抽奖 说明看到过太多骗点击量的大转盘抽奖,也写一个玩玩 需求 一个转盘界面 闪动的小点 奖品背景颜...

  • vue适配3到8个大转盘抽奖

    vue实现适配奖品不固定的大转盘抽奖,里面的实现代码就是vue+js,不需要jq,原理就是根据接口传过来的奖品数量...

网友评论

      本文标题:react实现抽奖大转盘

      本文链接:https://www.haomeiwen.com/subject/wpcnqctx.html