若是不想看步骤的能够直接看最后面有完整的代码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>
)
}
}
复制代码