环形进度条虽然很常用,但基本都是直接用各种组件库来搞,所以在此之前也没有自己真正实现过。偶然思考了以下这个问题,直接用CSS的话,好像还不太好实现,所以看了下svg实现的方案,也趁机熟悉一下svg——svg实现环形进度环出乎意料的简单。
一、效果预览
可在线体验效果:https://wintc.top/laboratory/#/circle-progress。
该效果代码大概如下:
<
可以看到,其中圆环图形部分对应一个svg元素,svg元素内有两个path标签,分别画了灰色背景圆环和红色进度环。接下来简单介绍一下这几个元素内的几个重要属性。
二、SVG坐标
svg的坐标系是一个直角坐标系,不过与初高中数学中的坐标系y轴正方向相反:
通过坐标系,可以约束svg图形从哪里开始画,画一个什么形状,到哪里结束等等。默认情况下,1个坐标单位和1屏幕像素对应。为了让我们实现的进度条组件复用性更高,我们可以在根级svg元素设置viewBox属性,用于约束缩放。比如:
<
这样不管svg实际宽度对应多少像素,其内部可见的坐标点x、y坐标都在0~100之间
三、<path>元素
path元素有一个最重要的属性就是d属性,d属性的值可以是一连串的指令拼接而成。一个指令由指令字母+参数组成。已上述例子中的第一个path为例:
<
d属性中用到了两种指令,M指令和A指令,完整的指令列表为:
-
- M = moveto
- L = lineto
- H = horizontal lineto
- V = vertical lineto
- C = curveto
- S = smooth curveto
- Q = quadratic Belzier curve
- T = smooth quadratic Belzier curveto
- A = elliptical Arc
- Z = closepath
以上所有命令均允许小写字母。大写表示绝对定位,小写表示相对定位。
这里仅仅介绍M指令和A指令,因为仅用这两种指令就可以完成进度环的绘制。
M指令很简单,后面跟随的两个数字x,y作为参数,表示移动画笔到x,y坐标,这时候还没有开始画线;如果使用小写字母m后面跟随数字dx, dy,则表示画笔从当前位置水平、垂直方向各移动d、dy个坐标(相对当前位置而不是原点进行移动)。
A指令稍微复杂,因为参数实在太多了。A指令作用是画椭圆弧形,指令格式为:
A
椭圆有长轴和短轴两个轴线,在A指令里通过前两个参数rx、ry来表示,这里我们为了画个圆,所以rx、ry设置为一致即可。试想,通过M指令规定了起点,通过rx、ry规定了弧线的长短轴,很显然我们还需要其它约束条件来得到一条圆弧。A指令的最后两个参数x、y约束了椭圆弧线的终点。给定起点A、终点B、长短轴rx/ry,可以得到4条弧线(如下图)。
要想确定下图中的某一条弧线,还需要另外两个参数large-arc-flag和sweep-flag,两个参数的可选值都是0和1。sweep-flag表示起点到终点是顺时针还是逆时针,下图中前两种情况即为顺时针(sweep-flag设置为1),后两种情况为逆时针(sweep-flag设置为0)。对于顺时针的两条弧线,large-arc-flag控制取长弧还是短弧,1为长弧,0为短弧。
A指令还有一个参数是x-axis-rotation,可以用于控制弧线旋转的角度。
通过path元素,我们已经可以刻画任意角度的圆弧,配上一个完整的背景圆弧环,就可以完成0 ~ 100%任意进度的进度环了。
四、0 ~ 100%任意进度进度环
任意进度的进度环,假设起点固定为圆环最顶部的点,无非是根据进度计算上述path中的各个参数的值。根据角度和圆弧半径计算终点坐标,就是高中所学的“极坐标转换为直角坐标”,利用三角函数直接转换即可。而使用长弧还是短弧,我们只用判断进度是否大于一半即可。原理很简单,Vue组件代码如下:
<
进度变化的时候,如果直接改变可能会表现得很生硬,这里使用了stroke-dasharray这个CSS属性做过渡效果,这样在进度增加的时候,有一个动画增加的效果。这个CSS属性用一个偶数个数字(如果数字为奇数个,则重复一遍变为偶数)来描述线条的虚实相间效果,第一个数字表示线条实线长度,第二个数字表示空白线条长度,依次类推循环。
至此,一个圆形svg进度环⭕️就完成了。
作者:MuMa