221 lines
6.3 KiB
JavaScript
221 lines
6.3 KiB
JavaScript
|
var _ = require('underscore');
|
||
|
var Backbone = require('backbone');
|
||
|
var WidgetDefinitionModel = require('./widget-definition-model');
|
||
|
var checkAndBuildOpts = require('builder/helpers/required-opts');
|
||
|
|
||
|
var REQUIRED_OPTS = [
|
||
|
'configModel',
|
||
|
'mapId',
|
||
|
'layerDefinitionsCollection',
|
||
|
'analysisDefinitionNodesCollection'
|
||
|
];
|
||
|
|
||
|
/**
|
||
|
* Collection of widget definitions, synhronizes the internal definitions and the widget models.
|
||
|
*/
|
||
|
module.exports = Backbone.Collection.extend({
|
||
|
comparator: 'order',
|
||
|
|
||
|
model: function (attrs, opts) {
|
||
|
var self = opts.collection;
|
||
|
attrs.order = !_.isUndefined(attrs.order) ? attrs.order : 0;
|
||
|
var model = new WidgetDefinitionModel(attrs, {
|
||
|
parse: true, // make sure data is structured as expected
|
||
|
collection: self,
|
||
|
configModel: self._configModel,
|
||
|
mapId: self._mapId
|
||
|
});
|
||
|
return model;
|
||
|
},
|
||
|
|
||
|
initialize: function (models, opts) {
|
||
|
var self = this;
|
||
|
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
|
||
|
|
||
|
this._bindLayerStyleChanges();
|
||
|
|
||
|
this._attrsForThisTypeMap = {
|
||
|
formula: function (model) {
|
||
|
return {
|
||
|
column: model.get('column'),
|
||
|
operation: model.get('operation') || 'max'
|
||
|
};
|
||
|
},
|
||
|
category: function (model) {
|
||
|
var columnName = model.get('column');
|
||
|
return {
|
||
|
aggregation: model.get('aggregation') || 'count',
|
||
|
aggregation_column: model.get('aggregation_column') || columnName,
|
||
|
column: columnName,
|
||
|
widget_style_definition: model.get('widget_style_definition') || WidgetDefinitionModel.getDefaultWidgetStyle('category'),
|
||
|
auto_style_definition: undefined
|
||
|
};
|
||
|
},
|
||
|
histogram: function (model) {
|
||
|
return {
|
||
|
column: model.get('column'),
|
||
|
bins: model.get('bins') || 10,
|
||
|
column_type: 'number',
|
||
|
widget_style_definition: model.get('widget_style_definition') || WidgetDefinitionModel.getDefaultWidgetStyle('histogram'),
|
||
|
auto_style_definition: undefined
|
||
|
};
|
||
|
},
|
||
|
'time-series': function (model) {
|
||
|
return {
|
||
|
column: model.get('column'),
|
||
|
bins: model.get('bins') || 256,
|
||
|
aggregation: model.get('aggregation'),
|
||
|
column_type: self.getColumnType(model.get('column'), model.get('source')),
|
||
|
widget_style_definition: model.get('widget_style_definition') || WidgetDefinitionModel.getDefaultWidgetStyle('time-series')
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
},
|
||
|
|
||
|
url: function () {
|
||
|
var baseUrl = this._configModel.get('base_url');
|
||
|
return baseUrl + '/api/v3/maps/' + this._mapId + '/widgets';
|
||
|
},
|
||
|
|
||
|
parse: function (response) {
|
||
|
return response && response.widgets
|
||
|
? response.widgets
|
||
|
: [];
|
||
|
},
|
||
|
|
||
|
_bindLayerStyleChanges: function () {
|
||
|
this._layerDefinitionsCollection.bind('change:style_properties', this._onLayerStyleChanged, this);
|
||
|
},
|
||
|
|
||
|
_onLayerStyleChanged: function (layerDefModel) {
|
||
|
var styleModel = layerDefModel.styleModel;
|
||
|
var isAllowed = styleModel && styleModel.canApplyAutoStyle();
|
||
|
var affectedWidgets = this.where({ layer_id: layerDefModel.id });
|
||
|
|
||
|
_.each(affectedWidgets, function (widgetDefModel) {
|
||
|
var isNowAllowed = widgetDefModel.get('auto_style_allowed');
|
||
|
var willBeAllowed = isAllowed;
|
||
|
var attrs = {
|
||
|
auto_style_allowed: willBeAllowed
|
||
|
};
|
||
|
|
||
|
if (isNowAllowed !== willBeAllowed) {
|
||
|
// if autostyle is not allow, we should clean auto_style_definition
|
||
|
if (willBeAllowed === false) {
|
||
|
attrs = _.extend(attrs, { auto_style_definition: '' });
|
||
|
}
|
||
|
widgetDefModel.save(attrs);
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
|
||
|
addWidget: function (widgetModel, attrs) {
|
||
|
var self = this;
|
||
|
var ORDER_NUMBER_TO_APPEAR_ON_TOP = -1;
|
||
|
|
||
|
return new Promise(function (resolve, reject) {
|
||
|
_.extend(attrs, { order: ORDER_NUMBER_TO_APPEAR_ON_TOP });
|
||
|
|
||
|
self.create(attrs, {
|
||
|
wait: true,
|
||
|
success: function (model) {
|
||
|
resolve(model);
|
||
|
},
|
||
|
error: function (response, error) {
|
||
|
reject(error);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
},
|
||
|
|
||
|
updateWidgetsOrder: function (numberOfWidgets) {
|
||
|
this.each(function (widgetDefinitionModel, index) {
|
||
|
widgetDefinitionModel.set({ order: index });
|
||
|
});
|
||
|
|
||
|
return this.saveAsync(numberOfWidgets);
|
||
|
},
|
||
|
|
||
|
saveAsync: function (updatedWidgets) {
|
||
|
var self = this;
|
||
|
|
||
|
this.trigger('loading', updatedWidgets);
|
||
|
|
||
|
return new Promise(function (resolve, reject) {
|
||
|
self.save({
|
||
|
wait: true,
|
||
|
success: function (collection) {
|
||
|
self.trigger('successAdd', updatedWidgets);
|
||
|
resolve(collection);
|
||
|
},
|
||
|
error: function (response, error) {
|
||
|
self.trigger('errorAdd', response);
|
||
|
reject(error);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
},
|
||
|
|
||
|
save: function (options) {
|
||
|
options = options || {};
|
||
|
Backbone.sync('update', this, options);
|
||
|
},
|
||
|
|
||
|
attrsForThisType: function (newType, m) {
|
||
|
return this._attrsForThisTypeMap[newType](m);
|
||
|
},
|
||
|
|
||
|
resetableAttrsForTypeMap: function (type) {
|
||
|
switch (type) {
|
||
|
case 'formula':
|
||
|
return [];
|
||
|
case 'category':
|
||
|
return ['aggregation'];
|
||
|
case 'histogram':
|
||
|
return ['bins', 'column_type'];
|
||
|
case 'time-series':
|
||
|
return ['bins', 'aggregation', 'column_type'];
|
||
|
}
|
||
|
},
|
||
|
|
||
|
isThereTimeSeries: function (opts) {
|
||
|
opts = opts || {};
|
||
|
|
||
|
var timeSeries = opts.animated ? this.findWhere({ type: 'time-series', animated: opts.animated }) : this.findWhere({ type: 'time-series' });
|
||
|
return !!timeSeries;
|
||
|
},
|
||
|
|
||
|
isThereOtherWidgets: function () {
|
||
|
return !!this.find(function (widgetModel) {
|
||
|
return widgetModel.get('type') !== 'time-series';
|
||
|
});
|
||
|
},
|
||
|
|
||
|
_getNextOrder: function () {
|
||
|
if (this.isEmpty()) {
|
||
|
return 0;
|
||
|
} else {
|
||
|
var lastItemByOrder = this.max(function (mdl) {
|
||
|
return mdl.get('order');
|
||
|
});
|
||
|
return lastItemByOrder.get('order') + 1;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
widgetsOwnedByLayer: function (layerId) {
|
||
|
var widgets = this.where({ layer_id: layerId });
|
||
|
|
||
|
return widgets.length;
|
||
|
},
|
||
|
|
||
|
getColumnType: function (columnName, source) {
|
||
|
var column;
|
||
|
var node = this._analysisDefinitionNodesCollection.get(source);
|
||
|
var schemaModel = node && node.querySchemaModel;
|
||
|
if (schemaModel && schemaModel.get('status') === 'fetched') {
|
||
|
column = schemaModel.columnsCollection.findWhere({ name: columnName });
|
||
|
}
|
||
|
return column && column.get('type');
|
||
|
}
|
||
|
});
|