|
1 <!DOCTYPE html> |
|
2 <html> |
|
3 <head> |
|
4 <title>Marimekko 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 rect { |
|
14 stroke: #000; |
|
15 } |
|
16 |
|
17 svg { |
|
18 shape-rendering: crispEdges; |
|
19 } |
|
20 |
|
21 </style> |
|
22 </head> |
|
23 <body> |
|
24 <script type="text/javascript"> |
|
25 |
|
26 var w = 960, |
|
27 h = 500, |
|
28 m = 20, |
|
29 x = d3.scale.linear().range([0, w - 3 * m]), |
|
30 y = d3.scale.linear().range([0, h - 2 * m]), |
|
31 z = d3.scale.category10(), |
|
32 n = d3.format(",d"), |
|
33 p = d3.format("%"); |
|
34 |
|
35 var svg = d3.select("body").append("svg:svg") |
|
36 .attr("width", w) |
|
37 .attr("height", h) |
|
38 .append("svg:g") |
|
39 .attr("transform", "translate(" + 2 * m + "," + m + ")"); |
|
40 |
|
41 d3.json("marimekko.json", function(data) { |
|
42 var offset = 0; |
|
43 |
|
44 // Nest values by segment. We assume each segment+market is unique. |
|
45 var segments = d3.nest() |
|
46 .key(function(d) { return d.segment; }) |
|
47 .entries(data); |
|
48 |
|
49 // Compute the total sum, the per-segment sum, and the per-market offset. |
|
50 // You can use reduce rather than reduceRight to reverse the ordering. |
|
51 // We also record a reference to the parent segment for each market. |
|
52 var sum = segments.reduce(function(v, p) { |
|
53 return (p.offset = v) + (p.sum = p.values.reduceRight(function(v, d) { |
|
54 d.parent = p; |
|
55 return (d.offset = v) + d.value; |
|
56 }, 0)); |
|
57 }, 0); |
|
58 |
|
59 // Add x-axis ticks. |
|
60 var xtick = svg.selectAll(".x") |
|
61 .data(x.ticks(10)) |
|
62 .enter().append("svg:g") |
|
63 .attr("class", "x") |
|
64 .attr("transform", function(d) { return "translate(" + x(d) + "," + y(1) + ")"; }); |
|
65 |
|
66 xtick.append("svg:line") |
|
67 .attr("y2", 6) |
|
68 .style("stroke", "#000"); |
|
69 |
|
70 xtick.append("svg:text") |
|
71 .attr("y", 8) |
|
72 .attr("text-anchor", "middle") |
|
73 .attr("dy", ".71em") |
|
74 .text(p); |
|
75 |
|
76 // Add y-axis ticks. |
|
77 var ytick = svg.selectAll(".y") |
|
78 .data(y.ticks(10)) |
|
79 .enter().append("svg:g") |
|
80 .attr("class", "y") |
|
81 .attr("transform", function(d) { return "translate(0," + y(1 - d) + ")"; }); |
|
82 |
|
83 ytick.append("svg:line") |
|
84 .attr("x1", -6) |
|
85 .style("stroke", "#000"); |
|
86 |
|
87 ytick.append("svg:text") |
|
88 .attr("x", -8) |
|
89 .attr("text-anchor", "end") |
|
90 .attr("dy", ".35em") |
|
91 .text(p); |
|
92 |
|
93 // Add a group for each segment. |
|
94 var segments = svg.selectAll(".segment") |
|
95 .data(segments) |
|
96 .enter().append("svg:g") |
|
97 .attr("class", "segment") |
|
98 .attr("xlink:title", function(d) { return d.key; }) |
|
99 .attr("transform", function(d) { return "translate(" + x(d.offset / sum) + ")"; }); |
|
100 |
|
101 // Add a rect for each market. |
|
102 var markets = segments.selectAll(".market") |
|
103 .data(function(d) { return d.values; }) |
|
104 .enter().append("svg:a") |
|
105 .attr("class", "market") |
|
106 .attr("xlink:title", function(d) { return d.market + " " + d.parent.key + ": " + n(d.value); }) |
|
107 .append("svg:rect") |
|
108 .attr("y", function(d) { return y(d.offset / d.parent.sum); }) |
|
109 .attr("height", function(d) { return y(d.value / d.parent.sum); }) |
|
110 .attr("width", function(d) { return x(d.parent.sum / sum); }) |
|
111 .style("fill", function(d) { return z(d.market); }); |
|
112 }); |
|
113 |
|
114 </script> |
|
115 </body> |
|
116 </html> |