extjs-gpl
Version:
GPL licensed version of Sencha Ext JS
480 lines (418 loc) • 16.3 kB
JavaScript
Ext.define('KitchenSink.view.charts.combination.UnemploymentController', {
extend: 'Ext.app.ViewController',
alias: 'controller.unemployment',
// State regions.
// A region line spans from the 'start' state through the 'end' state.
regions: [{
name: 'Northeast Region',
start: 'CT',
end: 'VT'
}, {
name: 'Southeast Region',
start: 'AL',
end: 'VA'
}, {
name: 'Midwest Region',
start: 'WI',
end: 'AR'
}, {
name: 'Southwest Region',
start: 'AZ',
end: 'UT'
}, {
name: 'Northwest Region',
start: 'AK',
end: 'WY'
}],
regionIndex: 0,
linePadding: 5,
tickSize: 10,
startAngle: 0,
endAngle: 0,
region: null,
/**
* Adds ticks to the ends of a region line.
* @param surface The surface to put the ticks into.
* @param attr The style of the ticks.
* @param angles Array with angles to put the ticks at.
* @param sprites The array to add the created tick sprites to (for future reference).
*/
addTicks: function (surface, attr, angles, sprites) {
var linePadding = this.linePadding,
tickSize = this.tickSize,
i, ln, angle;
for (i = 0, ln = angles.length; i < ln; i++) {
angle = angles[i] + attr.rotationRads;
sprites.push(surface.add({
type: 'line',
strokeStyle: 'gray',
translationX: attr.translationX,
translationY: attr.translationY,
fromX: attr.centerX + (attr.endRho + linePadding) * Math.cos(angle),
fromY: attr.centerY + (attr.endRho + linePadding) * Math.sin(angle),
toX: attr.centerX + (attr.endRho + linePadding + tickSize) * Math.cos(angle),
toY: attr.centerY + (attr.endRho + linePadding + tickSize) * Math.sin(angle)
}));
}
},
// This renderer is called for each pie slice of the series only once
// on initial chart render. The renderer doesn't actually change
// the style of the series sprites. Its only job is to create
// and position the region sprites in the chart.
onDummySliceRender: function (sprite, config, data, index) {
// Please see the comments in the KitchenSink.store.Unemployment class
// for more info on the meaning of the record fields.
var me = this,
ln = me.regions.length,
record = data.store.getAt(index),
label = record.get('label'),
spriteSurface = sprite.getSurface(), // 'series' surface
chart = spriteSurface.ownerCt,
overlaySurface = chart.getSurface('overlay'),
attr = sprite.attr,
region;
// Because the regionIndex is declared and initialized in the closure
// that's only executed once (when the view is defined),
// we need to reset the regionIndex every time the example is shown.
if (chart.resetRegionIndex) {
me.regionIndex = 0;
delete chart.resetRegionIndex;
}
// If it's a sector that shows the change in unemployment with a color
if (label !== '' && label !== 'year') {
// If not all region sprites have been created yet.
if (me.regionIndex !== ln) {
// Since the renderer function is called for all the sectors
// of the 'pie' series sprite in the store record order,
// we can create region sprites on the first 'swipe' through the sectors
// when the pie series sprite is rendered for the first time,
// and remove the renderer afterwards.
me.region = region = me.regions[me.regionIndex];
if (label === region.start) {
me.startAngle = attr.startAngle;
region.startIndex = index;
} else if (label === region.end) {
me.endAngle = attr.endAngle;
region.endIndex = index;
region.sprites = [];
region.sprites.push(overlaySurface.add({
type: 'arc',
strokeStyle: 'gray',
cx: attr.centerX,
cy: attr.centerY,
r: attr.endRho + me.linePadding,
translationX: attr.translationX,
translationY: attr.translationY,
rotationRads: attr.rotationRads,
startAngle: me.startAngle,
endAngle: me.endAngle
}));
me.addTicks(overlaySurface, attr, [me.startAngle, me.endAngle], region.sprites);
// Label region lines with text sprites.
region.sprites.push(overlaySurface.add({
type: 'arctext',
text: region.name,
spacing: 2,
centerX: attr.centerX,
centerY: attr.centerY,
radius: attr.endRho + me.linePadding * 2,
angle: ((me.startAngle + me.endAngle) * 0.5 + attr.rotationRads) / Math.PI * 180,
translationX: attr.translationX,
translationY: attr.translationY,
template: {
type: 'text',
fontSize: 13,
fontWeight: 'normal',
fillStyle: 'gray'
}
}));
me.regionIndex++;
}
}
}
sprite.attr.renderer = null;
},
onSliceRender2012: function (sprite, config, data, index) {
// Please see the comments in the KitchenSink.store.Unemployment class
// for more info on the meaning of the record fields.
var record = data.store.getAt(index),
label = record.get('label'),
unemployment = record.get('y2012'),
style = {};
if (label === '') { // a separating sector
style.fillStyle = 'none';
style.strokeStyle = 'none';
} else if (label === 'year') { // a sector that shows a year
style.fillStyle = 'rgba(70, 70, 69, 1.0)';
} else { // a sector that shows the change in unemployment with a color
style.fillStyle = this.getStateColor(unemployment);
}
return style;
},
onLabelRender2012: function (text, sprite, config, data, index) {
if (text === 'year') {
return {
text: '2012',
font: 'bold 16px sans-serif'
};
}
},
onSliceRender2011: function (sprite, config, data, index) {
var record = data.store.getAt(index),
label = record.get('label'),
style = {};
if (label === '') {
style.fillStyle = 'none';
style.strokeStyle = 'none';
} else if (label === 'year') {
style.fillStyle = 'rgba(70, 70, 69, 1.0)';
} else {
style.fillStyle = this.getStateColor(record.get('y2011'));
}
return style;
},
onLabelRender2011: function (text, sprite, config, data, index) {
if (text === 'year') {
return {
text: '2011'
};
} else {
return {
hidden: true
};
}
},
onSliceRender2010: function (sprite, config, data, index) {
var record = data.store.getAt(index),
label = record.get('label'),
style = {};
if (label === '') {
style.fillStyle = 'none';
style.strokeStyle = 'none';
} else if (label === 'year') {
style.fillStyle = 'rgba(70, 70, 69, 1.0)';
} else {
style.fillStyle = this.getStateColor(record.get('y2010'));
}
return style;
},
onLabelRender2010: function (text, sprite, config, data, index) {
if (text === 'year') {
return {
text: '2010'
};
} else {
return {
hidden: true
};
}
},
onSliceRender2009: function (sprite, config, data, index) {
var record = data.store.getAt(index),
label = record.get('label'),
style = {};
if (label === '') {
style.fillStyle = 'none';
style.strokeStyle = 'none';
} else if (label === 'year') {
style.fillStyle = 'rgba(70, 70, 69, 1.0)';
} else {
style.fillStyle = this.getStateColor(record.get('y2009'));
}
return style;
},
onLabelRender2009: function (text, sprite, config, data, index) {
if (text === 'year') {
return {
text: '2009'
};
} else {
return {
hidden: true
};
}
},
onSliceRender2008: function (sprite, config, data, index) {
var record = data.store.getAt(index),
label = record.get('label'),
style = {};
if (label === '') {
style.fillStyle = 'none';
style.strokeStyle = 'none';
} else if (label === 'year') {
style.fillStyle = 'rgba(70, 70, 69, 1.0)';
} else {
style.fillStyle = this.getStateColor(record.get('y2008'));
}
return style;
},
onLabelRender2008: function (text, sprite, config, data, index) {
if (text === 'year') {
return {
text: '2008'
};
} else {
return {
hidden: true
};
}
},
onSliceRender2007: function (sprite, config, data, index) {
var record = data.store.getAt(index),
label = record.get('label'),
style = {};
if (label === '') {
style.fillStyle = 'none';
style.strokeStyle = 'none';
} else if (label === 'year') {
style.fillStyle = 'rgba(70, 70, 69, 1.0)';
} else {
style.fillStyle = this.getStateColor(record.get('y2007'));
}
return style;
},
onLabelRender2007: function (text, sprite, config, data, index) {
if (text === 'year') {
return {
text: '2007'
};
} else {
return {
hidden: true
};
}
},
onItemHighlight: function (chart, item) {
// The 'item' parameter here is an object that holds information
// about the highlighted item, like its 'index', the 'series' it belongs to,
// the associated store 'record' and its 'field'.
var regions = this.regions,
label = item.record.get('label'),
cartesianChart = this.lookupReference('cartesian'),
data = item.record.data,
i, j, ik, jk, region, sprite;
if (!label || label === 'year') {
// Don't highlight the sectors that separate the regions
// and the sector that shows the year.
item.series.setAttributesForItem(item, {
highlighted: false
});
} else {
chart.getSurface('chart').get('stateName').setAttributes({
text: item.record.get('state')
});
// Display unemployment changes for the highlighted state inside the cartesian chart.
cartesianChart.setStore({
fields: ['year', 'percent'],
data: [
{year: '2007', percent: data.y2007},
{year: '2008', percent: data.y2008},
{year: '2009', percent: data.y2009},
{year: '2010', percent: data.y2010},
{year: '2011', percent: data.y2011},
{year: '2012', percent: data.y2012}
]
});
}
if (!regions) {
return;
}
// Find the region the highlighted state sector belongs to and highlight its sprites,
// while unhighlighting all other regions.
for (i = 0, ik = regions.length; i < ik; i++) {
region = regions[i];
if (item.index >= region.startIndex && item.index <= region.endIndex) {
if (!region.highlighted) {
for (j = 0, jk = region.sprites.length; j < jk; j++) {
sprite = region.sprites[j];
if (sprite.type === 'arctext') {
sprite.getTemplate().setAttributes({
fillStyle: 'red'
});
} else {
sprite.setAttributes({
strokeStyle: 'red',
lineWidth: 1.5
});
}
}
region.highlighted = true;
}
} else if (region.highlighted) {
for (j = 0, jk = region.sprites.length; j < jk; j++) {
sprite = region.sprites[j];
if (sprite.type === 'arctext') {
sprite.getTemplate().setAttributes({
fillStyle: 'black'
});
} else {
sprite.setAttributes({
strokeStyle: 'gray',
lineWidth: 1
});
}
}
region.highlighted = false;
}
}
if (!Ext.is.Desktop) {
chart.redraw();
}
},
onBarRender: function (sprite, config, data, index) {
var percent = data.store.getAt(index).get('percent');
return {
fillStyle: this.getStateColor(percent)
};
},
// Returns color based on percentage change in unemployment.
getStateColor: function (unemployment) {
if (unemployment < -1.5) {
return 'rgba(114, 166, 185, 1.0)';
} else if (unemployment < -0.5) {
return 'rgba(194, 212, 221, 1.0)';
} else if (unemployment < 0.5) {
return 'rgba(126, 135, 142, 1.0)';
} else if (unemployment < 1.5) {
return 'rgba(179, 113, 114, 1.0)';
} else {
return 'rgba(146, 50, 51, 1.0)';
}
},
onAfterRender: function (chart) {
// Get the series used for highlighting (belong to a separate chart,
// that uses 'itemhighlight' interaction).
var series = chart.getSeries()[0],
store = chart.getStore(),
index = store.find('label', 'CA');
chart.resetRegionIndex = true;
chart.on({
redraw: function () {
// Highlight the California state by default.
chart.setHighlightItem(series.getItemByIndex(index, 'sprites'));
// Re-render the overlay surface with the state region sprites
// to make sure they are positioned correctly.
chart.getSurface('overlay').renderFrame();
},
single: true
});
},
onBeforeRender: function () {
// Make Ext.draw.TextMeasurer use the Ext.util.TextMetrics to measure text,
// which is a more precise but much slower solution.
// For this example it shouldn't be a noticable performace hit,
// since we made optimizations elsewhere.
Ext.draw.TextMeasurer.precise = true;
},
destroy: function () {
var regions = this.regions,
i, region;
for (i = 0; i < regions.length; i++) {
region = regions[i];
delete region.sprites;
}
this.regionIndex = 0;
Ext.draw.TextMeasurer.precise = false;
this.callParent();
}
});