【微信小程式】自適應Canvas 帶跑馬燈的辛運大轉盤 內附程式碼和詳解
阿新 • • 發佈:2019-02-09
第一篇關於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裡邊了,有不理解的地方可以給我留言哦,下邊放上圖片資源:
今天的博文就到這裡了,希望能幫到各位,也希望能給我點個贊鼓勵鼓勵我~ 不然的話,我就要讓我大哥胖虎錘死在座各位的,包括躺著的和站著的!!