canvas双层复合饼图及点击效果的实现

众所周知,饼图在数据表达上起着至关重要的作用,它使数据更为直观,也更为清晰,所以对于业务需求方来说,能让用户一目了然看懂数据的,必然会采用饼图来表达。

当我们既想要表达数据的占比关系,又想表达某些数据之间的包含关系时,就要用到复合饼图了。

之前尝试过用Echart、Highcharts、Chart等框架,实现出的饼图较为美观,功能强大且容易上手,但要实现复合饼图,却总显的美中不足,以Echart为例,实现饼图只限于两种模式:

  • 'radius' 扇区圆心角展现数据的百分比,半径展现数据的大小。  
  • 'area' 所有扇区圆心角相同,仅通过半径展现数据大小。

 而我们的业务需求是:根据不同类型规定好圆心角角度(圆心角不相同),并根据各类型的实际份额与虚拟份额的占比显示半径的大小。

canvas双层复合饼图及点击效果的实现_第1张图片

由于框架的局限性,只能放弃框架纯手写一套实现业务需求,代码如下: 


实现逻辑:

1.首先 各类型radius半径相同,按规定角度画出浅色扇形代表虚拟份额各类型 ;

2.同样的方式,按照 实虚份额的占比*radius=实际份额的半径,绘制实际份额各类型;

3.添加点击事件,利用三角函数公式及点坐标位置判断是否在某一扇形内;

4.根据符合条件的扇形的索引,在重新绘图时,将此扇形的填充色更改,点击效果就做好了。

  

为了使饼图更加完善,小编经过不懈的努力钻研,在此基础上增加了指示线及文字说明功能;在draw()方法里调用pieLine()就可以了,效果图及代码:

canvas双层复合饼图及点击效果的实现_第2张图片

var endDeg = 0;
//指示线及文字说明
function pieLine(){
    for (var i = 0;i < nums.length; i ++){  
        ctx.beginPath();  
        var x = radius*Math.cos((endDeg+nums[i]/2)/180*Math.PI);
        var y = radius*Math.sin((endDeg+nums[i]/2)/180*Math.PI);
        // console.log("x="+x+"--y="+y);
        ctx.moveTo(x,y);
        var x1 = (radius+20)*Math.cos((endDeg+nums[i]/2)/180*Math.PI);
        var y1 = (radius+20)*Math.sin((endDeg+nums[i]/2)/180*Math.PI);
        ctx.lineTo(x1,y1);
        var x2 = (radius+20+20)*Math.cos((endDeg+nums[i]/2)/180*Math.PI);
        if(x1>0){
            x2 = x1+10;
        }else{
            x2 = x1-10;
        }
        ctx.lineTo(x2,y1);
        ctx.stroke();   //描边
        console.log(x2);
        //指示文字
        //计算文字宽度高度
        ctx.font = "12px scans-serif";  
        ctx.fillStyle = "#333";  
        var w = ctx.measureText(val[i]+"万").width > ctx.measureText(arrs[i]).width?ctx.measureText(val[i]+"万").width:ctx.measureText(arrs[i]).width;
        if(x2<0){
            x2 = x2-w;
        }
        ctx.fillText(arrs[i],x2,y1); 
        ctx.fillText(val[i]+"万",x2,y1+14); 
        endDeg += nums[i];  //起始角度 
    } 
}

 

你可能感兴趣的:(canvas画图)