2 |
2 |
3 export default Ember.Component.extend({ |
3 export default Ember.Component.extend({ |
4 didInsertElement: function(){ |
4 didInsertElement: function(){ |
5 var _this = this; |
5 var _this = this; |
6 |
6 |
7 var data = google.visualization.arrayToDataTable([ |
7 var margin = {top: 20, right: 0, bottom: 0, left: 0}, |
8 ['Location', 'Parent', 'Market trade volume (size)', 'Market increase/decrease (color)'], |
8 width = 560, |
9 ['Global', null, 0, 0], |
9 height = 600 - margin.top - margin.bottom, |
10 ['Français', 'Global', 859, 859], |
10 formatNumber = d3.format(",d"), |
11 ['Alsacien', 'Global', 851, 851], |
11 transitioning; |
12 ['Breton', 'Global', 403, 403], |
|
13 ['Occitan', 'Global', 344, 344], |
|
14 ['Judéo-espagnol', 'Global', 77, 77], |
|
15 ['Undetermined', 'Global', 45, 45], |
|
16 ['Langues régionales', 'Global', 175, 175], |
|
17 ['Langues non territoriales', 'Global', 48, 48], |
|
18 ['Les Creoles', 'Global', 47, 47], |
|
19 ['Guyane', 'Global', 59, 59], |
|
20 ['Mayotte', 'Global', 20, 20], |
|
21 ['Polynésie française', 'Global', 13, 13], |
|
22 ['Wallis et Futuna', 'Global', 43, 43], |
|
23 ['Nouvelle-Calédonie', 'Global', 68, 68], |
|
24 ['Langues d’oïl', 'Langues régionales', 75, 75], |
|
25 ['Francoprovençal', 'Langues régionales', 60, 60], |
|
26 ['Corse', 'Langues régionales', 40, 40], |
|
27 ['Langue des signes française (LSF)', 'Langues non territoriales', 40, 40], |
|
28 ['Berbère', 'Langues non territoriales', 8, 8], |
|
29 ['Creole de la Réunion', 'Les Creoles', 32, 32], |
|
30 ['Creole de la Guadeloupe', 'Les Creoles', 15, 15], |
|
31 ['Ndyuka-Trio Pidgin (njt)', 'Guyane', 31, 31], |
|
32 ['Palikúr (plu)', 'Guyane', 6, 6], |
|
33 ['Guianese Creole French (gcr)', 'Guyane', 4, 4], |
|
34 ['Eastern Maroon Creole (djk)', 'Guyane', 16, 16], |
|
35 ['Sranan Tongo (srn)', 'Guyane', 2, 2], |
|
36 ['Maore Comorian (swb)', 'Mayotte', 2, 2], |
|
37 ['Mauritian Sign Language (lsy)', 'Mayotte', 18, 18], |
|
38 ['West Uvean (uve)', 'Polynésie française', 13, 13], |
|
39 ['East Futuna (fud)', 'Wallis et Futuna', 23, 23], |
|
40 ['Wallisian (wls)', 'Wallis et Futuna', 20, 20], |
|
41 ['Nemi (nem)', 'Nouvelle-Calédonie', 15, 15], |
|
42 ['Xârâcùù (ane)', 'Nouvelle-Calédonie', 12, 12], |
|
43 ['Cemuhî (cam)', 'Nouvelle-Calédonie', 9, 9], |
|
44 ['Xaragure (axx)', 'Nouvelle-Calédonie', 9, 9], |
|
45 ['Iaai (iai)', 'Nouvelle-Calédonie', 8, 8], |
|
46 ['Nêlêmwa-Nixumwak (nee)', 'Nouvelle-Calédonie', 4, 4], |
|
47 ['Dehu (dhv)', 'Nouvelle-Calédonie', 2, 2], |
|
48 ['Nengone (nen)', 'Nouvelle-Calédonie', 2, 2], |
|
49 ['Ajië (aji)', 'Nouvelle-Calédonie', 1, 1], |
|
50 ['Numee (kdk)', 'Nouvelle-Calédonie', 1, 1], |
|
51 ['Yuaga (nua)', 'Nouvelle-Calédonie', 1, 1], |
|
52 ['Bwatoo (bwa)', 'Nouvelle-Calédonie', 4, 4] |
|
53 ]); |
|
54 |
12 |
55 var tree = new google.visualization.TreeMap(document.getElementById('chart_div')); |
13 var x = d3.scale.linear() |
|
14 .domain([0, width]) |
|
15 .range([0, width]); |
56 |
16 |
57 tree.draw(data, { |
17 var y = d3.scale.linear() |
58 minColor: '#E0EEEF', |
18 .domain([0, height]) |
59 midColor: '#7CACAE', |
19 .range([0, height]); |
60 maxColor: '#2D7073', |
20 |
61 headerHeight: 15, |
21 var treemap = d3.layout.treemap() |
62 fontColor: 'black', |
22 .children(function(d, depth) { return depth ? null : d._children; }) |
63 showScale: true |
23 .sort(function(a, b) { return a.value - b.value; }) |
|
24 .ratio(height / width * 0.5 * (1 + Math.sqrt(5))) |
|
25 .round(false); |
|
26 |
|
27 var svg = d3.select("#chart_div").append("svg") |
|
28 .attr("width", width + margin.left + margin.right) |
|
29 .attr("height", height + margin.bottom + margin.top) |
|
30 .style("margin-left", -margin.left + "px") |
|
31 .style("margin.right", -margin.right + "px") |
|
32 .append("g") |
|
33 .attr("transform", "translate(" + margin.left + "," + margin.top + ")") |
|
34 .style("shape-rendering", "crispEdges"); |
|
35 |
|
36 var grandparent = svg.append("g") |
|
37 .attr("class", "grandparent"); |
|
38 |
|
39 grandparent.append("rect") |
|
40 .attr("y", -margin.top) |
|
41 .attr("width", width) |
|
42 .attr("height", margin.top); |
|
43 |
|
44 grandparent.append("text") |
|
45 .attr("x", 6) |
|
46 .attr("y", 6 - margin.top) |
|
47 .attr("dy", ".75em"); |
|
48 |
|
49 d3.json("langues.json", function(root) { |
|
50 initialize(root); |
|
51 accumulate(root); |
|
52 layout(root); |
|
53 display(root); |
|
54 |
|
55 function initialize(root) { |
|
56 root.x = root.y = 0; |
|
57 root.dx = width; |
|
58 root.dy = height; |
|
59 root.depth = 0; |
|
60 } |
|
61 |
|
62 // Aggregate the values for internal nodes. This is normally done by the |
|
63 // treemap layout, but not here because of our custom implementation. |
|
64 // We also take a snapshot of the original children (_children) to avoid |
|
65 // the children being overwritten when when layout is computed. |
|
66 function accumulate(d) { |
|
67 return (d._children = d.children) |
|
68 ? d.value = d.children.reduce(function(p, v) { return p + accumulate(v); }, 0) |
|
69 : d.value; |
|
70 } |
|
71 |
|
72 // Compute the treemap layout recursively such that each group of siblings |
|
73 // uses the same size (1×1) rather than the dimensions of the parent cell. |
|
74 // This optimizes the layout for the current zoom state. Note that a wrapper |
|
75 // object is created for the parent node for each group of siblings so that |
|
76 // the parent’s dimensions are not discarded as we recurse. Since each group |
|
77 // of sibling was laid out in 1×1, we must rescale to fit using absolute |
|
78 // coordinates. This lets us use a viewport to zoom. |
|
79 function layout(d) { |
|
80 if (d._children) { |
|
81 treemap.nodes({_children: d._children}); |
|
82 d._children.forEach(function(c) { |
|
83 c.x = d.x + c.x * d.dx; |
|
84 c.y = d.y + c.y * d.dy; |
|
85 c.dx *= d.dx; |
|
86 c.dy *= d.dy; |
|
87 c.parent = d; |
|
88 layout(c); |
|
89 }); |
|
90 } |
|
91 } |
|
92 |
|
93 function display(d) { |
|
94 grandparent |
|
95 .datum(d.parent) |
|
96 .on("click", transition) |
|
97 .select("text") |
|
98 .text(name(d)); |
|
99 |
|
100 var g1 = svg.insert("g", ".grandparent") |
|
101 .datum(d) |
|
102 .attr("class", "depth"); |
|
103 |
|
104 var g = g1.selectAll("g") |
|
105 .data(d._children) |
|
106 .enter().append("g"); |
|
107 |
|
108 g.classed("bla", true).on("click", selectHandler) |
|
109 |
|
110 g.filter(function(d) { return d._children; }) |
|
111 .classed("children", true) |
|
112 .on("click", transition); |
|
113 |
|
114 // g.selectAll(".child") |
|
115 // .data(function(d) { return d._children || [d]; }) |
|
116 // .enter().append("rect") |
|
117 // .attr("class", "child") |
|
118 // .call(rect); |
|
119 |
|
120 g.append("rect") |
|
121 .attr("class", "parent") |
|
122 // .attr("fill", (d.color || "#bbb")) |
|
123 .call(rect) |
|
124 .append("title") |
|
125 .text(function(d) { return formatNumber(d.value); }); |
|
126 |
|
127 g.append("text") |
|
128 .attr("dy", ".75em") |
|
129 .text(function(d) { return d.name; }) |
|
130 .call(text); |
|
131 |
|
132 function transition(d) { |
|
133 if (transitioning || !d) return; |
|
134 selectHandler(d); |
|
135 transitioning = true; |
|
136 |
|
137 var g2 = display(d), |
|
138 t1 = g1.transition().duration(750), |
|
139 t2 = g2.transition().duration(750); |
|
140 |
|
141 // Update the domain only after entering new elements. |
|
142 x.domain([d.x, d.x + d.dx]); |
|
143 y.domain([d.y, d.y + d.dy]); |
|
144 |
|
145 // Enable anti-aliasing during the transition. |
|
146 svg.style("shape-rendering", null); |
|
147 |
|
148 // Draw child nodes on top of parent nodes. |
|
149 svg.selectAll(".depth").sort(function(a, b) { return a.depth - b.depth; }); |
|
150 |
|
151 // Fade-in entering text. |
|
152 g2.selectAll("text").style("fill-opacity", 0); |
|
153 |
|
154 // Transition to the new view. |
|
155 t1.selectAll("text").call(text).style("fill-opacity", 0); |
|
156 t2.selectAll("text").call(text).style("fill-opacity", 1); |
|
157 t1.selectAll("rect").call(rect); |
|
158 t2.selectAll("rect").call(rect); |
|
159 |
|
160 // Remove the old node when the transition is finished. |
|
161 t1.remove().each("end", function() { |
|
162 svg.style("shape-rendering", "crispEdges"); |
|
163 transitioning = false; |
|
164 }); |
|
165 } |
|
166 |
|
167 function selectHandler (d){ |
|
168 if (d.name === "Global"){ |
|
169 return _this.sendAction('action', null); |
|
170 } |
|
171 _this.sendAction('action', d.name); |
|
172 } |
|
173 |
|
174 return g; |
|
175 } |
|
176 |
|
177 function text(text) { |
|
178 text.attr("x", function(d) { return x(d.x) + 6; }) |
|
179 .attr("y", function(d) { return y(d.y) + 6; }); |
|
180 } |
|
181 |
|
182 function rect(rect) { |
|
183 rect.attr("x", function(d) { return x(d.x); }) |
|
184 .attr("y", function(d) { return y(d.y); }) |
|
185 .attr("width", function(d) { return x(d.x + d.dx) - x(d.x); }) |
|
186 .attr("height", function(d) { return y(d.y + d.dy) - y(d.y); }) |
|
187 .attr("fill", function(d) { return (d.color || "#bbb")}); |
|
188 } |
|
189 |
|
190 function name(d) { |
|
191 return d.parent |
|
192 ? name(d.parent) + "." + d.name |
|
193 : d.name; |
|
194 } |
64 }); |
195 }); |
65 |
|
66 function selectHandler (){ |
|
67 _this.sendAction('action', data.getValue(tree.getSelection()[0].row, 0)); |
|
68 } |
|
69 |
|
70 google.visualization.events.addListener(tree, 'select', selectHandler); |
|
71 |
|
72 } |
196 } |
73 }); |
197 }); |