cartodb/lib/assets/javascripts/builder/editor/style/style-definition-model.js
2020-06-15 10:58:47 +08:00

254 lines
6.8 KiB
JavaScript
Executable File

var Backbone = require('backbone');
var _ = require('underscore');
var StylesFactory = require('./styles-factory');
var StyleConstants = require('builder/components/form-components/_constants/_style');
var UndoManager = require('builder/data/undo-manager');
module.exports = Backbone.Model.extend({
parse: function (r) {
r = r || {};
return _.extend(
{
type: r.type,
autogenerated: r && r.autogenerated
},
r.properties
);
},
initialize: function (attrs, opts) {
if (!this.get('type')) {
this.setDefaultPropertiesByType(StyleConstants.Type.SIMPLE, 'point' /* geometryType */);
}
UndoManager.init(this, { track: true });
},
resetPropertiesFromAutoStyle: function () {
if (this._stylesPreAutoStyle) {
delete this.attributes.autoStyle;
this.set(this._stylesPreAutoStyle);
this.removeStylesPreAutoStyle();
}
},
removeStylesPreAutoStyle: function () {
delete this._stylesPreAutoStyle;
},
setPropertiesFromAutoStyle: function (params) {
if (!params.definition) throw new Error('definition is required');
if (!params.geometryType) throw new Error('geometryType is required');
if (!params.widgetId) throw new Error('widgetId is required');
if (!this._stylesPreAutoStyle) {
this._stylesPreAutoStyle = JSON.parse(JSON.stringify(this.attributes));
}
// In order to trigger a proper change at the end of this function, we have
// to make a clear change in the attributes, like delete the autoStyle property.
delete this.attributes.autoStyle;
var extendAutoStyleProperties = function (attribute, newProperties) {
var properties = this.get(attribute);
// Check domain quotes
if (newProperties.color && newProperties.color.domain) {
var quotedDomain = _.compact(
_.map(newProperties.color.domain, function (name) {
if (name && name !== true) {
return '"' + name.toString().replace(/"/g, '\\"').replace(/\n/g, '\\n') + '"';
} else {
return name;
}
})
);
newProperties.color.static = true;
newProperties.color.domain = quotedDomain;
newProperties.color.quantification = 'category';
newProperties.color.attribute_type = 'string';
} else {
newProperties.color.bins = newProperties.color.range.length;
newProperties.color.quantification = 'quantiles';
newProperties.color.attribute_type = 'number';
}
properties = _.extend(
properties,
newProperties
);
return properties;
}.bind(this);
var currentAttrs = JSON.parse(JSON.stringify(this.attributes));
var geometryType = params.geometryType;
var definition = params.definition[geometryType];
if (definition) {
if (geometryType === 'line') {
currentAttrs.stroke = extendAutoStyleProperties('stroke', definition);
} else {
currentAttrs.fill = extendAutoStyleProperties('fill', definition);
}
}
this.set(
_.extend(
{
type: StyleConstants.Type.SIMPLE,
autoStyle: params.widgetId
},
currentAttrs
)
);
},
setDefaultPropertiesByType: function (styleType, geometryType, silently) {
// Get default aggregation and properties from factory and apply them
this.set(
_.extend(
{
type: styleType
},
StylesFactory.getDefaultStyleAttrsByType(styleType, geometryType)
), {
silently: !!silently
}
);
// Although we want to make the change silently, we have several places listening
// for style changes, so we trigger this custom event
if (silently) {
this.trigger('style:update');
}
},
setFill: function (type) {
var simpleFill = StylesFactory.getDefaultStyleAttrsByType(type, 'point');
this.set('fill', simpleFill.fill);
},
applyLastState: function () {
this._undoManager.stopTracking();
this.trigger('change');
this._undoManager.startTracking();
},
resetStyles: function () {
this.setDefaultPropertiesByType(StyleConstants.Type.NONE, '');
},
// Backend will migrate current wizard properties to style properties,
// providing a flag which indicates if it is generated by them
isAutogenerated: function () {
return this.get('autogenerated');
},
isAggregatedType: function () {
return _.contains(StylesFactory.getAggregationTypes(), this.get('type'));
},
isAnimation: function () {
return this.get('type') === StyleConstants.Type.ANIMATION;
},
isHeatmap: function () {
return this.get('type') === StyleConstants.Type.HEATMAP;
},
hasNoneStyles: function () {
return this.get('type') === StyleConstants.Type.NONE;
},
canApplyAutoStyle: function () {
return this.get('type') === StyleConstants.Type.SIMPLE;
},
getColumnsUsedForStyle: function () {
var fillColumns = this._getFillColumns();
var strokeColumns = this._getStrokeColumns();
var labelColumns = this._getLabelColumns();
var aggregationColumns = this._getAggregationColumns();
return [].concat(fillColumns, strokeColumns, labelColumns, aggregationColumns);
},
// Unflatten attributes
toJSON: function () {
return {
type: this.get('type'),
properties: _.omit(this.attributes, 'type', 'autogenerated')
};
},
_getFillColumns: function () {
var columns = [];
var fill = this.get('fill');
if (fill && fill.color && fill.color.attribute) {
columns.push({
name: fill.color.attribute,
type: fill.color.attribute_type || 'string'
});
}
if (fill && fill.size && fill.size.attribute) {
columns.push({
name: fill.size.attribute,
type: 'number'
});
}
return columns;
},
_getStrokeColumns: function () {
var columns = [];
var stroke = this.get('stroke');
if (stroke && stroke.color && stroke.color.attribute) {
columns.push({
name: stroke.color.attribute,
type: stroke.color.attribute_type || 'string'
});
}
if (stroke && stroke.size && stroke.size.attribute) {
columns.push({
name: stroke.size.attribute,
type: 'number'
});
}
return columns;
},
_getLabelColumns: function () {
var columns = [];
// Labels
var labels = this.get('labels');
if (labels && labels.attribute && labels.enabled) {
columns.push({
name: labels.attribute
});
}
return columns;
},
_getAggregationColumns: function () {
var columns = [];
var aggregation = this.get('aggregation');
if (aggregation && aggregation.value && aggregation.value.attribute) {
columns.push({
name: aggregation.value.attribute,
type: aggregation.value.attribute_type || 'string'
});
}
return columns;
}
});