]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | Ext.define('KitchenSink.view.charts.combination.UnemploymentController', {\r |
2 | extend: 'Ext.app.ViewController',\r | |
3 | alias: 'controller.unemployment',\r | |
4 | \r | |
5 | // State regions.\r | |
6 | // A region line spans from the 'start' state through the 'end' state.\r | |
7 | regions: [{\r | |
8 | name: 'Northeast Region',\r | |
9 | start: 'CT',\r | |
10 | end: 'VT'\r | |
11 | }, {\r | |
12 | name: 'Southeast Region',\r | |
13 | start: 'AL',\r | |
14 | end: 'VA'\r | |
15 | }, {\r | |
16 | name: 'Midwest Region',\r | |
17 | start: 'WI',\r | |
18 | end: 'AR'\r | |
19 | }, {\r | |
20 | name: 'Southwest Region',\r | |
21 | start: 'AZ',\r | |
22 | end: 'UT'\r | |
23 | }, {\r | |
24 | name: 'Northwest Region',\r | |
25 | start: 'AK',\r | |
26 | end: 'WY'\r | |
27 | }],\r | |
28 | \r | |
29 | regionIndex: 0,\r | |
30 | linePadding: 5,\r | |
31 | tickSize: 10,\r | |
32 | startAngle: 0,\r | |
33 | endAngle: 0,\r | |
34 | region: null,\r | |
35 | \r | |
36 | /**\r | |
37 | * Adds ticks to the ends of a region line.\r | |
38 | * @param surface The surface to put the ticks into.\r | |
39 | * @param attr The style of the ticks.\r | |
40 | * @param angles Array with angles to put the ticks at.\r | |
41 | * @param sprites The array to add the created tick sprites to (for future reference).\r | |
42 | */\r | |
43 | addTicks: function (surface, attr, angles, sprites) {\r | |
44 | var linePadding = this.linePadding,\r | |
45 | tickSize = this.tickSize,\r | |
46 | i, ln, angle;\r | |
47 | \r | |
48 | for (i = 0, ln = angles.length; i < ln; i++) {\r | |
49 | angle = angles[i] + attr.rotationRads;\r | |
50 | sprites.push(surface.add({\r | |
51 | type: 'line',\r | |
52 | strokeStyle: 'gray',\r | |
53 | \r | |
54 | translationX: attr.translationX,\r | |
55 | translationY: attr.translationY,\r | |
56 | \r | |
57 | fromX: attr.centerX + (attr.endRho + linePadding) * Math.cos(angle),\r | |
58 | fromY: attr.centerY + (attr.endRho + linePadding) * Math.sin(angle),\r | |
59 | \r | |
60 | toX: attr.centerX + (attr.endRho + linePadding + tickSize) * Math.cos(angle),\r | |
61 | toY: attr.centerY + (attr.endRho + linePadding + tickSize) * Math.sin(angle)\r | |
62 | }));\r | |
63 | }\r | |
64 | },\r | |
65 | \r | |
66 | // This renderer is called for each pie slice of the series only once\r | |
67 | // on initial chart render. The renderer doesn't actually change\r | |
68 | // the style of the series sprites. Its only job is to create\r | |
69 | // and position the region sprites in the chart.\r | |
70 | onDummySliceRender: function (sprite, config, data, index) {\r | |
71 | // Please see the comments in the KitchenSink.store.Unemployment class\r | |
72 | // for more info on the meaning of the record fields.\r | |
73 | var me = this,\r | |
74 | ln = me.regions.length,\r | |
75 | record = data.store.getAt(index),\r | |
76 | label = record.get('label'),\r | |
77 | spriteSurface = sprite.getSurface(), // 'series' surface\r | |
78 | chart = spriteSurface.ownerCt,\r | |
79 | overlaySurface = chart.getSurface('overlay'),\r | |
80 | attr = sprite.attr,\r | |
81 | region;\r | |
82 | \r | |
83 | // Because the regionIndex is declared and initialized in the closure\r | |
84 | // that's only executed once (when the view is defined),\r | |
85 | // we need to reset the regionIndex every time the example is shown.\r | |
86 | if (chart.resetRegionIndex) {\r | |
87 | me.regionIndex = 0;\r | |
88 | delete chart.resetRegionIndex;\r | |
89 | }\r | |
90 | \r | |
91 | // If it's a sector that shows the change in unemployment with a color\r | |
92 | if (label !== '' && label !== 'year') {\r | |
93 | \r | |
94 | // If not all region sprites have been created yet.\r | |
95 | if (me.regionIndex !== ln) {\r | |
96 | // Since the renderer function is called for all the sectors\r | |
97 | // of the 'pie' series sprite in the store record order,\r | |
98 | // we can create region sprites on the first 'swipe' through the sectors\r | |
99 | // when the pie series sprite is rendered for the first time,\r | |
100 | // and remove the renderer afterwards.\r | |
101 | me.region = region = me.regions[me.regionIndex];\r | |
102 | \r | |
103 | if (label === region.start) {\r | |
104 | \r | |
105 | me.startAngle = attr.startAngle;\r | |
106 | region.startIndex = index;\r | |
107 | \r | |
108 | } else if (label === region.end) {\r | |
109 | \r | |
110 | me.endAngle = attr.endAngle;\r | |
111 | region.endIndex = index;\r | |
112 | \r | |
113 | region.sprites = [];\r | |
114 | \r | |
115 | region.sprites.push(overlaySurface.add({\r | |
116 | type: 'arc',\r | |
117 | strokeStyle: 'gray',\r | |
118 | \r | |
119 | cx: attr.centerX,\r | |
120 | cy: attr.centerY,\r | |
121 | \r | |
122 | r: attr.endRho + me.linePadding,\r | |
123 | \r | |
124 | translationX: attr.translationX,\r | |
125 | translationY: attr.translationY,\r | |
126 | rotationRads: attr.rotationRads,\r | |
127 | \r | |
128 | startAngle: me.startAngle,\r | |
129 | endAngle: me.endAngle\r | |
130 | }));\r | |
131 | \r | |
132 | me.addTicks(overlaySurface, attr, [me.startAngle, me.endAngle], region.sprites);\r | |
133 | \r | |
134 | // Label region lines with text sprites.\r | |
135 | region.sprites.push(overlaySurface.add({\r | |
136 | type: 'arctext',\r | |
137 | text: region.name,\r | |
138 | spacing: 2,\r | |
139 | centerX: attr.centerX,\r | |
140 | centerY: attr.centerY,\r | |
141 | radius: attr.endRho + me.linePadding * 2,\r | |
142 | angle: ((me.startAngle + me.endAngle) * 0.5 + attr.rotationRads) / Math.PI * 180,\r | |
143 | translationX: attr.translationX,\r | |
144 | translationY: attr.translationY,\r | |
145 | template: {\r | |
146 | type: 'text',\r | |
147 | fontSize: 13,\r | |
148 | fontWeight: 'normal',\r | |
149 | fillStyle: 'gray'\r | |
150 | \r | |
151 | }\r | |
152 | }));\r | |
153 | me.regionIndex++;\r | |
154 | }\r | |
155 | \r | |
156 | }\r | |
157 | }\r | |
158 | \r | |
159 | sprite.attr.renderer = null;\r | |
160 | },\r | |
161 | \r | |
162 | onSliceRender2012: function (sprite, config, data, index) {\r | |
163 | // Please see the comments in the KitchenSink.store.Unemployment class\r | |
164 | // for more info on the meaning of the record fields.\r | |
165 | var record = data.store.getAt(index),\r | |
166 | label = record.get('label'),\r | |
167 | unemployment = record.get('y2012'),\r | |
168 | style = {};\r | |
169 | \r | |
170 | if (label === '') { // a separating sector\r | |
171 | style.fillStyle = 'none';\r | |
172 | style.strokeStyle = 'none';\r | |
173 | } else if (label === 'year') { // a sector that shows a year\r | |
174 | style.fillStyle = 'rgba(70, 70, 69, 1.0)';\r | |
175 | } else { // a sector that shows the change in unemployment with a color\r | |
176 | style.fillStyle = this.getStateColor(unemployment);\r | |
177 | }\r | |
178 | return style;\r | |
179 | },\r | |
180 | \r | |
181 | onLabelRender2012: function (text, sprite, config, data, index) {\r | |
182 | if (text === 'year') {\r | |
183 | return {\r | |
184 | text: '2012',\r | |
185 | font: 'bold 16px sans-serif'\r | |
186 | };\r | |
187 | }\r | |
188 | },\r | |
189 | \r | |
190 | onSliceRender2011: function (sprite, config, data, index) {\r | |
191 | var record = data.store.getAt(index),\r | |
192 | label = record.get('label'),\r | |
193 | style = {};\r | |
194 | \r | |
195 | if (label === '') {\r | |
196 | style.fillStyle = 'none';\r | |
197 | style.strokeStyle = 'none';\r | |
198 | } else if (label === 'year') {\r | |
199 | style.fillStyle = 'rgba(70, 70, 69, 1.0)';\r | |
200 | } else {\r | |
201 | style.fillStyle = this.getStateColor(record.get('y2011'));\r | |
202 | }\r | |
203 | return style;\r | |
204 | },\r | |
205 | \r | |
206 | onLabelRender2011: function (text, sprite, config, data, index) {\r | |
207 | if (text === 'year') {\r | |
208 | return {\r | |
209 | text: '2011'\r | |
210 | };\r | |
211 | } else {\r | |
212 | return {\r | |
213 | hidden: true\r | |
214 | };\r | |
215 | }\r | |
216 | },\r | |
217 | \r | |
218 | onSliceRender2010: function (sprite, config, data, index) {\r | |
219 | var record = data.store.getAt(index),\r | |
220 | label = record.get('label'),\r | |
221 | style = {};\r | |
222 | \r | |
223 | if (label === '') {\r | |
224 | style.fillStyle = 'none';\r | |
225 | style.strokeStyle = 'none';\r | |
226 | } else if (label === 'year') {\r | |
227 | style.fillStyle = 'rgba(70, 70, 69, 1.0)';\r | |
228 | } else {\r | |
229 | style.fillStyle = this.getStateColor(record.get('y2010'));\r | |
230 | }\r | |
231 | return style;\r | |
232 | },\r | |
233 | \r | |
234 | onLabelRender2010: function (text, sprite, config, data, index) {\r | |
235 | if (text === 'year') {\r | |
236 | return {\r | |
237 | text: '2010'\r | |
238 | };\r | |
239 | } else {\r | |
240 | return {\r | |
241 | hidden: true\r | |
242 | };\r | |
243 | }\r | |
244 | },\r | |
245 | \r | |
246 | onSliceRender2009: function (sprite, config, data, index) {\r | |
247 | var record = data.store.getAt(index),\r | |
248 | label = record.get('label'),\r | |
249 | style = {};\r | |
250 | \r | |
251 | if (label === '') {\r | |
252 | style.fillStyle = 'none';\r | |
253 | style.strokeStyle = 'none';\r | |
254 | } else if (label === 'year') {\r | |
255 | style.fillStyle = 'rgba(70, 70, 69, 1.0)';\r | |
256 | } else {\r | |
257 | style.fillStyle = this.getStateColor(record.get('y2009'));\r | |
258 | }\r | |
259 | return style;\r | |
260 | },\r | |
261 | \r | |
262 | onLabelRender2009: function (text, sprite, config, data, index) {\r | |
263 | if (text === 'year') {\r | |
264 | return {\r | |
265 | text: '2009'\r | |
266 | };\r | |
267 | } else {\r | |
268 | return {\r | |
269 | hidden: true\r | |
270 | };\r | |
271 | }\r | |
272 | },\r | |
273 | \r | |
274 | onSliceRender2008: function (sprite, config, data, index) {\r | |
275 | var record = data.store.getAt(index),\r | |
276 | label = record.get('label'),\r | |
277 | style = {};\r | |
278 | \r | |
279 | if (label === '') {\r | |
280 | style.fillStyle = 'none';\r | |
281 | style.strokeStyle = 'none';\r | |
282 | } else if (label === 'year') {\r | |
283 | style.fillStyle = 'rgba(70, 70, 69, 1.0)';\r | |
284 | } else {\r | |
285 | style.fillStyle = this.getStateColor(record.get('y2008'));\r | |
286 | }\r | |
287 | return style;\r | |
288 | },\r | |
289 | \r | |
290 | onLabelRender2008: function (text, sprite, config, data, index) {\r | |
291 | if (text === 'year') {\r | |
292 | return {\r | |
293 | text: '2008'\r | |
294 | };\r | |
295 | } else {\r | |
296 | return {\r | |
297 | hidden: true\r | |
298 | };\r | |
299 | }\r | |
300 | },\r | |
301 | \r | |
302 | onSliceRender2007: function (sprite, config, data, index) {\r | |
303 | var record = data.store.getAt(index),\r | |
304 | label = record.get('label'),\r | |
305 | style = {};\r | |
306 | \r | |
307 | if (label === '') {\r | |
308 | style.fillStyle = 'none';\r | |
309 | style.strokeStyle = 'none';\r | |
310 | } else if (label === 'year') {\r | |
311 | style.fillStyle = 'rgba(70, 70, 69, 1.0)';\r | |
312 | } else {\r | |
313 | style.fillStyle = this.getStateColor(record.get('y2007'));\r | |
314 | }\r | |
315 | return style;\r | |
316 | },\r | |
317 | \r | |
318 | onLabelRender2007: function (text, sprite, config, data, index) {\r | |
319 | if (text === 'year') {\r | |
320 | return {\r | |
321 | text: '2007'\r | |
322 | };\r | |
323 | } else {\r | |
324 | return {\r | |
325 | hidden: true\r | |
326 | };\r | |
327 | }\r | |
328 | },\r | |
329 | \r | |
330 | onItemHighlight: function (chart, item) {\r | |
331 | // The 'item' parameter here is an object that holds information\r | |
332 | // about the highlighted item, like its 'index', the 'series' it belongs to,\r | |
333 | // the associated store 'record' and its 'field'.\r | |
334 | \r | |
335 | var regions = this.regions,\r | |
336 | label = item.record.get('label'),\r | |
337 | cartesianChart = this.lookupReference('cartesian'),\r | |
338 | data = item.record.data,\r | |
339 | i, j, ik, jk, region, sprite;\r | |
340 | \r | |
341 | if (!label || label === 'year') {\r | |
342 | // Don't highlight the sectors that separate the regions\r | |
343 | // and the sector that shows the year.\r | |
344 | item.series.setAttributesForItem(item, {\r | |
345 | highlighted: false\r | |
346 | });\r | |
347 | } else {\r | |
348 | chart.getSurface('chart').get('stateName').setAttributes({\r | |
349 | text: item.record.get('state')\r | |
350 | });\r | |
351 | // Display unemployment changes for the highlighted state inside the cartesian chart.\r | |
352 | cartesianChart.setStore({\r | |
353 | fields: ['year', 'percent'],\r | |
354 | data: [\r | |
355 | {year: '2007', percent: data.y2007},\r | |
356 | {year: '2008', percent: data.y2008},\r | |
357 | {year: '2009', percent: data.y2009},\r | |
358 | {year: '2010', percent: data.y2010},\r | |
359 | {year: '2011', percent: data.y2011},\r | |
360 | {year: '2012', percent: data.y2012}\r | |
361 | ]\r | |
362 | });\r | |
363 | }\r | |
364 | \r | |
365 | if (!regions) {\r | |
366 | return;\r | |
367 | }\r | |
368 | \r | |
369 | // Find the region the highlighted state sector belongs to and highlight its sprites,\r | |
370 | // while unhighlighting all other regions.\r | |
371 | for (i = 0, ik = regions.length; i < ik; i++) {\r | |
372 | region = regions[i];\r | |
373 | if (item.index >= region.startIndex && item.index <= region.endIndex) {\r | |
374 | if (!region.highlighted) {\r | |
375 | for (j = 0, jk = region.sprites.length; j < jk; j++) {\r | |
376 | sprite = region.sprites[j];\r | |
377 | if (sprite.type === 'arctext') {\r | |
378 | sprite.getTemplate().setAttributes({\r | |
379 | fillStyle: 'red'\r | |
380 | });\r | |
381 | } else {\r | |
382 | sprite.setAttributes({\r | |
383 | strokeStyle: 'red',\r | |
384 | lineWidth: 1.5\r | |
385 | });\r | |
386 | }\r | |
387 | }\r | |
388 | region.highlighted = true;\r | |
389 | }\r | |
390 | } else if (region.highlighted) {\r | |
391 | for (j = 0, jk = region.sprites.length; j < jk; j++) {\r | |
392 | sprite = region.sprites[j];\r | |
393 | if (sprite.type === 'arctext') {\r | |
394 | sprite.getTemplate().setAttributes({\r | |
395 | fillStyle: 'black'\r | |
396 | });\r | |
397 | } else {\r | |
398 | sprite.setAttributes({\r | |
399 | strokeStyle: 'gray',\r | |
400 | lineWidth: 1\r | |
401 | });\r | |
402 | }\r | |
403 | }\r | |
404 | region.highlighted = false;\r | |
405 | }\r | |
406 | }\r | |
407 | \r | |
408 | if (!Ext.is.Desktop) {\r | |
409 | chart.redraw();\r | |
410 | }\r | |
411 | },\r | |
412 | \r | |
413 | onBarRender: function (sprite, config, data, index) {\r | |
414 | var percent = data.store.getAt(index).get('percent');\r | |
415 | \r | |
416 | return {\r | |
417 | fillStyle: this.getStateColor(percent)\r | |
418 | };\r | |
419 | },\r | |
420 | \r | |
421 | // Returns color based on percentage change in unemployment.\r | |
422 | getStateColor: function (unemployment) {\r | |
423 | if (unemployment < -1.5) {\r | |
424 | return 'rgba(114, 166, 185, 1.0)';\r | |
425 | } else if (unemployment < -0.5) {\r | |
426 | return 'rgba(194, 212, 221, 1.0)';\r | |
427 | } else if (unemployment < 0.5) {\r | |
428 | return 'rgba(126, 135, 142, 1.0)';\r | |
429 | } else if (unemployment < 1.5) {\r | |
430 | return 'rgba(179, 113, 114, 1.0)';\r | |
431 | } else {\r | |
432 | return 'rgba(146, 50, 51, 1.0)';\r | |
433 | }\r | |
434 | },\r | |
435 | \r | |
436 | onAfterRender: function (chart) {\r | |
437 | // Get the series used for highlighting (belong to a separate chart,\r | |
438 | // that uses 'itemhighlight' interaction).\r | |
439 | var series = chart.getSeries()[0],\r | |
440 | store = chart.getStore(),\r | |
441 | index = store.find('label', 'CA');\r | |
442 | \r | |
443 | chart.resetRegionIndex = true;\r | |
444 | chart.on({\r | |
445 | redraw: function () {\r | |
446 | // Highlight the California state by default.\r | |
447 | chart.setHighlightItem(series.getItemByIndex(index, 'sprites'));\r | |
448 | // Re-render the overlay surface with the state region sprites\r | |
449 | // to make sure they are positioned correctly.\r | |
450 | chart.getSurface('overlay').renderFrame();\r | |
451 | },\r | |
452 | single: true\r | |
453 | });\r | |
454 | },\r | |
455 | \r | |
456 | onBeforeRender: function () {\r | |
457 | // Make Ext.draw.TextMeasurer use the Ext.util.TextMetrics to measure text,\r | |
458 | // which is a more precise but much slower solution.\r | |
459 | // For this example it shouldn't be a noticable performace hit,\r | |
460 | // since we made optimizations elsewhere.\r | |
461 | Ext.draw.TextMeasurer.precise = true;\r | |
462 | },\r | |
463 | \r | |
464 | onDestroy: function () {\r | |
465 | var regions = this.regions,\r | |
466 | i, region;\r | |
467 | \r | |
468 | for (i = 0; i < regions.length; i++) {\r | |
469 | region = regions[i];\r | |
470 | delete region.sprites;\r | |
471 | }\r | |
472 | \r | |
473 | this.regionIndex = 0;\r | |
474 | \r | |
475 | Ext.draw.TextMeasurer.precise = false;\r | |
476 | }\r | |
477 | \r | |
478 | }); |