|
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> |