D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
adewes
Full window
Github gist
Hierarchical Pie Chart
<!DOCTYPE html> <html> <meta charset="utf-8" /> <style> html { font-family: Century Gothic, Arial, Helvetica; font-size:1em; } body { padding:10px; } form { } #code_hierarchy { position:relative; width:600px; margin:0 auto; } #code_hierarchy_legend { height:100px; font-size:1.4em; text-align:center; } </style> <head> <script src="https://d3js.org/d3.v3.js"></script> <script lang="text/javascript"> function init_code_hierarchy_plot(element_id,data,count_function,color_function,title_function,legend_function) { var plot = document.getElementById(element_id); while (plot.hasChildNodes()) { plot.removeChild(plot.firstChild); } var width = plot.offsetWidth; var height = width; var x_margin = 40; var y_margin = 40; var max_depth=3; var data_slices = []; var max_level = 4; var svg = d3.select("#"+element_id).append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + width / 2 + "," + height * .52 + ")"); function process_data(data,level,start_deg,stop_deg) { var name = data[0]; var total = count_function(data); var children = data[2]; var current_deg = start_deg; if (level > max_level) { return; } if (start_deg == stop_deg) { return; } data_slices.push([start_deg,stop_deg,name,level,data[1]]); for (var key in children) { child = children[key]; var inc_deg = (stop_deg-start_deg)/total*count_function(child); var child_start_deg = current_deg; current_deg+=inc_deg; var child_stop_deg = current_deg; var span_deg = child_stop_deg-child_start_deg; process_data(child,level+1,child_start_deg,child_stop_deg); } } process_data(data,0,0,360./180.0*Math.PI); var ref = data_slices[0]; var next_ref = ref; var last_refs = []; var thickness = width/2.0/(max_level+2)*1.1; var arc = d3.svg.arc() .startAngle(function(d) { if(d[3]==0){return d[0];}return d[0]+0.01; }) .endAngle(function(d) { if(d[3]==0){return d[1];}return d[1]-0.01; }) .innerRadius(function(d) { return 1.1*d[3]*thickness; }) .outerRadius(function(d) { return (1.1*d[3]+1)*thickness; }); var slices = svg.selectAll(".form") .data(function(d) { return data_slices; }) .enter() .append("g"); slices.append("path") .attr("d", arc) .attr("id",function(d,i){return element_id+i;}) .style("fill", function(d) { return color_function(d);}) .attr("class","form"); slices.on("click",animate); if (title_function != undefined) { slices.append("svg:title") .text(title_function); } if (legend_function != undefined) { slices.on("mouseover",update_legend) .on("mouseout",remove_legend); var legend = d3.select("#"+element_id+"_legend") function update_legend(d) { legend.html(legend_function(d)); legend.transition().duration(200).style("opacity","1"); } function remove_legend(d) { legend.transition().duration(1000).style("opacity","0"); } } function get_start_angle(d,ref) { if (ref) { var ref_span = ref[1]-ref[0]; return (d[0]-ref[0])/ref_span*Math.PI*2.0 } else { return d[0]; } } function get_stop_angle(d,ref) { if (ref) { var ref_span = ref[1]-ref[0]; return (d[1]-ref[0])/ref_span*Math.PI*2.0 } else { return d[0]; } } function get_level(d,ref) { if (ref) { return d[3]-ref[3]; } else { return d[3]; } } function rebaseTween(new_ref) { return function(d) { var level = d3.interpolate(get_level(d,ref),get_level(d,new_ref)); var start_deg = d3.interpolate(get_start_angle(d,ref),get_start_angle(d,new_ref)); var stop_deg = d3.interpolate(get_stop_angle(d,ref),get_stop_angle(d,new_ref)); var opacity = d3.interpolate(100,0); return function(t) { return arc([start_deg(t),stop_deg(t),d[2],level(t)]); } } } var animating = false; function animate(d) { if (animating) { return; } animating = true; var revert = false; var new_ref; if (d == ref && last_refs.length > 0) { revert = true; last_ref = last_refs.pop(); } if (revert) { d = last_ref; new_ref = ref; svg.selectAll(".form") .filter( function (b) { if (b[0] >= last_ref[0] && b[1] <= last_ref[1] && b[3] >= last_ref[3]) { return true; } return false; } ) .transition().duration(1000).style("opacity","1").attr("pointer-events","all"); } else { new_ref = d; svg.selectAll(".form") .filter( function (b) { if (b[0] < d[0] || b[1] > d[1] || b[3] < d[3]) { return true; } return false; } ) .transition().duration(1000).style("opacity","0").attr("pointer-events","none"); } svg.selectAll(".form") .filter( function (b) { if (b[0] >= new_ref[0] && b[1] <= new_ref[1] && b[3] >= new_ref[3]) { return true; } return false; } ) .transition().duration(1000).attrTween("d",rebaseTween(d)); setTimeout(function(){ animating = false; if (! revert) { last_refs.push(ref); ref = d; } else { ref = d; } },1000); }; } function init_plots() { function count_function(d) { return d[1][0]; } function label_function(d) { return d[2]+": "+d[4][0]+" characters, "+d[4][1]+" lines of code."; } function legend_function(d) { return "<h2>"+d[2]+" </h2><p>"+d[4][0]+" characters, "+d[4][1]+" lines of code.</p>" } var color = d3.scale.category20c(); function color_function(d) { return color(d[2]); } d3.select(self.frameElement).style("height", "800px"); init_code_hierarchy_plot("code_hierarchy",code_hierarchy_data,count_function,color_function,label_function,legend_function); } window.onload = init_plots; window.onresize = init_plots; </script> <script type="text/javascript" src="data.js"></script> </head> <body> <p>Click on a segment to get a zoomed-in view of its children.<br />Check out the full example <a href="https://www.andreas-dewes.de/code_is_beautiful" target="_blank">here</a>.</p> <div id="code_hierarchy_legend"> </div> <div id="code_hierarchy"> </div> </body> </html>
Modified
http://d3js.org/d3.v3.js
to a secure url
https://d3js.org/d3.v3.js