利用SVG实现表示百分比的圆环

6,793 阅读3分钟

前言

最近项目中有一个页面需要显示一个带有百分比的圆环,效果如下:

image

我在网上找了些资料后发现很多人都是用SVG实现的

实现步骤

最开始,我其实只找到了这么个demo,它只是实现了圆环的基本效果:

image

可我我要的圆角加渐变怎么办呢?于是又找找找,发现了两个重要属性能实现,圆角是靠stroke-linecap属性设为round就可以了,颜色渐变就负责一些了,直接上代码吧:

<defs>
              <linearGradient id='svg_1' x1='0%' y1='0%' x2='100%' y2='64.9%'>
                <stop offset='0%' stop-color='#f8cb9c' />
                <stop offset='50%' stop-color='#ef9383' />
                <stop offset='100%' stop-color='#ea7575' />
              </linearGradient>
            </defs>
<circle
              cx='90'
              cy='90'
              r='80'
              strokeWidth='12'
              stroke='url(#svg_1)'
              fill='none'
              stroke-linecap='round'
              transform='matrix(0,-1,1,0,0,180)'
              strokeDasharray={this.getRingPercent(resultObj.score, 80)}
            ></circle>

感觉有点像css的·keyframes`有木有,通过设置几个节点的颜色值从而达到一个渐变的效果。

最后总体说一些实现思路,实际上就是通过两个circle标签,一个现实的是底色的环,一个是变化的环,而这个根据数值变化的环主要是靠stroke-dasharray属性实现的:

stroke-dasharray 的两个值,一个表示虚线的长度,另一个表示虚线与虚线之间的间距,而间距之间是一片空白,所以图形从圆变成了圆弧。然而这好像和我们想象中的有点不一样,我们希望它是从右上方开始的。所以我们需要转换一下坐标系。

所以stroke-dasharray第一个值就是你要展示的圆弧长度,而第二个值就是圆弧的周长,这个都是可以换算出来的。

用react实现的完整代码如下:

<svg width='180' height='180' viewBox='0 0 180 180'>
            <defs>
              <linearGradient id='svg_1' x1='0%' y1='0%' x2='100%' y2='64.9%'>
                <stop offset='0%' stop-color='#f8cb9c' />
                <stop offset='50%' stop-color='#ef9383' />
                <stop offset='100%' stop-color='#ea7575' />
              </linearGradient>
            </defs>
            <circle
              cx='90'
              cy='90'
              r='80'
              strokeWidth='12'
              stroke='#3e2eae'
              fill='none'
            ></circle>
            <circle
              cx='90'
              cy='90'
              r='80'
              strokeWidth='12'
              stroke='url(#svg_1)'
              fill='none'
              stroke-linecap='round'
              transform='matrix(0,-1,1,0,0,180)'
              strokeDasharray={this.getRingPercent(resultObj.score, 80)}
            ></circle>
          </svg>

// 计算圆环长度数据
  getRingPercent = (percent, r) => {
    let perimeter = Math.PI * 2 * r; //周长
    return (percent / 100) * perimeter + ' ' + perimeter;
  };

目前实现的最终效果如下:

image

总结

其实这只是用SVG实现的一个很小的例子,后来无意中翻看像F2这种图形库时发现已经有现成的实现了,该是怪自己孤陋寡闻啊,哈哈,所以我相当于造了一个简单的轮子吧,毕竟我这个项目也只需要这个一个小图形,就引以整个库对性能也不好,他们那些库也无非是用SVG或者convas实现的,嗯,也只能这样安慰自己了,哈哈。

还是希望有机会多用用SVG和canvas吧,觉得这种矢量绘图还蛮有意思的,目前对SVG的api了解还不是很多,相当于照葫芦画瓢,用的多了对一些核心API理解多了应该会更得心应手一些!

参考