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

开始

这一切需要从一个(简单)的需求开始,在最开始对设计第一眼看到这张图的时候,感觉挺简单的嘛,直接用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. Mybatis时间范围查询,亲测有效

    Md2All export document .output_wrapper pre code{font-family: Consolas, Inconsolata, Courier, monospa ...

  2. golang 容器的学习与实践

    golang 提供了几个简单的容器供我们使用,本文在介绍几种Golang 容器的基础上,实现一个基于Golang 容器的LRU算法. 容器介绍 Golang 容器位于 container 包下,提供了 ...

  3. 学习Vue第四节,v-model和双向数据绑定

    Vue指令之v-model和双向数据绑定 <!DOCTYPE html> <html> <head> <meta charset="utf-8&qu ...

  4. D. Kefa and Dishes(状压)

    永久打开的传送门 \(这次总算没有写砸........\) \(设f[i][j]为上一次吃的i物品状态为j的最大收益\) \(那么我们就暴力枚举所有状态i,然后在当前状态找出一个没吃的食物j,再去找一 ...

  5. Oracle的三种循环

    一.loop循环 语法:声明循环变量loop判断循环条件 ,如果循环条件不成立,跳出循环if 条件表达式 thenexit;end if;语句块;改变循环变量的值end loop; 举例:输出1到10 ...

  6. CC2530应用——按键控制灯光状态变化

    独立新建工程并编写.编译代码,实现按键控制灯光闪烁状态的变换,实现以下任务要求:[1]程序开始运行:D4灯闪烁,D3.D5.D6灯熄灭.[2]按下模块上的SW1按键松开后,实现D5.D6灯轮流闪烁.[ ...

  7. CC2530入门

    一.简介 单片机(MCU)就是一个将微型计算机系统制作到里面的集成电路芯片. 微控制器的基本结构:内核+外设.内核通过寄存器控制外设:外设通过中断系统通知内核:内核与外设之间通过总线传输数据.地址及控 ...

  8. react——key值的理解

    key不是给开发者使用的,是给react在diff算法中使用的,diff算法会比较新旧虚拟dom,并且是同层比较,当同一层中有多个元素的时候,会比较这一层的key值, 如果key相同,属性改变积极更新 ...

  9. LeetCode--Sort Array By Parity && N-Repeated Element in Size 2N Array (Easy)

    905. Sort Array By Parity (Easy)# Given an array A of non-negative integers, return an array consist ...

  10. C# 中 枚举Enum 一些转换的方法整理

    工作中 经常遇到枚举 的一些转换  特别是获取枚举备注等  特地整理下 方法以后使用 public void TestMethod1() { TestEnumOne colorEnum = TestE ...