从一个渐变圆角进度条浅出画一个圆

开始

这一切需要从一个(简单)的需求开始,在最开始对设计第一眼看到这张图的时候,感觉挺简单的嘛,直接用echarts饼图模拟出来一个就好了

echarts

然后上echarts试了一下发现实现不出来了

设计图这边采用的是锥形渐变,而echarts只有线性渐变和径向渐变。

css

然后准备换种方案,css就有锥形渐变,然后通过conic-gradient加上mask画出了一个渐变的环形然后可以再通过剪裁实现出进度的展示。

但是存在两个问题,一个是conic-gradient属性兼容性不好ie和火狐都不支持,二个是后来发现了还存在一个需求进度条的两端需要有圆角,然后这种实现方式就不行了。

其实在写这篇文章的时候才想到一个方法就是在两端加上两个半圆形,不过得计算半圆形的位置。

Canvas & SVG

在我的理解中在页面上作图总共有四种方式。

  • dom+css
  • Canvas
  • SVG
  • WebGL

WebGL是一头雾水还是试试Canvas和SVG吧,因为更熟悉Canvas一些,我这边就采用Canvas来试试。

Canvas可以轻松的实现圆角和环形,但是他的api里面居然没有锥形渐变

然后就想着尝试手动来实现一个锥形渐变,然后查阅资料看到了一篇文章手把手教你画圆锥渐变,就是相当于画圆嘛,我们可以通过一条线一条线的画从而画出一个圆,然后把两端渐变的颜色通过计算找到中间画圆的每一条线的颜色组合起来就是一个渐变的效果了。

然后问题就是给你两个色值怎么计算中间的线段的颜色,其实对于rgba的颜色我们可以看到他是由四个数字组成的,那我把这四个数字分别求出四组长度相同且组内间隔相同的中间值那就可以得到颜色的中间值了,然后在搭配上张老师硬核的色值转换JS HEX十六进制与RGB,HSL颜色的相互转换那就可以实现出我们想要的效果了。

通过一个开始颜色和一个结束颜色,默认是rgba的颜色,num是分段数,就可以求出中间每一段的颜色了

  // 把颜色分段
const beginColor = begin.slice(5, -1).split(',').map(item => Number(item))
const endColor = end.slice(5, -1).split(',').map(item => Number(item))
// 分段后的颜色储存在这个数组
const middleColor = [[], [], [], []]
// 循环rgba四种
beginColor.forEach((item, index) => {
// 当前的值每段颜色之间的间隔
const differ = (endColor[index] - item) / (num - 1)
// 循环分段数的次数
for(let i = 0; i< num; i++) {
// 每次加上这个间隔
middleColor[index].push((item + differ * i).toFixed(2))
}
})
console.log(middleColor)
console.log(num)

然后绘制的话就是一段一段的画了,麻烦的地方就是计算每次从多少的角度画到多少的角度

  for(let i = 0; i< num; i++) {
ctx.beginPath()
// 这里是每次绘制的过程
// 每次绘制一段小圆弧
// 最后一段只需要画一段就好
if(i === num - 1)
ctx.arc( 150 * dpr,150 * dpr, 100 * dpr, (Math.PI * 2 * value) / num * i, (Math.PI * 2 * value) / num * (i + 1));
else
ctx.arc( 150 * dpr,150 * dpr, 100 * dpr, (Math.PI * 2 * value) / num * i, (Math.PI * 2 * value) / num * (i + 2));
ctx.lineWidth = 60;
// ctx.lineCap = "round";
ctx.strokeStyle= `rgba(${middleColor[0][i]}, ${middleColor[1][i]}, ${middleColor[2][i]}, ${middleColor[3][i]})`;
ctx.stroke();
ctx.closePath()
}

结果非常的顺利,就是自己想要的结果,具体怎么一段一段的画,怎么求出颜色的中间值看这里

优化

其实把绘制的过程放慢看

就是这个过程,每次画一段,每段不同的颜色组合起来就是一个渐变色,然后分段数再加多一点就会靠上去很流畅。

在完成后发现了几个问题,首先是在分段数很少的时候就会出现一块一块的间隔

就像这样,我大概分析了一下,猜测这个间隔出现的原因应该是我计算每一段的角度的时候肯定有除不尽的,我就四舍五入了,应该就会产生一些小间隔。

然后我就觉得把分段数提高应该就会好一些,然后就发现分段数高间隔会生成类似于摩尔纹的东西

然后就开始思考怎么去消除,最后想到了一种方案就是在每次绘制的时候绘制两段的长度,然后移动只移动一段的长度,就会下一段覆盖在上一段,就不会有间隔了,然后颜色渐变也还是一段一段的不会有影响。

然后还有一个问题就是有锯齿,不清楚,解决方案也很简单,就是把你的画布放大指定倍数,然后半径也放大同样的倍数,最后dom的高宽不变,就会让绘制的图形更加的清晰。

总结

到此这个问题就算是解决了,然后我还顺便写了一个库,大家有兴趣的可以去使用一下,我还加上了数字,动画也可以支持多段渐变gradient-ring-progress

通过这次的需求我收获到了,做东西需要完全的去了解了需求再去确定实现方案然后再动手,实现方案其实有非常多种,我们需要找到的是最合适的解决方案。最后抄袭张老师的一句话

然而一个人的积累总是有限,而创意总是无限的,因此一定还有其他更好更妙更简单的实现,欢迎分享欢迎指教!

参考资料

CSS conic-gradient()锥形渐变简介

手把手教你画圆锥渐变

JS HEX十六进制与RGB,HSL颜色的相互转换

canvas锥形渐变进度条的更多相关文章

  1. 自定义控件之圆形颜色渐变进度条--SweepGradient

    前几天在群里面有人找圆形可颜色渐变进度条,其中主要的知识点是SweepGradient: mSweepGradient = new SweepGradient(240, 360, new int[] ...

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

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

  3. 【iOS】环形渐变进度条实现

    之前有人在找渐变进度条的效果,闲来无事就顺手写了一个,然后画了视图层级,方便讲解. 环境信息: Mac OS X 10.10.3 Xcode 6.3.1 iOS 8.3 效果图: 源码下载地址: ht ...

  4. canvas绘制圆形进度条(或显示当前已浏览网页百分比)

    使用canvas绘制圆形进度条,或者是网页加载进度条 或者是显示你浏览了本网页多少-- 由于个浏览器的计算差异,打开浏览器时 初始值有所不同,但是当拉倒网页底部时,均显示100%. 兼容性:测试浏览器 ...

  5. Canvas实现环形进度条

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

  6. iOS圆弧渐变进度条的实现

    由于项目需要一个环形渐变进度条显示课程,这方便网上的确有很多相关资料但是,都是比较零散的而且,大多数只是放一堆代码就算完了.这里我想详细写一篇我自己实现这个进度条的过程. 实现一个圆弧进度条主要分为三 ...

  7. android自己定义渐变进度条

    项目中须要用到一个弧形渐变的进度条,通过android自带是不能实现的.我是没有找到实现的方法,有大神知道的能够指点.效果图是以下这种 这是通过继承VIew来绘制出来的,网上也有相似的,可是代码那是相 ...

  8. iOS 渐变进度条

    #import <UIKit/UIKit.h> @interface JianBianView : UIView //为了增加一个表示进度条的进行,可们可以使用mask属性来屏蔽一部分 @ ...

  9. canvas绘制环形进度条

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

随机推荐

  1. keep-alive的深入理解与使用(配合router-view缓存整个路由页面)

    原文链接: 点我 在搭建 vue 项目时,有某些组件没必要多次渲染,所以需要将组件在内存中进行‘持久化’,此时 <keep-alive> 便可以派上用场了. <keep-alive& ...

  2. Java——接口相关知识

    1.接口用interface来声明 //定义一个动物接口 public interface Animal{ public void eat(); public void travel(); } 2.接 ...

  3. Javajdk的安装

    初次接触Java,这是我真正接触的第一门编程语言,在学习它之前,我曾看过一些c语言的书籍,可是并没有进行代码实现,在上手了Java后,并不懂的如何让代码运行,通过一点一点的学习和积累,今天记录下Jav ...

  4. jQuery的相关尺寸获取 - 学习笔记

    获取元素相对于文档的偏移量 获取当前元素相对于父级元素的偏移量 获取文档滚动距离 获取元素的宽度和高度 设置元素的宽度和高度 获取可视区域的宽度和高度 获取文档的宽度和高度 获取元素相对于文档的偏移量 ...

  5. 【Linux】1 创建目录:mkdir

    mkdir命令用于创建目录,如同一路径下创建单个或多个目录.递归创建目录,但同路径下不能创建同名目录,且目录名区分大小写. [命令] mkdir [用途] 创建目录(单个目录/多个目录) [语法] m ...

  6. Coursera课程笔记----计算导论与C语言基础----Week 7

    C语言中的数据成分(Week7) 内存 把内存想象成长带,带子上有许多方格,每个方格有8位(8bit) 2^10 = 1024 1B = 8 b 1KB = 1024Byte MB.GB.TB.PB- ...

  7. 数组的操作。1,JS数组去重。2,把数组中存在的某个值,全部找出来。3在JS数组指定位置插入元素。。。

    1,数组去重 let arr = [1,2,3,4,5,6,1,2,3,'a','b','a']; let temp = []; // 作为存储新数组使用 for(let i = 0; i < ...

  8. angular前端框架简单小案例

    一.angular表达式 <head> <meta charset="UTF-8"> <title>Title</title> &l ...

  9. 2020年腾讯实习生C++面试题&持续更新中(2)

    2020年腾讯实习生C++面试题&持续更新中(2) hello,大家好~ 我是好好学习天天,天天编程的天天,一个每天都死磕技术,及时分享的技术宅~ 昨天分享的题目不知道大家是否看过了,以后我计 ...

  10. 2018-06-19 Javascript 基础2

    js变量类型测试:typeof()->五种 (number,string,boolean,object,undefined): instanceof->检查某个对象是否是某个构造器产生的 ...