app/assets/javascripts/widgets/indicators/stacked/StackedChartIndicator.js
define(
[
'backbone',
'underscore',
'd3',
'handlebars',
'widgets/views/IndicatorView',
'widgets/models/IndicatorModel',
'widgets/indicators/stacked/StackedChart',
'text!widgets/templates/indicators/no-data.handlebars',
'text!widgets/templates/indicators/stacked/stackedchart.handlebars',
'text!widgets/templates/indicators/stacked/stackedchart-legend.handlebars'
],
function(
Backbone,
_,
d3,
Handlebars,
IndicatorView,
IndicatorModel,
StackedChart,
noDataTpl,
tpl,
legendTpl
) {
'use strict';
var StackedChartIndicator = IndicatorView.extend({
templates: {
noData: Handlebars.compile(noDataTpl),
legend: Handlebars.compile(legendTpl),
chart: Handlebars.compile(tpl)
},
events: function() {
return _.extend({}, IndicatorView.prototype.events, {
'change .section': 'changeSection'
});
},
initialize: function(setup) {
this.constructor.__super__.initialize.apply(this, [setup]);
this.$el.addClass('is-loading');
this.model = new (Backbone.Model.extend({
defaults: setup.model
}))();
this.fetchData(setup);
},
fetchData: function(setup) {
var status = {
promises: []
};
_.each(
this.model.get('indicators'),
_.bind(function(i) {
var deferred = $.Deferred();
new IndicatorModel({ id: i.id })
.fetch({
data: this.setFetchParams(setup.data)
})
.done(function(data) {
deferred.resolve(data);
});
status.promises.push(deferred);
}, this)
);
// Promises of each country resolved
$.when.apply(null, status.promises).then(
_.bind(function() {
this.$el.removeClass('is-loading');
var args = Array.prototype.slice.call(arguments);
var values = _.flatten(
_.compact(
_.map(args, function(i) {
return i.values;
})
)
);
if (!!values.length) {
values = _.groupBy(values, 'indicator_id');
var unit = this.model.get('unit');
var filtered = _.filter(this.model.get('indicators'), function(
i
) {
return values[i.id] && values[i.id][0];
});
var data = _.map(filtered, function(i) {
var aux = values[i.id][0];
var displayName = '';
if (aux) {
displayName = aux.id_1
? aux.sub_nat_name // eslint-disable-line
: aux.boundary_name !== 'administrative boundary'
? aux.boundary_name
: aux.country_name;
}
i.location_name = displayName;
i.data = values[i.id];
return i;
});
this.model.set('data', data);
this.render();
} else {
this.$el.html(this.templates.noData({ classname: 'pie' }));
}
}, this)
);
},
render: function() {
this.$el.html(this.templates.chart());
this.cacheVars();
this.setStatusValues();
this.drawGraph();
return this;
},
parseData: function() {
var totalVal = _.findWhere(this.model.get('data'), { type: 'total' })
.data[0].value;
var shortened = d3.format(',.0f')(totalVal);
var scientific = d3.format('.3s')(totalVal);
return {
cumulative: this.model.get('cumulative'),
location_name: this.model.get('data')[0].location_name,
total: totalVal > 1000 ? scientific : shortened,
millionsTotal: shortened
};
},
cacheVars: function() {
this.$legend = this.$el.find('.stacked-legend');
},
setStatusValues: function() {
var t = this.model.toJSON();
if (!!t.section) {
this.$section.val(t.section);
this.$section_name.text(t.section);
}
},
// SELECT
changeSection: function(e) {
this.$section_name.text($(e.currentTarget).val());
},
// GRAPH
drawGraph: function() {
var data = this.getGraphData();
var rangeX = this.getRangeX(data);
var rangeY = this.getRangeY(data);
var indicators = this.model.get('indicators');
this.stackedChart = new StackedChart({
parent: this,
el: this.$el.find('#stacked-graph')[0],
id: _.pluck(indicators, 'id').join(''),
data: data,
indicators: indicators,
unit: this.model.get('unit'),
unitname: this.model.get('unitname'),
rangeX: rangeX,
rangeY: rangeY,
lock: this.model.get('lock'),
sizing: { top: 10, right: 10, bottom: 20, left: 0 },
innerPadding: { top: 20, right: 10, bottom: 20, left: 50 },
keys: { x: 'year', y: 'value' }
});
this.stackedChart.render();
},
_drawLegend: function(legend) {
this.$legend.html(this.templates.legend({ legend: legend }));
},
// get the range of years;
getRangeX: function() {
var values = _.flatten(_.union(Array.prototype.slice.call(arguments)));
var min = _.min(values, function(o) {
return o.year;
}).year;
var max = _.max(values, function(o) {
return o.year;
}).year;
return [min, max];
},
// get the range of values;
getRangeY: function() {
var values = _.flatten(_.union(Array.prototype.slice.call(arguments)));
var min = _.min(values, function(o) {
return o.value;
}).value;
var max = _.max(values, function(o) {
return o.value;
}).value;
// We add the 20ยบ part of the max and the min value to prevent the y-axis disappear,
return [min - Math.abs(min / 20), max + Math.abs(max / 20)];
},
getGraphData: function() {
var parseDate = d3.time.format('%Y').parse;
var stackedIndicators = _.where(this.model.get('data'), {
type: 'stacked'
});
return _.map(stackedIndicators, function(indicator) {
return _.map(indicator.data, function(data) {
return {
year: parseDate(data.year.toString()),
value: data.value
};
});
});
}
});
return StackedChartIndicator;
}
);