之前写过一篇CSS3的饼图全面解析,这次给大家分享一个SVG实现饼图的全面解析。
既然是绘制饼图,那么显然需要绘制圆形。
// 一个简单的圆形,具有一定宽度的描边。 <svg width="100px" height="100px" viewBox="0 0 100 100"> <circle r="30" cx="50" cy="50" fill="yellowgreen" stroke="#655" stroke-width="30" /> </svg>
描边刚好是从半径30的位置开始左右两边平均各分配15px的宽度,这样整个圆形看起来就像是45px的半径宽度。
于是,如果我们将描边的宽度设置为半径的两倍,那么整个圆都会被描边所覆盖。
接着利用stroke-dasharray这个属性设置描边的点划线的图案范式,也就是指定短划线和缺口的长度。取值是一个数列,使用逗号或空格分开,依次表示短划线的长度,缺口的长度。
// 设置描边宽度为半径的两倍,同时指定stroke-dasharray属性 <svg width="100px" height="100px" viewBox="0 0 100 100"> <circle r="25" cx="50" cy="50" fill="yellowgreen" stroke="#655" stroke-width="50" stroke-dasharray="20 10"/> </svg>
此时,如果我们将第二个值(缺口的长度)设置为整个描边的长度,那么第一个值(短划线的长度)就变的有意义了,可以用它来表示百分比。从而实现饼图。
// 圆的半径为25 周长2*PI*R=158 那么stroke-dasharray的第二个值就设置为158 <svg width="100px" height="100px" viewBox="0 0 100 100"> <circle r="25" cx="50" cy="50" fill="yellowgreen" stroke="#655" stroke-width="50" stroke-dasharray="16 158"/> </svg>
16/158刚好约等于10%,由实际效果图也能看出来。
但是这里有个小问题,那就是描边都是从0度开始的,怎么将起始点移动到圆的最上方呢?那就是利用变换,也就是rotate旋转。将svg元素的世界坐标轴进行逆时针方向90度旋转即可。
最后给circle这个元素加上一个CSS3动画(当然也可以考虑使用SMIL动画)就可以实现饼图百分比从0到100的动画效果了。
// stroke-dasharray属性的第一个值从0变化到158 <svg width="100px" height="100px" viewBox="0 0 100 100"> <circle r="25" cx="50" cy="50" fill="yellowgreen" stroke="#655" stroke-width="50" stroke-dasharray="0 158"/> </svg>
@keyframes fillup{ to{ stroke-dasharray: 158 158; } } svg{ transform: rotate(-90deg); background: yellowgreen; border-radius: 50%; }circle{ animation: fillup 5s linear infinite;}
直接看效果图即可:
@keyframes fillup{
to{
stroke-dasharray: 158 158;
}
}
.pie{
transform: rotate(-90deg);
background: yellowgreen;
border-radius: 50%;
}
.pie-part{
animation: fillup 5s linear infinite;
}
拔高篇
如何给饼图添加第三种颜色呢?
这时候就要派出另外一个stroke系列属性: stroke-dashoffset
stroke-dashoffset这个属性是用来指定stroke-dasharray属性中短划线的偏移量。
先上一个简单的小案例
<svg width="100px" height="100px" viewBox="0 0 100 100"> <rect x="0" y="0" width="100" height="100" fill="#123456" stroke="#ccc" stroke-width="0.5"/> <line x1="0" y1="50" x2="100" y2="50" stroke="#fff" stroke-width="1" stroke-dasharray="10 5" /> </svg>
<svg width="100px" height="100px" viewBox="0 0 100 100"> <rect x="0" y="0" width="100" height="100" fill="#123456" stroke="#ccc" stroke-width="0.5"/> <line x1="0" y1="50" x2="100" y2="50" stroke="#fff" stroke-width="1" stroke-dasharray="10 5" stroke-dashoffset="-5" /> </svg>
<svg width="100px" height="100px" viewBox="0 0 100 100"> <rect x="0" y="0" width="100" height="100" fill="#123456" stroke="#ccc" stroke-width="0.5"/> <line x1="0" y1="50" x2="100" y2="50" stroke="#fff" stroke-width="1" stroke-dasharray="10 5" stroke-dashoffset="5" /> </svg>
效果图如下,可见当stroke-dashoffset设置为负数时,点划线的位置会后移,而设置为正数时,点划线的位置会前移。
那么利用这个特性,我们完全可以在svg中绘制多个圆形,每个圆形根据各自的百分比数设置对应的stroke-dasharray属性的第一个属性值。而将stroke-dashoffset设置为前面已有百分比的数值总和的负数。还需要注意一点的就是后面覆盖的圆必须设置fill=none 其实第一个圆也可以不用设置fill颜色,因为整个画布已经fill了一种颜色。
<svg width="100px" height="100px" viewBox="0 0 100 100"> <circle r="25" cx="50" cy="50" fill="none" stroke="#f00" stroke-width="50" stroke-dasharray="16 158" /> <circle r="25" cx="50" cy="50" fill="none" stroke="#0f0" stroke-width="50" stroke-dasharray="48 158" stroke-dashoffset="-16"/> <circle r="25" cx="50" cy="50" fill="none" stroke="#00f" stroke-width="50" stroke-dasharray="79 158" stroke-dashoffset="-64"/> </svg>
总结篇
其实实现饼图效果的方案无非就是CSS3,Canvas,SVG。如果是报表应用,那完全可以用Canvas来实现,而且现成的CanvasJS库也非常多: chart.js, echart.js, c3.js d3.js等等。
而如果是显示饼图动画loading效果,那可以用SVG来简单处理,甚至很容易给饼图添加多种颜色。CSS3实现饼图loading效果则还需要一定的数学计算。当然SVG也有现成的库,也可以用来绘制报表应用。