canvas实现环形渐变进度条(vue)

it2024-11-02  14

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>
最新回复(0)