1. 程式人生 > >【微信小程式】自適應Canvas 帶跑馬燈的辛運大轉盤 內附程式碼和詳解

【微信小程式】自適應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裡邊了,有不理解的地方可以給我留言哦,下邊放上圖片資源:

今天的博文就到這裡了,希望能幫到各位,也希望能給我點個贊鼓勵鼓勵我~  不然的話,我就要讓我大哥胖虎錘死在座各位的,包括躺著的和站著的!!