d3.js同心环图 [英] d3.js concentric ring chart

查看:295
本文介绍了d3.js同心环图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在寻找一个弧形环图。



$

 如果数据多或少, //绘制标签
valueLabels = value_group.selectAll(text.value)。data(reversedata)
valueLabels.enter()。append(svg:text)
.attr class,value)
.attr(transform,function(d){
var rings = counts;

returntranslate radius + 55)/ rings +,0);
})
.attr(dx,function(d,i){
return 19 * i;})
.attr(dy,function(d,i){
return -5;
})
.attr(text-anchor,function(d){
returnstart;
})text(function(d){
return d.value;
});

valueLabels.transition()。duration(300).attrTween(d,arcTween)
valueLabels.exit()。remove


解决方案

我已经设法修复所有的错误 - 是最终的代码作为jquery插件,享受





http:// jsfiddle .net / NYEaX / 165 /

  $(document).ready(function(){


(function($){
var methods = {
el:,
init:function(options){
var clone = jQuery .extend(true,{},options [data]);
var preparedData = methods.setData(clone);

methods.el = this;
方法。 setup(prepareData,options [width],options [height]);
},
setup:function(data,w,h){

= methods.el [selector];

var padding = 20;


var chart = d3.select(selector).append(svg:svg)
.attr(class,chart)
。 attr(width,w)
.attr(height,h)
.append(svg:g)
.attr(class,concentricchart)
.attr(transform,translate(+((w / 3)+ padding)+,+ h / 3 +)

methods.radius = Math.min(w,h)/ 2;

var label_group = chart.append(svg:g)
.attr(class,label_group)
.attr(transform,translate +((w / 3)-15)+,+( - h / 4)+)

var legend_group = chart.append(svg:g)
.attr(class,legend_group)
.attr(transform,translate +((w / 3)-130)+,+(( - h / 4)-5)+

var value_group = chart.append(svg:g)
.attr(class,value_group)
.attr(transform,translate 0,+(h / 4)+));

var path_group = chart.append(svg:g)
.attr(class,path_group)
.attr(transform,translate 0,+(h / 4)+));


this.generateArcs(selector,data);
},
update:function(data){
var clone = jQuery.extend(true,{},data);

var preparedData = methods.setData(clone);

methods.el = this;
methods.animate(preparedData);
methods.oldData = preparedData;
},
animate:function(data){
var that = this;

var selector = methods.el [selector];

that.generateArcs(selector,data);
},
setData:function(data){
var diameter = 2 * Math.PI * this.radius;
var localData = new Array();

var segmentValueSum = 0;
$ .each(data [0] .segments,function(ri,va){
segmentValueSum + = va.value;
});

segmentValueSum = 200; //一致的总数跨越不同的数据集

$ .each(data [0] .segments,function(ri,value){
var segmentValue = value.value;

var fraction = segmentValue / segmentValueSum;

var arcBatchLength = fraction * 4 * Math.PI;
var arcPartition = arcBatchLength;

var startAngle = Math.PI / 2;
var endAngle = startAngle + arcPartition;

data [0] .segments [ri] [startAngle] = startAngle;
data [0] .segments [ri] [endAngle] = endAngle;
data [0] .segments [ri] [index] = ri;
} );

localData.push(data [0] .segments);

return localData [0];
},
textOffset:10,
generateArcs:function(selector,data){
var that = this;

var chart = d3.select(selector);

//将上一个值追加到它。
$ .each(data,function(index,value){
if(that.oldData [index]!= undefined){
data [index] [previousEndAngle] = oldData [index] .endAngle;
}
else {
data [index] [previousEndAngle] = 0;
}
}

var thickness = $(selector).data(thickness);
var ir =($(selector).data(width)/ 3);


var path_group = d3.select(selector +'.path_group');

var arcpaths = path_group.selectAll(path)
.data(data);

arcpaths.enter()。append(svg:path)
.attr(class,function(d,i){
return d.machineType;
})
.style(fill,function(d,i){
return d.color;
})
.transition()
.ease(elastic)
.duration(750)
.attrTween(d,function(d){
return that.arcTween(d,thickness,ir);
});

arcpaths.transition()
.ease(elastic)
.style(fill,function(d,i){
return d.color ;
})
.duration(750)
.attrTween(d,function(d){
return that.arcTween(d,thickness,ir);
});

arcpaths.exit()。transition()
.ease(bounce)
.duration(750)
.attrTween d){
return that.arcTween(d,thickness,ir);
})
.remove();

//绘制标签
that.drawLabels(chart,data,ir,thickness);
that.buildLegend(chart,data);
},
arcTween:function(b,thickness,ir){
var that = methods;

var prev = JSON.parse(JSON.stringify(b));
prev.endAngle = b.previousEndAngle;
var i = d3.interpolate(prev,b);

return function(t){
return that.getArc(thickness,ir)(i(t));
};
},
drawLabels:function(chart,data,ir,thickness){
$(methods.el [selector] +'.value_group')。

var that = this;

var reversedata = data.reverse();
var counts = data.length;

var value_group = d3.select(methods.el [selector] +'.value_group');

valueLabels = value_group.selectAll(text.value)。data(reversedata)
valueLabels.enter()。append(svg:text)
.attr class,value)
.attr(transform,function(d){
returntranslate(+(that.getRadiusRing(ir,counts-1))+ );
})
.attr(dx,function(d,i){
return 20 * i;})
.attr (d,i){
return -5;
})
.attr(text-anchor,function(d){
returnstart;
})。text(function(d){
return d.value;
});

valueLabels
.transition()
.duration(300)
.attrTween(d,function(d){
return that.arcTween (d,thickness,ir);
})

valueLabels
.exit()
.remove();
},
buildLegend:function(chart,data){
console.log(build legend);
$(methods.el [selector] +'.label_group')。empty();
$(methods.el [selector] +'.legend_group')。empty();


var label_group = d3.select(methods.el [selector] +'.label_group');

//绘制标签
labels = label_group.selectAll(text.labels)
.data(data.reverse());

labels.enter()。append(svg:text)
.attr(class,labels)
.attr d,i){
return 19 * i
})
.attr(text-anchor,function(d){
returnstart;
})
.text(function(d){
return d.label;
});

labels.exit()。remove();

var legend_group = d3.select(methods.el [selector] +'.legend_group');

legend = legend_group.selectAll(circle)。data(data);

legend.enter()。append(svg:circle)
.attr(cx,100)
.attr(cy i){
return 19 * i
})
.attr(r,7)
.attr(width,18)
.attr height,18)
.style(fill,function(d){
return d.color;
});

legend.exit()。remove();
},
getRadiusRing:function(ir,i){
return ir-(i * 20);
},
getArc:function(thick,ir){
var that = this;

var arc = d3.svg.arc()
.innerRadius(function(d){
return that.getRadiusRing(ir,d.index);
})
.outerRadius(function(d){
return that.getRadiusRing(ir + thickness,d.index);
})
.startAngle ){
return d.startAngle;
})
.endAngle(function(d,i){
return d.endAngle;
}
return arc;
},
radius:100,
oldData:
};

$ .fn.concentric = function(methodOrOptions){
if(methods [methodOrOptions]){
return methods [methodOrOptions] .apply(this,Array.prototype.slice .call(arguments,1));
} else if(typeof methodOrOptions ==='object'||!methodOrOptions){
//默认为init
return methods.init.apply(this,arguments)
} else {
$ .error('Method'+ methodOrOptions +'does not exist');
}
};

})(jQuery);




var dataCharts = [
{
data:[
{
segments :[
{
label:Turkey,
value:25,
color:red
},
{
label:United States,
value:40,
color:blue
},
{
label:Switzerland,
value:60,
color:green
},
{
label ,
value:80,
color:gold
}
]
}
]
} b $ b {
data:[
{
segments:[
{
label:Peanut Butter,
value:50,
color:red
},
{
label:Tea,
value:25,
color:orange
},
{
label:Cheese,
value:25,
color :purple
}
]
}
]
},
{
data:[
{
segments:[
{
label:Jam,
value:90,
color:purple
},
{
label:Lemons,
value:15,
color:brown
}
]
}
]
}
];

var clone = jQuery.extend(true,{},dataCharts);

// __ invoke concentric
$('[data-role =concentric]')每个函数(索引){
var selector =concetric ;

$(this).attr(id,selector);

var options = {
data:clone [0] .data,
width:$(this).data(width),
height:$(this).data(height)
}

$ + selector).concentric(options);
});


$(。testers a)。on(click,function(e){
e.preventDefault();

var clone = jQuery.extend(true,{},dataCharts);

var min = 0;
var max = 2;

// __ invoke concentric $每个函数(索引){
pos = Math.floor(Math.random()*(max - min + 1))+ b $ b $('[data-role =concentric min;
console.log(id,$(this).attr(id));
$(#+ $(this).attr(id))。同心('update',clone [pos] .data);
});

});

});


I am looking to develop an arc ring chart. Where each new set of data is displayed as a concentric ring inside the other.

http://jsfiddle.net/NYEaX/101/

I've tried to take a sum of the values in the data, and use this to help develop a proportion algorithm, to ensure each arc never does more than one cycle.

this part manages the concentric ring.

getArc: function(){
            var that = this;

            var radiusArray = [100, 80];

            function getRadiusRing(i){
                return that.radius-(i*20);              
            }
            var thickness = 15;

            var arc = d3.svg.arc()
                    .innerRadius(function(d){
                        return getRadiusRing(d.index);                      
                    })
                    .outerRadius(function(d){
                        return getRadiusRing(d.index)+thickness;    
                    })
                    .startAngle(function(d, i){
                        return d.startAngle;
                    })
                    .endAngle(function(d, i){
                        return d.endAngle;
                    });     
            return arc;
        }

but I think there is a flaw in the end angle calculations. If you enable more data - the concentric rings although they form correctly have suspicious arc lengths where they wrap around the entire chart?

setData: function(data){
            var diameter = 2 * Math.PI * this.radius;           
            var localData = new Array();

            var segmentValueSum = 0;
            $.each(data[0].segments, function( ri, va) {
                segmentValueSum+= va.value;
            });

            $.each(data[0].segments, function(ri, value) {

                var segmentValue = value.value;

                var fraction = segmentValue/segmentValueSum;

                var arcBatchLength = fraction*2*Math.PI;
                var arcPartition = arcBatchLength;      

                var startAngle = 0;
                var endAngle = ((ri+1)*arcPartition);               

                data[0].segments[ri]["startAngle"] = startAngle;
                data[0].segments[ri]["endAngle"] = endAngle;
                data[0].segments[ri]["index"] = ri;
            });

            localData.push(data[0].segments);

            return localData[0];        
        }


trying to build the chart to look like the following

I've enhanced the chart, but still have issues with the placement and updating of the legend, rings and values. Why is old data remaining? http://jsfiddle.net/NYEaX/123/

if there is more or less data - the labels don't get placed correctly

 //draw labels                      
            valueLabels = value_group.selectAll("text.value").data(reversedata)
            valueLabels.enter().append("svg:text")
            .attr("class", "value")
            .attr("transform", function(d) {
                var rings = counts;

                return "translate("+(that.radius+55)/rings+", 0)";
            })
             .attr("dx", function(d, i){
                return 19*i;            })
            .attr("dy", function(d, i){
                return -5;
            })
            .attr("text-anchor", function(d){
                return "start";
            }).text(function(d){
                return d.value;
            });

            valueLabels.transition().duration(300).attrTween("d", arcTween)
            valueLabels.exit().remove();   

解决方案

I've managed to fix all the bugs - Here is the final code as a jquery plugin, enjoy

http://jsfiddle.net/NYEaX/165/

$(document).ready(function() {


            (function( $ ){
                var methods = {
                    el: "",
                    init : function(options) {
                        var clone = jQuery.extend(true, {}, options["data"]);
                        var preparedData = methods.setData(clone);

                        methods.el = this;          
                        methods.setup(preparedData, options["width"], options["height"]);
                    },
                    setup: function(data, w, h){

                        var selector = methods.el["selector"];

                        var padding = 20;


                        var chart = d3.select(selector).append("svg:svg")
                            .attr("class", "chart")
                            .attr("width", w)
                            .attr("height", h)
                        .append("svg:g")
                            .attr("class", "concentricchart")
                            .attr("transform", "translate("+((w/3)+padding)+","+h/3+")");

                        methods.radius = Math.min(w, h) / 2;

                        var label_group = chart.append("svg:g")
                            .attr("class", "label_group")
                            .attr("transform", "translate("+((w/3)-15)+","+(-h/4)+")");

                        var legend_group = chart.append("svg:g")
                            .attr("class", "legend_group")
                            .attr("transform", "translate("+((w/3)-130)+","+((-h/4)-5)+")");

                        var value_group = chart.append("svg:g")
                            .attr("class", "value_group")
                            .attr("transform", "translate(0,"+(h/4)+")");

                        var path_group = chart.append("svg:g")
                            .attr("class", "path_group")
                            .attr("transform", "translate(0,"+(h/4)+")");               


                        this.generateArcs(selector, data);      
                    },
                    update: function(data){
                        var clone = jQuery.extend(true, {}, data);

                        var preparedData = methods.setData(clone);

                        methods.el = this;
                        methods.animate(preparedData);          
                        methods.oldData = preparedData;
                    },
                    animate: function(data){
                        var that = this;

                        var selector = methods.el["selector"];

                        that.generateArcs(selector, data);
                    },  
                    setData: function(data){
                            var diameter = 2 * Math.PI * this.radius;           
                            var localData = new Array();

                            var segmentValueSum = 0;
                            $.each(data[0].segments, function( ri, va) {
                                segmentValueSum+= va.value;
                            });

                            segmentValueSum = 200;//consistent total accross different data sets

                            $.each(data[0].segments, function(ri, value) {
                                var segmentValue = value.value;

                                var fraction = segmentValue/segmentValueSum;

                                var arcBatchLength = fraction*4*Math.PI;
                                var arcPartition = arcBatchLength;      

                                var startAngle = Math.PI/2;         
                                var endAngle = startAngle + arcPartition; 

                                data[0].segments[ri]["startAngle"] = startAngle;
                                data[0].segments[ri]["endAngle"] = endAngle;
                                data[0].segments[ri]["index"] = ri;
                            });

                            localData.push(data[0].segments);

                            return localData[0];        
                    },
                    textOffset: 10,
                    generateArcs: function(selector, data){
                        var that = this;

                        var chart = d3.select(selector);

                        //append previous value to it.          
                        $.each(data, function(index, value) {
                            if(that.oldData[index] != undefined){
                                data[index]["previousEndAngle"] = that.oldData[index].endAngle;
                            }
                            else{
                                data[index]["previousEndAngle"] = 0;
                            }
                        });     

                        var thickness = $(selector).data("thickness");
                        var ir = ($(selector).data("width")/3);


                        var path_group = d3.select(selector+ ' .path_group');

                        var arcpaths = path_group.selectAll("path")
                            .data(data);

                        arcpaths.enter().append("svg:path")
                            .attr("class", function(d, i){
                                return d.machineType;
                            })  
                            .style("fill", function(d, i){
                                return d.color;
                            })
                            .transition()
                            .ease("elastic")
                            .duration(750)
                            .attrTween("d", function(d){
                                 return that.arcTween(d, thickness, ir);
                            });      

                        arcpaths.transition()
                            .ease("elastic")
                            .style("fill", function(d, i){
                                return d.color;
                            })
                            .duration(750)
                            .attrTween("d", function(d){
                                 return that.arcTween(d, thickness, ir);
                            });      

                        arcpaths.exit().transition()
                            .ease("bounce")
                            .duration(750)
                            .attrTween("d", function(d){
                                 return that.arcTween(d, thickness, ir);
                            })   
                            .remove();

                        //draw labels       
                        that.drawLabels(chart, data, ir, thickness);
                        that.buildLegend(chart, data);
                    },
                    arcTween: function(b, thickness, ir){
                        var that = methods;

                        var prev = JSON.parse(JSON.stringify(b));
                        prev.endAngle = b.previousEndAngle;
                        var i = d3.interpolate(prev, b);

                        return function(t) {
                            return that.getArc(thickness, ir)(i(t));
                        };
                    },
                    drawLabels: function(chart, data, ir, thickness){
                        $(methods.el["selector"]+' .value_group').empty();

                        var that = this;

                        var reversedata = data.reverse();
                        var counts = data.length;

                        var value_group = d3.select(methods.el["selector"]+ ' .value_group');

                        valueLabels = value_group.selectAll("text.value").data(reversedata)
                        valueLabels.enter().append("svg:text")
                            .attr("class", "value")
                            .attr("transform", function(d) {       
                                return "translate("+(that.getRadiusRing(ir, counts-1))+", 0)";
                            })
                            .attr("dx", function(d, i){
                                return 20*i;            })
                            .attr("dy", function(d, i){
                                return -5;
                            })
                            .attr("text-anchor", function(d){
                                return "start";
                            }).text(function(d){
                                return d.value;
                            });

                        valueLabels
                            .transition()
                            .duration(300)
                            .attrTween("d", function(d){
                                return that.arcTween(d, thickness, ir);
                            })

                        valueLabels
                            .exit()
                            .remove();      
                    },
                    buildLegend: function(chart, data){
                        console.log("build legend");
                        $(methods.el["selector"]+' .label_group').empty();
                        $(methods.el["selector"]+' .legend_group').empty();


                        var label_group = d3.select(methods.el["selector"]+ ' .label_group');

                        //draw labels                       
                        labels = label_group.selectAll("text.labels")
                            .data(data.reverse());            

                        labels.enter().append("svg:text")
                            .attr("class", "labels")
                            .attr("dy", function(d, i){
                                return 19*i
                            })
                            .attr("text-anchor", function(d){
                                return "start";
                            })
                            .text(function(d){
                                return d.label;
                            });

                        labels.exit().remove();

                        var legend_group = d3.select(methods.el["selector"]+ ' .legend_group');

                        legend = legend_group.selectAll("circle").data(data);

                        legend.enter().append("svg:circle")
                            .attr("cx", 100)
                            .attr("cy", function(d, i){
                                return 19*i
                            })
                            .attr("r", 7)   
                            .attr("width", 18)
                            .attr("height", 18)
                            .style("fill", function(d){
                                return d.color;
                            });

                        legend.exit().remove();
                    },
                    getRadiusRing: function(ir, i){
                        return ir-(i*20);               
                    },
                    getArc: function(thickness, ir){
                        var that = this;

                        var arc = d3.svg.arc()
                            .innerRadius(function(d){
                                return that.getRadiusRing(ir, d.index);                     
                            })
                            .outerRadius(function(d){
                                return that.getRadiusRing(ir+thickness, d.index);   
                            })
                            .startAngle(function(d, i){
                                return d.startAngle;
                            })
                            .endAngle(function(d, i){
                                return d.endAngle;
                            });
                        return arc;
                    },
                    radius: 100,
                    oldData: ""
                };

                $.fn.concentric = function(methodOrOptions) {
                    if ( methods[methodOrOptions] ) {
                        return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
                    } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
                        // Default to "init"
                        return methods.init.apply( this, arguments );
                    } else {
                        $.error( 'Method ' +  methodOrOptions + ' does not exist' );
                    }    
                };

            })(jQuery);




            var dataCharts = [
                {
                    "data": [
                        {
                            "segments": [
                                {
                                    "label": "Turkey",
                                    "value": 25,
                                    "color": "red"
                                },
                                {
                                    "label": "United States",
                                    "value": 40,
                                    "color": "blue"                         
                                },
                                {
                                    "label": "Switzerland",
                                    "value": 60,
                                    "color": "green"                            
                                },
                                {
                                    "label": "Iceland",
                                    "value": 80,
                                    "color": "gold"
                                }                           
                            ]
                        }
                    ]
                },
                {
                    "data": [
                        {
                            "segments": [
                                {
                                    "label": "Peanut Butter",
                                    "value": 50,
                                    "color": "red"
                                },
                                {
                                    "label": "Tea",
                                    "value": 25,
                                    "color": "orange"                           
                                },
                                {
                                    "label": "Cheese",
                                    "value": 25,
                                    "color": "purple"                           
                                }                       
                            ]
                        }
                    ]
                } ,
                {
                    "data": [
                        {
                            "segments": [
                                {
                                    "label": "Jam",
                                    "value": 90,
                                    "color": "purple"
                                },
                                {
                                    "label": "Lemons",
                                    "value": 15,
                                    "color": "brown"                            
                                }                       
                            ]
                        }
                    ]
                }           
            ];

            var clone = jQuery.extend(true, {}, dataCharts);

                //__invoke concentric
                $('[data-role="concentric"]').each(function(index) {
                    var selector = "concetric"+index;

                    $(this).attr("id", selector);

                    var options = {
                        data: clone[0].data,
                        width: $(this).data("width"),
                        height: $(this).data("height")
                    }

                    $("#"+selector).concentric(options);
                });


            $(".testers a").on( "click", function(e) {
                e.preventDefault();

                var clone = jQuery.extend(true, {}, dataCharts);

                var min = 0;
                var max = 2;

                //__invoke concentric
                $('[data-role="concentric"]').each(function(index) {
                    pos = Math.floor(Math.random() * (max - min + 1)) + min;
                    console.log("id", $(this).attr("id"));
                    $("#"+$(this).attr("id")).concentric('update', clone[pos].data);
                });

            }); 

});

这篇关于d3.js同心环图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆