环形图

假设我们现在有一组数据:

var data = [
    {type: "苹果",number: 124}, 
    {type: "香蕉",number: 56},
    {type: "栗子",number: 310}
];

我们希望采用环形图来显示,最终的效果如下:

单一的情况

我们先不考虑边缘的提示文字和折线,只考虑中间的环形如何绘制。

首先,我们需要求解出数值的和,这样才能会绘制的时候知道每个环的占比:

var sum = 0;
for (var i = 0; i < data.length; i++) sum += data[i].number;

现在,就可以通过循环的方式一个个绘制圆环了:

// beginDeg表示当前绘制的环的开始弧度,我们从-0.5PI的地方开始绘制
var beginDeg = -Math.PI * 0.5, deg; 

for (var i = 0; i < data.length; i++) {
    // 计算占比和和2PI相乘得出当前环的弧度
    deg = data[i].number / sum * Math.PI * 2; 

    // 以(200, 200)为圆心,内外半径分别是100和200,从弧度beginDeg开始,绘制弧度deg的圆弧
    painter.fillArc(200, 200, 100, 200, beginDeg, deg);

    beginDeg += deg; // 计算下一个环的开始弧度
}
具体代码请看评论区的【代码一】

带提示折线文字

可以发现,折线和文字的绘制关键点在于每个圆弧对应的折线的那三个点的位置,关于位置的计算,我们借助rotate来计算。语法如下:

var dot = $$.rotate(cx, cy, deg, x, y);

点(x,y)围绕中心(cx,cy)旋转deg度,最后返回一个长度为2的一维数组,表示旋转后点的位置。

基于此,我们考虑如果有一个弧形的中心弧度恰好位于0度的情况。那么,连线的前两个点(第三个点基于第二个点就很容易得出了)就自然应该是:[cx+radius,cy]、[cx+radius+10,cy],这里假设每段的长度为10。

对应到具体的代码就是:

var beginDeg = -Math.PI * 0.5, deg;
for (var i = 0; i < data.length; i++) {
    deg = data[i].number / sum * Math.PI * 2;

    var dot1 = $$.rotate(cx, cy, beginDeg + deg * 0.5, cx + radius, cy);
    var dot2 = $$.rotate(cx, cy, beginDeg + deg * 0.5, cx + radius + 10, cy);

    beginDeg += deg;
}

而对于第三个点,经过观察可以发现:如果第二个位于圆心的右边,就是第二个点右移动10,否则左移动10。由此可得:

var dot3=[ dot2[0]>cx ? dot2[0]+10 : dot2[0]-10 , dot2[1] ];

由此得到了三个点的位置,对于折线而言,直接连接起来即可:

painter
    .beginPath()
    .moveTo(dot1[0], dot1[1]).lineTo(dot2[0], dot2[1])
    .lineTo(dot3[0], dot3[1])
    .stroke();

对于文字而言,直接在dot3的位置绘制即可,只不过,需要考虑到文字是左对齐还是右对齐,和第三个点的求法类似,直接看代码即可:

painter
    .config('textAlign' , dot2[0]>cx ? "left" : "right")
    .fillText(data[i].type, dot3[0], dot3[1]);
具体代码请看评论区的【代码二】

你好2007
179 声望4 粉丝

走一步,再走一步。