canvas繪製圓形動畫圓角進度條

若是不想看步驟的能夠直接看最後面有完整的代碼

最近在作一個圓形的進度條,在網上看了一些例子有些地方不太理解,後來本身寫了個一個分享一下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點位置

而後是畫一個進度的圓弧

畫圓弧度,主要是須要計算出起點的弧度終點的弧度動畫

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' 這個是設置最終繪製的線是帶圓角的

起點的弧度計算方式

const startRadian = progess >= maxPro ? 0 : Math.PI * 1.5this

咱們但願點的起點位置是鐘錶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

當前效果圖片

clipboard.png

動畫實現

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相等中止計時,期間每次繪製ip

完整的代碼

我用react 寫的因此直接把react的整個代碼粘過來了,若是不須要的能夠只拿繪圖的那一部分get

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>
    )
  }
}
相關文章
相關標籤/搜索