toolkit/javascript/d3/examples/showreel/showreel.html
changeset 47 c0b4a8b5a012
equal deleted inserted replaced
46:efd9c589177a 47:c0b4a8b5a012
       
     1 <!DOCTYPE html>
       
     2 <html>
       
     3   <head>
       
     4     <script type="text/javascript" src="../../d3.js"></script>
       
     5     <script type="text/javascript" src="../../d3.csv.js"></script>
       
     6     <script type="text/javascript" src="../../d3.geo.js"></script>
       
     7     <script type="text/javascript" src="../../d3.geom.js"></script>
       
     8     <script type="text/javascript" src="../../d3.layout.js"></script>
       
     9     <script type="text/javascript" src="../../d3.time.js"></script>
       
    10     <style type="text/css">
       
    11 
       
    12 svg {
       
    13   border: solid 1px #000;
       
    14   display: block;
       
    15   margin: auto;
       
    16   font-family: "Helvetica Neue";
       
    17 }
       
    18 
       
    19 .line {
       
    20   fill: none;
       
    21   stroke: #000;
       
    22   stroke-width: 2px;
       
    23 }
       
    24 
       
    25     </style>
       
    26   </head>
       
    27   <body>
       
    28     <script type="text/javascript">
       
    29 
       
    30 var m = [120, 60, 60, 60],
       
    31     w = 1280 - m[1] - m[3],
       
    32     h = 720 - m[0] - m[2];
       
    33 
       
    34 var x = d3.time.scale().range([0, w - 60]),
       
    35     y = d3.scale.linear().range([h / 4 - 20, 0]),
       
    36     duration = 1500,
       
    37     delay = 500;
       
    38 
       
    39 var color = d3.scale.category10();
       
    40 
       
    41 var svg = d3.select("body").append("svg:svg")
       
    42     .attr("width", w + m[1] + m[3])
       
    43     .attr("height", h + m[0] + m[2])
       
    44   .append("svg:g")
       
    45     .attr("transform", "translate(" + m[3] + "," + m[0] + ")");
       
    46 
       
    47 var stocks,
       
    48     symbols;
       
    49 
       
    50 // A line generator, for the dark stroke.
       
    51 var line = d3.svg.line()
       
    52     .interpolate("basis")
       
    53     .x(function(d) { return x(d.date); })
       
    54     .y(function(d) { return y(d.price); });
       
    55 
       
    56 // A line generator, for the dark stroke.
       
    57 var axis = d3.svg.line()
       
    58     .interpolate("basis")
       
    59     .x(function(d) { return x(d.date); })
       
    60     .y(h);
       
    61 
       
    62 // A area generator, for the dark stroke.
       
    63 var area = d3.svg.area()
       
    64     .interpolate("basis")
       
    65     .x(function(d) { return x(d.date); })
       
    66     .y0(h / 4 - 20)
       
    67     .y1(function(d) { return y(d.price); });
       
    68 
       
    69 d3.csv("../data/stocks.csv", function(data) {
       
    70   var parse = d3.time.format("%b %Y").parse,
       
    71       filter = {AAPL: 1, AMZN: 1, MSFT: 1, IBM: 1};
       
    72 
       
    73   stocks = data.filter(function(d) { return d.symbol in filter; });
       
    74 
       
    75   // Nest stock values by symbol.
       
    76   symbols = d3.nest()
       
    77       .key(function(d) { return d.symbol; })
       
    78       .entries(stocks);
       
    79 
       
    80   // Parse dates and numbers. We assume values are sorted by date.
       
    81   // Also compute the maximum price per symbol, needed for the y-domain.
       
    82   symbols.forEach(function(s) {
       
    83     s.values.forEach(function(d) { d.date = parse(d.date); d.price = +d.price; });
       
    84     s.maxPrice = d3.max(s.values, function(d) { return d.price; });
       
    85     s.sumPrice = d3.sum(s.values, function(d) { return d.price; });
       
    86   });
       
    87 
       
    88   // Sort by maximum price, descending.
       
    89   symbols.sort(function(a, b) { return b.maxPrice - a.maxPrice; });
       
    90 
       
    91   // Compute the minimum and maximum date across symbols.
       
    92   x.domain([
       
    93     d3.min(symbols, function(d) { return d.values[0].date; }),
       
    94     d3.max(symbols, function(d) { return d.values[d.values.length - 1].date; })
       
    95   ]);
       
    96 
       
    97   var g = svg.selectAll("g")
       
    98       .data(symbols)
       
    99     .enter().append("svg:g")
       
   100       .attr("class", "symbol");
       
   101 
       
   102   setTimeout(lines, duration);
       
   103 });
       
   104 
       
   105 function lines() {
       
   106 
       
   107   var g = svg.selectAll(".symbol")
       
   108       .attr("transform", function(d, i) { return "translate(0," + i * h / 4 + ")"; });
       
   109 
       
   110   g.each(function(d) {
       
   111     var e = d3.select(this);
       
   112 
       
   113     e.append("svg:path")
       
   114         .attr("class", "line");
       
   115 
       
   116     e.append("svg:circle")
       
   117         .attr("r", 5)
       
   118         .style("fill", function(d) { return color(d.key); })
       
   119         .style("stroke", "#000")
       
   120         .style("stroke-width", "2px");
       
   121 
       
   122     e.append("svg:text")
       
   123         .attr("x", 12)
       
   124         .attr("dy", ".31em")
       
   125         .text(d.key);
       
   126   });
       
   127 
       
   128   function draw(k) {
       
   129     g.each(function(d) {
       
   130       var e = d3.select(this);
       
   131       y.domain([0, d.maxPrice]);
       
   132 
       
   133       e.select("path")
       
   134           .attr("d", function(d) { return line(d.values.slice(0, k + 1)); });
       
   135 
       
   136       e.selectAll("circle, text")
       
   137           .data(function(d) { return [d.values[k], d.values[k]]; })
       
   138           .attr("transform", function(d) { return "translate(" + x(d.date) + "," + y(d.price) + ")"; });
       
   139     });
       
   140   }
       
   141 
       
   142   var k = 1, n = symbols[0].values.length;
       
   143   d3.timer(function() {
       
   144     draw(k);
       
   145     if ((k += 2) >= n - 1) {
       
   146       draw(n - 1);
       
   147       setTimeout(horizons, 500);
       
   148       return true;
       
   149     }
       
   150   });
       
   151 }
       
   152 
       
   153 function horizons() {
       
   154   svg.insert("svg:defs", ".symbol")
       
   155     .append("svg:clipPath")
       
   156       .attr("id", "clip")
       
   157     .append("svg:rect")
       
   158       .attr("width", w)
       
   159       .attr("height", h / 4 - 20);
       
   160 
       
   161   var color = d3.scale.ordinal()
       
   162       .range(["#c6dbef", "#9ecae1", "#6baed6"]);
       
   163 
       
   164   var g = svg.selectAll(".symbol")
       
   165       .attr("clip-path", "url(#clip)");
       
   166 
       
   167   g.select("circle").transition()
       
   168       .duration(duration)
       
   169       .attr("transform", function(d) { return "translate(" + (w - 60) + "," + (-h / 4) + ")"; })
       
   170       .remove();
       
   171 
       
   172   g.select("text").transition()
       
   173       .duration(duration)
       
   174       .attr("transform", function(d) { return "translate(" + (w - 60) + "," + (h / 4 - 20) + ")"; })
       
   175       .attr("dy", "0em");
       
   176 
       
   177   g.each(function(d) {
       
   178     y.domain([0, d.maxPrice]);
       
   179 
       
   180     d3.select(this).selectAll(".area")
       
   181         .data(d3.range(3))
       
   182       .enter().insert("svg:path", ".line")
       
   183         .attr("class", "area")
       
   184         .attr("transform", function(d) { return "translate(0," + (d * (h / 4 - 20)) + ")"; })
       
   185         .attr("d", area(d.values))
       
   186         .style("fill", function(d, i) { return color(i); })
       
   187         .style("fill-opacity", 1e-6);
       
   188 
       
   189     y.domain([0, d.maxPrice / 3]);
       
   190 
       
   191     d3.select(this).selectAll(".line").transition()
       
   192         .duration(duration)
       
   193         .attr("d", line(d.values))
       
   194         .style("stroke-opacity", 1e-6);
       
   195 
       
   196     d3.select(this).selectAll(".area").transition()
       
   197         .duration(duration)
       
   198         .style("fill-opacity", 1)
       
   199         .attr("d", area(d.values))
       
   200         .each("end", function() { d3.select(this).style("fill-opacity", null); });
       
   201   });
       
   202 
       
   203   setTimeout(areas, duration + delay);
       
   204 }
       
   205 
       
   206 function areas() {
       
   207   var g = svg.selectAll(".symbol");
       
   208 
       
   209   axis
       
   210       .y(h / 4 - 21);
       
   211 
       
   212   g.select(".line")
       
   213       .attr("d", function(d) { return axis(d.values); });
       
   214 
       
   215   g.each(function(d) {
       
   216     y.domain([0, d.maxPrice]);
       
   217 
       
   218     d3.select(this).select(".line").transition()
       
   219         .duration(duration)
       
   220         .style("stroke-opacity", 1)
       
   221         .each("end", function() { d3.select(this).style("stroke-opacity", null); });
       
   222 
       
   223     d3.select(this).selectAll(".area")
       
   224         .filter(function(d, i) { return i; })
       
   225       .transition()
       
   226         .duration(duration)
       
   227         .style("fill-opacity", 1e-6)
       
   228         .attr("d", area(d.values))
       
   229         .remove();
       
   230 
       
   231     d3.select(this).selectAll(".area")
       
   232         .filter(function(d, i) { return !i; })
       
   233       .transition()
       
   234         .duration(duration)
       
   235         .style("fill", color(d.key))
       
   236         .attr("d", area(d.values));
       
   237   });
       
   238 
       
   239   svg.select("defs").transition()
       
   240       .duration(duration)
       
   241       .remove();
       
   242 
       
   243   g.transition()
       
   244       .duration(duration)
       
   245       .each("end", function() { d3.select(this).attr("clip-path", null); });
       
   246 
       
   247   setTimeout(stackedArea, duration + delay);
       
   248 }
       
   249 
       
   250 function stackedArea() {
       
   251   var stack = d3.layout.stack()
       
   252       .values(function(d) { return d.values; })
       
   253       .x(function(d) { return d.date; })
       
   254       .y(function(d) { return d.price; })
       
   255       .out(function(d, y0, y) { d.price0 = y0; })
       
   256       .order("reverse");
       
   257 
       
   258   stack(symbols);
       
   259 
       
   260   y
       
   261       .domain([0, d3.max(symbols[0].values.map(function(d) { return d.price + d.price0; }))])
       
   262       .range([h, 0]);
       
   263 
       
   264   line
       
   265       .y(function(d) { return y(d.price0); });
       
   266 
       
   267   area
       
   268       .y0(function(d) { return y(d.price0); })
       
   269       .y1(function(d) { return y(d.price0 + d.price); });
       
   270 
       
   271   var t = svg.selectAll(".symbol").transition()
       
   272       .duration(duration)
       
   273       .attr("transform", "translate(0,0)")
       
   274       .each("end", function() { d3.select(this).attr("transform", null); });
       
   275 
       
   276   t.select("path.area")
       
   277       .attr("d", function(d) { return area(d.values); });
       
   278 
       
   279   t.select("path.line")
       
   280       .style("stroke-opacity", function(d, i) { return i < 3 ? 1e-6 : 1; })
       
   281       .attr("d", function(d) { return line(d.values); });
       
   282 
       
   283   t.select("text")
       
   284       .attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
       
   285 
       
   286   setTimeout(streamgraph, duration + delay);
       
   287 }
       
   288 
       
   289 function streamgraph() {
       
   290   var stack = d3.layout.stack()
       
   291       .values(function(d) { return d.values; })
       
   292       .x(function(d) { return d.date; })
       
   293       .y(function(d) { return d.price; })
       
   294       .out(function(d, y0, y) { d.price0 = y0; })
       
   295       .order("reverse")
       
   296       .offset("wiggle");
       
   297 
       
   298   stack(symbols);
       
   299 
       
   300   line
       
   301       .y(function(d) { return y(d.price0); });
       
   302 
       
   303   var t = svg.selectAll(".symbol").transition()
       
   304       .duration(duration);
       
   305 
       
   306   t.select("path.area")
       
   307       .attr("d", function(d) { return area(d.values); });
       
   308 
       
   309   t.select("path.line")
       
   310       .style("stroke-opacity", 1e-6)
       
   311       .attr("d", function(d) { return line(d.values); });
       
   312 
       
   313   t.select("text")
       
   314       .attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
       
   315 
       
   316   setTimeout(overlappingArea, duration + delay);
       
   317 }
       
   318 
       
   319 function overlappingArea() {
       
   320   var g = svg.selectAll(".symbol");
       
   321 
       
   322   line
       
   323       .y(function(d) { return y(d.price0 + d.price); });
       
   324 
       
   325   g.select(".line")
       
   326       .attr("d", function(d) { return line(d.values); });
       
   327 
       
   328   y
       
   329       .domain([0, d3.max(symbols.map(function(d) { return d.maxPrice; }))])
       
   330       .range([h, 0]);
       
   331 
       
   332   area
       
   333       .y0(h)
       
   334       .y1(function(d) { return y(d.price); });
       
   335 
       
   336   line
       
   337       .y(function(d) { return y(d.price); });
       
   338 
       
   339   var t = g.transition()
       
   340       .duration(duration);
       
   341 
       
   342   t.select(".line")
       
   343       .style("stroke-opacity", 1)
       
   344       .attr("d", function(d) { return line(d.values); });
       
   345 
       
   346   t.select(".area")
       
   347       .style("fill-opacity", .5)
       
   348       .attr("d", function(d) { return area(d.values); });
       
   349 
       
   350   t.select("text")
       
   351       .attr("dy", ".31em")
       
   352       .attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price) + ")"; });
       
   353 
       
   354   svg.append("svg:line")
       
   355       .attr("class", "line")
       
   356       .attr("x1", 0)
       
   357       .attr("x2", w - 60)
       
   358       .attr("y1", h)
       
   359       .attr("y2", h)
       
   360       .style("stroke-opacity", 1e-6)
       
   361     .transition()
       
   362       .duration(duration)
       
   363       .style("stroke-opacity", 1);
       
   364 
       
   365   setTimeout(groupedBar, duration + delay);
       
   366 }
       
   367 
       
   368 function groupedBar() {
       
   369   x = d3.scale.ordinal()
       
   370       .domain(symbols[0].values.map(function(d) { return d.date; }))
       
   371       .rangeBands([0, w - 60], .1);
       
   372 
       
   373   var x1 = d3.scale.ordinal()
       
   374       .domain(symbols.map(function(d) { return d.key; }))
       
   375       .rangeBands([0, x.rangeBand()]);
       
   376 
       
   377   var g = svg.selectAll(".symbol");
       
   378 
       
   379   var t = g.transition()
       
   380       .duration(duration);
       
   381 
       
   382   t.select(".line")
       
   383       .style("stroke-opacity", 1e-6)
       
   384       .remove();
       
   385 
       
   386   t.select(".area")
       
   387       .style("fill-opacity", 1e-6)
       
   388       .remove();
       
   389 
       
   390   g.each(function(p, j) {
       
   391     d3.select(this).selectAll("rect")
       
   392         .data(function(d) { return d.values; })
       
   393       .enter().append("svg:rect")
       
   394         .attr("x", function(d) { return x(d.date) + x1(p.key); })
       
   395         .attr("y", function(d) { return y(d.price); })
       
   396         .attr("width", x1.rangeBand())
       
   397         .attr("height", function(d) { return h - y(d.price); })
       
   398         .style("fill", color(p.key))
       
   399         .style("fill-opacity", 1e-6)
       
   400       .transition()
       
   401         .duration(duration)
       
   402         .style("fill-opacity", 1);
       
   403   });
       
   404 
       
   405   setTimeout(stackedBar, duration + delay);
       
   406 }
       
   407 
       
   408 function stackedBar() {
       
   409   x.rangeRoundBands([0, w - 60], .1);
       
   410 
       
   411   var stack = d3.layout.stack()
       
   412       .values(function(d) { return d.values; })
       
   413       .x(function(d) { return d.date; })
       
   414       .y(function(d) { return d.price; })
       
   415       .out(function(d, y0, y) { d.price0 = y0; })
       
   416       .order("reverse");
       
   417 
       
   418   var g = svg.selectAll(".symbol");
       
   419 
       
   420   stack(symbols);
       
   421 
       
   422   y
       
   423       .domain([0, d3.max(symbols[0].values.map(function(d) { return d.price + d.price0; }))])
       
   424       .range([h, 0]);
       
   425 
       
   426   var t = g.transition()
       
   427       .duration(duration / 2);
       
   428 
       
   429   t.select("text")
       
   430       .delay(symbols[0].values.length * 10)
       
   431       .attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
       
   432 
       
   433   t.selectAll("rect")
       
   434       .delay(function(d, i) { return i * 10; })
       
   435       .attr("y", function(d) { return y(d.price0 + d.price); })
       
   436       .attr("height", function(d) { return h - y(d.price); })
       
   437       .each("end", function() {
       
   438         d3.select(this)
       
   439             .style("stroke", "#fff")
       
   440             .style("stroke-opacity", 1e-6)
       
   441           .transition()
       
   442             .duration(duration / 2)
       
   443             .attr("x", function(d) { return x(d.date); })
       
   444             .attr("width", x.rangeBand())
       
   445             .style("stroke-opacity", 1);
       
   446       });
       
   447 
       
   448   setTimeout(transposeBar, duration + symbols[0].values.length * 10 + delay);
       
   449 }
       
   450 
       
   451 function transposeBar() {
       
   452   x
       
   453       .domain(symbols.map(function(d) { return d.key; }))
       
   454       .rangeRoundBands([0, w], .2);
       
   455 
       
   456   y
       
   457       .domain([0, d3.max(symbols.map(function(d) { return d3.sum(d.values.map(function(d) { return d.price; })); }))]);
       
   458 
       
   459   var stack = d3.layout.stack()
       
   460       .x(function(d, i) { return i; })
       
   461       .y(function(d) { return d.price; })
       
   462       .out(function(d, y0, y) { d.price0 = y0; });
       
   463 
       
   464   stack(d3.zip.apply(null, symbols.map(function(d) { return d.values; }))); // transpose!
       
   465 
       
   466   var g = svg.selectAll(".symbol");
       
   467 
       
   468   var t = g.transition()
       
   469       .duration(duration / 2);
       
   470 
       
   471   t.selectAll("rect")
       
   472       .delay(function(d, i) { return i * 10; })
       
   473       .attr("y", function(d) { return y(d.price0 + d.price) - 1; })
       
   474       .attr("height", function(d) { return h - y(d.price) + 1; })
       
   475       .attr("x", function(d) { return x(d.symbol); })
       
   476       .attr("width", x.rangeBand())
       
   477       .style("stroke-opacity", 1e-6);
       
   478 
       
   479   t.select("text")
       
   480       .attr("x", 0)
       
   481       .attr("transform", function(d) { return "translate(" + (x(d.key) + x.rangeBand() / 2) + "," + h + ")"; })
       
   482       .attr("dy", "1.31em")
       
   483       .each("end", function() { d3.select(this).attr("x", null).attr("text-anchor", "middle"); });
       
   484 
       
   485   svg.select("line").transition()
       
   486       .duration(duration)
       
   487       .attr("x2", w);
       
   488 
       
   489   setTimeout(donut,  duration / 2 + symbols[0].values.length * 10 + delay);
       
   490 }
       
   491 
       
   492 function donut() {
       
   493   var g = svg.selectAll(".symbol");
       
   494 
       
   495   g.selectAll("rect").remove();
       
   496 
       
   497   var pie = d3.layout.pie()
       
   498       .value(function(d) { return d.sumPrice; });
       
   499 
       
   500   var arc = d3.svg.arc();
       
   501 
       
   502   g.append("svg:path")
       
   503       .style("fill", function(d) { return color(d.key); })
       
   504       .data(function() { return pie(symbols); })
       
   505     .transition()
       
   506       .duration(duration)
       
   507       .tween("arc", arcTween);
       
   508 
       
   509   g.select("text").transition()
       
   510       .duration(duration)
       
   511       .attr("dy", ".31em");
       
   512 
       
   513   svg.select("line").transition()
       
   514       .duration(duration)
       
   515       .attr("y1", 2 * h)
       
   516       .attr("y2", 2 * h)
       
   517       .remove();
       
   518 
       
   519   function arcTween(d) {
       
   520     var path = d3.select(this),
       
   521         text = d3.select(this.parentNode.appendChild(this.previousSibling)),
       
   522         x0 = x(d.data.key),
       
   523         y0 = h - y(d.data.sumPrice);
       
   524 
       
   525     return function(t) {
       
   526       var r = h / 2 / Math.min(1, t + 1e-3),
       
   527           a = Math.cos(t * Math.PI / 2),
       
   528           xx = (-r + (a) * (x0 + x.rangeBand()) + (1 - a) * (w + h) / 2),
       
   529           yy = ((a) * h + (1 - a) * h / 2),
       
   530           f = {
       
   531             innerRadius: r - x.rangeBand() / (2 - a),
       
   532             outerRadius: r,
       
   533             startAngle: a * (Math.PI / 2 - y0 / r) + (1 - a) * d.startAngle,
       
   534             endAngle: a * (Math.PI / 2) + (1 - a) * d.endAngle
       
   535           };
       
   536 
       
   537       path.attr("transform", "translate(" + xx + "," + yy + ")");
       
   538       path.attr("d", arc(f));
       
   539       text.attr("transform", "translate(" + arc.centroid(f) + ")translate(" + xx + "," + yy + ")rotate(" + ((f.startAngle + f.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
       
   540     };
       
   541   }
       
   542 
       
   543   setTimeout(donutExplode, duration + delay);
       
   544 }
       
   545 
       
   546 /*
       
   547 function donutTransition() {
       
   548   var r0 = h / 2 - x.rangeBand() / 2,
       
   549       r1 = h / 2,
       
   550       pie1 = d3.layout.pie().value(function(d) { return d.sumPrice; })(symbols),
       
   551       pie2 = d3.layout.pie().value(function(d) { return d.maxPrice; })(symbols),
       
   552       arc = d3.svg.arc();
       
   553 
       
   554   svg.selectAll(".symbol path")
       
   555       .map(function(d, i) {
       
   556         d = pie1[i];
       
   557         d.innerRadius = r0;
       
   558         d.outerRadius = r1;
       
   559         d.next = pie2[i];
       
   560         return d;
       
   561       })
       
   562       .each(transitionSplit);
       
   563 
       
   564   function transitionSplit(d, i) {
       
   565     d3.select(this).transition()
       
   566         .duration(duration / 2)
       
   567         .tween("arc", tweenArc({
       
   568           innerRadius: i & 1 ? r0 : (r0 + r1) / 2,
       
   569           outerRadius: i & 1 ? (r0 + r1) / 2 : r1
       
   570         }))
       
   571         .each("end", transitionRotate);
       
   572   }
       
   573 
       
   574   function transitionRotate(d, i) {
       
   575     var a0 = d.next.startAngle + d.next.endAngle,
       
   576         a1 = d.startAngle - d.endAngle;
       
   577     d3.select(this).transition()
       
   578         .duration(duration / 2)
       
   579         .tween("arc", tweenArc({
       
   580           startAngle: (a0 + a1) / 2,
       
   581           endAngle: (a0 - a1) / 2
       
   582         }))
       
   583         .each("end", transitionResize);
       
   584   }
       
   585 
       
   586   function transitionResize(d, i) {
       
   587     d3.select(this).transition()
       
   588         .duration(duration / 2)
       
   589         .tween("arc", tweenArc({
       
   590           startAngle: d.next.startAngle,
       
   591           endAngle: d.next.endAngle
       
   592         }))
       
   593         .each("end", transitionUnite);
       
   594   }
       
   595 
       
   596   function transitionUnite(d, i) {
       
   597     d3.select(this).transition()
       
   598         .duration(duration / 2)
       
   599         .tween("arc", tweenArc({
       
   600           innerRadius: r0,
       
   601           outerRadius: r1
       
   602         }));
       
   603   }
       
   604 
       
   605   function tweenArc(b) {
       
   606     return function(a) {
       
   607       var path = d3.select(this),
       
   608           text = d3.select(this.nextSibling),
       
   609           i = d3.interpolate(a, b);
       
   610       for (var key in b) a[key] = b[key]; // update data
       
   611       return function(t) {
       
   612         var a = i(t);
       
   613         path.attr("d", arc(a));
       
   614         text.attr("transform", "translate(" + arc.centroid(a) + ")translate(" + w / 2 + "," + h / 2 +")rotate(" + ((a.startAngle + a.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
       
   615       };
       
   616     }
       
   617   }
       
   618 
       
   619   setTimeout(donutExplode, 2 * duration + delay);
       
   620 }
       
   621 */
       
   622 
       
   623 function donutExplode() {
       
   624   var r0a = h / 2 - x.rangeBand() / 2,
       
   625       r1a = h / 2,
       
   626       r0b = 2 * h - x.rangeBand() / 2,
       
   627       r1b = 2 * h,
       
   628       arc = d3.svg.arc();
       
   629 
       
   630   svg.selectAll(".symbol path")
       
   631       .each(transitionExplode);
       
   632 
       
   633   function transitionExplode(d, i) {
       
   634     d.innerRadius = r0a;
       
   635     d.outerRadius = r1a;
       
   636     d3.select(this).transition()
       
   637         .duration(duration / 2)
       
   638         .tween("arc", tweenArc({
       
   639           innerRadius: r0b,
       
   640           outerRadius: r1b
       
   641         }));
       
   642   }
       
   643 
       
   644   function tweenArc(b) {
       
   645     return function(a) {
       
   646       var path = d3.select(this),
       
   647           text = d3.select(this.nextSibling),
       
   648           i = d3.interpolate(a, b);
       
   649       for (var key in b) a[key] = b[key]; // update data
       
   650       return function(t) {
       
   651         var a = i(t);
       
   652         path.attr("d", arc(a));
       
   653         text.attr("transform", "translate(" + arc.centroid(a) + ")translate(" + w / 2 + "," + h / 2 +")rotate(" + ((a.startAngle + a.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
       
   654       };
       
   655     }
       
   656   }
       
   657 }
       
   658 
       
   659     </script>
       
   660   </body>
       
   661 </html>