|
1 <!DOCTYPE html> |
|
2 <html> |
|
3 <head> |
|
4 <title>Donut 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 body { |
|
10 font: 10px sans-serif; |
|
11 } |
|
12 |
|
13 </style> |
|
14 </head> |
|
15 <body> |
|
16 <script type="text/javascript"> |
|
17 |
|
18 var w = 400, |
|
19 h = 400, |
|
20 r1 = Math.min(w, h) / 2, |
|
21 r0 = r1 * .6, |
|
22 n = 10, |
|
23 q = 0, |
|
24 data0 = d3.range(n).map(Math.random), |
|
25 data1 = d3.range(n).map(Math.random), |
|
26 data, |
|
27 color = d3.scale.category20(), |
|
28 arc = d3.svg.arc(), |
|
29 donut = d3.layout.pie().sort(null); |
|
30 |
|
31 var vis = d3.select("body") |
|
32 .append("svg:svg") |
|
33 .attr("width", w) |
|
34 .attr("height", h); |
|
35 |
|
36 vis.selectAll("g.arc") |
|
37 .data(arcs(data0, data1)) |
|
38 .enter().append("svg:g") |
|
39 .attr("class", "arc") |
|
40 .attr("transform", "translate(" + r1 + "," + r1 + ")") |
|
41 .append("svg:path") |
|
42 .attr("fill", function(d, i) { return color(i); }) |
|
43 .attr("d", arc); |
|
44 |
|
45 window.addEventListener("keypress", swap, false); |
|
46 |
|
47 function arcs(data0, data1) { |
|
48 var arcs0 = donut(data0), |
|
49 arcs1 = donut(data1), |
|
50 i = -1, |
|
51 arc; |
|
52 while (++i < n) { |
|
53 arc = arcs0[i]; |
|
54 arc.innerRadius = r0; |
|
55 arc.outerRadius = r1; |
|
56 arc.next = arcs1[i]; |
|
57 } |
|
58 return arcs0; |
|
59 } |
|
60 |
|
61 function swap() { |
|
62 d3.selectAll("g.arc > path") |
|
63 .data(++q & 1 ? arcs(data0, data1) : arcs(data1, data0)) |
|
64 .each(transitionSplit); |
|
65 } |
|
66 |
|
67 // 1. Wedges split into two rings. |
|
68 function transitionSplit(d, i) { |
|
69 d3.select(this) |
|
70 .transition().duration(1000) |
|
71 .attrTween("d", tweenArc({ |
|
72 innerRadius: i & 1 ? r0 : (r0 + r1) / 2, |
|
73 outerRadius: i & 1 ? (r0 + r1) / 2 : r1 |
|
74 })) |
|
75 .each("end", transitionRotate); |
|
76 } |
|
77 |
|
78 // 2. Wedges translate to be centered on their final position. |
|
79 function transitionRotate(d, i) { |
|
80 var a0 = d.next.startAngle + d.next.endAngle, |
|
81 a1 = d.startAngle - d.endAngle; |
|
82 d3.select(this) |
|
83 .transition().duration(1000) |
|
84 .attrTween("d", tweenArc({ |
|
85 startAngle: (a0 + a1) / 2, |
|
86 endAngle: (a0 - a1) / 2 |
|
87 })) |
|
88 .each("end", transitionResize); |
|
89 } |
|
90 |
|
91 // 3. Wedges then update their values, changing size. |
|
92 function transitionResize(d, i) { |
|
93 d3.select(this) |
|
94 .transition().duration(1000) |
|
95 .attrTween("d", tweenArc({ |
|
96 startAngle: d.next.startAngle, |
|
97 endAngle: d.next.endAngle |
|
98 })) |
|
99 .each("end", transitionUnite); |
|
100 } |
|
101 |
|
102 // 4. Wedges reunite into a single ring. |
|
103 function transitionUnite(d, i) { |
|
104 d3.select(this) |
|
105 .transition().duration(1000) |
|
106 .attrTween("d", tweenArc({ |
|
107 innerRadius: r0, |
|
108 outerRadius: r1 |
|
109 })); |
|
110 } |
|
111 |
|
112 function tweenArc(b) { |
|
113 return function(a) { |
|
114 var i = d3.interpolate(a, b); |
|
115 for (var key in b) a[key] = b[key]; // update data |
|
116 return function(t) { |
|
117 return arc(i(t)); |
|
118 }; |
|
119 }; |
|
120 } |
|
121 |
|
122 </script> |
|
123 </body> |
|
124 </html> |