cartodb/lib/assets/javascripts/deep-insights/widgets/widget-model.js
2020-06-15 10:58:47 +08:00

237 lines
6.8 KiB
JavaScript

var _ = require('underscore');
var cdb = require('internal-carto.js');
var AutoStylerFactory = require('./auto-style/factory');
var TIME_SERIES_TYPE = 'time-series';
var HISTOGRAM_TYPE = 'histogram';
/**
* Default widget model
*
* Note: Currently all widgets have a dependency on a dataview, why it makes sense to have it here.
* If you need a widget model that's backed up by a dataview model please implement your own model and adhere to the
* public interface instead of extending/hacking this one.
*/
module.exports = cdb.core.Model.extend({
defaults: {
attrsNames: [],
show_stats: false,
show_source: false
},
defaultState: {
'collapsed': false
},
initialize: function (attrs, models, opts) {
opts = opts || {};
if (!models.dataviewModel) throw new Error('dataviewModel is required.');
if (!models.layerModel) throw new Error('layerModel is required.');
this.dataviewModel = models.dataviewModel;
this.layerModel = models.layerModel;
// Autostyle could be disabled initially if the styles have an aggregation
// If no option, autoStyleEnabled by default
this._autoStyleEnabledWhenCreated = opts.autoStyleEnabled === undefined ? true : opts.autoStyleEnabled;
this.activeAutoStyler();
this.listenTo(this, 'change:style', this.activeAutoStyler);
},
activeAutoStyler: function () {
if (this.isAutoStyleEnabled() && !this.autoStyler) {
this.autoStyler = AutoStylerFactory.get(this.dataviewModel, this.layerModel, this.get('style'));
}
},
/**
* @public
* @param {Object} attrs, not that it should be
* @return {Boolean} true if at least one attribute was changed
* @throws {Error} Should throw an error if the attrs are invalid or inconsistent
*/
update: function (attrs) {
var wAttrs = _.pick(attrs, this.get('attrsNames'));
this.set(wAttrs);
this.dataviewModel.update(attrs);
this._triggerChangesInAutoStyle();
return !!(this.changedAttributes() || this.dataviewModel.changedAttributes());
},
_triggerChangesInAutoStyle: function () {
var changed = this.changed && this.changed.style && this.changed.style.auto_style && this.changed.style.auto_style.definition;
var previous = this.previousAttributes();
var former = previous.style && previous.style.auto_style && previous.style.auto_style.definition;
if (!_.isEqual(changed, former)) {
this.trigger('customAutoStyle', this);
}
},
/**
* @public
*/
remove: function () {
this.dataviewModel.remove();
this.trigger('destroy', this);
this.stopListening();
},
isAutoStyleEnabled: function () {
var styles = this.get('style');
if (this.get('type') === 'category' || this.get('type') === 'histogram') {
if (!styles || !styles.auto_style) {
// Only when styles are undefined we check the autostyle option
return this._autoStyleEnabledWhenCreated;
}
return styles && styles.auto_style && styles.auto_style.allowed;
} else {
return false;
}
},
getWidgetColor: function () {
var styles = this.get('style');
var widgetStyle = styles && styles.widget_style;
var widgetColor = widgetStyle && widgetStyle.definition &&
widgetStyle.definition.color &&
widgetStyle.definition.color.fixed;
var widgetColorChanged = (widgetStyle && widgetStyle.widget_color_changed) ||
(widgetStyle && !widgetStyle.widget_color_changed && widgetColor !== '#9DE0AD');
return widgetColorChanged && widgetColor;
},
hasColorsAutoStyle: function () {
var autoStyle = this.getAutoStyle();
var hasDefinedColors = false;
if (!autoStyle || _.isEmpty(autoStyle) || _.isEmpty(autoStyle.definition)) {
return false;
}
// Check colors in all geometries
_.each(autoStyle.definition, function (geometryStyle) {
if (geometryStyle.color && geometryStyle.color.range && geometryStyle.color.range.length > 0) {
hasDefinedColors = true;
}
}, this);
return hasDefinedColors;
},
getColor: function (name) {
if (this.isAutoStyleEnabled() && this.isAutoStyle() && this.get('type') === 'category') {
return this.autoStyler.colors.getColorByCategory(name);
} else {
return this.getWidgetColor();
}
},
isAutoStyle: function () {
return this.get('autoStyle');
},
autoStyle: function () {
if (!this.isAutoStyleEnabled()) return;
if (!this.dataForAutoStyle()) return;
var layer = this.layerModel;
var initialStyle = layer.get('cartocss');
if (!initialStyle && layer.get('meta')) {
initialStyle = layer.get('meta').cartocss;
}
layer.set('initialStyle', initialStyle);
var style = this.autoStyler.getStyle();
layer.set('cartocss', style);
this.set('autoStyle', true);
},
dataForAutoStyle: function () {
return this.dataviewModel.get('data').length > 0;
},
reapplyAutoStyle: function () {
var style = this.autoStyler.getStyle();
this.layerModel.set('cartocss', style);
this.set('autoStyle', true);
},
cancelAutoStyle: function (noRestore) {
if (!noRestore) {
this.layerModel.restoreCartoCSS();
}
this.set('autoStyle', false);
},
getAutoStyle: function () {
var style = this.get('style');
var layerModel = this.layerModel;
var cartocss = layerModel.get('cartocss') || (layerModel.get('meta') && layerModel.get('meta').cartocss);
if (this.isAutoStyleEnabled() && this.autoStyler) {
if (style && style.auto_style && style.auto_style.definition) {
var toRet = _.extend(style.auto_style, {cartocss: cartocss});
return _.extend({}, toRet, {definition: this.autoStyler.getDef(cartocss)});
} else {
return {
definition: this.autoStyler.getDef(cartocss),
cartocss: cartocss
};
}
}
return {};
},
_updateAutoStyle: function (_model, style) {
if (this.autoStyler) {
this.autoStyler.updateStyle(style);
}
if (this.isAutoStyle()) {
this.reapplyAutoStyle();
}
},
setInitialState: function (state) {
this.initialState = state || {};
},
applyInitialState: function () {
var attrs = _.extend(
this.initialState,
{hasInitialState: true}
);
this.setState(attrs);
},
setState: function (state) {
this.set(state);
},
getState: function () {
var state = {};
for (var key in this.defaultState) {
var attribute = this.get(key);
var defaultValue = this.defaultState[key];
if (typeof defaultValue !== 'undefined' && typeof attribute !== 'undefined' && !_.isEqual(attribute, defaultValue)) {
state[key] = attribute;
}
}
return state;
},
forceResize: function () {
var type = this.get('type');
if (type === TIME_SERIES_TYPE ||
type === HISTOGRAM_TYPE) {
this.trigger('forceResize');
}
}
});