您好,登錄后才能下訂單哦!
這篇文章主要介紹了canvas怎么實現2d環形統計圖的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇canvas怎么實現2d環形統計圖文章都會有所收獲,下面我們一起來看看吧。
中間得環形圖以及里面的文字就是通過 canvas 2d 繪制出來的,下面看代碼。
WXML
<view class="row chart-container"> <canvas type="2d" class="chart" id="myChart2d" /> <view class="col center"> <view class="row-center" wx:for="{{chartData}}" wx:key="chartData" > <view class="circle" ></view> <view class="project-item font-size-12 flex1 row"> <view>{{item.title}}</view> <view class="flex1 margin-left-16"> {{item.numb}}</view> <view class="margin-left-16"> {{item.percent}}%</view> </view> </view> </view> </view>
這里并不需要多少代碼,但是 type 和 id 一定要,而且記得 class 指定寬高。
WXSS
.chart { width: 112px; height: 112px; } .row{ display:flex; flex-direction:row; } .col{ display:flex; flex-direction:column; } .row-center{ display:flex; flex-direction:row; align-items: center; } .flex1{ flex: 1; } .center{ margin: auto; width: fit-content; } .circle { width: 18rpx; height: 18rpx; border-radius: 9rpx; box-sizing: border-box; } .project-item { font-family: PingFangSC-Regular, PingFang SC; font-weight: 400; color: #616161; line-height: 34rpx; margin-left: 8rpx; } .margin-left-16{ margin-left: 16rpx; } .font-size-12{ font-size: 24rpx; }
這里就是上面說的指定寬高了,暫時先用 px 作為單位,其他不知道會不會有問題。
JS
Component({ properties: { show: { type: Boolean, value: false, observer: function (newVal, oldVal) { // 首次進來頁面圖標無法加載,監聽頁面切換來顯示 let isFirstComeIn = this.data.isFirstComeIn if (isFirstComeIn) { this.getCanvas() this.data.isFirstComeIn = false } } } }, lifetimes: { attached: function () { // 初始化加載數據 this.getData() }, }, data: { // 畫布相關 isFirstComeIn: true, context: null, height: 0, width: 0, // 圖表數據 chartData: [{ title: '待檢查項目', color: '#FF9000', numb: 0, percent: 0 }, { title: '進行中項目', color: '#1FD55C', numb: 0, percent: 0 }, { title: '已完成項目', color: '#0B7BFB', numb: 0, percent: 0 }, { title: '已終止項目', color: '#616161', numb: 0, percent: 0 }], } methods: { getCanvas() { // 有的手機下拉刷新會造成畫兩個不同大小的餅圖 let that = this; let query = wx.createSelectorQuery().in(this) query.select('#myChart2d') .fields({ node: true, size: true }) .exec((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) that.setData({ width: res[0].width * dpr, height: res[0].height * dpr, context: ctx }) // 首次進來畫圖 that.drawPieChart2d() }) }, // 下拉刷新 onPullDownRefresh() { this.getData() }, // 獲取數據 getData() { app.request({ url: 'you/url', data: {}, finish: function () { wx.stopPullDownRefresh(); }, success: function (res) { let count = res.undoCount + res.doingCount + res.finishCount + res.stopCount let chartData = that.data.chartData if (count != 0) { chartData[0].numb = res.undoCount chartData[0].percent = (res.undoCount * 100 / count).toFixed(2) chartData[1].numb = res.doingCount chartData[1].percent = (res.doingCount * 100 / count).toFixed(2) chartData[2].numb = res.finishCount chartData[2].percent = (res.finishCount * 100 / count).toFixed(2) chartData[3].numb = res.stopCount chartData[3].percent = (res.stopCount * 100 / count).toFixed(2) } else { chartData[0].numb = 0 chartData[0].percent = 0 chartData[1].numb = 0 chartData[1].percent = 0 chartData[2].numb = 0 chartData[2].percent = 0 chartData[3].numb = 0 chartData[3].percent = 0 } that.setData({ chartData: chartData, }) // 因為本頁作為組件隱藏了,首次進來無法獲取canvas高度,首次進來另外處理 if (!that.data.isFirstComeIn) { that.drawPieChart2d() } } }) } // 一次性使用,前面是舊 canvas,注釋的是一次性調用 canvas 2d 代碼 drawPieChart() { // 組件中使用需要增加 this const ctx = wx.createCanvasContext('myChart', this); //設置半徑 let radius = 56; let center = { x: 56, y: 56 }; // 設置數據、總數 let data = this.data.chartData let count = 0; data.forEach(element => { count += element.numb }); for (let i = 0; i < data.length; i++) { //計算占比,總長為 2PI let start = 0; for (let j = 0; j < i; j++) { start += data[j].numb / count * 2 * Math.PI } var end = start + data[i].numb / count * 2 * Math.PI ctx.beginPath() ctx.arc(center.x, center.y, radius, start, end) ctx.setLineWidth(1) ctx.lineTo(center.x, center.y) ctx.setStrokeStyle('#fff') ctx.setFillStyle(data[i].color) ctx.fill(); ctx.closePath(); ctx.stroke(); } ctx.beginPath() radius = 40; ctx.arc(center.x, center.y, radius, 0, 2 * Math.PI) ctx.setFillStyle('#fafafa') ctx.fill() ctx.closePath(); ctx.stroke(); ctx.fillStyle = "#2E2E2E"; ctx.setFontSize(20) ctx.setTextAlign('center') ctx.fillText('' + count, 56, 50); ctx.setFontSize(14) ctx.setTextAlign('center') ctx.fillText('評估項目數', 56, 70);; ctx.draw() // let query = wx.createSelectorQuery().in(this) // query.select('#myChart2d') // .fields({ // node: true, // size: true // }) // .exec((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) // //設置半徑 // let radius = 56; // let center = { // x: 56, // y: 56 // }; // // 設置數據、總數 // let data = this.data.chartData // let count = 0; // data.forEach(element => { // count += element.numb // }); // // 開始畫圖 // ctx.clearRect(0, 0, res[0].width * dpr, res[0].height * dpr) // for (let i = 0; i < data.length; i++) { // //計算占比,總長為 2PI // let start = 0; // for (let j = 0; j < i; j++) { // start += data[j].numb / count * 2 * Math.PI // } // var end = start + data[i].numb / count * 2 * Math.PI // ctx.beginPath() // ctx.arc(center.x, center.y, radius, start, end) // ctx.lineWidth = 1 // ctx.lineTo(center.x, center.y) // ctx.strokeStyle = '#fff' // ctx.fillStyle = data[i].color // ctx.closePath(); // ctx.fill(); // } // radius = 40; // ctx.beginPath() // ctx.arc(center.x, center.y, radius, 0, 2 * Math.PI) // ctx.fillStyle = '#fafafa' // ctx.closePath() // ctx.fill() // ctx.fillStyle = "#2E2E2E"; // ctx.font = "20px Arial"; // ctx.textAlign = 'center' // ctx.fillText('' + count, 56, 50) // ctx.font = "14px Arial"; // ctx.fillText('評估項目數', 56, 70) // }) }, drawPieChart2d() { let ctx = this.data.context //設置半徑 let radius = 56; let center = { x: 56, y: 56 }; // 設置數據、總數 let data = this.data.chartData let count = 0; data.forEach(element => { count += element.numb }); // 開始畫圖 ctx.beginPath() ctx.clearRect(0, 0, this.data.width, this.data.height); for (let i = 0; i < data.length; i++) { //計算占比,總長為 2PI let start = 0; for (let j = 0; j < i; j++) { start += data[j].numb / count * 2 * Math.PI } var end = start + data[i].numb / count * 2 * Math.PI ctx.beginPath() ctx.lineWidth = 1 ctx.strokeStyle = '#fff' ctx.fillStyle = data[i].color ctx.arc(center.x, center.y, radius, start, end) ctx.lineTo(center.x, center.y) ctx.closePath(); ctx.fill(); } radius = 40; ctx.beginPath() ctx.fillStyle = '#fafafa' ctx.arc(center.x, center.y, radius, 0, 2 * Math.PI) ctx.closePath() ctx.fill() ctx.fillStyle = "#2E2E2E"; ctx.font = "20px Arial"; ctx.textAlign = 'center' ctx.fillText('' + count, 56, 50) ctx.font = "14px Arial"; ctx.fillText('評估項目數', 56, 70) }, } })
這里寫的有些復雜了,但是復雜的東西能學到的也多吧,在組件中使用都掌握了,在 Page 中使用那就得心應手了,下面詳細講講。
實際上繪制圖表并不需要這么多的代碼,在Page也好,在組件頁面也好,其實只需要在需要繪制的時候調用上面 js 中 drawPieChart 代碼即可,前面是舊版本的canvas,后面注釋的是 canvas 2d的寫法,可以對比看看,還是有些去別的,特別是字體大小坑了我一把。
但是為什么要寫這么多代碼呢?還是解決一些出現的問題,下面詳細介紹。
下拉刷新會造成畫兩個不同大小的餅圖
問題很奇怪,而且只在某些機型出現。仔細研究一下發現這個問題是因為繪制圖表的時候,多次調用一次性生成圖表函數造成的,即每次獲取到的 canvas 對象可能不太一樣了,具體什么不一樣了,我就沒有仔細研究了,可能是頁面發生了變化造成的。
這里的解決辦法就是只獲取一次 canvas,后面就用它不停的繪制圖表,當繪需要制新的圖表時,清空原來內容并繪制。首先提取出一個函數獲取 canvas,這個函數要在 page 的 onReady中監聽,這里再組件中也可以在 lifetimes 的 ready 方法中監聽,都是一樣的。獲取到 canvas 對象后設置為全局變量,后面繪制的的時候取這個變量繪制就可以了。
這里我們把 getCanvas 寫在了組件頁面第一次顯示時觸發,原因看下面問題。
首次進來頁面圖表無法加載
這個問題是我們自定義的底部導航欄引入的,因為組件頁面的出現后就被設置成了隱藏狀態,所以 canvas 并沒有獲得到寬高,導致圖表不顯示。
解決辦法就是在組件頁面第一次顯示的時候觸發 getCanvas 函數,這里監聽 show 屬性的寫法可以參考我前面自定義底部導航欄的博客,就不詳述了。第一次顯示的問題,用到了一個全局變量,一旦觸發了,這個變量就永久設置為 false,使 getCanvas 函數不會再次執行。
同時,在第一次獲取數據時因為 canvas 未獲取到,應該暫時不繪制圖表,當第一次進入頁面后,拿到 canvas 對象了,再進行繪制。后面在拉取數據,例如下拉刷新,因為 canvas 已經獲取到了,就不用特殊處理了。
getCanvas() { ... // 首次進來畫圖 that.drawPieChart2d() } getData() { ... // 因為本頁作為組件隱藏了,首次進來無法獲取canvas高度,首次進來另外處理 if (!that.data.isFirstComeIn) { that.drawPieChart2d() } }
圖表數據處理
這里還碰到一個很奇怪的問題,就是我一開始把數據的百分比算成四位小數,在頁面綁定的時候乘上100加上百分號再顯示,按理來說應該顯示小數點后兩位的百分比值,可實際卻是取小數點后兩位并不生效,小數點后面取了十幾位,可能時在頁面計算的時候出了問題。所以這里最好在 JS 中算好值,保留小數點后幾位,再進行數據綁定。計算的時候,分母不為零千萬別忘了。
關于“canvas怎么實現2d環形統計圖”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“canvas怎么實現2d環形統計圖”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。