周末好,今天给大家带来一款接地气的环形进度条组件vue-awesome-progress。近日被设计小姐姐要求实现这么一个环形进度条效果,大体由四部分组成,分别是底色圆环,进度弧,环内文字,进度圆点。设计稿截图如下:
我的第一反应还是找现成的组件,市面上很多组件都实现了前3点,独独没找到能画进度圆点的组件,不然稍加定制也能复用。既然没有现成的组件,只有自己用vue + canvas撸一个了。
效果图先放个效果图,然后再说下具体实现过程,各位看官且听我慢慢道来。
安装与使用源码地址,欢迎star和提issue。
安装 npm install --save vue-awesome-progress 使用 全局注册 import Vue from 'vue' import VueAwesomeProgress from "vue-awesome-progress" Vue.use(VueAwesomeProgress) 局部使用 import VueAwesomeProgress from "vue-awesome-progress" export default { components: { VueAwesomeProgress }, // 其他代码 } webpack配置由于当前版本发布时,未进行babel编译,因此使用时需要自行将vue-awesome-progress纳入babel-loader的解析范围。示例如下:
// resolve函数是连接路径的,方法体是path.join(__dirname, "..", dir) { test: /\.js$/, loader: "babel-loader", include: [ resolve("src"), resolve("node_modules/vue-awesome-progress") ] } 静态展示任何事都不是一蹴而就的,我们首先来实现一个静态的效果,然后再实现动画效果,甚至是复杂的控制逻辑。
确定画布大小第一步是确定画布大小。从设计稿我们可以直观地看到,整个环形进度条的最外围是由进度圆点确定的,而进度圆点的圆心在圆环圆周上。
因此我们得出伪代码如下:
// canvasSize: canvas宽度/高度 // outerRadius: 外围半径 // pointRadius: 圆点半径 // pointRadius: 圆环半径 canvasSize = 2 * outerRadius = 2 * (pointRadius + circleRadius)据此我们可以定义如下组件属性:
props: { circleRadius: { type: Number, default: 40 }, pointRadius: { type: Number, default: 6 } }, computed: { // 外围半径 outerRadius() { return this.circleRadius + this.pointRadius }, // canvas宽/高 canvasSize() { return 2 * this.outerRadius + 'px' } }那么canvas大小也可以先进行绑定了
<template> <canvas ref="canvasDemo" :width="canvasSize" :height="canvasSize" /> </template> 获取绘图上下文getContext('2d')方法返回一个用于在canvas上绘图的环境,支持一系列2d绘图API。
mounted() { // 在$nextTick初始化画布,不然dom还未渲染好 this.$nextTick(() => { this.initCanvas() }) }, methods: { initCanvas() { var canvas = this.$refs.canvasDemo; var ctx = canvas.getContext('2d'); } } 画底色圆环完成了上述步骤后,我们就可以着手画各个元素了。我们先画圆环,这时我们还要定义两个属性,分别是圆环线宽circleWidth和圆环颜色circleColor。
circleWidth: { type: Number, default: 2 }, circleColor: { type: String, default: '#3B77E3' }canvas提供的画圆弧的方法是ctx.arc(),需要提供圆心坐标,半径,起止弧度,是否逆时针等参数。
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);我们知道,Web网页中的坐标系是这样的,从绝对定位的设置上其实就能看出来(top,left设置正负值会发生什么变化),而且原点(0, 0)是在盒子(比如说canvas)的左上角哦。
对于角度而言,0°是x轴正向,默认是顺时针方向旋转。
圆环的圆心就是canvas的中心,所以x, y 取outerRadius的值就可以了。
ctx.strokeStyle = this.circleColor; ctx.lineWidth = this.circleWidth; ctx.beginPath(); ctx.arc(this.outerRadius, this.outerRadius, this.circleRadius, 0, this.deg2Arc(360)); ctx.stroke();注意arc传的是弧度参数,而不是我们常理解的360°这种概念,因此我们需要将我们理解的360°转为弧度。
// deg转弧度 deg2Arc(deg) { return deg / 180 * Math.PI } 画文字调用fillText绘制文字,利用canvas.clientWidth / 2和canvas.clientWidth / 2取得中点坐标,结合控制文字对齐的两个属性textAlign和textBaseline,我们可以将文字绘制在画布中央。文字的值由label属性接收,字体大小由fontSize属性接收,颜色则取的fontColor。
if (this.label) { ctx.font = `${this.fontSize}px Arial,"Microsoft YaHei"` ctx.fillStyle = this.fontColor; ctx.textAlign = 'center' ctx.textBaseline = 'middle' ctx.fillText(this.label, canvas.clientWidth / 2, canvas.clientWidth / 2); } 画进度弧