SVG绘制环形进度条

Fw恶龙

莫里兹·柯尼利斯·艾雪-天鹅

原文地址:https://segmentfault.com/a/1190000021878369
作者:Fw恶龙
本文首发于:思否

一、需求

  1. 根据0-1百分比显示进度条;
  2. 进度条需要有间隔;
  3. 进度条样式需要发光;

需求图.jpg

二、绘制进度条

方案一:使用path绘制圆弧

  1. 根据百分比(per),计算终点坐标:

    var deg = 2 * Math.PI * per + Math.PI / 2;  // 该百分比对应的角度
    var y = Math.sin(deg) * this.data.radius + this.data.center.y;  // 利用正弦函数计算出坐标值y
    var x = Math.cos(deg) * this.data.radius + this.data.center.x;  // 利用余弦函数计算出坐标值x
  2. 根据百分比(per),求得需要绘制的是大角弧(1),还是小角弧(0),需要注意的是在绘制100%的圆弧即圆时,需要分成两段弧来绘制,即先绘制一个半圆,再绘制另一个半圆:

    if (per >= 0 && per <= 0.5) {
        this.data.laf = 0;
    } else if (per > 0.5 && per < 1) {
        this.data.laf = 1;
    }
  3. 根据高亮部分与间隔部分所占百分比,设置stroke-dasharray属性(对于有需求2的需要这步操作):

    this.data.perimeter = 2 * Math.PI * this.data.radius;   // 圆形周长
    $().css('stroke-dasharray', this.data.perStart * this.data.perimeter + " " + this.data.perEnd * this.data.perimeter);

方案二:使用circle绘制圆,配合stroke-dasharray属性绘制进度条效果

  1. 根据百分比(per),计算stroke-dasharray对应的值:

    this.data.perimeter = 2 * Math.PI * this.data.radius;   // 圆形周长
    $().css('stroke-dasharray', this.data.perLen + " " + (this.data.perimeter - this.data.perLen););

    无间隔.jpg

  2. 根据百分比(per),计算stroke-dasharray对应的值(对于有需求2的需要这步操作):

    this.perStartLen = this.data.perimeter * this.data.perStart;// 高亮部分长度
    this.perEndLen = this.data.perimeter * this.data.perEnd;    // 间隔部分长度
    
    for(var i = 0; this.data.perLen > 0; i++) {
        if(i%2 == 0) {  // 向stroke-dasharray添加高亮部分长度
            if(this.data.perLen <= this.perStartLen) {  // 若当前百分比落在高亮区域,则该间隔加上剩余的进度条高亮长度
                this.data.strokeDasharray += this.data.perLen + ' ' + this.data.perLenRemain;
                this.data.perLen -=  this.data.perLen;
            } else {                                    // 否则,向stroke-dasharray添加间隔部分长度this.perStartLen
                this.data.strokeDasharray += this.perStartLen + ' ';
                this.data.perLen -=  this.perStartLen;
            }
        } else {        // 向stroke-dasharray添加间隔部分长度
            if(this.data.perLen <= this.perEndLen) {    // 若当前百分比落在间隔区域,则该间隔加上剩余的进度条长度
                this.data.strokeDasharray += (this.data.perLen + this.data.perLenRemain) + ' ';
                this.data.perLen -=  this.data.perLen;
            } else {                                    // 否则,向stroke-dasharray添加间隔部分长度this.perEndLen
                this.data.strokeDasharray += this.perEndLen + ' ';
                this.data.perLen -=  this.perEndLen;
            }
        }
    }

    有间隔.jpg

  3. 需要注意的是,对于没有需求2的进度条,可以为进度条添加动画效果;而对于有需求2的进度条动画效果未达到预期,有待深入研究;

三、添加样式

  1. 外发光

    <svg id="cw_svg" filter="url(#f1)">
    <defs>
        <filter id="f1">
            <feGaussianBlur result="blurOut" in="SourceGraphic" stdDeviation="6" />
            <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
        </filter>
    </defs>
  2. 旋转svg容器:由于起点位置根据需求不同会在不同位置,这个角度计算不写在js里。

四、示例(源代码)

阅读 2.1k

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视。

191 声望
11 粉丝
0 条评论

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视。

191 声望
11 粉丝
文章目录
宣传栏