toolkit/javascript/d3/examples/bar/bar-hierarchy.html
changeset 47 c0b4a8b5a012
equal deleted inserted replaced
46:efd9c589177a 47:c0b4a8b5a012
       
     1 <!DOCTYPE html>
       
     2 <html>
       
     3   <head>
       
     4     <title>Hierarchical Bar Chart</title>
       
     5     <script type="text/javascript" src="../../d3.js"></script>
       
     6     <script type="text/javascript" src="../../d3.layout.js"></script>
       
     7     <style type="text/css">
       
     8 
       
     9 text {
       
    10   font: 10px sans-serif;
       
    11 }
       
    12 
       
    13 rect.background {
       
    14   fill: white;
       
    15 }
       
    16 
       
    17 .axis {
       
    18   shape-rendering: crispEdges;
       
    19 }
       
    20 
       
    21 .axis path, .axis line {
       
    22   fill: none;
       
    23   stroke: #000;
       
    24 }
       
    25 
       
    26     </style>
       
    27   </head>
       
    28   <body>
       
    29     <script type="text/javascript">
       
    30 
       
    31 var m = [20, 20, 20, 120], // top right bottom left
       
    32     w = 960 - m[1] - m[3], // width
       
    33     h = 500 - m[0] - m[2], // height
       
    34     x = d3.scale.linear().range([0, w]),
       
    35     y = 20, // bar height
       
    36     z = d3.scale.ordinal().range(["steelblue", "#ccc"]), // bar color
       
    37     duration = 750,
       
    38     delay = 25;
       
    39 
       
    40 var hierarchy = d3.layout.partition()
       
    41     .value(function(d) { return d.size; });
       
    42 
       
    43 var xAxis = d3.svg.axis()
       
    44     .scale(x)
       
    45     .orient("top");
       
    46 
       
    47 var svg = d3.select("body").append("svg:svg")
       
    48     .attr("width", w + m[1] + m[3])
       
    49     .attr("height", h + m[0] + m[2])
       
    50   .append("svg:g")
       
    51     .attr("transform", "translate(" + m[3] + "," + m[0] + ")");
       
    52 
       
    53 svg.append("svg:rect")
       
    54     .attr("class", "background")
       
    55     .attr("width", w)
       
    56     .attr("height", h)
       
    57     .on("click", up);
       
    58 
       
    59 svg.append("svg:g")
       
    60     .attr("class", "x axis");
       
    61 
       
    62 svg.append("svg:g")
       
    63     .attr("class", "y axis")
       
    64   .append("svg:line")
       
    65     .attr("y1", "100%");
       
    66 
       
    67 d3.json("../data/flare.json", function(root) {
       
    68   hierarchy.nodes(root);
       
    69   x.domain([0, root.value]).nice();
       
    70   down(root, 0);
       
    71 });
       
    72 
       
    73 function down(d, i) {
       
    74   if (!d.children || this.__transition__) return;
       
    75   var end = duration + d.children.length * delay;
       
    76 
       
    77   // Mark any currently-displayed bars as exiting.
       
    78   var exit = svg.selectAll(".enter").attr("class", "exit");
       
    79 
       
    80   // Entering nodes immediately obscure the clicked-on bar, so hide it.
       
    81   exit.selectAll("rect").filter(function(p) { return p === d; })
       
    82       .style("fill-opacity", 1e-6);
       
    83 
       
    84   // Enter the new bars for the clicked-on data.
       
    85   // Per above, entering bars are immediately visible.
       
    86   var enter = bar(d)
       
    87       .attr("transform", stack(i))
       
    88       .style("opacity", 1);
       
    89 
       
    90   // Have the text fade-in, even though the bars are visible.
       
    91   // Color the bars as parents; they will fade to children if appropriate.
       
    92   enter.select("text").style("fill-opacity", 1e-6);
       
    93   enter.select("rect").style("fill", z(true));
       
    94 
       
    95   // Update the x-scale domain.
       
    96   x.domain([0, d3.max(d.children, function(d) { return d.value; })]).nice();
       
    97 
       
    98   // Update the x-axis.
       
    99   svg.selectAll(".x.axis").transition().duration(duration).call(xAxis);
       
   100 
       
   101   // Transition entering bars to their new position.
       
   102   var enterTransition = enter.transition()
       
   103       .duration(duration)
       
   104       .delay(function(d, i) { return i * delay; })
       
   105       .attr("transform", function(d, i) { return "translate(0," + y * i * 1.2 + ")"; });
       
   106 
       
   107   // Transition entering text.
       
   108   enterTransition.select("text").style("fill-opacity", 1);
       
   109 
       
   110   // Transition entering rects to the new x-scale.
       
   111   enterTransition.select("rect")
       
   112       .attr("width", function(d) { return x(d.value); })
       
   113       .style("fill", function(d) { return z(!!d.children); });
       
   114 
       
   115   // Transition exiting bars to fade out.
       
   116   var exitTransition = exit.transition()
       
   117       .duration(duration)
       
   118       .style("opacity", 1e-6)
       
   119       .remove();
       
   120 
       
   121   // Transition exiting bars to the new x-scale.
       
   122   exitTransition.selectAll("rect").attr("width", function(d) { return x(d.value); });
       
   123 
       
   124   // Rebind the current node to the background.
       
   125   svg.select(".background").data([d]).transition().duration(end); d.index = i;
       
   126 }
       
   127 
       
   128 function up(d) {
       
   129   if (!d.parent || this.__transition__) return;
       
   130   var end = duration + d.children.length * delay;
       
   131 
       
   132   // Mark any currently-displayed bars as exiting.
       
   133   var exit = svg.selectAll(".enter").attr("class", "exit");
       
   134 
       
   135   // Enter the new bars for the clicked-on data's parent.
       
   136   var enter = bar(d.parent)
       
   137       .attr("transform", function(d, i) { return "translate(0," + y * i * 1.2 + ")"; })
       
   138       .style("opacity", 1e-6);
       
   139 
       
   140   // Color the bars as appropriate.
       
   141   // Exiting nodes will obscure the parent bar, so hide it.
       
   142   enter.select("rect")
       
   143       .style("fill", function(d) { return z(!!d.children); })
       
   144     .filter(function(p) { return p === d; })
       
   145       .style("fill-opacity", 1e-6);
       
   146 
       
   147   // Update the x-scale domain.
       
   148   x.domain([0, d3.max(d.parent.children, function(d) { return d.value; })]).nice();
       
   149 
       
   150   // Update the x-axis.
       
   151   svg.selectAll(".x.axis").transition().duration(duration).call(xAxis);
       
   152 
       
   153   // Transition entering bars to fade in over the full duration.
       
   154   var enterTransition = enter.transition()
       
   155       .duration(end)
       
   156       .style("opacity", 1);
       
   157 
       
   158   // Transition entering rects to the new x-scale.
       
   159   // When the entering parent rect is done, make it visible!
       
   160   enterTransition.select("rect")
       
   161       .attr("width", function(d) { return x(d.value); })
       
   162       .each("end", function(p) { if (p === d) d3.select(this).style("fill-opacity", null); });
       
   163 
       
   164   // Transition exiting bars to the parent's position.
       
   165   var exitTransition = exit.selectAll("g").transition()
       
   166       .duration(duration)
       
   167       .delay(function(d, i) { return i * delay; })
       
   168       .attr("transform", stack(d.index));
       
   169 
       
   170   // Transition exiting text to fade out.
       
   171   exitTransition.select("text")
       
   172       .style("fill-opacity", 1e-6);
       
   173 
       
   174   // Transition exiting rects to the new scale and fade to parent color.
       
   175   exitTransition.select("rect")
       
   176       .attr("width", function(d) { return x(d.value); })
       
   177       .style("fill", z(true));
       
   178 
       
   179   // Remove exiting nodes when the last child has finished transitioning.
       
   180   exit.transition().duration(end).remove();
       
   181 
       
   182   // Rebind the current parent to the background.
       
   183   svg.select(".background").data([d.parent]).transition().duration(end);;
       
   184 }
       
   185 
       
   186 // Creates a set of bars for the given data node, at the specified index.
       
   187 function bar(d) {
       
   188   var bar = svg.insert("svg:g", ".y.axis")
       
   189       .attr("class", "enter")
       
   190       .attr("transform", "translate(0,5)")
       
   191     .selectAll("g")
       
   192       .data(d.children)
       
   193     .enter().append("svg:g")
       
   194       .style("cursor", function(d) { return !d.children ? null : "pointer"; })
       
   195       .on("click", down);
       
   196 
       
   197   bar.append("svg:text")
       
   198       .attr("x", -6)
       
   199       .attr("y", y / 2)
       
   200       .attr("dy", ".35em")
       
   201       .attr("text-anchor", "end")
       
   202       .text(function(d) { return d.name; });
       
   203 
       
   204   bar.append("svg:rect")
       
   205       .attr("width", function(d) { return x(d.value); })
       
   206       .attr("height", y);
       
   207 
       
   208   return bar;
       
   209 }
       
   210 
       
   211 // A stateful closure for stacking bars horizontally.
       
   212 function stack(i) {
       
   213   var x0 = 0;
       
   214   return function(d) {
       
   215     var tx = "translate(" + x0 + "," + y * i * 1.2 + ")";
       
   216     x0 += x(d.value);
       
   217     return tx;
       
   218   };
       
   219 }
       
   220 
       
   221     </script>
       
   222   </body>
       
   223 </html>