【微信小程序】自适应Canvas 带跑马灯的辛运大转盘 内附代码和详解

第一篇关于Canvas环形进度条的博文获得不少关注度,时隔这么多日才发出第二篇关于Canvas的博文,并不是我懈怠了,而是最近公司比较忙,写好的demo一直没机会发,今天公司终于闲下来了,把我做好的demo整理一下发上来,给喜欢canvas的初学者看看,因为本人也是初学者,所以一下内容仅供参考,有不理解的地方或者有更好的想法,都可以与我联系,互相探讨一下。

决定写这个幸运大转盘是因为网上的素材很有限,可能是因为太简单,大佬们都没有发的很详细,跑马灯的介绍也是一星半点,现在我把我的思路和代码给大家展示一下,希望能帮到大家。

按照惯例,先看效果图。

下面是代码:

wxml:

<view class='content'>
  <canvas canvas-id='bgCanvas' id='canvas-bg' class='canvasII'></canvas>
  <view class='canvasI' style="{{isRotate?'transform:rotate('+isRotate+'deg)':''}};">
  <canvas canvas-id='canvasI' id="canvas-one" class='canvasI' ></canvas>
  </view>
  <cover-image class='start' src="/images/start.png" catchtap='start' />
</view>

wxss:

.content{
  width: 90%;
  height: 600rpx;
  background-color: #666;
  margin: 0 auto;
  margin-top: 100rpx;
  position: relative;
  /* display: flex;
  align-items: center;
  justify-content: center; */
}
.canvasI{
  width: 500rpx;
  height: 500rpx;
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  margin: auto auto;
  transition:all 3s ease;
}
.canvasII{
  width: 600rpx;
  height: 600rpx;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto auto;
}
.start{
  position: absolute;
  width: 100rpx;
  height: 100rpx;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto auto;
}

js:

const ctx = wx.createCanvasContext("canvasI"); //创建id为canvasI的绘图
const ctx2 = wx.createCanvasContext("bgCanvas");//创建id为bgCanvas的背景绘图
var mytime;//跑马灯定时器名称
var lamp = 0; //判断跑马灯闪烁标记
var w2 = "";
var h2 = "";
var w1 = "";
var h1 = "";
Page({

  /**
   * 页面的初始数据
   */
  data: {
    itemsNum: 6, //大转盘等分数
    itemsArc: 0, //大转盘每等分角度
    color: ["#FFB932", "#ffd57c"],//扇形的背景颜色交替;
    text: ["一等奖", "二等奖", "三等奖", "四等奖", "五等奖", "六等奖"],//每个扇形中的文字填充
    isRotate: 0,
  },
  start() { //点击抽奖按钮, 为了达到慢速开始慢速结束的效果,在这里使用css3的过渡效果
    console.log("start");
    // 五等奖:0
    // 六等奖:300
    // 一等奖:240
    // 二等奖:180
    // 三等奖:120
    // 四等奖:60
    let that = this;

    // 指定获奖结果
    let n = that.data.isRotate; //传入指定的旋转角度,内部指定获奖结果。在指定角度上加上旋转基数模拟转盘随机旋转。

    //随机获奖结果
    let rand = Math.random() * 1000;//取一个随机的旋转角度,使获奖结果随机化。
    n = n + rand - (rand % 60) + 1440; //1440为旋转基数,最低要旋转1440度,即4圈。rand-(rand%60) 这个是让指针永远停在扇形中心的算法。n + 是为了重复点击的时候有足够的旋转角度。
    console.log(n % 360);
    that.setData({
      isRotate: n,
    })
  },
  // startt() {
  //   let that = this;
  //   let n = that.data.isRotate; //传入指定的旋转角度,内部指定获奖结果。在指定角度上加上旋转基数模拟转盘随机旋转。

  //   //随机获奖结果
  //   let rand = Math.random() * 1000;//取一个随机的旋转角度,使获奖结果随机化。
  //   n = n + rand - (rand % 60) + 1440; //1440为旋转基数,最低要旋转1440度,即4圈。rand-(rand%60) 这个是让指针永远停在扇形中心的算法。n + 是为了重复点击的时候有足够的旋转角度。
  //   ctx.save();
  //   ctx.beginPath();
  //   ctx.rotate(w1, h1);
  //   ctx.rotate(n * Math.PI / 180);
  //   ctx.draw(true);
  // },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (e) {
    let that = this;
    let itemsArc = 360 / that.data.itemsNum;//获取大转盘每等分的角度。
    that.setData({
      itemsArc
    }, function () {
      wx.createSelectorQuery().select('#canvas-one').boundingClientRect(function (rect) {
        w1 = parseInt(rect.width / 2);
        h1 = parseInt(rect.height / 2);
        console.log("w1,h1", w1, h1)
        that.Items(itemsArc);//每一份扇形的内部绘制。
      }).exec()
      mytime = setInterval(that.light, 1000);//启动跑马灯定时器。
    })

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    var that = this;
    wx.createSelectorQuery().select('#canvas-bg').boundingClientRect(function (rect) {//监听canvas的宽高
      w2 = parseInt(rect.width / 2);//获取canvas宽度的一半;
      h2 = parseInt(rect.height / 2);//获取canvas高度的一半
      console.log(w2, h2); //获取canvas宽高一半的原因是为了便于找到中心点
      that.light();
    }).exec()
  },
  light() { //跑马灯的绘制
    let that = this;
    let itemsNum = that.data.itemsNum;
    lamp++;
    if (lamp >= 2) {
      lamp = 0
    }
    ctx2.beginPath();
    ctx2.arc(w2, h2, w2, 0, 2 * Math.PI);//绘制底色为红色的圆形
    ctx2.setFillStyle("#DF1E14");
    ctx2.fill();
    ctx2.beginPath();
    ctx2.arc(w2, h2, w2 - 15, 0, 2 * Math.PI);//绘制底色为深黄的圆形
    ctx2.setFillStyle("#F5AD26");
    ctx2.fill();
    for (let i = 0; i < itemsNum * 2; i++) {//跑马灯小圆圈比大圆盘等分数量多一倍。
      ctx2.save();
      ctx2.beginPath();
      ctx2.translate(w2, h2);
      ctx2.rotate(30 * i * Math.PI / 180);
      ctx2.arc(0, w2 - 15, 8, 0, 2 * Math.PI);//绘制坐标为(0,-135)的圆形跑马灯小圆圈。

      //跑马灯第一次闪烁时与第二次闪烁时绘制相反的颜色,再配上定时器循环闪烁就可以达到跑马灯一闪一闪的效果了。

      if (lamp == 0) { //第一次闪烁时偶数奇数的跑马灯各绘制一种颜色
        if (i % 2 == 0) {
          ctx2.setFillStyle("#FBF1A9");
        } else {
          ctx2.setFillStyle("#fbb936");
        }
      } else { //第二次闪烁时偶数奇数的跑马灯颜色对调。
        if (i % 2 == 0) {
          ctx2.setFillStyle("#fbb936");
        } else {
          ctx2.setFillStyle("#FBF1A9");
        }
      }
      ctx2.fill();
      ctx2.restore();//恢复之前保存的上下文,可以将循环出来的跑马灯都保存下来。没有这一句那么每循环出一个跑马灯则上一个跑马灯绘图将被覆盖,
    }
    ctx2.draw();

  },

  Items(e) {
    console.log("items,w1,h1", w1, h1)
    let that = this;
    let itemsArc = e;//每一份扇形的角度
    let Num = that.data.itemsNum;//等分数量
    let text = that.data.text;//放文字的数组
    for (let i = 0; i < Num; i++) {
      ctx.beginPath();
      ctx.moveTo(w1, h1);
      ctx.arc(w1, h1, w1 - 5, itemsArc * i * Math.PI / 180, (itemsArc + itemsArc * i) * Math.PI / 180);//绘制扇形,注意下一个扇形比上一个扇形多一个itemsArc的角度。
      ctx.closePath();
      if (i % 2 == 0) {//绘制偶数扇形和奇数扇形的颜色不同
        ctx.setFillStyle(that.data.color[0]);
      } else {
        ctx.setFillStyle(that.data.color[1]);
      }
      ctx.fill();
      ctx.save();
      ctx.beginPath();
      ctx.setFontSize(12);//设置文字字号大小
      ctx.setFillStyle("#000");//设置文字颜色
      ctx.setTextAlign("center");//使文字垂直居中显示
      ctx.setTextBaseline("middle");//使文字水平居中显示
      ctx.translate(w1, h1);//将原点移至圆形圆心位置
      ctx.rotate((itemsArc * (i + 2)) * Math.PI / 180);//旋转文字,从 i+2 开始,因为扇形是从数学意义上的第四象限第一个开始的,文字目前的位置是在圆心正上方,所以起始位置要将其旋转2个扇形的角度让其与第一个扇形的位置一致。
      ctx.fillText(text[i], 0, -(h1 * 0.8));
      ctx.restore();//保存绘图上下文,使上一个绘制的扇形保存住。
    }
    that.Images();
    ctx.draw(true);//参数为true的时候,保存当前画布的内容,继续绘制
  },

  Images() {//绘制奖品图片,与绘制文字方法一致。
    let that = this;
    let itemsArc = that.data.itemsArc;
    let Num = that.data.itemsNum;
    for (let i = 0; i < Num; i++) {
      ctx.save();
      ctx.beginPath();
      ctx.translate(w1, h1);
      ctx.rotate(itemsArc * (i + 2) * Math.PI / 180);
      ctx.drawImage("/images/quan.jpg", -(w1 * 0.2), -(h1 * 0.6), (w1 * 0.4), (h1 * 0.2));
      ctx.restore();
    }
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  }
})

详细的解释我都我都写在js里边了,有不理解的地方可以给我留言哦,下边放上图片资源:

今天的博文就到这里了,希望能帮到各位,也希望能给我点个赞鼓励鼓励我~  不然的话,我就要让我大哥胖虎锤死在座各位的,包括躺着的和站着的!!

 

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 46
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 46
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值