若是不想看步驟的能夠直接看最後面有完整的代碼react
最近在作一個圓形的進度條,在網上看了一些例子有些地方不太理解,後來本身寫了個一個分享一下
先上一個最終的效果canvas
const cvsWitdh = 220
const cvsHeight = 220
const progess = 50 // 定義進度爲50
const maxPro = 100 // 定義總進度爲100
const r = 100 // 定義圓的半徑爲100
this.cvs.width = cvsWitdh
this.cvs.height = cvsHeight
const ctx = this.cvs.getContext('2d')
ctx.lineWidth = 10
ctx.strokeStyle = '#15496B'
ctx.arc(r + 10, r + 10, r, 0, 2 * Math.PI)
ctx.stroke() // 至此大圓畫完
複製代碼
上面的代碼須要注意的是 arc 方法的最後一側參數是
弧度(2π)
不是角度,畫圓的起點是表的3點的位置開始畫的不是12點位置
bash
畫圓弧度,主要是須要計算出起點的弧度
和終點的弧度
動畫
ctx.beginPath()
ctx.lineCap = 'round'
// 下面是漸變的代碼不須要的能夠換成純色
let grd = ctx.createLinearGradient(0, 0, 220, 220)
grd.addColorStop(0, 'red')
grd.addColorStop(1, 'blue')
ctx.strokeStyle = grd
const startRadian = progress >= maxPro ? 0 : Math.PI * 1.5
const rate = progress / maxPro
const endRadian = progress >= maxPro ? 2 * Math.PI : 2 * Math.PI * rate - Math.PI / 2
ctx.arc(r + 10, r + 10, r, startRadian, endRadian)
ctx.stroke()
複製代碼
上面的代碼中
ctx.lineCap = 'round'
這個是設置最終繪製的線是帶圓角的ui
const startRadian = progess >= maxPro ? 0 : Math.PI * 1.5
this
咱們但願點的起點位置是鐘錶12點鐘
位置,整個圓的弧度是 2π==360°
推算得知12點鐘的位置是 1.5π==270°
spa
const rate = progress / maxPro
const endRadian = progress >= maxPro ? 2 * Math.PI : 2 * Math.PI * rate - Math.PI / 2
複製代碼
const rate = progress / maxProo
得值爲進度佔圓的比率
2π * rate
就是進度所須要的弧度
因爲 arc
方法畫圓的起點是3點的方向
而咱們的起點是12點方向
因此咱們還須要減掉一個 Math.PI / 2
最終就得出了咱們上面的公式code
因爲當progress等於maxPro
的時候算出來的終點等於咱們的起點最終畫的就會有問題,因此咱們在計算起點終點的時候作了判斷 progress >= maxPro
時畫整圓component
當前效果cdn
let currentProgress = 1
const timer = setInterval(() => {
if (currentProgress >= progress) {
currentProgress = progress
clearInterval(timer)
}
ctx.beginPath()
ctx.lineCap = 'round'
// 下面是漸變的代碼不須要的能夠換成純色
let grd = ctx.createLinearGradient(0, 0, 220, 220)
grd.addColorStop(0, 'red')
grd.addColorStop(1, 'blue')
ctx.strokeStyle = grd
const startRadian = currentProgress >= maxPro ? 0 : Math.PI * 1.5
const rate = currentProgress / maxPro
const endRadian = currentProgress >= maxPro ? 2 * Math.PI : 2 * Math.PI * rate - Math.PI / 2
ctx.arc(r + 10, r + 10, r, startRadian, endRadian)
ctx.stroke()
currentProgress++
}, 10)
複製代碼
動畫的實現也很是的簡單,咱們只需定義一個臨時的進度 currentProgress
經過定時器每次累加這個進度知道與progress
相等中止計時,期間每次繪製
我用react 寫的因此直接把react的整個代碼粘過來了,若是不須要的能夠只拿繪圖的那一部分
import React from 'react'
export default class Test extends React.Component {
componentDidMount () {
this.renderProgress(30)
}
renderProgress (progress) {
const cvsWitdh = 220
const cvsHeight = 220
const maxPro = 100 // 定義總進度爲100
const r = 100 // 定義圓的半徑爲100
this.cvs.width = cvsWitdh
this.cvs.height = cvsHeight
const ctx = this.cvs.getContext('2d')
ctx.lineWidth = 10
ctx.strokeStyle = '#15496B'
ctx.arc(r + 10, r + 10, r, 0, 2 * Math.PI) // 2 * Math.PI === 360 度 最後一個參數表明的是圓的弧度
ctx.stroke() // 至此大圓畫完
if (progress === 0) {
return
}
let currentProgress = 1
const timer = setInterval(() => {
if (currentProgress >= progress) {
currentProgress = progress
clearInterval(timer)
}
ctx.beginPath()
ctx.lineCap = 'round'
// 下面是漸變的代碼不須要的能夠換成純色
let grd = ctx.createLinearGradient(0, 0, 220, 220)
grd.addColorStop(0, 'red')
grd.addColorStop(1, 'blue')
ctx.strokeStyle = grd
const startRadian = currentProgress >= maxPro ? 0 : Math.PI * 1.5
const rate = currentProgress / maxPro
const endRadian = currentProgress >= maxPro ? 2 * Math.PI : 2 * Math.PI * rate - Math.PI / 2
ctx.arc(r + 10, r + 10, r, startRadian, endRadian)
ctx.stroke()
currentProgress++
}, 10)
}
render () {
return (
<div>
<br />
<br />
<canvas
ref={ref => {
this.cvs = ref
}}
/>
<br />
<br />
<button onClick={() => {
this.renderProgress(60)
}}>從新loadprogress</button>
</div>
)
}
}
複製代碼