191 lines
5.7 KiB
JavaScript
191 lines
5.7 KiB
JavaScript
|
var _ = require('underscore');
|
||
|
var CoreView = require('backbone/core-view');
|
||
|
var placeholderTemplate = require('./placeholder.tpl');
|
||
|
var contentTemplate = require('./content.tpl');
|
||
|
var HistogramView = require('./histogram-view');
|
||
|
var TimeSeriesHeaderView = require('./time-series-header-view');
|
||
|
var DropdownView = require('../dropdown/widget-dropdown-view');
|
||
|
var layerColors = require('../../util/layer-colors');
|
||
|
var analyses = require('../../data/analyses');
|
||
|
var escapeHTML = require('../../util/escape-html');
|
||
|
|
||
|
/**
|
||
|
* Widget content view for a time-series
|
||
|
*/
|
||
|
module.exports = CoreView.extend({
|
||
|
className: 'CDB-Widget-body CDB-Widget-body--timeSeries',
|
||
|
|
||
|
initialize: function () {
|
||
|
if (!this.model.dataviewModel) throw new Error('dataviewModel is required');
|
||
|
if (!this.model.layerModel) throw new Error('layerModel is required');
|
||
|
|
||
|
this._dataviewModel = this.model.dataviewModel;
|
||
|
this._layerModel = this.model.layerModel;
|
||
|
this._selectedAmount = 0;
|
||
|
this._initBinds();
|
||
|
},
|
||
|
|
||
|
render: function () {
|
||
|
this.clearSubViews();
|
||
|
this.$el.empty();
|
||
|
|
||
|
var sourceId = this._dataviewModel.get('source').id;
|
||
|
var letter = layerColors.letter(sourceId);
|
||
|
var sourceColor = layerColors.getColorForLetter(letter);
|
||
|
var sourceType = this._dataviewModel.getSourceType() || '';
|
||
|
var isSourceType = this._dataviewModel.isSourceType();
|
||
|
var layerName = isSourceType
|
||
|
? this.model.get('table_name')
|
||
|
: this._layerModel.get('layer_name');
|
||
|
|
||
|
if (this._isDataEmpty() || this._hasError()) {
|
||
|
this.$el.append(placeholderTemplate({
|
||
|
hasTorqueLayer: false
|
||
|
}));
|
||
|
} else {
|
||
|
this.$el.append(contentTemplate({
|
||
|
sourceId: sourceId,
|
||
|
sourceType: analyses.title(sourceType),
|
||
|
isSourceType: isSourceType,
|
||
|
showSource: this.model.get('show_source') && letter !== '',
|
||
|
sourceColor: sourceColor,
|
||
|
layerName: escapeHTML(layerName)
|
||
|
}));
|
||
|
this._createHistogramView();
|
||
|
this._createHeaderView();
|
||
|
this._createDropdownView();
|
||
|
this._updateRange();
|
||
|
}
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
_initBinds: function () {
|
||
|
this._dataviewModel.once('error', function () {
|
||
|
console.log('the tiler does not support non-torque layers just yet…');
|
||
|
});
|
||
|
|
||
|
this.listenTo(this._dataviewModel, 'change:data', this.render);
|
||
|
this.listenToOnce(this.model, 'change:hasInitialState', this.render);
|
||
|
|
||
|
this.listenTo(this._layerModel, 'change:layer_name', this.render);
|
||
|
this.add_related_model(this._layerModel);
|
||
|
},
|
||
|
|
||
|
_createHistogramView: function () {
|
||
|
if (this._histogramView) {
|
||
|
this._histogramView.remove();
|
||
|
}
|
||
|
|
||
|
this._histogramView = new HistogramView({
|
||
|
timeSeriesModel: this.model,
|
||
|
dataviewModel: this._dataviewModel,
|
||
|
layerModel: this._layerModel,
|
||
|
rangeFilter: this._dataviewModel.filter,
|
||
|
displayShadowBars: !this.model.get('normalized'),
|
||
|
normalized: !!this.model.get('normalized')
|
||
|
});
|
||
|
|
||
|
this.addView(this._histogramView);
|
||
|
this.$('.js-content').append(this._histogramView.render().el);
|
||
|
},
|
||
|
|
||
|
_createHeaderView: function () {
|
||
|
if (this._headerView) {
|
||
|
this._headerView.remove();
|
||
|
}
|
||
|
|
||
|
this._headerView = new TimeSeriesHeaderView({
|
||
|
dataviewModel: this._dataviewModel,
|
||
|
layerModel: this._layerModel,
|
||
|
rangeFilter: this._dataviewModel.filter,
|
||
|
timeSeriesModel: this.model,
|
||
|
showClearButton: true,
|
||
|
selectedAmount: this._selectedAmount
|
||
|
});
|
||
|
|
||
|
if (!this._histogramView) {
|
||
|
throw new Error('Histogram view must be instantiated before the header view');
|
||
|
}
|
||
|
this._headerView.bind('resetFilter', this._histogramView.resetFilter, this._histogramView);
|
||
|
this.addView(this._headerView);
|
||
|
this.$('.js-title').append(this._headerView.render().el);
|
||
|
},
|
||
|
|
||
|
_createDropdownView: function () {
|
||
|
if (this._dropdownView) {
|
||
|
this._dropdownView.remove();
|
||
|
}
|
||
|
|
||
|
this._dropdownView = new DropdownView({
|
||
|
model: this.model,
|
||
|
target: '.js-actions',
|
||
|
container: this.$('.js-header'),
|
||
|
flags: {
|
||
|
localTimezone: this._dataviewModel.getColumnType() === 'date',
|
||
|
normalizeHistogram: true,
|
||
|
canCollapse: false
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.addView(this._dropdownView);
|
||
|
},
|
||
|
|
||
|
_updateRange: function () {
|
||
|
var bars = this._calculateBars();
|
||
|
var bins = this._dataviewModel.get('bins');
|
||
|
var lo = Math.max(bars.loBarIndex, 0);
|
||
|
var hi = Math.min(bars.hiBarIndex, bins);
|
||
|
if (lo > 0 || hi < bins) {
|
||
|
this._histogramView.selectRange(lo, hi);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_calculateBars: function () {
|
||
|
var data = this._dataviewModel.getData();
|
||
|
var min = this.model.get('min');
|
||
|
var max = this.model.get('max');
|
||
|
var loBarIndex = this.model.get('lo_index');
|
||
|
var hiBarIndex = this.model.get('hi_index');
|
||
|
var startMin;
|
||
|
var startMax;
|
||
|
|
||
|
if (data.length > 0) {
|
||
|
if (!_.isNumber(min) && !_.isNumber(loBarIndex)) {
|
||
|
loBarIndex = 0;
|
||
|
} else if (_.isNumber(min) && !_.isNumber(loBarIndex)) {
|
||
|
startMin = _.findWhere(data, {start: min});
|
||
|
loBarIndex = (startMin && startMin.bin) || 0;
|
||
|
}
|
||
|
|
||
|
if (!_.isNumber(max) && !_.isNumber(hiBarIndex)) {
|
||
|
hiBarIndex = data.length;
|
||
|
} else if (_.isNumber(max) && !_.isNumber(hiBarIndex)) {
|
||
|
startMax = _.findWhere(data, {end: max});
|
||
|
hiBarIndex = (startMax && startMax.bin + 1) || data.length;
|
||
|
}
|
||
|
} else {
|
||
|
loBarIndex = 0;
|
||
|
hiBarIndex = data.length;
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
loBarIndex: loBarIndex,
|
||
|
hiBarIndex: hiBarIndex
|
||
|
};
|
||
|
},
|
||
|
|
||
|
_appendView: function (view) {
|
||
|
this.addView(view);
|
||
|
this.$el.append(view.render().el);
|
||
|
},
|
||
|
|
||
|
_isDataEmpty: function () {
|
||
|
var data = this._dataviewModel.getUnfilteredData();
|
||
|
return _.isEmpty(data) || _.size(data) === 0;
|
||
|
},
|
||
|
|
||
|
_hasError: function () {
|
||
|
return this._dataviewModel.has('error');
|
||
|
}
|
||
|
});
|