1.画板部分
<!--画布尺寸的控制-->
<div class="canvas_area" ref="canvasArea">
<canvas :id="id" width="208px" height="208px"></canvas>
</div>
2.css样式
<style lang="less" scoped>
.total {
width: 100vw;
height: 100vh;
background-color: rgb(244, 244, 244);
/*background-color: #ffffff;*/
}
.bg_par {
background-color: rgb(244, 244, 244);
}
.canvas_area{
/* transform 缩小后会有占位情况*/
/*transform:scale(0.5, 0.5);*/
/*-webkit-transform:scale(0.5, 0.5); !*兼容-webkit-引擎浏览器*!*/
/*-moz-transform:scale(0.5, 0.5);*/
display: flex;
align-items: center;
justify-content: center;
zoom: 0.55;
canvas{
background-color: transparent;
}
}
</style>
3.js部分
<script>
export default {
...
//涉及到的一些变量
data () {
return {
title: '环形进度条',
canvas: '',
cacheCanvas: '',
keeprate: ' ',该进度条的数值 //可根据需要自行调整
id: '', // 设置画布id
context: '',
cirX: 0, // 圆心x坐标
cirY: 0, // 圆心y坐标
cirR: 0, // 圆半径
ratio: '', // 绘制圆环占整个圆的比例 百分比小数
rad: 0,
ballR: 8, // 填充小球半径
timer: '',
tempRatio: 0,
speed: 1, // 加载速度
width: '', // 画布宽高
height: '',
rate: '',
speed2: 1.5 // 减速
}
}
...
mounted () {
// 进行数据初始化的一些处理
/* 进行弧度计算 将360度分成100份,那么每一份就是rad度 */
this.rad = (Math.PI * 2) / 100
console.log('ratio' + this.ratio)
// 获取画布的宽 高
this.width = document.getElementById(this.id).offsetWidth
this.height = document.getElementById(this.id).offsetHeight
// 设置圆心
this.cirX = this.width / 2
this.cirY = this.height / 2
// 设置圆的半径
this.cirR = 87
this.initCanvas()
},
...
methods: {
initCanvas () {
...此处省略部分逻辑代码...
if (!this.cacheCanvas) {
this.cacheCanvas = document.createElement('canvas')
this.cacheCanvas.width = this.width
this.cacheCanvas.height = this.height
}
this.context = this.cacheCanvas.getContext('2d')
this.context.save()
this.context.clearRect(0, 0, this.canvas.width + 1, this.canvas.height + 1) // 部分Android机器很奇葩,如果局部刷新会出现空白的情况
this.drawBottomCircle() // 绘制
this.context.restore()
// 双缓冲,先画到临时canvas,再转到正式canvas
// 获取到对应的canvas元素
this.canvas = document.getElementById(this.id)
// 创建 context 对象
this.context = this.canvas.getContext('2d')
this.context.clearRect(0, 0, this.canvas.width + 1, this.canvas.height + 1)
this.context.drawImage(this.cacheCanvas, 0, 0, this.canvas.width, this.canvas.height)
if (this.rate > 0) {
window.requestAnimationFrame(this.drawFrame, this.canvas)
} else {
// 如果该进度值不存在的情况下则只显示底环和文字
this.drawBottomCircle()
this.fillTextContent('--')
}
},
/* 绘制底层圆环 */
drawBottomCircle () {
// 开始一个新的绘制路径
this.context.beginPath()
// 设置弧线颜色
this.context.strokeStyle = 'rgb(254,238,225)'
this.context.lineWidth = '8'
this.context.arc(this.cirX, this.cirY, this.cirR, 0, 2 * Math.PI, false)
// 按指定路径绘制弧线
this.context.stroke()
this.context.closePath()
},
/* 绘制上层填充路径 */
drawTopFillPath (n) {
if (this.rate >= 0) {
// 处理某些度数时效果无法正常显示 属于优化,占位
n = Math.floor(n)
if (n > 50) n = n - 3
// 圆环起始位置,正下方
let startAngle = -1.375 * Math.PI / 2
// 圆环结束位置,一个整圆(Math.PI*2)乘以比例 + 起始位置
let endAngle = -1.375 * Math.PI / 2 + n * (this.rad)
// 每次绘制的弧度单位,越小颜色分布越均匀,但图形较小时边缘越糙
const unit = 0.05
// 根据最小弧度单位计算整个圆弧可以切成多少小份
let division = parseInt((endAngle - startAngle) / unit, 10)
// 生成渐变色数组 此处传的值为渐变的两个颜色的十六进制,如果取到的是rgb,可
//以通过下面的colorHex() 方法进行转化
let gradient = this.gradientColor([255, 187, 165], [255, 89, 38], division)
let start = startAngle
let end = start
for (let i = 0; i < division; i++) {
this.context.beginPath()
this.context.lineCap = 'round'
end = start + unit
this.context.lineWidth = '22'
this.context.strokeStyle = gradient[i]
this.context.arc(this.cirX, this.cirY, this.cirR, start, end)
this.context.stroke()
start += unit
}
}
},
/* 绘制上层填充小球 */
drawTopFillBall () {
if (this.rate > 0) {
// 填充小球颜色 rgb(203,215,253)
this.context.fillStyle = '#ffffff'
// 计算小球位置
this.context.beginPath()
let rad = 247.5
// 坐标微调
let x = Math.cos(rad) * this.cirR + 21
let y = Math.sin(rad) * this.cirR + 19
this.context.arc(x + this.cirX, this.cirY - y, this.ballR, 0, 2 * Math.PI)
// this.context.arc(x + this.cirX, this.cirY - y, this.ballR, 0, 2 * Math.PI)
this.context.closePath()
this.context.fill()
}
},
/* 进行文字填充 */
fillTextContent (n) {
if (n !== '--') {
n = n.toFixed(2) + '%'
}
// this.context.beginPath()
this.context.fillStyle = 'rgb(255,87,34)'
this.context.font = '38px ArialMT'
this.context.textAlign = 'center'
this.context.textBaseline = 'middle'
this.context.fillText(n, this.cirX, this.cirY - 12)
this.context.fillStyle = 'rgb(153,153,153)'
this.context.font = '24px HiraginoSansGB-W3'
this.context.fillText('进度', this.cirX, this.cirY + 37)
},
drawFrame () {
window.requestAnimationFrame(this.drawFrame, this.canvas)
this.context.clearRect(0, 0, this.width, this.height)
// 绘制底层圆环
this.drawBottomCircle()
// 绘制上层填充轨迹
this.drawTopFillPath(this.tempRatio)
// 绘制上层填充小球
this.drawTopFillBall()
// 进行文字填充 此处可以添加自己的逻辑处理
....
this.fillTextContent(this.tempRatio)
//进行动画的加速减速控制 自行调整 通过对speed变量的控制实现加速减速
...此处可以添加自己的逻辑处理...
},
// startColor:开始颜色hex endColor:结束颜色hex step:几个阶级(几步)
gradientColor (startColor, endColor, step) {
// let startRGB = this.colorRgb(startColor)// 转换为rgb数组模式
let startR = startColor[0]
let startG = startColor[1]
let startB = startColor[2]
// let endRGB = this.colorRgb(endColor)
let endR = endColor[0]
let endG = endColor[1]
let endB = endColor[2]
let sR = (endR - startR) / step// 总差值
let sG = (endG - startG) / step
let sB = (endB - startB) / step
var colorArr = []
for (var i = 0; i < step; i++) {
// 计算每一步的hex值
var hex = this.colorHex('rgb(' + parseInt((sR * i + startR)) + ',' + parseInt((sG * i + startG)) + ',' + parseInt((sB * i + startB)) + ')')
colorArr.push(hex)
}
return colorArr
},
// rgb转化为十六进制的方法
colorHex (rgb) {
var _this = rgb
var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
if (/^(rgb|RGB)/.test(_this)) {
var aColor = _this.replace(/(?:(|)|rgb|RGB)*/g, '').split(',')
var strHex = '#'
for (var i = 0; i < aColor.length; i++) {
var hex = Number(aColor[i]).toString(16)
hex = hex < 10 ? 0 + '' + hex : hex// 保证每个rgb的值为2位
if (hex === '0') {
hex += hex
}
strHex += hex
}
if (strHex.length !== 7) {
strHex = _this
}
return strHex
} else if (reg.test(_this)) {
var aNum = _this.replace(/#/, '').split('')
if (aNum.length === 6) {
return _this
} else if (aNum.length === 3) {
var numHex = '#'
for (let i = 0; i < aNum.length; i += 1) {
numHex += (aNum[i] + aNum[i])
}
return numHex
}
} else {
return _this
}
}
}
}
</script>