07_微信小程序之大轉盤自定義組件編寫
一.界面佈局
經過傳入的size控制圓盤大小css
<!--components/turntable/index.wxml--> <view class="turntable" style="width:{ { size}}rpx; height:{ { size}}rpx;"> <image class="outer" src="../../images/outer.png"></image> <canvas class="canvas" type="2d" id="canvas"></canvas> <image class="start" src="../../images/start.png"></image> </view>
/* components/turntable/index.wxss */ .turntable { position: relative; margin-left: 50%; transform: translateX(-50%); } .outer { width: 100%; height: 100%; } .canvas { position: absolute; left: 40rpx; top: 40rpx; width: calc(100% - 80rpx); height: calc(100% - 80rpx); } .start { position: absolute; width: 112rpx; height: 124rpx; left: 50%; top: 50%; transform: translate(-50%,-50%); z-index: 99; }
// components/turntable/index.js Component({ /** * 組件的屬性列表 */ properties: { size: { type: Number, value: 600, observer: function(newVal, oldVal) { this.setData({ size: newVal }) } } }, /** * 組件的初始數據 */ data: { }, /** * 組件的方法列表 */ methods: { } })
二.根據獎品個數繪製扇形組成圓盤
// components/turntable/index.js Component({ /** * 組件的屬性列表 */ properties: { size: { type: Number, value: 600, observer: function(newVal, oldVal) { this.setData({ size: newVal }) } }, prizeList: { type: Array, value: [], observer: function(newVal, oldVal) { this.setData({ prizeList: newVal }) this.initTurntable() } } }, /** * 組件的初始數據 */ data: { }, /** * 組件的方法列表 */ methods: { initTurntable: function() { var that = this const query = that.createSelectorQuery() query.select('#canvas') .fields({ node: true, size: true }) .exec((res) => { console.log(res) const canvas = res[0].node const ctx = canvas.getContext('2d') const dpr = wx.getSystemInfoSync().pixelRatio canvas.width = res[0].width * dpr canvas.height = res[0].height * dpr ctx.scale(dpr, dpr) //圓心座標 var centerX = (res[0].width/2) var centerY = (res[0].height/2) //半徑 var radius = (res[0].width/2) //獎品數量 var num = that.data.prizeList.length // 扇形旋轉轉角度 var rotateDeg = 360 / num / 2 + 90 //繪製扇形 for(var i = 0; i < num; i++) { // 保存當前狀態 ctx.save(); // 開始一條新路徑 ctx.beginPath(); // 位移到圓心,下面須要圍繞圓心旋轉 ctx.translate(centerX, centerY); // 從(0, 0)座標開始定義一條新的子路徑 ctx.moveTo(0, 0); // 旋轉弧度,需將角度轉換爲弧度,使用 degrees * Math.PI/180 公式進行計算。 ctx.rotate((360 / num * i - rotateDeg) * Math.PI / 180); // 繪製圓弧 ctx.arc(0, 0, radius, 0, 2 * Math.PI / num, false); var k = i%3 var colors = ['#D7D7D7', '#FEF43E', '#EF7683'] var color = colors[k] ctx.fillStyle = color // 填充扇形 ctx.fill(); // 繪製邊框 ctx.lineWidth = 0.5; ctx.strokeStyle = '#e4370e'; ctx.stroke(); // 恢復前一個狀態 ctx.restore(); } }) } } })
坑坑坑,因爲canvas2d在模擬器上的兼容性不是很理想,按理說canvas以2d模式渲染時,開始按鈕應該會覆蓋在畫布上顯示,可是以下圖所示,並無:
node
那麼再用真機試試看:
android
能夠看到在ios是正常的,可是在android端卻仍是不顯示開始按鈕,這就尷尬了,並且本人親測,前面幾天在android端canvas2d的渲染一切正常,因而乎開始檢查代碼,最終仍是沒發現什麼問題🐶ios
最後發現微信小程序的sdk 2.14.0 版本顯示灰度中,正好本人手機上小程序的sdk版本是2.14.0,因而大膽猜測應該是這個緣由了,固然,這種狀況能夠等待微信的灰度完成後,在看下正常與否
canvas
這個問題其實咱們沒必要擔憂,由於咱們只須要把畫布畫出的圓盤轉換成圖片,做爲背景顯示在view標籤上,這裏的畫布只是用來繪製圓盤,並不用於顯示,因此須要將畫布移出顯示範圍小程序
三.將圓盤轉爲base64並顯示
<!--components/turntable/index.wxml--> <view class="turntable" style="width:{ { size}}rpx; height:{ { size}}rpx;"> <image class="outer" src="./images/outer.png"></image> <canvas class="canvas" type="2d" id="canvas"></canvas> <view class="secs" style="background-size: cover; background-image: url({ {secs}});"></view> <image class="start" src="./images/start.png"></image> </view>
/* components/turntable/index.wxss */ .turntable { position: relative; margin-left: 50%; transform: translateX(-50%); } .outer { width: 100%; height: 100%; } .canvas { position: fixed; left: 40rpx; top: -10000px; width: calc(100% - 80rpx); height: calc(100% - 80rpx); } .secs { position: absolute; left: 40rpx; top: 40rpx; width: calc(100% - 80rpx); height: calc(100% - 80rpx); } .start { position: absolute; width: 112rpx; height: 124rpx; left: 50%; top: 50%; transform: translate(-50%,-50%); z-index: 99; }
// components/turntable/index.js Component({ /** * 組件的屬性列表 */ properties: { size: { type: Number, value: 600, observer: function(newVal, oldVal) { this.setData({ size: newVal }) } }, prizeList: { type: Array, value: [], observer: function(newVal, oldVal) { this.setData({ prizeList: newVal }) this.initTurntable() } } }, /** * 組件的初始數據 */ data: { }, /** * 組件的方法列表 */ methods: { initTurntable: function() { var that = this const query = that.createSelectorQuery() query.select('#canvas') .fields({ node: true, size: true }) .exec((res) => { console.log(res) const canvas = res[0].node const ctx = canvas.getContext('2d') const dpr = wx.getSystemInfoSync().pixelRatio canvas.width = res[0].width * dpr canvas.height = res[0].height * dpr ctx.scale(dpr, dpr) //圓心座標 var centerX = (res[0].width/2) var centerY = (res[0].height/2) //半徑 var radius = (res[0].width/2) //獎品數量 var num = that.data.prizeList.length // 扇形旋轉轉角度 var rotateDeg = 360 / num / 2 + 90 //繪製扇形 for(var i = 0; i < num; i++) { // 保存當前狀態 ctx.save(); // 開始一條新路徑 ctx.beginPath(); // 位移到圓心,下面須要圍繞圓心旋轉 ctx.translate(centerX, centerY); // 從(0, 0)座標開始定義一條新的子路徑 ctx.moveTo(0, 0); // 旋轉弧度,需將角度轉換爲弧度,使用 degrees * Math.PI/180 公式進行計算。 ctx.rotate((360 / num * i - rotateDeg) * Math.PI / 180); // 繪製圓弧 ctx.arc(0, 0, radius, 0, 2 * Math.PI / num, false); var k = i%3 var colors = ['#D7D7D7', '#FEF43E', '#EF7683'] var color = colors[k] ctx.fillStyle = color // 填充扇形 ctx.fill(); // 繪製邊框 ctx.lineWidth = 0.5; ctx.strokeStyle = '#e4370e'; ctx.stroke(); // 恢復前一個狀態 ctx.restore(); } //轉換畫布內容爲base64圖片 var dataURL=canvas.toDataURL('image/png', 1); that.setData({ secs: dataURL }) }) } } })
到此,大轉盤的樣子算是出來了,接下來咱們讓它轉起來吧微信小程序
四.控制轉盤旋轉
<!--components/turntable/index.wxml--> <view class="turntable" style="width:{ { size}}rpx; height:{ { size}}rpx;"> <image class="outer" src="./images/outer.png"></image> <canvas class="canvas" type="2d" id="canvas"></canvas> <view class="secs" style="background-size: cover; background-image: url({ {secs}}); transform: { { transform}}" bindtransitionend="transitionEnd"></view> <image class="start" src="./images/start.png" bindtap="start"></image> </view>
// components/turntable/index.js Component({ /** * 組件的屬性列表 */ properties: { size: { type: Number, value: 600, observer: function(newVal, oldVal) { this.setData({ size: newVal }) } }, prizeList: { type: Array, value: [], observer: function(newVal, oldVal) { this.setData({ prizeList: newVal }) this.initTurntable() } } }, /** * 組件的初始數據 */ data: { transform: "" }, /** * 組件的方法列表 */ methods: { initTurntable: function() { var that = this const query = that.createSelectorQuery() query.select('#canvas') .fields({ node: true, size: true }) .exec((res) => { console.log(res) const canvas = res[0].node const ctx = canvas.getContext('2d') const dpr = wx.getSystemInfoSync().pixelRatio canvas.width = res[0].width * dpr canvas.height = res[0].height * dpr ctx.scale(dpr, dpr) //圓心座標 var centerX = (res[0].width/2) var centerY = (res[0].height/2) //半徑 var radius = (res[0].width/2) //獎品數量 var num = that.data.prizeList.length // 扇形旋轉轉角度 var rotateDeg = 360 / num / 2 + 90 //繪製扇形 for(var i = 0; i < num; i++) { // 保存當前狀態 ctx.save(); // 開始一條新路徑 ctx.beginPath(); // 位移到圓心,下面須要圍繞圓心旋轉 ctx.translate(centerX, centerY); // 從(0, 0)座標開始定義一條新的子路徑 ctx.moveTo(0, 0); // 旋轉弧度,需將角度轉換爲弧度,使用 degrees * Math.PI/180 公式進行計算。 ctx.rotate((360 / num * i - rotateDeg) * Math.PI / 180); // 繪製圓弧 ctx.arc(0, 0, radius, 0, 2 * Math.PI / num, false); var k = i%3 var colors = ['#D7D7D7', '#FEF43E', '#EF7683'] var color = colors[k] ctx.fillStyle = color // 填充扇形 ctx.fill(); // 繪製邊框 ctx.lineWidth = 0.5; ctx.strokeStyle = '#e4370e'; ctx.stroke(); // 恢復前一個狀態 ctx.restore(); } //轉換畫布內容爲base64圖片 var dataURL=canvas.toDataURL('image/png', 1); that.setData({ secs: dataURL }) }) }, start: function(event) { this.goto(0) }, goto: function(index) { var isTurning = this.data.isTurning if(isTurning) { return } this.setData({ transform: "rotate(" + 0 + "deg); transition: transform 5s ease-in-out" }) this.setData({ isTurning: true }) this.setData({ runRotate:0 }) var prizeNum = this.data.prizeList.length var rotate = 360/prizeNum * (prizeNum-index) var sRotate = 360*10+rotate this.setData({ transform: "rotate(" + sRotate + "deg); transition: transform 5s ease-in-out" }) }, transitionEnd: function(event) { //這裏轉盤中止直接就重置轉盤了,實際應該是先彈窗提示用戶中獎與否,在用戶關閉彈窗時,再重置轉盤 var that = this setTimeout(function() { that.setData({ transform: "", isTurning: false }) }, 3000) } } })
錄屏效果不是很好😂微信
五.擺放獎品
<!--components/turntable/index.wxml--> <view class="turntable" style="width:{ { size}}rpx; height:{ { size}}rpx;"> <image class="outer" src="./images/outer.png"></image> <canvas class="canvas" type="2d" id="canvas"></canvas> <view class="secs" style="background-size: cover; background-image: url({ {secs}}); transform: { { transform}}" bindtransitionend="transitionEnd"> <view class="sec" wx:for="{ {prizeList}}" style="transform:rotate({ { index*360/prizeList.length}}deg);transform-origin: { { centerX}}px { { centerY}}px;"> <view class="prize-name">大禮包</view> <image class="prize-image" src="./images/gift.png"></image> </view> </view> <image class="start" src="./images/start.png" bindtap="start"></image> </view>
/* components/turntable/index.wxss */ .turntable { position: relative; margin-left: 50%; transform: translateX(-50%); } .outer { width: 100%; height: 100%; } .canvas { position: fixed; left: 40rpx; top: -10000px; width: calc(100% - 80rpx); height: calc(100% - 80rpx); } .secs { position: absolute; left: 40rpx; top: 40rpx; width: calc(100% - 80rpx); height: calc(100% - 80rpx); } .start { position: absolute; width: 112rpx; height: 124rpx; left: 50%; top: 50%; transform: translate(-50%,-50%); z-index: 99; } .sec { position: absolute; width: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; padding-top: 10%; } .prize-name { font-size: 28rpx; color: 666; } .prize-image { width: 50rpx; height: 50rpx; margin-top: 8rpx; }
完xss