D3.js之饼图动画2

上篇只是说了饼图的从无到有的旋转动画,这次来说说怎么给饼图添加外接注释加连线,以及数据更新的动画。

虽然d3.js写的麻烦,我看了几天echart,发现只要套套模板更改一下参数就行,但是d3可塑性很高,完全由你想象,想怎么画就怎么画。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>头疼</title>
</head>
<style type="text/css">
    
    button{
        position: absolute;
        margin: 10px;
    }
</style>
<body>
    <button οnclick="changeData()">更换数据</button>
    <script type="text/javascript" src='../js/d3.js'></script>
    <script type="text/javascript">
        var width = 500+100;
        var height = 500;
        
        var dataset=[["标签1",30],["标签2",20],["标签3",43],["标签4",55],["标签5",13]];
        
        var outerRadius = 150; //外半径
            var innerRadius = 0; //内半径,为0则中间没有空白
        var arc = d3.svg.arc() //弧生成器
                .innerRadius(innerRadius) //设置内半径
                .outerRadius(outerRadius); //设置外半径
        var color = d3.scale.category20();//构造20种颜色的序数比例尺,索引值可以是字符串或数字
        var pie = d3.layout.pie()   //饼图布局
            .sort(null)             //不排序,不写则会从大到小,顺时针排序。
            .value(function(d){  return d[1]});     //设置value值为上面的2二维数组中的数字
        var piedata=pie(dataset);
        var svg = d3.select("body")             //添加一个svg并且设置宽高
                .append("svg")
                .attr("width", width)
                .attr("height", height);

         var arcs=svg.selectAll(".arc")             
            .data(piedata) //返回是pie(data0)
            .enter().append("g")
            .attr("class", "arc")
            .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")   //将圆心平移到svg的中心
            .append("path")
            .attr("fill", function(d, i) {
                return color(i);            //根据下标填充颜色
            })
            .attr("d", function(d, i) {
                return arc(d);              ///调用上面的弧生成器
            });

         var text=svg.selectAll(".text")
            .data(piedata) //返回是pie(data0)
            .enter().append("g")
            .attr("class", "text")
            .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
            .append("text")
            .style('text-anchor', function(d, i) {
                //根据文字在是左边还是右边,在右边文字是start,文字默认都是start。
                return (d.startAngle + d.endAngle)/2 < Math.PI ? 'start' : 'end';
            })
            .attr('transform', function(d, i) {
                var pos = arc.centroid(d);      //centroid(d)计算弧中心
                pos[0]=outerRadius*((d.startAngle+d.endAngle)/2<Math.PI?1.4:-1.4)
                pos[1]*=2.1;                    //将文字移动到外面去。
                return 'translate(' + pos + ')';
            })
            .attr("dy",".3em")              //将文字向下便宜.3em
            .text(function(d) {             //设置文本
                return d.data[0];   
            })

         var text2=svg.selectAll(".text2")
            .data(piedata) //返回是pie(data0)
            .enter().append("g")
            .attr("class", "text")
            .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
            .append("text")
            .style('text-anchor',"middle")
            .attr('transform', function(d, i) {
                var pos = arc.centroid(d);          //将数字放在圆弧中心
                return 'translate(' + pos + ')';
            })
            .text(function(d) {
                return d.data[1];
            })
             var line = svg.selectAll(".line")      //添加文字和弧之间的连线
                .data(piedata) //返回是pie(data0)
                .enter().append("g")
                .attr("class", "line")
                .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
                .append("polyline")
                .attr('points', function(d, i) {
                    var pos1= arc.centroid(d),pos2= arc.centroid(d),pos3= arc.centroid(d);
                    pos1[0]*=2,pos1[1]*=2;
                    pos2[0]*=2.1,pos2[1]*=2.1
                    pos3[0]=outerRadius*((d.startAngle+d.endAngle)/2<Math.PI?1.4:-1.4)
                    pos3[1]*=2.1;
                    //pos1表示圆弧的中心边缘位置,pos2是网上稍微去了一下,pos3就是将pos2平移后得到的位置
                    //三点链接在一起就成了线段。
                    return [pos1,pos2,pos3];
                })
                .style('fill', 'none')
                .style('stroke',function(d,i){
                    return color(i);
                })
                .style('stroke-width', "3px")
                .style('stroke-dasharray',"5px")

             var label=svg.selectAll('.label')      //添加右上角的标签
                    .data(piedata)
                    .enter()
                    .append('g')
                    .attr("transform","translate("+(width-50)+","+10+")")
                    ;   
                label.append('rect')        //标签中的矩形
                    .style('fill',function(d,i){
                        return color(i);
                    })
                    .attr('x',function(d,i){
                        return 0;
                    })
                    .attr("y",function(d,i){
                        return 10+i*30;
                    })
                    .attr('rx','5')     //rx=ry 会出现圆角
                    .attr('ry','5')
                    .attr('width',50)
                    .attr('height',20)
                    ;
                label.append('text')            //标签中的文字
                    .attr('x',function(d,i){
                        return 25;              //因为rect宽度是50,所以把文字偏移25,在后面再将文字设置居中
                    })
                    .attr("y",function(d,i){        
                        return 15+10+i*30;
                    })
                    .text(function(d){
                        return d.data[0];
                    })
                    .style({
                        "font-size":"10px",
                        "text-anchor":"middle",
                        'fill':"white",
                        "font-weight":600
                    })
            function changeData(){
                random()
                var pie2=pie(dataset);
                piedata.forEach(function(d,i){
                    d.laststartAngle=d.startAngle;
                    d.lastendAngle=d.endAngle;
                    d.startAngle=pie2[i].startAngle;
                    d.endAngle=pie2[i].endAngle;
                })
                arcs.data(piedata)
                    .transition().duration(800)
                    .attrTween("d", tweenArc(function(d, i) {
                    return {
                        startAngle: d.laststartAngle,
                        endAngle: d.lastendAngle,
                    };
                }))
                text.data(piedata)
                    .transition().duration(800)
                    .style('text-anchor', function(d, i) {
                        //圆的中心位置在哪里,在右边文字是start
                        return (d.startAngle + d.endAngle)/2 < Math.PI ? 'start' : 'end';
                    })
                    .attr('transform', function(d, i) {
                        console.log(d);
                        var pos = arc.centroid(d);
                        pos[0] = outerRadius * ((d.startAngle + d.endAngle)/2 < Math.PI ? 1.4 : -1.4)
                        pos[1] *= 2;
                        return 'translate(' + pos + ')';
                    });
                text2.data(piedata)
                    .transition().duration(800)
                    .attr('transform', function(d, i) {
                        var pos = arc.centroid(d);
                        return 'translate(' + pos + ')';
                    }).text(function(d) {
                        return d.data[1];
                    });
                line.data(piedata)
                    .transition().duration(800)
                    .attr('points', function(d, i) {
                    var pos1= arc.centroid(d),pos2= arc.centroid(d),pos3= arc.centroid(d);
                    pos1[0]*=2,pos1[1]*=2;
                    pos2[0]*=2.1,pos2[1]*=2.1
                    pos3[0]=outerRadius*((d.startAngle+d.endAngle)/2<Math.PI?1.4:-1.4)
                    pos3[1]*=2.1;
                    console.log(pos1);
                    return [pos1,pos2,pos3];
                })
            }
             function random(){
                    var n=5;
                    while(n--){dataset[n][1]=Math.floor(Math.random()*40+10)}
                }
             function tweenArc(b) {
                return function(a, i) {
                    var d = b.call(this, a, i),
                        i = d3.interpolate(d, a);
                    return function(t) {
                        return arc(i(t));
                    };
                };
             }
    </script>
</body>
</html>

上面只是图片,大家可以粘贴代码来运行一下。


可以点击上面的更新数据来实现饼图动画。d3.js还是很神奇的,有好多想法,尤其是看了官网好多非常酷炫的例子。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值