周末好,今天给大家带来一款接地气的环形进度条组件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
},
// 其他代码
}

script标签引入组件

同时也支持直接使用script标签引入哦,满足有这部分需求的朋友。

<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
<script src="path-to/vue-awesome-progress.min.js"></script>
</head>
<body>
<div id="app"></div>
<script>
new Vue({
el: "#app",
template: '<vue-awesome-progress :percentage="40"></vue-awesome-progress>'
})
</script>
</body>
</html>

静态展示

任何事都不是一蹴而就的,我们首先来实现一个静态的效果,然后再实现动画效果,甚至是复杂的控制逻辑。

确定画布大小

第一步是确定画布大小。从设计稿我们可以直观地看到,整个环形进度条的最外围是由进度圆点确定的,而进度圆点的圆心在圆环圆周上。

因此我们得出伪代码如下:

// 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网页中的坐标系是这样的,从绝对定位的设置上其实就能看出来(topleft设置正负值会发生什么变化),而且原点(0, 0)是在盒子(比如说canvas)的左上角哦。

对于角度而言,x轴正向,默认是顺时针方向旋转。

圆环的圆心就是canvas的中心,所以x , youterRadius的值就可以了。

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 / 2canvas.clientWidth / 2取得中点坐标,结合控制文字对齐的两个属性textAligntextBaseline,我们可以将文字绘制在画布中央。文字的值由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);
}

画进度弧

支持普通颜色和渐变色,withGradient默认为true,代表使用渐变色绘制进度弧,渐变方向我默认给的从上到下。如果希望使用普通颜色,withGradientfalse即可,并可以通过lineColor自定义颜色。

if (this.withGradient) {
this.gradient = ctx.createLinearGradient(this.circleRadius, 0, this.circleRadius, this.circleRadius * 2);
this.lineColorStops.forEach(item => {
this.gradient.addColorStop(item.percent, item.color);
});
}

其中lineColorStops是渐变色的颜色偏移断点,由父组件传入,可传入任意个颜色断点,格式如下:

colorStops2: [
{ percent: 0, color: '#FF9933' },
{ percent: 1, color: '#FF4949' }
]

画一条从上到下的进度弧,即270°90°

ctx.strokeStyle = this.withGradient ? this.gradient : this.lineColor;
ctx.lineWidth = this.lineWidth;
ctx.beginPath();
ctx.arc(this.outerRadius, this.outerRadius, this.circleRadius, this.deg2Arc(270), this.deg2Arc(90));
ctx.stroke();

其中lineWidth是弧线的宽度,由父组件传入

lineWidth: {
type: Number,
default: 8
}

画进度圆点

最后我们需要把进度圆点补上,我们先写死一个角度90°,显而易见,圆点坐标为(this.outerRadius, this.outerRadius + this.circleRadius)

画圆点的代码如下:

ctx.fillStyle = this.pointColor;
ctx.beginPath();
ctx.arc(this.outerRadius, this.outerRadius + this.circleRadius, this.pointRadius, 0, this.deg2Arc(360));
ctx.fill();

其中pointRadius是圆点的半径,由父组件传入:

pointRadius: {
type: Number,
default: 6
}

角度自定义

当然,进度条的角度是灵活定义的,包括开始角度,结束角度,都应该由调用者随意给出。因此我们再定义一个属性angleRange,用于接收起止角度。

angleRange: {
type: Array,
default: function() {
return [270, 90]
}
}

有了这个属性,我们就可以随意地画进度弧和圆点了,哈哈哈哈。

老哥,这种圆点坐标怎么求?

噗......看来高兴过早了,最重要的是根据不同角度求得圆点的圆心坐标,这让我顿时犯了难。

经过冷静思考,我脑子里闪过了一个利用正余弦公式求坐标的思路,但前提是坐标系原点如果在圆环外接矩形的左上角才好算。仔细想想,冇问题啦,我先给坐标系平移一下,最后求出来结果,再补个平移差值不就行了嘛。

用初中数学知识撸一个canvas环形进度条的更多相关文章

  1. canvas环形进度条

    <style> canvas { border: 1px solid red; margin: 100px; }</style> <canvas id="rin ...

  2. 【css】如何实现环形进度条

    最近团队的童鞋接到了一个有关环形进度条的需求,想要还原一个native的沿环轨迹渐变进度条的效果,看到这个效果的时候,笔者陷入了沉思.. 环形进度条的效果,最先想到的就是使用CSS利用两个半圆的hac ...

  3. 环形进度条的实现方法总结和动态时钟绘制(CSS3、SVG、Canvas)

    缘由: 在某一个游戏公司的笔试中,最后一道大题是,“用CSS3实现根据动态显示时间和环形进度[效果如下图所示],且每个圆环的颜色不一样,不需要考虑IE6~8的兼容性”.当时第一想法是用SVG,因为SV ...

  4. Canvas实现环形进度条

    Canvas实现环形进度条 直接上代码: <canvas width="200" height="200" >60%</canvas> ...

  5. 用svg实现一个环形进度条

    svg实现环形进度条需要用到的知识: 1.会使用path的d属性画一个圆环 //用svg的path元素的A命令画圆 <path d=" M cx cy m 0 -r a r r 0 1 ...

  6. canvas绘制环形进度条

    <!DOCTYPE html> <html > <head> <meta http-equiv="content-type" conten ...

  7. html5 canvas绘制环形进度条,环形渐变色仪表图

    html5 canvas绘制环形进度条,环形渐变色仪表图                                             在绘制圆环前,我们需要知道canvas arc() 方 ...

  8. canvas实现半圆环形进度条

    html部分 <canvas id="canvas" width="150" height="150"> <p>抱歉 ...

  9. Android简易实战教程--第十七话《自定义彩色环形进度条》

    转载请注明出处:http://blog.csdn.net/qq_32059827/article/details/52203533   点击打开链接 在Android初级教程里面,介绍了shape用法 ...

随机推荐

  1. 快学Scala 第四课 (多维数组,与Java集合的互操作)

    Scala二维数组的定义: val arr2 = Array.ofDim[String](2, 2) arr2(0)(0) = "aa" arr2(1)(0) = "bb ...

  2. Android NDK(一) ndk-build构建工具进行NDK开发

    本文目录 一.androidstudio环境 二.快捷键配置 三.新建项目 四.NDK开发 五.so文件编译 一. androidstudio的环境 在SDK Tools中安装NDK开发环境(File ...

  3. C#使用GUID作为随机数种子

    使用C#默认的Random无参构造的next生成的随机数,在快速生成随机数的时候,会出现大批量的重复.使用guid作为随机数种子,效果会好很多 Guid temp = Guid.NewGuid(); ...

  4. EF Core设置字段默认时间

    ---恢复内容开始--- 在EF的官方文档上只提到了用 Fluent API来设置默认值. 但是我们日常开发中,会把公用字段都写成基类.比如行创建时间 在需要默认时间的字段加上一个特性 [Databa ...

  5. 如何选择一款适合自己操作系统、Windows、Mac还是Linux?

    如何选择一款适合自己操作系统.Windows.Mac还是Linux? 作者:我们都很努力着 简介:电脑已经逐渐离不开我们生活,但是如何选择一个我们最佳,最适合的电脑操作系统就成了一些困难选择人士的一个 ...

  6. [Windows内核分析]KPCR结构体介绍 (CPU控制区 Processor Control Region)

    Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html 逆向分析操作系统内核代码至少需要具备两项技能: 段页汇编代码非常懂 ...

  7. cocos2d-x C++ 工程初探

    经过较为繁琐的环境搭建后,我们终于运行出了一个helloworld窗口,可以正式上手cocos了 现在我们就从改代码开始玩起 窗口 我们之前讲到AppDelegate类是程序的入口,所以和窗口有关的设 ...

  8. 【JZOJ4807】破解

    Description 历经千辛万苦,ddddddpppppp 终于找到了IBN5100. dp 事先了解到SERN 共有T 个密码,每个密码是一个长度为N 的01 串,他要利用IBN5100 的特殊 ...

  9. Tomcat基本知识(一)

    顶层架构先上一张Tomcat的顶层结构图(图A),如下: Tomcat中最顶层的容器是Server,代表着整个服务器,从上图中可以看出,一个Server可以包含至少一个Service,用于具体提供服务 ...

  10. CTFd平台部署

    学校要办ctf了,自己一个人给学校搭建踩了好多坑啊..这里记录一下吧 心累心累 这里只记录尝试成功的过程 有些尝试失败的就没贴上来 为各位搭建的时候节省一部分时间吧. ubuntu18搭建 0x01 ...