Initial commit
This commit is contained in:
43
lib/assets/javascripts/builder/editor/style/style-cartocss-model.js
Executable file
43
lib/assets/javascripts/builder/editor/style/style-cartocss-model.js
Executable file
@@ -0,0 +1,43 @@
|
||||
var Backbone = require('backbone');
|
||||
var UndoManager = require('builder/data/undo-manager.js');
|
||||
var _ = require('underscore');
|
||||
|
||||
/**
|
||||
* CartoCSS Undo-redo model
|
||||
*/
|
||||
module.exports = Backbone.Model.extend({
|
||||
|
||||
defaults: {
|
||||
content: ''
|
||||
},
|
||||
|
||||
initialize: function (attrs, opts) {
|
||||
this._history = this._generateHistory(opts && opts.history);
|
||||
|
||||
UndoManager.init(this, {
|
||||
track: true,
|
||||
history: this._history
|
||||
});
|
||||
},
|
||||
|
||||
_generateHistory: function (history) {
|
||||
if (history && history.length) {
|
||||
var data = _.reduce(history, function (memo, cartocss) {
|
||||
memo.push({
|
||||
content: cartocss
|
||||
});
|
||||
return memo;
|
||||
}, [], this);
|
||||
return data;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
getHistory: function () {
|
||||
return _.pluck(
|
||||
this.getUndoHistory(),
|
||||
'content'
|
||||
);
|
||||
}
|
||||
});
|
||||
78
lib/assets/javascripts/builder/editor/style/style-cartocss-view.js
Executable file
78
lib/assets/javascripts/builder/editor/style/style-cartocss-view.js
Executable file
@@ -0,0 +1,78 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var CodeMirrorView = require('builder/components/code-mirror/code-mirror-view');
|
||||
var FactoryHints = require('builder/editor/editor-hints/factory-hints');
|
||||
var CSSHints = require('builder/editor/editor-hints/css-hints');
|
||||
var checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
var REQUIRED_OPTS = [
|
||||
'layerDefinitionModel',
|
||||
'styleModel',
|
||||
'codemirrorModel',
|
||||
'editorModel',
|
||||
'querySchemaModel',
|
||||
'onApplyEvent',
|
||||
'overlayModel'
|
||||
];
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
module: 'editor:style:style-cartocss-view',
|
||||
|
||||
className: 'Editor-styleContentCartoCSS Editor-content',
|
||||
|
||||
initialize: function (opts) {
|
||||
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
|
||||
|
||||
this._initBinds();
|
||||
|
||||
FactoryHints.init({
|
||||
querySchemaModel: this._querySchemaModel,
|
||||
layerDefinitionModel: this._layerDefinitionModel,
|
||||
tokens: CSSHints
|
||||
});
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this.$el.empty();
|
||||
|
||||
this._initViews();
|
||||
this._toggleOverlay();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this._layerDefinitionModel, 'change:cartocss', this._updateEditorContent);
|
||||
this.listenTo(this._overlayModel, 'change:visible', this._toggleOverlay);
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
var hints = FactoryHints.reset().hints;
|
||||
this.codeMirrorView = new CodeMirrorView({
|
||||
model: this._codemirrorModel,
|
||||
addons: ['color-picker'],
|
||||
hints: hints,
|
||||
tips: [
|
||||
_t('editor.style.code-mirror.save')
|
||||
]
|
||||
});
|
||||
this.codeMirrorView.bind('codeSaved', this._triggerCodeSaved, this);
|
||||
this.addView(this.codeMirrorView);
|
||||
this.$el.append(this.codeMirrorView.render().el);
|
||||
},
|
||||
|
||||
_toggleOverlay: function () {
|
||||
var isDisabled = this._overlayModel.get('visible');
|
||||
this.$el.toggleClass('is-disabled', isDisabled);
|
||||
},
|
||||
|
||||
_updateEditorContent: function () {
|
||||
if (this._editorModel.get('edition') === false) {
|
||||
this.codeMirrorView.setContent(this._layerDefinitionModel.get('cartocss'));
|
||||
}
|
||||
},
|
||||
|
||||
_triggerCodeSaved: function (code, view) {
|
||||
this._onApplyEvent && this._onApplyEvent();
|
||||
}
|
||||
});
|
||||
3
lib/assets/javascripts/builder/editor/style/style-content-sql-error.tpl
Executable file
3
lib/assets/javascripts/builder/editor/style/style-content-sql-error.tpl
Executable file
@@ -0,0 +1,3 @@
|
||||
<h2 class="CDB-Text CDB-Size-huge is-light u-secondaryTextColor">
|
||||
<%= body %>
|
||||
</h2>
|
||||
304
lib/assets/javascripts/builder/editor/style/style-content-view.js
Executable file
304
lib/assets/javascripts/builder/editor/style/style-content-view.js
Executable file
@@ -0,0 +1,304 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var CoreView = require('backbone/core-view');
|
||||
|
||||
var StyleFormView = require('./style-form/style-form-view');
|
||||
var StylesFactory = require('./styles-factory');
|
||||
var CarouselFormView = require('builder/components/carousel-form-view');
|
||||
var CarouselCollection = require('builder/components/custom-carousel/custom-carousel-collection');
|
||||
var Notifier = require('builder/components/notifier/notifier');
|
||||
var MetricsTracker = require('builder/components/metrics/metrics-tracker');
|
||||
var MetricsTypes = require('builder/components/metrics/metrics-types');
|
||||
|
||||
var StyleConstants = require('builder/components/form-components/_constants/_style');
|
||||
|
||||
var styleSQLErrorTemplate = require('./style-content-sql-error.tpl');
|
||||
var actionErrorTemplate = require('builder/editor/layers/sql-error-action.tpl');
|
||||
var layerTabMessageTemplate = require('builder/editor/layers/layer-tab-message.tpl');
|
||||
|
||||
var checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
var EXTRA_STYLE_PROPERTIES = [
|
||||
'fillSize',
|
||||
'fillColor',
|
||||
'strokeSize',
|
||||
'strokeColor'
|
||||
];
|
||||
|
||||
var EXTRA_LABELS_STYLE_PROPERTIES = [
|
||||
'fillSize',
|
||||
'fillColor',
|
||||
'haloSize',
|
||||
'haloColor'
|
||||
];
|
||||
|
||||
var REQUIRED_OPTS = [
|
||||
'configModel',
|
||||
'layerDefinitionsCollection',
|
||||
'userModel',
|
||||
'layerDefinitionModel',
|
||||
'userActions',
|
||||
'styleModel',
|
||||
'overlayModel',
|
||||
'queryGeometryModel',
|
||||
'querySchemaModel',
|
||||
'freezeTorgeAggregation',
|
||||
'editorModel',
|
||||
'modals',
|
||||
'layerContentModel'
|
||||
];
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
module: 'editor/style/style-content-view',
|
||||
|
||||
className: 'Editor-styleContent',
|
||||
|
||||
initialize: function (opts) {
|
||||
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
|
||||
|
||||
this._initViewState();
|
||||
this._buildAggregationCarouselCollection();
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this.$el.empty();
|
||||
|
||||
if (this._isErrored()) {
|
||||
this._renderError();
|
||||
} else if (this._viewState.get('isDataFiltered')) {
|
||||
this._renderFilteredData();
|
||||
} else {
|
||||
this._initViews();
|
||||
}
|
||||
|
||||
this._toggleOverlay();
|
||||
return this;
|
||||
},
|
||||
|
||||
_initViewState: function () {
|
||||
this._viewState = new Backbone.Model({
|
||||
isDataFiltered: false
|
||||
});
|
||||
|
||||
this._setViewValues();
|
||||
},
|
||||
|
||||
_buildAggregationCarouselCollection: function () {
|
||||
if (this._carouselCollection) {
|
||||
this.stopListening(this._carouselCollection, 'change:selected');
|
||||
}
|
||||
this._carouselCollection = new CarouselCollection(
|
||||
_.map(StylesFactory.getStyleTypes(this._styleModel.get('type'), this._queryGeometryModel.get('simple_geom')), function (type) {
|
||||
return {
|
||||
selected: this._styleModel.get('type') === type.value,
|
||||
val: type.value,
|
||||
label: type.label,
|
||||
template: function () {
|
||||
return (type.iconTemplate && type.iconTemplate()) || type.value;
|
||||
},
|
||||
tooltip: type.tooltip
|
||||
};
|
||||
}, this)
|
||||
);
|
||||
this.listenTo(this._carouselCollection, 'change:selected', this._onSelectAggregation);
|
||||
|
||||
return this._carouselCollection;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this._layerDefinitionModel, 'change:autoStyle', this._onAutoStyleChanged);
|
||||
this.listenTo(this._layerDefinitionModel, 'change', this._onStyleChanged);
|
||||
this.listenTo(this._styleModel, 'change:fill', this._onStyleChanged);
|
||||
this.listenTo(this._styleModel, 'change:labels', this._onStyleLabelChanged);
|
||||
this.listenTo(this._styleModel, 'undo redo', this.render);
|
||||
this.listenTo(this._layerContentModel, 'change:state', this._setViewValues);
|
||||
this.listenTo(this._layerContentModel, 'change:state', this._checkEditorModel);
|
||||
this.listenTo(this._overlayModel, 'change:visible', this._toggleOverlay);
|
||||
this.listenTo(this._viewState, 'change:isDataFiltered', this.render);
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
if (this._queryGeometryModel.get('simple_geom') === 'point') {
|
||||
this._renderCarousel();
|
||||
}
|
||||
|
||||
this._renderForm();
|
||||
},
|
||||
|
||||
_toggleOverlay: function () {
|
||||
var isDisabled = this._overlayModel.get('visible');
|
||||
this.$el.toggleClass('is-disabled', isDisabled);
|
||||
},
|
||||
|
||||
_isErrored: function () {
|
||||
return this._layerContentModel.isErrored();
|
||||
},
|
||||
|
||||
_onAutoStyleChanged: function (layerDefModel) {
|
||||
var isAutoStyleApplied = layerDefModel.get('autoStyle');
|
||||
|
||||
if (!isAutoStyleApplied) {
|
||||
this.render();
|
||||
} else {
|
||||
this._styleModel.unbind('change', this._onStyleChanged, this);
|
||||
this._styleModel.once('change', function () {
|
||||
this.render();
|
||||
this._styleModel.bind('change', this._onStyleChanged, this);
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
_checkEditorModel: function () {
|
||||
this._queryGeometryModel.hasValueAsync()
|
||||
.then(function (hasGeometry) {
|
||||
this._editorModel.set({ disabled: this._isErrored() || !hasGeometry });
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_renderError: function () {
|
||||
this.$el.append(
|
||||
styleSQLErrorTemplate({
|
||||
body: _t('editor.error-query.body', {
|
||||
action: actionErrorTemplate({
|
||||
label: _t('editor.error-query.label')
|
||||
})
|
||||
})
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
_renderFilteredData: function () {
|
||||
this.$el.append(
|
||||
layerTabMessageTemplate({
|
||||
message: _t('editor.layers.warnings.no-data.message'),
|
||||
action: _t('editor.layers.warnings.no-data.action-message')
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
_renderCarousel: function () {
|
||||
var view = new CarouselFormView({
|
||||
collection: this._buildAggregationCarouselCollection(),
|
||||
template: require('./style-form-types.tpl')
|
||||
});
|
||||
this.addView(view);
|
||||
this.$el.append(view.render().el);
|
||||
},
|
||||
|
||||
_onSelectAggregation: function (model) {
|
||||
var alreadyTorqueLayer = this._layerDefinitionsCollection.isThereAnyTorqueLayer();
|
||||
var isTorqueLayer = this._layerDefinitionModel.get('type') === 'torque';
|
||||
|
||||
var styleType;
|
||||
var isTorqueType;
|
||||
var currentGeometryType;
|
||||
|
||||
if (model.get('selected')) {
|
||||
styleType = model.getValue();
|
||||
currentGeometryType = this._queryGeometryModel.get('simple_geom');
|
||||
|
||||
isTorqueType = (styleType === StyleConstants.Type.HEATMAP || styleType === StyleConstants.Type.ANIMATION);
|
||||
|
||||
if (alreadyTorqueLayer && !isTorqueLayer && isTorqueType) {
|
||||
this._freezeTorgeAggregation(styleType, currentGeometryType);
|
||||
} else {
|
||||
// If an animated or a heatmap style is selected, we should move the layer to the
|
||||
// top, but if it is in the most high position, we shouldn't do anything
|
||||
if (isTorqueType && !this._layerDefinitionsCollection.isDataLayerOnTop(this._layerDefinitionModel)) {
|
||||
this._moveTorqueLayerToTop(function () {
|
||||
this._setDefaultProperties(styleType, currentGeometryType);
|
||||
}.bind(this));
|
||||
} else {
|
||||
this._setDefaultProperties(styleType, currentGeometryType, false /* silently */);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_setDefaultProperties: function (styleType, currentGeometryType, silently) {
|
||||
var previousType = this._styleModel.get('type');
|
||||
this._styleModel.setDefaultPropertiesByType(styleType, currentGeometryType, silently);
|
||||
|
||||
MetricsTracker.track(MetricsTypes.AGGREGATED_GEOMETRIES, {
|
||||
previous_agg_type: previousType,
|
||||
agg_type: styleType
|
||||
});
|
||||
},
|
||||
|
||||
_moveTorqueLayerToTop: function (callback) {
|
||||
var notification = Notifier.addNotification({
|
||||
status: 'loading',
|
||||
info: _t('editor.layers.moveTorqueLayer.loading'),
|
||||
closable: true
|
||||
});
|
||||
|
||||
this._layerDefinitionsCollection.once('layerMoved', function () {
|
||||
if (callback) { callback(); }
|
||||
|
||||
notification.set({
|
||||
status: 'success',
|
||||
info: _t('editor.layers.moveTorqueLayer.success'),
|
||||
delay: Notifier.DEFAULT_DELAY
|
||||
});
|
||||
}, this);
|
||||
|
||||
this._userActions.moveLayer({
|
||||
from: this._layerDefinitionModel.get('order'),
|
||||
to: this._layerDefinitionsCollection.getTopDataLayerIndex()
|
||||
});
|
||||
},
|
||||
|
||||
_renderForm: function () {
|
||||
if (this._querySchemaModel.get('query')) {
|
||||
var view = new StyleFormView({
|
||||
layerDefinitionsCollection: this._layerDefinitionsCollection,
|
||||
layerDefinitionModel: this._layerDefinitionModel,
|
||||
styleModel: this._styleModel,
|
||||
configModel: this._configModel,
|
||||
userModel: this._userModel,
|
||||
queryGeometryModel: this._queryGeometryModel,
|
||||
querySchemaModel: this._querySchemaModel,
|
||||
modals: this._modals
|
||||
});
|
||||
this.$el.append(view.render().el);
|
||||
this.addView(view);
|
||||
}
|
||||
},
|
||||
|
||||
_onStyleChanged: function () {
|
||||
this._styleModel.set('autogenerated', false);
|
||||
this._unsetExtraStyleProperties();
|
||||
this._layerDefinitionModel.save();
|
||||
|
||||
MetricsTracker.track(MetricsTypes.MODIFIED_STYLE_FORM, {
|
||||
layer_id: this._layerDefinitionModel.get('id'),
|
||||
cartocss: this._layerDefinitionModel.get('cartocss'),
|
||||
style_properties: this._layerDefinitionModel.get('style_properties')
|
||||
});
|
||||
},
|
||||
|
||||
_unsetExtraStyleProperties: function () {
|
||||
EXTRA_STYLE_PROPERTIES.forEach(function (property) {
|
||||
this._styleModel.unset(property, { silent: true });
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_onStyleLabelChanged: function () {
|
||||
var labels = this._styleModel.get('labels');
|
||||
|
||||
EXTRA_LABELS_STYLE_PROPERTIES.forEach(function (property) {
|
||||
delete labels[property];
|
||||
});
|
||||
|
||||
this._styleModel.set('labels', labels, { silent: true });
|
||||
},
|
||||
|
||||
_setViewValues: function () {
|
||||
this._layerDefinitionModel.isDataFiltered()
|
||||
.then(function (isDataFiltered) {
|
||||
this._viewState.set('isDataFiltered', isDataFiltered);
|
||||
}.bind(this));
|
||||
}
|
||||
});
|
||||
707
lib/assets/javascripts/builder/editor/style/style-converter.js
Executable file
707
lib/assets/javascripts/builder/editor/style/style-converter.js
Executable file
@@ -0,0 +1,707 @@
|
||||
var _ = require('underscore');
|
||||
var camshaftReference = require('builder/data/camshaft-reference');
|
||||
var Utils = require('builder/helpers/utils');
|
||||
var InputQualitativeRamps = require('builder/components/input-color/input-qualitative-ramps/main-view.js');
|
||||
|
||||
var CONFIG = {
|
||||
GENERIC_STYLE: camshaftReference.getDefaultCartoCSSForType(),
|
||||
DEFAULT_HEATMAP_COLORS: ['blue', 'cyan', 'lightgreen', 'yellow', 'orange', 'red']
|
||||
};
|
||||
|
||||
// utilities
|
||||
function _null () { return ''; }
|
||||
|
||||
function makeCartoCSS (obj, prefix) {
|
||||
var css = '';
|
||||
prefix = prefix || '';
|
||||
for (var k in obj) {
|
||||
css += prefix + k + ': ' + obj[k] + ';\n';
|
||||
}
|
||||
return css;
|
||||
}
|
||||
|
||||
function makeColorRamp (props, isTorqueCategory) {
|
||||
var attribute = isTorqueCategory ? 'value' : props.attribute;
|
||||
var c = ['ramp([' + attribute + ']'];
|
||||
|
||||
if (props.range) {
|
||||
if (_.isArray(props.range)) {
|
||||
c.push('(' + props.range.join(', ') + ')');
|
||||
} else {
|
||||
// colorramp name
|
||||
c.push(props.range);
|
||||
if (props.bins) {
|
||||
c.push(props.bins);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (props.domain) {
|
||||
if (isTorqueCategory) {
|
||||
c.push('(' + _.map(props.domain, function (val, i) {
|
||||
return i + 1;
|
||||
}).join(', ') + ')');
|
||||
} else if (props.static) {
|
||||
// It comes from an autostyle, so we have to set the categories explicitly
|
||||
var parsedDomain = _.filter(props.domain, function (name) {
|
||||
return name !== '"Other"';
|
||||
});
|
||||
c.push('(' + parsedDomain.join(', ') + ')');
|
||||
} else {
|
||||
c.push('(' +
|
||||
_.filter(
|
||||
_.map(props.domain, function (val, i) {
|
||||
// Maps api converts null or empty value in empty string
|
||||
// and in the fill component we label them with a locale
|
||||
// so we use the same locale to generate the cartocss
|
||||
return val === '' ? _t('form-components.editors.fill.input-qualitative-ramps.null') : val;
|
||||
}),
|
||||
function (val) {
|
||||
return !_.isUndefined(val);
|
||||
}).join(', ') +
|
||||
')'
|
||||
);
|
||||
c.push('"="');
|
||||
}
|
||||
}
|
||||
if (props.quantification) {
|
||||
c.push(props.quantification.toLowerCase());
|
||||
}
|
||||
|
||||
if (isTorqueCategory) {
|
||||
c.push('"="');
|
||||
}
|
||||
|
||||
return c.join(', ') + ')';
|
||||
}
|
||||
|
||||
function makeWidthRamp (props) {
|
||||
var c = ['ramp([' + props.attribute + ']'];
|
||||
|
||||
if (props.range) {
|
||||
var min = props.range[0];
|
||||
var max = props.range[1];
|
||||
|
||||
c.push('range(' + min + ', ' + max + ')');
|
||||
}
|
||||
|
||||
if (props.quantification) {
|
||||
var quantification = props.quantification.toLowerCase();
|
||||
|
||||
if (props.bins) {
|
||||
c.push(quantification + '(' + props.bins + ')');
|
||||
} else {
|
||||
c.push(quantification);
|
||||
}
|
||||
}
|
||||
|
||||
return c.join(', ') + ')';
|
||||
}
|
||||
|
||||
// size
|
||||
function pointSize (props) {
|
||||
var css = {};
|
||||
if (props.fixed !== undefined) {
|
||||
css['marker-width'] = props.fixed;
|
||||
} else if (props.attribute) {
|
||||
css['marker-width'] = makeWidthRamp(props);
|
||||
} else {
|
||||
// throw new Error('size should contain a fixed value or an attribute')
|
||||
}
|
||||
return css;
|
||||
}
|
||||
|
||||
function blending (b, geometryType, animatedType) {
|
||||
var css = {};
|
||||
var property = geometryType + '-comp-op';
|
||||
if (b !== 'none' && b !== undefined && animatedType !== 'heatmap') {
|
||||
if (animatedType === 'simple') {
|
||||
property = 'comp-op';
|
||||
}
|
||||
css[property] = b;
|
||||
}
|
||||
return css;
|
||||
}
|
||||
|
||||
// fill
|
||||
function pointFill (props, animationType) {
|
||||
var css = {};
|
||||
var color = props && props.color || {};
|
||||
var isTorqueCategory = animationType && !color.fixed;
|
||||
var markerFillOpacity = color.opacity;
|
||||
|
||||
if (props.size) {
|
||||
css = pointSize(props.size);
|
||||
}
|
||||
if (color) {
|
||||
if (color.fixed !== undefined) {
|
||||
css['marker-fill'] = color.fixed;
|
||||
} else if (color.attribute) {
|
||||
css['marker-fill'] = makeColorRamp(color, isTorqueCategory);
|
||||
}
|
||||
if (color.operation) {
|
||||
css['marker-comp-op'] = color.operation;
|
||||
}
|
||||
|
||||
css['marker-fill-opacity'] = markerFillOpacity != null ? markerFillOpacity : 1;
|
||||
|
||||
if (hasImagesSelected(props.images) || hasImagesSelected(color.images)) {
|
||||
css['marker-file'] = markerFill(props.images || color.images, color);
|
||||
} else if (props.image || color.image) {
|
||||
var url = props.image;
|
||||
|
||||
if (color.image) {
|
||||
url = 'url(\'' + color.image + '\')';
|
||||
}
|
||||
|
||||
css['marker-file'] = url;
|
||||
}
|
||||
}
|
||||
if (!animationType) {
|
||||
css['marker-allow-overlap'] = true;
|
||||
}
|
||||
return css;
|
||||
}
|
||||
|
||||
function hasImagesSelected (images) {
|
||||
if (!images) return false;
|
||||
if (!_.isArray(images)) return false;
|
||||
|
||||
return _.some(images, function (image) {
|
||||
return image !== '';
|
||||
});
|
||||
}
|
||||
|
||||
function getFalsyCategory (category) {
|
||||
var DEFAULT_CATEGORY = "''";
|
||||
if (_isInvalidCategory(category)) return DEFAULT_CATEGORY;
|
||||
|
||||
return category
|
||||
? category === 0 ? '0' : DEFAULT_CATEGORY
|
||||
: category;
|
||||
}
|
||||
|
||||
function markerFill (images, color) {
|
||||
if (!_.isArray(images) || !color || !color.attribute) {
|
||||
return;
|
||||
}
|
||||
|
||||
var columnName = '[' + color.attribute + ']';
|
||||
var filesUrls = [];
|
||||
var categoryNames = [];
|
||||
|
||||
_.each(images, function (image, index) {
|
||||
if (image !== '') {
|
||||
var urlFormat = 'url(\'' + image + '\')';
|
||||
filesUrls.push(urlFormat);
|
||||
if (!_.isUndefined(color.domain[index])) {
|
||||
var category = color.domain[index] || getFalsyCategory(color.domain[index]);
|
||||
categoryNames.push(category);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return 'ramp(' + columnName + ', (' + filesUrls.join(', ') + '), (' + categoryNames.join(', ') + '), "="' + ')';
|
||||
}
|
||||
|
||||
function polygonFill (props) {
|
||||
var css = {};
|
||||
if (props.color) {
|
||||
if (props.color.fixed !== undefined) {
|
||||
css['polygon-fill'] = props.color.fixed;
|
||||
} else if (props.color.attribute) {
|
||||
css['polygon-fill'] = makeColorRamp(props.color);
|
||||
}
|
||||
if (props.color.operation) {
|
||||
css['polygon-comp-op'] = props.color.operation;
|
||||
}
|
||||
if (_.isNumber(props.color.opacity)) {
|
||||
css['polygon-opacity'] = props.color.opacity;
|
||||
}
|
||||
}
|
||||
|
||||
return css;
|
||||
}
|
||||
|
||||
// stroke
|
||||
function pointStroke (props, animationType) {
|
||||
var css = {};
|
||||
|
||||
if (animationType === 'heatmap') {
|
||||
return css;
|
||||
}
|
||||
|
||||
if (props.size) {
|
||||
css['marker-line-width'] = props.size.fixed;
|
||||
}
|
||||
if (props.color) {
|
||||
if (props.color.fixed !== undefined) {
|
||||
css['marker-line-color'] = props.color.fixed;
|
||||
} else if (props.color.attribute) {
|
||||
css['marker-line-color'] = makeColorRamp(props.color);
|
||||
}
|
||||
if (_.isNumber(props.color.opacity)) {
|
||||
css['marker-line-opacity'] = props.color.opacity;
|
||||
}
|
||||
}
|
||||
return css;
|
||||
}
|
||||
|
||||
function polygonStroke (props) {
|
||||
var css = {};
|
||||
if (props.size) {
|
||||
if (props.size.fixed !== undefined) {
|
||||
css['line-width'] = props.size.fixed;
|
||||
} else if (props.size.attribute) {
|
||||
css['line-width'] = makeWidthRamp(props.size);
|
||||
}
|
||||
}
|
||||
if (props.color) {
|
||||
if (props.color.fixed) {
|
||||
css['line-color'] = props.color.fixed;
|
||||
} else if (props.color.attribute) {
|
||||
css['line-color'] = makeColorRamp(props.color);
|
||||
}
|
||||
if (_.isNumber(props.color.opacity)) {
|
||||
css['line-opacity'] = props.color.opacity;
|
||||
}
|
||||
}
|
||||
return css;
|
||||
}
|
||||
|
||||
function isValidAttribute (attr) {
|
||||
return attr && attr !== '';
|
||||
}
|
||||
|
||||
function pointAnimated (props) {
|
||||
var css = {};
|
||||
if (isValidAttribute(props.attribute)) {
|
||||
css['-torque-frame-count'] = props.steps;
|
||||
css['-torque-animation-duration'] = props.duration;
|
||||
css['-torque-time-attribute'] = '"' + props.attribute + '"';
|
||||
if (props.isCategory) {
|
||||
css['-torque-aggregation-function'] = '"CDB_Math_Mode(value)"';
|
||||
} else {
|
||||
css['-torque-aggregation-function'] = '"count(1)"';
|
||||
}
|
||||
css['-torque-resolution'] = props.resolution;
|
||||
css['-torque-data-aggregation'] = props.overlap ? 'cumulative' : 'linear';
|
||||
}
|
||||
return css;
|
||||
}
|
||||
|
||||
function _labels (props) {
|
||||
var css = {};
|
||||
if (isValidAttribute(props.attribute)) {
|
||||
css['text-name'] = '[' + props.attribute + ']';
|
||||
css['text-face-name'] = "'" + props.font + "'";
|
||||
if (props.fill) {
|
||||
css['text-size'] = props.fill.size.fixed;
|
||||
|
||||
if (props.fill.color.opacity != null && props.fill.color.opacity < 1) {
|
||||
css['text-fill'] = Utils.hexToRGBA(props.fill.color.fixed, props.fill.color.opacity);
|
||||
} else {
|
||||
css['text-fill'] = props.fill.color.fixed;
|
||||
}
|
||||
}
|
||||
css['text-label-position-tolerance'] = 0;
|
||||
if (props.halo) {
|
||||
css['text-halo-radius'] = props.halo.size.fixed;
|
||||
|
||||
if (props.halo.color.opacity != null && props.halo.color.opacity < 1) {
|
||||
css['text-halo-fill'] = Utils.hexToRGBA(props.halo.color.fixed, props.halo.color.opacity);
|
||||
} else {
|
||||
css['text-halo-fill'] = props.halo.color.fixed;
|
||||
}
|
||||
}
|
||||
css['text-dy'] = props.offset === undefined ? -10 : props.offset;
|
||||
css['text-allow-overlap'] = props.overlap === undefined ? true : props.overlap;
|
||||
css['text-placement'] = props.placement;
|
||||
css['text-placement-type'] = 'dummy';
|
||||
}
|
||||
return css;
|
||||
}
|
||||
|
||||
function imageFilters (props) {
|
||||
var css = {};
|
||||
if (props.ramp) {
|
||||
css['image-filters'] = 'colorize-alpha(' + props.ramp.join(',') + ')';
|
||||
}
|
||||
return css;
|
||||
}
|
||||
|
||||
var cartocssFactory = {
|
||||
animated: {
|
||||
point: pointAnimated,
|
||||
line: _null,
|
||||
polygon: _null
|
||||
},
|
||||
|
||||
trails: {
|
||||
point: trails,
|
||||
line: _null,
|
||||
polygon: _null
|
||||
},
|
||||
|
||||
fill: {
|
||||
point: pointFill,
|
||||
line: _null,
|
||||
polygon: polygonFill
|
||||
},
|
||||
|
||||
stroke: {
|
||||
point: pointStroke,
|
||||
line: polygonStroke,
|
||||
polygon: polygonStroke
|
||||
},
|
||||
|
||||
labels: {
|
||||
point: _labels,
|
||||
line: _labels,
|
||||
polygon: _labels
|
||||
},
|
||||
|
||||
imageFilters: {
|
||||
point: imageFilters,
|
||||
line: imageFilters,
|
||||
polygon: imageFilters
|
||||
},
|
||||
|
||||
blending: {
|
||||
point: function (attrs, animationType) { return blending(attrs, 'marker', animationType); },
|
||||
line: function (attrs) { return blending(attrs, 'line'); },
|
||||
polygon: function (attrs) { return blending(attrs, 'polygon'); }
|
||||
}
|
||||
};
|
||||
|
||||
var heatmapConversion = function (style, animated, configModel) {
|
||||
// modify the size
|
||||
style.fill = _.clone(style.fill);
|
||||
var ramp = style.fill.color.range;
|
||||
style.fill.size = style.fill.size || { fixed: 35 };
|
||||
|
||||
style.fill.image = 'url(' + configModel.get('app_assets_base_url') + '/unversioned/images/alphamarker.png)';
|
||||
|
||||
style.fill.color = {
|
||||
fixed: style.fill.color.fixed || 'white',
|
||||
opacity: style.fill.color.opacity
|
||||
};
|
||||
|
||||
// switch to torque
|
||||
// add image filters
|
||||
if (ramp !== undefined) {
|
||||
style.imageFilters = {
|
||||
ramp: _.isArray(ramp) ? ramp : CONFIG.DEFAULT_HEATMAP_COLORS
|
||||
};
|
||||
}
|
||||
return style;
|
||||
};
|
||||
|
||||
var styleConversion = {
|
||||
animation: function (style, configModel) {
|
||||
if (style.style === 'heatmap') {
|
||||
return heatmapConversion(style, true, configModel);
|
||||
}
|
||||
},
|
||||
|
||||
heatmap: function (style, configModel) {
|
||||
return heatmapConversion(style, false, configModel);
|
||||
}
|
||||
};
|
||||
|
||||
function renderBlock (block, geometryType, animationType) {
|
||||
var css = {};
|
||||
for (var k in block) {
|
||||
var f = cartocssFactory[k];
|
||||
if (f) {
|
||||
css = _.extend(css, f[geometryType](block[k], animationType));
|
||||
}
|
||||
}
|
||||
return makeCartoCSS(css, ' ');
|
||||
}
|
||||
|
||||
function isTypeTorque (type) {
|
||||
return type === 'animation' || type === 'heatmap';
|
||||
}
|
||||
|
||||
function isCategoryType (styleDef, geometryType) {
|
||||
if (geometryType === 'line') {
|
||||
var stroke = styleDef.stroke;
|
||||
return stroke && stroke.color && stroke.color.fixed == null;
|
||||
}
|
||||
var fill = styleDef.fill;
|
||||
return fill && fill.color && fill.color.fixed == null;
|
||||
}
|
||||
|
||||
function generateCartoCSS (style, geometryType, configModel) {
|
||||
var css = '';
|
||||
var styleDef = style.properties;
|
||||
var isAnimatable = isTypeTorque(style.type);
|
||||
var isCategory = isCategoryType(styleDef, geometryType);
|
||||
var animationType = style.type === 'animation' && styleDef.style;
|
||||
|
||||
// Animated map 'controls'
|
||||
if (geometryType === 'point' && isAnimatable) {
|
||||
css += 'Map {\n';
|
||||
css += renderBlock({
|
||||
animated: _.extend({}, styleDef.animated, { isCategory: isCategory })
|
||||
}, geometryType);
|
||||
css += '}\n';
|
||||
}
|
||||
|
||||
// Main styles
|
||||
var omittedStyleAttrs = ['animated', 'labels'];
|
||||
if (geometryType === 'polygon') {
|
||||
omittedStyleAttrs.push('stroke');
|
||||
}
|
||||
css += '#layer {\n';
|
||||
css += renderBlock(_.omit(styleDef, omittedStyleAttrs), geometryType, animationType);
|
||||
css += '}';
|
||||
|
||||
// Outline (stroke for polygons) #12412
|
||||
if (styleDef.stroke && geometryType === 'polygon') {
|
||||
css += '\n#layer::outline {\n';
|
||||
css += renderBlock({ stroke: styleDef.stroke }, geometryType);
|
||||
css += '}';
|
||||
}
|
||||
|
||||
// Labels
|
||||
if (styleDef.labels && styleDef.labels.enabled && styleDef.labels.enabled !== 'false') {
|
||||
css += '\n#layer::labels {\n';
|
||||
css += renderBlock({ labels: styleDef.labels }, geometryType);
|
||||
css += '}';
|
||||
}
|
||||
|
||||
// Animated Map trails
|
||||
if (isAnimatable && styleDef.animated.trails && styleDef.animated.trails > 0) {
|
||||
css += cartocssFactory.trails[geometryType](styleDef);
|
||||
}
|
||||
|
||||
return css;
|
||||
}
|
||||
|
||||
function trails (def) {
|
||||
var baseWidth = def.fill.size && parseInt(def.fill.size.fixed, 10);
|
||||
var baseOpacity = def.fill.color.opacity != null ? def.fill.color.opacity : 1;
|
||||
if (!baseWidth) return '';
|
||||
return '\n' +
|
||||
_.range(1, parseInt(def.animated.trails, 10) + 1)
|
||||
.map(function (t) {
|
||||
return '#layer[frame-offset=' + t + '] {\n' +
|
||||
makeCartoCSS({ 'marker-width': baseWidth + 2 * t }, ' ') +
|
||||
makeCartoCSS({ 'marker-fill-opacity': baseOpacity / (2 * t) }, ' ') +
|
||||
'}';
|
||||
}
|
||||
).join('\n');
|
||||
}
|
||||
|
||||
function aggToSQL (agg) {
|
||||
if (agg.operator.toLowerCase() === 'count') {
|
||||
return 'count(1)';
|
||||
}
|
||||
return agg.operator + '(' + agg.attribute + ')';
|
||||
}
|
||||
|
||||
function regionTableMap (level) {
|
||||
var map = {
|
||||
'countries': 'aggregation.agg_admin0',
|
||||
'provinces': 'aggregation.agg_admin1'
|
||||
};
|
||||
return map[level];
|
||||
}
|
||||
|
||||
function hexabins (style, mapContext) {
|
||||
var aggregation = style.properties.aggregation;
|
||||
var sql = 'WITH hgrid AS (SELECT CDB_HexagonGrid(ST_Expand(!bbox!, CDB_XYZ_Resolution(<%= z %>) * <%= size %>), CDB_XYZ_Resolution(<%= z %>) * <%= size %>) as cell) SELECT hgrid.cell as the_geom_webmercator, <%= agg %> as agg_value, count(1)/power( <%= size %> * CDB_XYZ_Resolution(<%= z %>), 2 ) as agg_value_density, row_number() over () as cartodb_id FROM hgrid, <%= table %> i where ST_Intersects(i.the_geom_webmercator, hgrid.cell) GROUP BY hgrid.cell';
|
||||
return _.template(sql)({
|
||||
table: '(<%= sql %>)',
|
||||
size: aggregation.size,
|
||||
agg: aggToSQL(aggregation.value),
|
||||
z: mapContext.zoom
|
||||
});
|
||||
}
|
||||
|
||||
function squares (style, mapContext) {
|
||||
var aggregation = style.properties.aggregation;
|
||||
var sql = 'WITH hgrid AS (SELECT CDB_RectangleGrid ( ST_Expand(!bbox!, CDB_XYZ_Resolution(<%= z %>) * <%= size %>), CDB_XYZ_Resolution(<%= z %>) * <%= size %>, CDB_XYZ_Resolution(<%= z %>) * <%= size %>) as cell) SELECT hgrid.cell as the_geom_webmercator, <%= agg %> as agg_value, <%= agg %> /power( <%= size %> * CDB_XYZ_Resolution(<%= z %>), 2 ) as agg_value_density, row_number() over () as cartodb_id FROM hgrid, <%= table %> i where ST_Intersects(i.the_geom_webmercator, hgrid.cell) GROUP BY hgrid.cell';
|
||||
return _.template(sql)({
|
||||
table: '(<%= sql %>)',
|
||||
size: aggregation.size,
|
||||
agg: aggToSQL(aggregation.value),
|
||||
z: mapContext.zoom
|
||||
});
|
||||
}
|
||||
|
||||
function regions (style) {
|
||||
var aggregation = style.properties.aggregation;
|
||||
// TODO: add !bbox! tokens to help postgres with FDW join
|
||||
// I tested this on postgres 9.6, the planner seems to be doing weird, it takes
|
||||
// 7 seconds to query a simple tile with no join, I hope 9.5 works much better
|
||||
// Maybe using a CTE with the FDW table improves the thing
|
||||
// Normalize also by area using the real area (not projected one). Using the_geom_webmercator for that instead of the_geom
|
||||
// to avoid extra data going through the network in the FDW
|
||||
// use 2.6e-06 as minimum area (tile size at zoom level 31)
|
||||
var sql = [
|
||||
'SELECT _poly.*, _merge.points_agg/GREATEST(0.0000026, ST_Area((ST_Transform(the_geom, 4326))::geography)) as agg_value_density, _merge.points_agg as agg_value FROM <%= aggr_dataset %> _poly, lateral (',
|
||||
'SELECT <%= agg %> points_agg FROM (<%= table %>) _point where ST_Contains(_poly.the_geom_webmercator, _point.the_geom_webmercator) ) _merge'].join('\n');
|
||||
return _.template(sql)({
|
||||
table: '<%= sql %>',
|
||||
aggr_dataset: regionTableMap(aggregation.dataset),
|
||||
agg: aggToSQL(aggregation.value)
|
||||
});
|
||||
}
|
||||
|
||||
function animation (style, mapContext) {
|
||||
var color = style.properties.fill.color;
|
||||
var columnType = color.attribute_type;
|
||||
var columnName = color.attribute;
|
||||
var hasOthers = color.range && color.range.length > InputQualitativeRamps.MAX_VALUES;
|
||||
var categoryCount = color.domain && color.domain.length;
|
||||
|
||||
var s = ['select *, (CASE'];
|
||||
|
||||
if (color.fixed != null || color.domain == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function _normalizeValue (v) {
|
||||
return v.replace(/\n/g, '\\n').replace(/\"/g, '\\"').replace(/'/g, "''");
|
||||
}
|
||||
|
||||
for (var i = 0, l = categoryCount; i < l; i++) {
|
||||
var categoryName = color.domain[i];
|
||||
var categoryPos = i + 1;
|
||||
var value;
|
||||
|
||||
if (columnType !== 'string' || categoryName === null) {
|
||||
value = categoryName;
|
||||
} else {
|
||||
value = "'" + _normalizeValue(categoryName.replace(/(^")|("$)/g, '')) + "'";
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
s.push('WHEN "' + columnName + '" = ' + value + ' THEN ' + categoryPos);
|
||||
} else {
|
||||
s.push('WHEN "' + columnName + '" is NULL THEN ' + categoryPos);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasOthers) {
|
||||
s.push(' ELSE ' + (categoryCount + 1));
|
||||
}
|
||||
|
||||
s.push(' END) as value FROM (<%= sql %>) __wrapped');
|
||||
return s.join(' ');
|
||||
}
|
||||
|
||||
var SQLFactory = {
|
||||
hexabins: hexabins,
|
||||
squares: squares,
|
||||
regions: regions,
|
||||
animation: animation
|
||||
};
|
||||
|
||||
function generateSQL (style, geometryType, mapContext) {
|
||||
if (SQLFactory[style.type] === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (style.type !== 'animation' && style.properties.aggregation === undefined) {
|
||||
throw new Error('aggregation properties not available');
|
||||
}
|
||||
|
||||
var fn = SQLFactory[style.type];
|
||||
if (fn === undefined) {
|
||||
throw new Error("can't generate SQL for aggregation " + style.type);
|
||||
}
|
||||
return fn(style, mapContext);
|
||||
}
|
||||
|
||||
var AggregatedFactory = {
|
||||
simple: {
|
||||
geometryType: {
|
||||
point: 'point',
|
||||
line: 'line',
|
||||
polygon: 'polygon'
|
||||
}
|
||||
},
|
||||
hexabins: {
|
||||
geometryType: {
|
||||
point: 'polygon',
|
||||
line: null,
|
||||
polygon: null
|
||||
}
|
||||
},
|
||||
squares: {
|
||||
geometryType: {
|
||||
point: 'polygon',
|
||||
line: null,
|
||||
polygon: null
|
||||
}
|
||||
},
|
||||
regions: {
|
||||
geometryType: {
|
||||
point: 'polygon',
|
||||
line: null,
|
||||
polygon: null
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* given a styleDefinition object and the geometry type generates the query wrapper and the
|
||||
*/
|
||||
function generateStyle (style, geometryType, mapContext, configModel) {
|
||||
if (style.type === 'none') {
|
||||
return {
|
||||
cartoCSS: CONFIG.GENERIC_STYLE,
|
||||
sql: null,
|
||||
layerType: 'CartoDB'
|
||||
};
|
||||
}
|
||||
|
||||
if (style.type !== 'simple' && geometryType !== 'point') {
|
||||
throw new Error('aggregated styling does not work with ' + geometryType);
|
||||
}
|
||||
|
||||
// pre style conversion
|
||||
// some styles need some conversion, for example aggregated based on
|
||||
// torque need to move from aggregation to animated properties
|
||||
var conversion = styleConversion[style.type];
|
||||
var properties;
|
||||
if (conversion) {
|
||||
properties = conversion(style.properties, configModel);
|
||||
if (properties) {
|
||||
style.properties = properties;
|
||||
}
|
||||
}
|
||||
|
||||
// override geometryType for aggregated styles
|
||||
var geometryMapping = AggregatedFactory[style.type];
|
||||
if (geometryMapping) {
|
||||
geometryType = geometryMapping.geometryType[geometryType];
|
||||
}
|
||||
|
||||
if (!geometryType) {
|
||||
throw new Error('geometry type not supported for ' + style.type);
|
||||
}
|
||||
|
||||
var layerType = style.type === 'heatmap' || style.type === 'animation' ? 'torque' : 'CartoDB';
|
||||
|
||||
return {
|
||||
cartoCSS: generateCartoCSS(style, geometryType, configModel),
|
||||
sql: generateSQL(style, geometryType, mapContext),
|
||||
layerType: layerType
|
||||
};
|
||||
}
|
||||
|
||||
function _isInvalidCategory (category) {
|
||||
return category.length === 0 || typeof category === 'undefined';
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
configure: function (cfg) {
|
||||
_.extend(CONFIG, cfg);
|
||||
},
|
||||
generateStyle: generateStyle,
|
||||
GENERIC_STYLE: CONFIG.GENERIC_STYLE
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
var _ = require('underscore');
|
||||
var SimpleStyleDefaults = require('./simple-style-defaults');
|
||||
|
||||
module.exports = _.defaults({
|
||||
|
||||
generateAttributes: function (geometryType) {
|
||||
return _.extend(
|
||||
this._getStyleTypeAttrs(),
|
||||
this._getFillAttrs(geometryType),
|
||||
this._getStrokeAttrs(geometryType),
|
||||
{
|
||||
blending: 'lighter'
|
||||
},
|
||||
this._getAggrAttrs(geometryType),
|
||||
this._getAnimatedAttrs(geometryType)
|
||||
);
|
||||
},
|
||||
|
||||
_getStyleTypeAttrs: function () {
|
||||
return {
|
||||
style: 'simple'
|
||||
};
|
||||
},
|
||||
|
||||
_getAnimatedAttrs: function (geometryType) {
|
||||
return {
|
||||
animated: {
|
||||
attribute: null,
|
||||
overlap: false,
|
||||
duration: 30,
|
||||
steps: 256,
|
||||
trails: 2,
|
||||
resolution: 4
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
_getAggrAttrs: function (geometryType) {
|
||||
return {
|
||||
aggregation: {}
|
||||
};
|
||||
}
|
||||
}, SimpleStyleDefaults);
|
||||
@@ -0,0 +1,58 @@
|
||||
var _ = require('underscore');
|
||||
var SimpleStyleDefaults = require('./simple-style-defaults');
|
||||
var rampList = require('cartocolor');
|
||||
|
||||
module.exports = _.defaults({
|
||||
|
||||
generateAttributes: function (geometryType) {
|
||||
return _.extend(
|
||||
this._getFillAttrs(geometryType),
|
||||
this._getAggrAttrs(),
|
||||
this._getAnimatedAttrs(),
|
||||
this._getLabelsAttrs()
|
||||
);
|
||||
},
|
||||
|
||||
_getFillAttrs: function (geometryType) {
|
||||
var attrs = {
|
||||
fill: {
|
||||
'size': {
|
||||
fixed: 45
|
||||
},
|
||||
'color': {
|
||||
attribute: 'cartodb_id',
|
||||
range: rampList.ag_Sunset[7],
|
||||
bins: 6
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return attrs;
|
||||
},
|
||||
|
||||
_getAggrAttrs: function () {
|
||||
return {
|
||||
aggregation: {}
|
||||
};
|
||||
},
|
||||
|
||||
_getAnimatedAttrs: function (geometryType) {
|
||||
return {
|
||||
animated: {
|
||||
attribute: 'cartodb_id',
|
||||
overlap: false,
|
||||
duration: 30,
|
||||
steps: 1,
|
||||
trails: 0,
|
||||
resolution: 4
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
_getLabelsAttrs: function () {
|
||||
return {
|
||||
labels: {}
|
||||
};
|
||||
}
|
||||
|
||||
}, SimpleStyleDefaults);
|
||||
@@ -0,0 +1,44 @@
|
||||
var _ = require('underscore');
|
||||
var SimpleStyleDefaults = require('./simple-style-defaults');
|
||||
var DefaultFormValues = require('builder/data/default-form-styles.json');
|
||||
var Utils = require('builder/helpers/utils');
|
||||
var rampList = require('cartocolor');
|
||||
|
||||
module.exports = _.defaults({
|
||||
|
||||
_getAggrAttrs: function (geometryType) {
|
||||
return {
|
||||
aggregation: {
|
||||
size: 10,
|
||||
value: {
|
||||
operator: 'count',
|
||||
attribute: ''
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
_getStrokeAttrs: function (geometryType) {
|
||||
var strokeAttrs = DefaultFormValues['stroke'];
|
||||
return {
|
||||
stroke: Utils.cloneObject(strokeAttrs)
|
||||
};
|
||||
},
|
||||
|
||||
_getFillAttrs: function (geometryType) {
|
||||
var colors = rampList['ag_GrnYl'][5];
|
||||
return {
|
||||
fill: {
|
||||
'color': {
|
||||
attribute: 'agg_value',
|
||||
bins: '5',
|
||||
quantification: 'quantiles',
|
||||
// TODO: flip the ramp when basemap is black
|
||||
// range: rampList.ag_GrnYl[5].reverse()
|
||||
range: Utils.cloneObject(colors)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}, SimpleStyleDefaults);
|
||||
@@ -0,0 +1,32 @@
|
||||
var _ = require('underscore');
|
||||
var SimpleStyleDefaults = require('./simple-style-defaults');
|
||||
var rampList = require('cartocolor');
|
||||
|
||||
module.exports = _.defaults({
|
||||
_getAggrAttrs: function (geometryType) {
|
||||
return {
|
||||
aggregation: {
|
||||
dataset: 'countries',
|
||||
change: 'manual',
|
||||
value: {
|
||||
operator: 'count',
|
||||
attribute: ''
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
_getFillAttrs: function (geometryType) {
|
||||
return {
|
||||
fill: {
|
||||
'color': {
|
||||
attribute: 'agg_value_density',
|
||||
bins: '5',
|
||||
quantification: 'quantiles',
|
||||
range: _.clone(rampList.Emrld[5])
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}, SimpleStyleDefaults);
|
||||
@@ -0,0 +1,49 @@
|
||||
var _ = require('underscore');
|
||||
var StyleDefaults = require('./style-defaults');
|
||||
var DefaultCartography = require('builder/data/default-cartography.json');
|
||||
var DefaultFormValues = require('builder/data/default-form-styles.json');
|
||||
var Utils = require('builder/helpers/utils');
|
||||
|
||||
module.exports = _.defaults({
|
||||
|
||||
generateAttributes: function (geometryType) {
|
||||
return _.extend(
|
||||
{},
|
||||
this._getFillAttrs(geometryType),
|
||||
this._getStrokeAttrs(geometryType),
|
||||
{
|
||||
blending: DefaultFormValues['blending']
|
||||
},
|
||||
this._getAggrAttrs(geometryType),
|
||||
this._getLabelsAttrs()
|
||||
);
|
||||
},
|
||||
|
||||
_getFillAttrs: function (geometryType) {
|
||||
var fillAttrs = DefaultCartography['simple'][geometryType]['fill'];
|
||||
return {
|
||||
fill: Utils.cloneObject(fillAttrs)
|
||||
};
|
||||
},
|
||||
|
||||
_getStrokeAttrs: function (geometryType) {
|
||||
var strokeAttrs = DefaultCartography['simple'][geometryType]['stroke'];
|
||||
return {
|
||||
stroke: Utils.cloneObject(strokeAttrs)
|
||||
};
|
||||
},
|
||||
|
||||
_getAggrAttrs: function () {
|
||||
var aggrAttrs = DefaultFormValues['aggregation'];
|
||||
return {
|
||||
aggregation: Utils.cloneObject(aggrAttrs)
|
||||
};
|
||||
},
|
||||
|
||||
_getLabelsAttrs: function () {
|
||||
var labelsAttrs = DefaultFormValues['labels'];
|
||||
return {
|
||||
labels: Utils.cloneObject(labelsAttrs)
|
||||
};
|
||||
}
|
||||
}, StyleDefaults);
|
||||
@@ -0,0 +1,18 @@
|
||||
var _ = require('underscore');
|
||||
var HexabinsAggregationDefaults = require('./hexabins-aggregation-style-defaults');
|
||||
|
||||
module.exports = _.defaults({
|
||||
|
||||
_getAggrAttrs: function (geometryType) {
|
||||
return {
|
||||
aggregation: {
|
||||
size: 12,
|
||||
value: {
|
||||
operator: 'count',
|
||||
attribute: ''
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}, HexabinsAggregationDefaults);
|
||||
11
lib/assets/javascripts/builder/editor/style/style-defaults/style-defaults.js
Executable file
11
lib/assets/javascripts/builder/editor/style/style-defaults/style-defaults.js
Executable file
@@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
generateAttributes: function (geometryType) {
|
||||
return {
|
||||
fill: null,
|
||||
stroke: null,
|
||||
blending: null,
|
||||
aggregation: {},
|
||||
labels: {}
|
||||
};
|
||||
}
|
||||
};
|
||||
253
lib/assets/javascripts/builder/editor/style/style-definition-model.js
Executable file
253
lib/assets/javascripts/builder/editor/style/style-definition-model.js
Executable file
@@ -0,0 +1,253 @@
|
||||
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;
|
||||
}
|
||||
});
|
||||
9
lib/assets/javascripts/builder/editor/style/style-form-types.tpl
Executable file
9
lib/assets/javascripts/builder/editor/style/style-form-types.tpl
Executable file
@@ -0,0 +1,9 @@
|
||||
<div class="Editor-HeaderInfo">
|
||||
<div class="Editor-HeaderNumeration CDB-Text is-semibold u-rSpace--m">1</div>
|
||||
<div class="Editor-HeaderInfo-inner CDB-Text js-selector">
|
||||
<div class="Editor-HeaderInfo-title u-bSpace--m">
|
||||
<h2 class="CDB-Text CDB-HeaderInfo-titleText CDB-Size-large"><%- _t('editor.style.style-form.type.title-label') %></h2>
|
||||
</div>
|
||||
<p class="CDB-Text u-upperCase CDB-FontSize-small u-altTextColor u-bSpace--m js-highlight"><%- name %></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<h2 class="CDB-Text CDB-Size-huge is-light u-secondaryTextColor">
|
||||
<%- _t('editor.style.messages.none') %>
|
||||
</h2>
|
||||
@@ -0,0 +1,69 @@
|
||||
var Backbone = require('backbone');
|
||||
var CoreView = require('backbone/core-view');
|
||||
require('builder/components/form-components/index');
|
||||
var StyleShapeFormModel = require('./style-aggregation-properties-form-model');
|
||||
var template = require('./style-aggregation-form.tpl');
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
module: 'editor/style/style-form/style-aggregation-form/style-aggregation-form-view',
|
||||
|
||||
initialize: function (opts) {
|
||||
if (!opts.querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
if (!opts.queryGeometryModel) throw new Error('queryGeometryModel is required');
|
||||
if (!opts.styleModel) throw new Error('styleModel is required');
|
||||
if (!opts.modals) throw new Error('modals is required');
|
||||
if (!opts.configModel) throw new Error('configModel is required');
|
||||
if (!opts.userModel) throw new Error('userModel is required');
|
||||
|
||||
this._queryGeometryModel = opts.queryGeometryModel;
|
||||
this._querySchemaModel = opts.querySchemaModel;
|
||||
this._styleModel = opts.styleModel;
|
||||
this._configModel = opts.configModel;
|
||||
this._userModel = opts.userModel;
|
||||
this._modals = opts.modals;
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this._removeFormView();
|
||||
this.$el.html(template());
|
||||
this._initViews();
|
||||
return this;
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
this._aggrFormModel = new StyleShapeFormModel(
|
||||
this._styleModel.get('aggregation'),
|
||||
{
|
||||
queryGeometryModel: this._queryGeometryModel,
|
||||
querySchemaModel: this._querySchemaModel,
|
||||
styleModel: this._styleModel,
|
||||
configModel: this._configModel,
|
||||
userModel: this._userModel,
|
||||
modals: this._modals
|
||||
}
|
||||
);
|
||||
|
||||
this._aggrFormView = new Backbone.Form({
|
||||
model: this._aggrFormModel
|
||||
});
|
||||
|
||||
this._aggrFormView.bind('change', function () {
|
||||
this.commit();
|
||||
});
|
||||
|
||||
this.$('.js-aggregationForm').append(this._aggrFormView.render().el);
|
||||
},
|
||||
|
||||
_removeFormView: function () {
|
||||
if (this._aggrFormView) {
|
||||
this._aggrFormView.remove();
|
||||
}
|
||||
},
|
||||
|
||||
clean: function () {
|
||||
this._removeFormView();
|
||||
CoreView.prototype.clean.call(this);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
<div class="Editor-HeaderInfo js-aggregationOptions">
|
||||
<div class="Editor-HeaderNumeration CDB-Text is-semibold u-rSpace--m">2</div>
|
||||
<div class="Editor-HeaderInfo-inner CDB-Text js-selector">
|
||||
<div class="Editor-HeaderInfo-title u-bSpace--m">
|
||||
<h2 class="CDB-Text CDB-HeaderInfo-titleText CDB-Size-large"><%- _t('editor.style.style-form.aggregation.title-label') %></h2>
|
||||
</div>
|
||||
<p class="CDB-Text u-upperCase CDB-FontSize-small u-altTextColor u-bSpace--m js-highlight"><%- _t('editor.style.style-form.aggregation.desc') %></p>
|
||||
<div class="js-aggregationForm"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
var _ = require('underscore');
|
||||
var StyleFormDefaultModel = require('builder/editor/style/style-form/style-form-default-model');
|
||||
|
||||
module.exports = StyleFormDefaultModel.extend({
|
||||
|
||||
_FORM_NAME: 'aggregation',
|
||||
|
||||
_onChange: function () {
|
||||
this._styleModel.set('aggregation', _.clone(this.attributes));
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,121 @@
|
||||
var StyleFormAggregationDataset = require('builder/editor/style/style-form/style-form-dictionary/aggregation-dataset');
|
||||
var StyleFormAggregationSize = require('builder/editor/style/style-form/style-form-dictionary/aggregation-size');
|
||||
var StyleFormAggregationValue = require('builder/editor/style/style-form/style-form-dictionary/aggregation-value');
|
||||
|
||||
var StyleFormAnimatedAttribute = require('builder/editor/style/style-form/style-form-dictionary/animated-attribute');
|
||||
var StyleFormAnimatedDuration = require('builder/editor/style/style-form/style-form-dictionary/animated-duration');
|
||||
var StyleFormAnimatedOverlap = require('builder/editor/style/style-form/style-form-dictionary/animated-overlap');
|
||||
var StyleFormAnimatedResolution = require('builder/editor/style/style-form/style-form-dictionary/animated-resolution');
|
||||
var StyleFormAnimatedSteps = require('builder/editor/style/style-form/style-form-dictionary/animated-steps');
|
||||
var StyleFormAnimatedTrails = require('builder/editor/style/style-form/style-form-dictionary/animated-trails');
|
||||
|
||||
var StyleFormBlending = require('builder/editor/style/style-form/style-form-dictionary/blending');
|
||||
|
||||
var StyleFormFillColor = require('builder/editor/style/style-form/style-form-dictionary/fill-color');
|
||||
var StyleFormFillSize = require('builder/editor/style/style-form/style-form-dictionary/fill-size');
|
||||
|
||||
var StyleFormLabelsAttribute = require('builder/editor/style/style-form/style-form-dictionary/labels-attribute');
|
||||
var StyleFormLabelsFillSize = require('builder/editor/style/style-form/style-form-dictionary/labels-fill-size');
|
||||
var StyleFormLabelsFillColor = require('builder/editor/style/style-form/style-form-dictionary/labels-fill-color');
|
||||
var StyleFormLabelsFont = require('builder/editor/style/style-form/style-form-dictionary/labels-font');
|
||||
var StyleFormLabelsHaloSize = require('builder/editor/style/style-form/style-form-dictionary/labels-halo-size');
|
||||
var StyleFormLabelsHaloColor = require('builder/editor/style/style-form/style-form-dictionary/labels-halo-color');
|
||||
var StyleFormLabelsOffset = require('builder/editor/style/style-form/style-form-dictionary/labels-offset');
|
||||
var StyleFormLabelsOverlap = require('builder/editor/style/style-form/style-form-dictionary/labels-overlap');
|
||||
var StyleFormLabelsPlacement = require('builder/editor/style/style-form/style-form-dictionary/labels-placement');
|
||||
|
||||
var StyleFormStrokeSize = require('builder/editor/style/style-form/style-form-dictionary/stroke-size');
|
||||
var StyleFormStrokeColor = require('builder/editor/style/style-form/style-form-dictionary/stroke-color');
|
||||
|
||||
var StyleFormStyle = require('builder/editor/style/style-form/style-form-dictionary/style');
|
||||
var StyleFormHidden = require('builder/editor/style/style-form/style-form-dictionary/hidden');
|
||||
|
||||
/*
|
||||
* Dictionary that contains all the necessary components
|
||||
* for the styles form
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
'aggregation-dataset': function (params) {
|
||||
return StyleFormAggregationDataset.generate(params);
|
||||
},
|
||||
'aggregation-size': function (params) {
|
||||
return StyleFormAggregationSize.generate(params);
|
||||
},
|
||||
'aggregation-value': function (params) {
|
||||
return StyleFormAggregationValue.generate(params);
|
||||
},
|
||||
'animated-attribute': function (params) {
|
||||
return StyleFormAnimatedAttribute.generate(params);
|
||||
},
|
||||
'animated-enabled': function (params) {
|
||||
return StyleFormHidden.generate(params);
|
||||
},
|
||||
'animated-duration': function (params) {
|
||||
return StyleFormAnimatedDuration.generate(params);
|
||||
},
|
||||
'animated-overlap': function (params) {
|
||||
return StyleFormAnimatedOverlap.generate(params);
|
||||
},
|
||||
'animated-resolution': function (params) {
|
||||
return StyleFormAnimatedResolution.generate(params);
|
||||
},
|
||||
'animated-steps': function (params) {
|
||||
return StyleFormAnimatedSteps.generate(params);
|
||||
},
|
||||
'animated-trails': function (params) {
|
||||
return StyleFormAnimatedTrails.generate(params);
|
||||
},
|
||||
|
||||
'blending': function (params) {
|
||||
return StyleFormBlending.generate(params);
|
||||
},
|
||||
|
||||
'fillSize': function (params) {
|
||||
return StyleFormFillSize.generate(params);
|
||||
},
|
||||
'fillColor': function (params) {
|
||||
return StyleFormFillColor.generate(params);
|
||||
},
|
||||
|
||||
'labels-enabled': function (params) {
|
||||
return StyleFormHidden.generate(params);
|
||||
},
|
||||
'labels-attribute': function (params) {
|
||||
return StyleFormLabelsAttribute.generate(params);
|
||||
},
|
||||
'labels-fillSize': function (params) {
|
||||
return StyleFormLabelsFillSize.generate(params);
|
||||
},
|
||||
'labels-fillColor': function (params) {
|
||||
return StyleFormLabelsFillColor.generate(params);
|
||||
},
|
||||
'labels-font': function (params) {
|
||||
return StyleFormLabelsFont.generate(params);
|
||||
},
|
||||
'labels-haloSize': function (params) {
|
||||
return StyleFormLabelsHaloSize.generate(params);
|
||||
},
|
||||
'labels-haloColor': function (params) {
|
||||
return StyleFormLabelsHaloColor.generate(params);
|
||||
},
|
||||
'labels-offset': function (params) {
|
||||
return StyleFormLabelsOffset.generate(params);
|
||||
},
|
||||
'labels-overlap': function (params) {
|
||||
return StyleFormLabelsOverlap.generate(params);
|
||||
},
|
||||
'labels-placement': function (params) {
|
||||
return StyleFormLabelsPlacement.generate(params);
|
||||
},
|
||||
|
||||
'strokeSize': function (params) {
|
||||
return StyleFormStrokeSize.generate(params);
|
||||
},
|
||||
'strokeColor': function (params) {
|
||||
return StyleFormStrokeColor.generate(params);
|
||||
},
|
||||
'style': function (params) {
|
||||
return StyleFormStyle.generate(params);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var StyleFormComponents = require('./style-form-components-dictionary');
|
||||
var StyleConstants = require('builder/components/form-components/_constants/_style');
|
||||
var DEBOUNCE_TIME = 350;
|
||||
|
||||
module.exports = Backbone.Model.extend({
|
||||
|
||||
_FORM_NAME: '',
|
||||
|
||||
initialize: function (attrs, opts) {
|
||||
if (!opts.styleModel) throw new Error('Style model is required');
|
||||
if (!opts.modals) throw new Error('modals is required');
|
||||
this._styleModel = opts.styleModel;
|
||||
this._querySchemaModel = opts.querySchemaModel;
|
||||
this._queryGeometryModel = opts.queryGeometryModel;
|
||||
this._configModel = opts.configModel;
|
||||
this._userModel = opts.userModel;
|
||||
this._modals = opts.modals;
|
||||
this.schema = this._generateSchema();
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.bind('change', _.debounce(this._onChange.bind(this), DEBOUNCE_TIME), this);
|
||||
},
|
||||
|
||||
_onChange: function () {
|
||||
throw new Error('_onChange should be defined');
|
||||
},
|
||||
|
||||
_isTorqueCategory: function () {
|
||||
var fill = this._styleModel.get('fill');
|
||||
var color = fill && fill.color || {};
|
||||
|
||||
return this._styleModel.get('style') !== StyleConstants.Type.HEATMAP
|
||||
? !color.fixed
|
||||
: false;
|
||||
},
|
||||
|
||||
_generateSchema: function () {
|
||||
var querySchemaModel = this._querySchemaModel;
|
||||
var queryGeometryModel = this._queryGeometryModel;
|
||||
var configModel = this._configModel;
|
||||
var userModel = this._userModel;
|
||||
var modals = this._modals;
|
||||
var styleType = this._styleModel.get('type');
|
||||
var isAutoStyleApplied = this._styleModel.has('autoStyle');
|
||||
var animationType = this._styleModel.get('style');
|
||||
var formName = this._FORM_NAME ? this._FORM_NAME + '-' : '';
|
||||
|
||||
return _.reduce(this.attributes, function (attribute, value, key) {
|
||||
var formComponent = StyleFormComponents[formName + key];
|
||||
|
||||
if (formComponent) {
|
||||
attribute[key] = formComponent({
|
||||
styleType: styleType,
|
||||
isAutoStyleApplied: isAutoStyleApplied,
|
||||
animationType: animationType,
|
||||
querySchemaModel: querySchemaModel,
|
||||
queryGeometryModel: queryGeometryModel,
|
||||
modals: modals,
|
||||
userModel: userModel,
|
||||
configModel: configModel,
|
||||
isTorqueCategory: this._isTorqueCategory()
|
||||
});
|
||||
}
|
||||
|
||||
return attribute;
|
||||
}, {}, this);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Select',
|
||||
title: _t('editor.style.components.aggregation-dataset.label'),
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
options: [
|
||||
{
|
||||
val: 'countries'
|
||||
}, {
|
||||
val: 'provinces'
|
||||
}
|
||||
],
|
||||
editorAttrs: {
|
||||
help: _t('editor.style.components.aggregation-dataset.help')
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
generate: function (params) {
|
||||
return {
|
||||
type: 'Number',
|
||||
title: _t('editor.style.components.aggregation-size.label'),
|
||||
help: _t('editor.style.components.aggregation-size.label-help'),
|
||||
validators: ['required', {
|
||||
type: 'interval',
|
||||
min: 10,
|
||||
max: 100
|
||||
}],
|
||||
editorAttrs: {
|
||||
help: _t('editor.style.components.aggregation-size.help', { type: _t('editor.style.tooltips.' + params.styleType) })
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
var StyleFormDictionaryHelpers = require('builder/editor/style/style-form/style-form-helpers');
|
||||
|
||||
module.exports = {
|
||||
generate: function (params) {
|
||||
return {
|
||||
type: 'Operators',
|
||||
title: _t('editor.style.components.aggregation-value.label'),
|
||||
options: StyleFormDictionaryHelpers.getSchemaColumns(params.querySchemaModel),
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
help: _t('editor.style.components.aggregation-value.help')
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
var StyleFormDictionaryHelpers = require('builder/editor/style/style-form/style-form-helpers');
|
||||
var StyleConstants = require('builder/components/form-components/_constants/_style');
|
||||
|
||||
module.exports = {
|
||||
generate: function (params) {
|
||||
var filterFunction = function (item) {
|
||||
var columnType = item.get('type');
|
||||
return columnType && (columnType === 'number' || columnType === 'date');
|
||||
};
|
||||
|
||||
if (params.styleType === StyleConstants.Type.HEATMAP) {
|
||||
return StyleFormDictionaryHelpers.generateSelectWithSchemaColumns({
|
||||
componentName: 'animated-attribute',
|
||||
querySchemaModel: params.querySchemaModel,
|
||||
filterFunction: filterFunction
|
||||
});
|
||||
}
|
||||
|
||||
return StyleFormDictionaryHelpers.generateSelectByStyleType({
|
||||
componentName: 'animated-attribute',
|
||||
querySchemaModel: params.querySchemaModel,
|
||||
filterFunction: filterFunction,
|
||||
styleType: params.styleType
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Number',
|
||||
title: _t('editor.style.components.animated-duration.label'),
|
||||
validators: ['required', {
|
||||
type: 'interval',
|
||||
min: 0,
|
||||
max: 60
|
||||
}],
|
||||
editorAttrs: {
|
||||
help: _t('editor.style.components.animated-duration.help')
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
module.exports = {
|
||||
generate: function (params) {
|
||||
if (params.isTorqueCategory) {
|
||||
return {
|
||||
type: 'Hidden'
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'Radio',
|
||||
title: _t('editor.style.components.animated-overlap.label'),
|
||||
options: [
|
||||
{
|
||||
val: 'false',
|
||||
label: _t('editor.style.components.animated-overlap.options.false')
|
||||
}, {
|
||||
val: 'true',
|
||||
label: _t('editor.style.components.animated-overlap.options.true')
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Number',
|
||||
title: _t('editor.style.components.animated-resolution.label'),
|
||||
validators: ['required', {
|
||||
type: 'interval',
|
||||
min: 1,
|
||||
max: 16
|
||||
}],
|
||||
editorAttrs: {
|
||||
help: _t('editor.style.components.animated-resolution.help')
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Number',
|
||||
title: _t('editor.style.components.animated-steps.label'),
|
||||
validators: ['required', {
|
||||
type: 'interval',
|
||||
min: 1,
|
||||
max: 1024,
|
||||
step: 4
|
||||
}],
|
||||
editorAttrs: {
|
||||
help: _t('editor.style.components.animated-steps.help')
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Number',
|
||||
title: _t('editor.style.components.animated-trails.label'),
|
||||
validators: ['required', {
|
||||
type: 'interval',
|
||||
min: 0,
|
||||
max: 30
|
||||
}],
|
||||
editorAttrs: {
|
||||
help: _t('editor.style.components.animated-trails.help')
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
var _ = require('underscore');
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
var StyleConstants = require('builder/components/form-components/_constants/_style');
|
||||
|
||||
module.exports = {
|
||||
generate: function (params) {
|
||||
var blendingOptions = this._getBlendingOptions(params);
|
||||
var options = this._generateBlendingOptions(blendingOptions);
|
||||
|
||||
return {
|
||||
type: 'Select',
|
||||
title: _t('editor.style.components.blending.label'),
|
||||
options: options,
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
help: _t('editor.style.tooltips.blending')
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
_generateBlendingOptions: function (options) {
|
||||
return _.reduce(options, function (values, option) {
|
||||
values.push({
|
||||
val: option,
|
||||
label: _t('editor.style.components.blending.options.' + option)
|
||||
});
|
||||
|
||||
return values;
|
||||
}, []);
|
||||
},
|
||||
|
||||
_getBlendingOptions: function (params) {
|
||||
return params.styleType === StyleConstants.Type.ANIMATION
|
||||
? StyleConstants.Blending.ANIMATION
|
||||
: StyleConstants.Blending.SIMPLE;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,115 @@
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
var StyleFormDictionaryHelpers = require('builder/editor/style/style-form/style-form-helpers');
|
||||
var FillConstants = require('builder/components/form-components/_constants/_fill');
|
||||
var StyleConstants = require('builder/components/form-components/_constants/_style');
|
||||
|
||||
var NO_PANES_CLASS = 'Editor-formInner--NoTabs';
|
||||
|
||||
module.exports = {
|
||||
generate: function (params) {
|
||||
var editorAttrs = {
|
||||
help: {
|
||||
color: null,
|
||||
image: null
|
||||
},
|
||||
hidePanes: [],
|
||||
hideTabs: [],
|
||||
imageEnabled: false,
|
||||
hideNumericColumns: false,
|
||||
removeByValueCategory: false,
|
||||
categorizeColumns: false,
|
||||
geometryName: params.queryGeometryModel.get('simple_geom')
|
||||
};
|
||||
|
||||
var options = StyleFormDictionaryHelpers.getOptionsByStyleType({
|
||||
querySchemaModel: params.querySchemaModel,
|
||||
styleType: params.styleType,
|
||||
animationType: params.animationType
|
||||
});
|
||||
|
||||
var styleType = this._getStyleType(params);
|
||||
|
||||
if (styleType === StyleConstants.Type.REGIONS ||
|
||||
styleType === StyleConstants.Type.HEXABINS ||
|
||||
styleType === StyleConstants.Type.SQUARES) {
|
||||
editorAttrs.geometryName = 'polygon';
|
||||
editorAttrs.removeByValueCategory = true;
|
||||
}
|
||||
|
||||
this._setColor(editorAttrs, styleType);
|
||||
this._setEditorAttributesForHeatmaps(params, editorAttrs, styleType);
|
||||
this._setEditorAttributesForPoints(params, editorAttrs, styleType);
|
||||
this._setEditorAttributesForAnimation(params, editorAttrs, styleType);
|
||||
|
||||
return {
|
||||
type: 'FillColor',
|
||||
title: this._getTitle(params),
|
||||
options: options,
|
||||
fieldClass: editorAttrs.hidePanes.length >= 1 ? NO_PANES_CLASS : '',
|
||||
query: params.querySchemaModel.get('query'),
|
||||
configModel: params.configModel,
|
||||
userModel: params.userModel,
|
||||
validators: ['required'],
|
||||
editorAttrs: editorAttrs,
|
||||
modals: params.modals,
|
||||
dialogMode: DialogConstants.Mode.FLOAT
|
||||
};
|
||||
},
|
||||
|
||||
_getStyleType: function (params) {
|
||||
return params.queryGeometryModel.get('simple_geom') === StyleConstants.Type.POLYGON
|
||||
? StyleConstants.Type.POLYGON
|
||||
: params.styleType;
|
||||
},
|
||||
|
||||
_getTitle: function (params) {
|
||||
var geom = params.queryGeometryModel.get('simple_geom');
|
||||
return _t('editor.style.components.fillColor.' + geom) +
|
||||
' ' +
|
||||
_t('editor.style.components.fillColor.label');
|
||||
},
|
||||
|
||||
_setEditorAttributesForHeatmaps: function (params, editorAttrs, styleType) {
|
||||
if (styleType === StyleConstants.Type.HEATMAP) {
|
||||
editorAttrs.hidePanes = [FillConstants.Panes.FIXED];
|
||||
editorAttrs.help.color = _t('editor.style.tooltips.fill.color-heatmap');
|
||||
}
|
||||
},
|
||||
|
||||
_setEditorAttributesForPoints: function (params, editorAttrs, styleType) {
|
||||
if (styleType === StyleConstants.Type.SIMPLE && StyleFormDictionaryHelpers.hasGeometryOf(params, 'point')) {
|
||||
if (!params.isAutoStyleApplied) {
|
||||
this._setImage(editorAttrs, styleType);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_setEditorAttributesForAnimation: function (params, editorAttrs, styleType) {
|
||||
if (styleType === StyleConstants.Type.ANIMATION) {
|
||||
editorAttrs.hideTabs = [FillConstants.Tabs.BINS, FillConstants.Tabs.QUANTIFICATION];
|
||||
editorAttrs.hideNumericColumns = true;
|
||||
|
||||
if (params.animationType === 'simple') {
|
||||
editorAttrs.categorizeColumns = true;
|
||||
} else {
|
||||
editorAttrs.hidePanes = [FillConstants.Panes.FIXED];
|
||||
editorAttrs.help.color = _t('editor.style.tooltips.fill.color-heatmap');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_setColor: function (editorAttrs, styleType) {
|
||||
var tooltipColor = _t('editor.style.tooltips.fill.color', {
|
||||
type: _t('editor.style.tooltips.' + styleType)
|
||||
});
|
||||
|
||||
editorAttrs.help.color = tooltipColor;
|
||||
},
|
||||
|
||||
_setImage: function (editorAttrs, styleType) {
|
||||
editorAttrs.imageEnabled = true;
|
||||
editorAttrs.help.image = _t('editor.style.tooltips.fill.image', {
|
||||
type: _t('editor.style.tooltips.' + styleType)
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
var _ = require('underscore');
|
||||
var StyleFormDictionaryHelpers = require('builder/editor/style/style-form/style-form-helpers');
|
||||
var StyleConstants = require('builder/components/form-components/_constants/_style');
|
||||
var FillConstants = require('builder/components/form-components/_constants/_fill');
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
|
||||
var NO_PANES_CLASS = 'Editor-formInner--NoTabs';
|
||||
|
||||
module.exports = {
|
||||
generate: function (params) {
|
||||
this._checkForParams(params);
|
||||
|
||||
var optionsForStyle = StyleFormDictionaryHelpers.getOptionsByStyleType({
|
||||
querySchemaModel: params.querySchemaModel,
|
||||
styleType: params.styleType,
|
||||
animationType: params.animationType
|
||||
});
|
||||
|
||||
var size = this._buildFillSize(params, optionsForStyle);
|
||||
return size;
|
||||
},
|
||||
|
||||
_buildFillSize: function (params, optionsForStyle) {
|
||||
var self = this;
|
||||
var size = this._buildSize(params, {
|
||||
options: optionsForStyle,
|
||||
title: _t('editor.style.components.point-size.label'),
|
||||
editorAttrs: self._buildFillSizeAttrs(params)
|
||||
});
|
||||
|
||||
this._hideByValuePaneIfNeeded(params, size);
|
||||
return size;
|
||||
},
|
||||
|
||||
_buildFillSizeAttrs: function (params) {
|
||||
var sizeAttrs = _.extend(FillConstants.Size.DEFAULT, {
|
||||
help: 'editor.style.tooltips.fill.size',
|
||||
geometryName: params.queryGeometryModel.get('simple_geom')
|
||||
});
|
||||
this._setDefaultRangeIfNeeded(params, sizeAttrs);
|
||||
return sizeAttrs;
|
||||
},
|
||||
|
||||
_buildSize: function (params, customOptions) {
|
||||
var size = {
|
||||
type: 'Size',
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
validators: ['required']
|
||||
};
|
||||
return _.extend(size, customOptions);
|
||||
},
|
||||
|
||||
_checkForParams: function (params) {
|
||||
if (!params.querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
if (!params.styleType) throw new Error('styleType is required');
|
||||
},
|
||||
|
||||
_setDefaultRangeIfNeeded: function (params, sizeAttrs) {
|
||||
if (params.styleType === StyleConstants.Type.SIMPLE && StyleFormDictionaryHelpers.hasGeometryOf(params, 'point')) {
|
||||
sizeAttrs.defaultRange = [5, 20];
|
||||
}
|
||||
},
|
||||
|
||||
_hideByValuePaneIfNeeded: function (params, size) {
|
||||
if (_.contains([StyleConstants.Type.HEATMAP, StyleConstants.Type.ANIMATION], params.styleType)) {
|
||||
size.editorAttrs.hidePanes = [FillConstants.Panes.BY_VALUE];
|
||||
size.fieldClass = NO_PANES_CLASS;
|
||||
} else {
|
||||
size.editorAttrs.hidePanes = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
var _ = require('underscore');
|
||||
var StyleFormDictionaryHelpers = require('builder/editor/style/style-form/style-form-helpers');
|
||||
var StylesFactory = require('builder/editor/style/styles-factory');
|
||||
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
var FillConstants = require('builder/components/form-components/_constants/_fill');
|
||||
var StyleConstants = require('builder/components/form-components/_constants/_style');
|
||||
|
||||
module.exports = {
|
||||
generate: function (params) {
|
||||
var editorAttrs = {};
|
||||
|
||||
var options = StyleFormDictionaryHelpers.getOptionsByStyleType({
|
||||
querySchemaModel: params.querySchemaModel,
|
||||
styleType: params.styleType,
|
||||
animationType: params.animationType
|
||||
});
|
||||
|
||||
var styleType = params.queryGeometryModel.get('simple_geom') === StyleConstants.Type.POLYGON
|
||||
? StyleConstants.Type.POLYGON
|
||||
: params.styleType;
|
||||
|
||||
var color = {
|
||||
help: _t('editor.style.tooltips.fill.color', { type: _t('editor.style.tooltips.' + styleType) })
|
||||
};
|
||||
|
||||
var size = _.extend(FillConstants.Size.DEFAULT, {
|
||||
help: _t('editor.style.tooltips.fill.size', { type: _t('editor.style.tooltips.' + styleType) })
|
||||
});
|
||||
|
||||
var fillLabel = _t('editor.style.components.fill');
|
||||
|
||||
if (params.styleType === StyleConstants.Type.HEATMAP) {
|
||||
size.hidePanes = [FillConstants.Panes.BY_VALUE];
|
||||
color.hidePanes = [FillConstants.Panes.FIXED];
|
||||
}
|
||||
|
||||
if (params.styleType === StyleConstants.Type.SIMPLE && StyleFormDictionaryHelpers.hasGeometryOf(params, 'point')) {
|
||||
size.defaultRange = FillConstants.Size.DEFAULT_RANGE;
|
||||
|
||||
if (!params.isAutoStyleApplied) {
|
||||
color.imageEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.styleType === StyleConstants.Type.ANIMATION) {
|
||||
size.hidePanes = [FillConstants.Panes.BY_VALUE];
|
||||
color.hideTabs = [
|
||||
FillConstants.Tabs.BINS,
|
||||
FillConstants.Tabs.QUANTIFICATION
|
||||
];
|
||||
|
||||
if (params.animationType === 'simple') {
|
||||
color.categorizeColumns = true;
|
||||
} else {
|
||||
color.hidePanes = [FillConstants.Panes.FIXED];
|
||||
}
|
||||
}
|
||||
|
||||
if (_.contains(StylesFactory.getAggregationTypes(), params.styleType) ||
|
||||
StyleFormDictionaryHelpers.hasGeometryOf(params, 'polygon')) {
|
||||
fillLabel = _t('editor.style.components.color');
|
||||
}
|
||||
|
||||
editorAttrs.color = color;
|
||||
editorAttrs.size = size;
|
||||
|
||||
return {
|
||||
type: 'Fill',
|
||||
title: fillLabel,
|
||||
options: options,
|
||||
query: params.querySchemaModel.get('query'),
|
||||
configModel: params.configModel,
|
||||
userModel: params.userModel,
|
||||
validators: ['required'],
|
||||
editorAttrs: editorAttrs,
|
||||
modals: params.modals,
|
||||
dialogMode: DialogConstants.Mode.FLOAT
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Hidden'
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
var StyleFormDictionaryHelpers = require('builder/editor/style/style-form/style-form-helpers');
|
||||
|
||||
module.exports = {
|
||||
generate: function (params) {
|
||||
var filterFunction = function (item) {
|
||||
var columnName = item.get('name');
|
||||
var columnType = item.get('type');
|
||||
return columnName !== 'the_geom' && columnName !== 'the_geom_webmercator' && columnType !== 'date';
|
||||
};
|
||||
|
||||
return StyleFormDictionaryHelpers.generateSelectByStyleType({
|
||||
componentName: 'labels-attribute',
|
||||
querySchemaModel: params.querySchemaModel,
|
||||
styleType: params.styleType,
|
||||
filterFunction: filterFunction
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
var FillConstants = require('builder/components/form-components/_constants/_fill');
|
||||
|
||||
var NO_PANES_CLASS = 'Editor-formInner--NoTabs';
|
||||
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'FillColor',
|
||||
title: _t('editor.style.components.labels-fill-color'),
|
||||
fieldClass: NO_PANES_CLASS,
|
||||
options: [],
|
||||
validators: ['required'],
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
imageEnabled: false,
|
||||
hidePanes: [FillConstants.Panes.BY_VALUE]
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
var FillConstants = require('builder/components/form-components/_constants/_fill');
|
||||
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Size',
|
||||
title: _t('editor.style.components.labels-fill-size'),
|
||||
options: [],
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
min: 6,
|
||||
max: 24,
|
||||
hidePanes: [FillConstants.Panes.BY_VALUE]
|
||||
},
|
||||
validators: ['required'],
|
||||
fieldClass: 'Editor-formInner--NoTabs'
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Fill',
|
||||
title: _t('editor.style.components.labels-fill'),
|
||||
options: [],
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
size: {
|
||||
min: 6,
|
||||
max: 24,
|
||||
hidePanes: ['value']
|
||||
},
|
||||
color: {
|
||||
hidePanes: ['value']
|
||||
}
|
||||
},
|
||||
validators: ['required']
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
|
||||
var FONTS_LIST = [
|
||||
'Source Han Sans CN Regular',
|
||||
'Source Han Serif CN Regular',
|
||||
'DejaVu Sans Book',
|
||||
'Unifont Medium',
|
||||
'Open Sans Regular',
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Select',
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
options: FONTS_LIST
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
var FillConstants = require('builder/components/form-components/_constants/_fill');
|
||||
|
||||
var NO_PANES_CLASS = 'Editor-formInner--NoTabs';
|
||||
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'FillColor',
|
||||
title: _t('editor.style.components.labels-halo-color'),
|
||||
fieldClass: NO_PANES_CLASS,
|
||||
options: [],
|
||||
validators: ['required'],
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
hidePanes: [FillConstants.Panes.BY_VALUE]
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
var FillConstants = require('builder/components/form-components/_constants/_fill');
|
||||
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Size',
|
||||
title: _t('editor.style.components.labels-halo-size'),
|
||||
options: [],
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
hidePanes: [FillConstants.Panes.BY_VALUE]
|
||||
},
|
||||
validators: ['required'],
|
||||
fieldClass: 'Editor-formInner--NoTabs'
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Fill',
|
||||
title: _t('editor.style.components.labels-halo'),
|
||||
options: [],
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
size: {
|
||||
hidePanes: ['value']
|
||||
},
|
||||
color: {
|
||||
hidePanes: ['value']
|
||||
}
|
||||
},
|
||||
validators: ['required']
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Number',
|
||||
title: _t('editor.style.components.labels-offset'),
|
||||
validators: ['required', {
|
||||
type: 'interval',
|
||||
min: -15,
|
||||
max: 15
|
||||
}]
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Radio',
|
||||
title: _t('editor.style.components.labels-overlap.label'),
|
||||
options: [
|
||||
{
|
||||
val: 'true',
|
||||
label: _t('editor.style.components.labels-overlap.options.true')
|
||||
}, {
|
||||
val: 'false',
|
||||
label: _t('editor.style.components.labels-overlap.options.false')
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
var _ = require('underscore');
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
var PLACEMENTS = ['point', 'line', 'vertex', 'interior'];
|
||||
|
||||
return {
|
||||
type: 'Select',
|
||||
title: _t('editor.style.components.labels-placement.label'),
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
options: _.reduce(PLACEMENTS, function (values, type) {
|
||||
values.push({
|
||||
val: type,
|
||||
label: _t('editor.style.components.labels-placement.options.' + type)
|
||||
});
|
||||
|
||||
return values;
|
||||
}, []),
|
||||
editorAttrs: {
|
||||
showSearch: false
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,87 @@
|
||||
var StyleFormDictionaryHelpers = require('builder/editor/style/style-form/style-form-helpers');
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
var StyleConstants = require('builder/components/form-components/_constants/_style');
|
||||
|
||||
var NO_PANES_CLASS = 'Editor-formInner--NoTabs';
|
||||
|
||||
module.exports = {
|
||||
generate: function (params) {
|
||||
var strokeParams = {
|
||||
querySchemaModel: params.querySchemaModel,
|
||||
queryGeometryModel: params.queryGeometryModel,
|
||||
styleType: params.styleType,
|
||||
configModel: params.configModel,
|
||||
userModel: params.userModel,
|
||||
modals: params.modals
|
||||
};
|
||||
|
||||
return params.queryGeometryModel.get('simple_geom') === 'line'
|
||||
? this._generateLineStrokeColor(strokeParams)
|
||||
: this._generateSimpleStrokeColor(strokeParams, params.queryGeometryModel.get('simple_geom'));
|
||||
},
|
||||
|
||||
_generateLineStrokeColor: function (params) {
|
||||
if (!params.querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
if (!params.queryGeometryModel) throw new Error('queryGeometryModel is required');
|
||||
if (!params.configModel) throw new Error('configModel is required');
|
||||
if (!params.styleType) throw new Error('styleType is required');
|
||||
if (!params.userModel) throw new Error('userModel is required');
|
||||
if (!params.modals) throw new Error('modals is required');
|
||||
|
||||
var queryStatus = params.querySchemaModel.get('status');
|
||||
var isDisabled = queryStatus !== 'fetched';
|
||||
var helpMessage = _t('editor.style.components.stroke.' + queryStatus);
|
||||
|
||||
return {
|
||||
type: 'FillColor',
|
||||
title: _t('editor.style.components.stroke-color.label'),
|
||||
options: StyleFormDictionaryHelpers.getOptionsByStyleType({
|
||||
querySchemaModel: params.querySchemaModel,
|
||||
styleType: params.styleType
|
||||
}),
|
||||
query: params.querySchemaModel.get('query'),
|
||||
configModel: params.configModel,
|
||||
userModel: params.userModel,
|
||||
modals: params.modals,
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
imageEnabled: false,
|
||||
hidePanes: [],
|
||||
disabled: isDisabled,
|
||||
help: isDisabled ? helpMessage : _t('editor.style.tooltips.stroke.color', { type: _t('editor.style.tooltips.line') }),
|
||||
geometryName: params.queryGeometryModel.get('simple_geom')
|
||||
},
|
||||
validators: ['required']
|
||||
};
|
||||
},
|
||||
|
||||
_generateSimpleStrokeColor: function (params, type) {
|
||||
if (!params.querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
if (!params.configModel) throw new Error('configModel is required');
|
||||
if (!params.styleType) throw new Error('styleType is required');
|
||||
if (!params.userModel) throw new Error('userModel is required');
|
||||
if (!params.modals) throw new Error('modals is required');
|
||||
|
||||
var styleType = type === StyleConstants.Type.POLYGON
|
||||
? StyleConstants.Type.POLYGON
|
||||
: params.styleType;
|
||||
|
||||
return {
|
||||
type: 'FillColor',
|
||||
title: _t('editor.style.components.stroke-color.label'),
|
||||
fieldClass: NO_PANES_CLASS,
|
||||
options: [],
|
||||
query: params.querySchemaModel.get('query'),
|
||||
configModel: params.configModel,
|
||||
userModel: params.userModel,
|
||||
modals: params.modals,
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
imageEnabled: false,
|
||||
hidePanes: ['value'],
|
||||
help: _t('editor.style.tooltips.stroke.color', { type: _t('editor.style.tooltips.' + styleType) })
|
||||
},
|
||||
validators: ['required']
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,88 @@
|
||||
var _ = require('underscore');
|
||||
var StyleFormDictionaryHelpers = require('builder/editor/style/style-form/style-form-helpers');
|
||||
var FillConstants = require('builder/components/form-components/_constants/_fill');
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
|
||||
var NO_PANES_CLASS = 'Editor-formInner--NoTabs';
|
||||
|
||||
module.exports = {
|
||||
generate: function (params) {
|
||||
this._checkForParams(params);
|
||||
|
||||
if (params.queryGeometryModel.get('simple_geom') === 'line') {
|
||||
return this._buildLineStrokeSize(params);
|
||||
}
|
||||
return this._buildSimpleStrokeSize(params);
|
||||
},
|
||||
|
||||
_buildLineStrokeSize: function (params) {
|
||||
var options = StyleFormDictionaryHelpers.getOptionsByStyleType({
|
||||
querySchemaModel: params.querySchemaModel,
|
||||
styleType: params.styleType
|
||||
});
|
||||
|
||||
var self = this;
|
||||
var size = this._buildSize(params, {
|
||||
options: options,
|
||||
title: _t('editor.style.components.stroke-size.label'),
|
||||
editorAttrs: self._buildLineStrokeSizeAttrs(params)
|
||||
});
|
||||
|
||||
return size;
|
||||
},
|
||||
|
||||
_buildSimpleStrokeSize: function (params) {
|
||||
var self = this;
|
||||
var size = this._buildSize(params, {
|
||||
options: [],
|
||||
title: _t('editor.style.components.stroke-size.label'),
|
||||
editorAttrs: self._buildSimpleStrokeSizeAttrs(params)
|
||||
});
|
||||
size.fieldClass = NO_PANES_CLASS;
|
||||
|
||||
return size;
|
||||
},
|
||||
|
||||
_buildLineStrokeSizeAttrs: function (params) {
|
||||
var queryStatus = params.querySchemaModel.get('status');
|
||||
var isDisabled = queryStatus !== 'fetched';
|
||||
|
||||
var sizeAttrs = {
|
||||
min: 0,
|
||||
max: 50,
|
||||
disabled: isDisabled,
|
||||
defaultRange: [1, 5],
|
||||
help: '',
|
||||
geometryName: params.queryGeometryModel.get('simple_geom')
|
||||
};
|
||||
|
||||
return sizeAttrs;
|
||||
},
|
||||
|
||||
_buildSimpleStrokeSizeAttrs: function (params) {
|
||||
var sizeAttrs = {
|
||||
min: 0,
|
||||
max: 10,
|
||||
step: 0.5,
|
||||
hidePanes: [FillConstants.Panes.BY_VALUE],
|
||||
help: 'editor.style.tooltips.stroke.size',
|
||||
geometryName: params.queryGeometryModel.get('simple_geom')
|
||||
};
|
||||
return sizeAttrs;
|
||||
},
|
||||
|
||||
_buildSize: function (params, customOptions) {
|
||||
var size = {
|
||||
type: 'Size',
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
validators: ['required']
|
||||
};
|
||||
return _.extend(size, customOptions);
|
||||
},
|
||||
|
||||
_checkForParams: function (params) {
|
||||
if (!params.queryGeometryModel) throw new Error('queryGeometryModel is required');
|
||||
if (!params.querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
if (!params.styleType) throw new Error('styleType is required');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
var StyleFormDictionaryHelpers = require('builder/editor/style/style-form/style-form-helpers');
|
||||
|
||||
module.exports = {
|
||||
generate: function (params) {
|
||||
var strokeParams = {
|
||||
querySchemaModel: params.querySchemaModel,
|
||||
styleType: params.styleType,
|
||||
configModel: params.configModel,
|
||||
userModel: params.userModel,
|
||||
modals: params.modals
|
||||
};
|
||||
|
||||
if (params.queryGeometryModel.get('simple_geom') === 'line') {
|
||||
return StyleFormDictionaryHelpers.generateLineStroke(strokeParams);
|
||||
}
|
||||
|
||||
return StyleFormDictionaryHelpers.generateSimpleStroke(strokeParams, params.queryGeometryModel.get('simple_geom'));
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
generate: function () {
|
||||
return {
|
||||
type: 'Radio',
|
||||
title: _t('editor.style.components.type.label'),
|
||||
options: [
|
||||
{
|
||||
val: 'simple',
|
||||
label: _t('editor.style.components.type.options.points')
|
||||
}, {
|
||||
val: 'heatmap',
|
||||
label: _t('editor.style.components.type.options.heatmap')
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,180 @@
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
var StyleConstants = require('builder/components/form-components/_constants/_style');
|
||||
|
||||
module.exports = {
|
||||
getSchemaColumns: function (querySchemaModel, filterFunction) {
|
||||
if (!querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
|
||||
var columnsCollection = querySchemaModel.columnsCollection;
|
||||
if (filterFunction) {
|
||||
columnsCollection = columnsCollection.filter(filterFunction);
|
||||
}
|
||||
return columnsCollection.map(function (model) {
|
||||
var columnName = model.get('name');
|
||||
return {
|
||||
val: columnName,
|
||||
label: columnName,
|
||||
type: model.get('type')
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
getOptionsByStyleType: function (params) {
|
||||
if (!params.querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
var optionsArray = this.getSchemaColumns(params.querySchemaModel, params.filterFunction);
|
||||
|
||||
var CARTODB_ID = { val: 'cartodb_id', label: 'cartodb_id', type: 'number' };
|
||||
var AGG_VALUE = { val: 'agg_value', label: 'agg_value', type: 'number' };
|
||||
var AGG_VALUE_DENSITY = { val: 'agg_value_density', label: 'agg_value_density', type: 'number' };
|
||||
|
||||
switch (params.styleType) {
|
||||
case StyleConstants.Type.HEATMAP:
|
||||
optionsArray = [CARTODB_ID];
|
||||
break;
|
||||
case StyleConstants.Type.REGIONS:
|
||||
optionsArray = [AGG_VALUE, AGG_VALUE_DENSITY];
|
||||
break;
|
||||
case StyleConstants.Type.HEXABINS:
|
||||
case StyleConstants.Type.SQUARES:
|
||||
optionsArray = [AGG_VALUE];
|
||||
break;
|
||||
case StyleConstants.Type.ANIMATION:
|
||||
if (params.animationType === 'heatmap') {
|
||||
optionsArray = [CARTODB_ID];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Nothing
|
||||
}
|
||||
|
||||
return optionsArray;
|
||||
},
|
||||
|
||||
generateSelectByStyleType: function (params) {
|
||||
if (!params.componentName) throw new Error('componentName is required');
|
||||
if (!params.querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
if (!params.styleType) throw new Error('styleType is required');
|
||||
|
||||
var queryStatus = params.querySchemaModel.get('status');
|
||||
var isDisabled = queryStatus !== 'fetched';
|
||||
var helpMessage = _t('editor.style.components.' + params.componentName + '.' + queryStatus);
|
||||
|
||||
return {
|
||||
type: 'Select',
|
||||
title: _t('editor.style.components.' + params.componentName + '.label'),
|
||||
placeholder: _t('editor.style.components.' + params.componentName + '.placeholder'),
|
||||
help: isDisabled ? helpMessage : '',
|
||||
options: this.getOptionsByStyleType({
|
||||
querySchemaModel: params.querySchemaModel,
|
||||
filterFunction: params.filterFunction,
|
||||
styleType: params.styleType
|
||||
}),
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
validators: ['required'],
|
||||
editorAttrs: {
|
||||
disabled: isDisabled,
|
||||
help: _t('editor.style.components.' + params.componentName + '.help')
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
generateSelectWithSchemaColumns: function (componentName, querySchemaModel, filterFunction) {
|
||||
var queryStatus = querySchemaModel.get('status');
|
||||
var isDisabled = queryStatus !== 'fetched';
|
||||
var helpMessage = _t('editor.style.components.' + componentName + '.' + queryStatus);
|
||||
|
||||
return {
|
||||
type: 'Select',
|
||||
title: _t('editor.style.components.' + componentName + '.label'),
|
||||
help: isDisabled ? helpMessage : '',
|
||||
options: this.getSchemaColumns(querySchemaModel, filterFunction),
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
validators: ['required'],
|
||||
editorAttrs: {
|
||||
disabled: isDisabled,
|
||||
help: _t('editor.style.components.' + componentName + '.help')
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
generateSimpleStroke: function (params, type) {
|
||||
if (!params.querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
if (!params.configModel) throw new Error('configModel is required');
|
||||
if (!params.styleType) throw new Error('styleType is required');
|
||||
if (!params.userModel) throw new Error('userModel is required');
|
||||
if (!params.modals) throw new Error('modals is required');
|
||||
|
||||
var styleType = type === StyleConstants.Type.POLYGON
|
||||
? StyleConstants.Type.POLYGON
|
||||
: params.styleType;
|
||||
|
||||
return {
|
||||
type: 'Fill',
|
||||
title: _t('editor.style.components.stroke.label'),
|
||||
options: [],
|
||||
query: params.querySchemaModel.get('query'),
|
||||
configModel: params.configModel,
|
||||
userModel: params.userModel,
|
||||
modals: params.modals,
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
size: {
|
||||
min: 0,
|
||||
max: 10,
|
||||
step: 0.5,
|
||||
hidePanes: ['value'],
|
||||
help: _t('editor.style.tooltips.stroke.size', {type: _t('editor.style.tooltips.' + styleType)})
|
||||
},
|
||||
color: {
|
||||
hidePanes: ['value'],
|
||||
help: _t('editor.style.tooltips.stroke.color', {type: _t('editor.style.tooltips.' + styleType)})
|
||||
}
|
||||
},
|
||||
validators: ['required']
|
||||
};
|
||||
},
|
||||
|
||||
generateLineStroke: function (params) {
|
||||
if (!params.querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
if (!params.configModel) throw new Error('configModel is required');
|
||||
if (!params.styleType) throw new Error('styleType is required');
|
||||
if (!params.userModel) throw new Error('userModel is required');
|
||||
if (!params.modals) throw new Error('modals is required');
|
||||
|
||||
var queryStatus = params.querySchemaModel.get('status');
|
||||
var isDisabled = queryStatus !== 'fetched';
|
||||
var helpMessage = _t('editor.style.components.stroke.' + queryStatus);
|
||||
|
||||
return {
|
||||
type: 'Fill',
|
||||
title: _t('editor.style.components.stroke.label'),
|
||||
help: isDisabled ? helpMessage : '',
|
||||
options: this.getOptionsByStyleType({
|
||||
querySchemaModel: params.querySchemaModel,
|
||||
styleType: params.styleType
|
||||
}),
|
||||
query: params.querySchemaModel.get('query'),
|
||||
configModel: params.configModel,
|
||||
userModel: params.userModel,
|
||||
modals: params.modals,
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
min: 0,
|
||||
max: 50,
|
||||
disabled: isDisabled,
|
||||
size: {
|
||||
defaultRange: [1, 5],
|
||||
help: _t('editor.style.tooltips.stroke.size', {type: _t('editor.style.tooltips.line')})
|
||||
},
|
||||
color: {
|
||||
help: _t('editor.style.tooltips.stroke.color', {type: _t('editor.style.tooltips.line')})
|
||||
}
|
||||
},
|
||||
validators: ['required']
|
||||
};
|
||||
},
|
||||
|
||||
hasGeometryOf: function (params, type) {
|
||||
return params.queryGeometryModel && params.queryGeometryModel.get('simple_geom') === type;
|
||||
}
|
||||
};
|
||||
82
lib/assets/javascripts/builder/editor/style/style-form/style-form-view.js
Executable file
82
lib/assets/javascripts/builder/editor/style/style-form/style-form-view.js
Executable file
@@ -0,0 +1,82 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var StylePropertiesFormView = require('./style-properties-form/style-properties-form-view');
|
||||
var StyleAggregationFormView = require('./style-aggregation-form/style-aggregation-form-view');
|
||||
var noneFormMessage = require('./none-form-message.tpl');
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
module: 'editor/style/style-form/style-form-view',
|
||||
|
||||
className: 'Editor-formView',
|
||||
|
||||
initialize: function (opts) {
|
||||
if (!opts.layerDefinitionsCollection) throw new Error('layerDefinitionsCollection is required');
|
||||
if (!opts.layerDefinitionModel) throw new Error('layerDefinitionModel is required');
|
||||
if (!opts.querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
if (!opts.queryGeometryModel) throw new Error('queryGeometryModel is required');
|
||||
if (!opts.configModel) throw new Error('configModel is required');
|
||||
if (!opts.userModel) throw new Error('userModel is required');
|
||||
if (!opts.styleModel) throw new Error('styleModel is required');
|
||||
if (!opts.modals) throw new Error('modals is required');
|
||||
|
||||
this._querySchemaModel = opts.querySchemaModel;
|
||||
this._queryGeometryModel = opts.queryGeometryModel;
|
||||
this._configModel = opts.configModel;
|
||||
this._userModel = opts.userModel;
|
||||
this._layerDefinitionsCollection = opts.layerDefinitionsCollection;
|
||||
this._layerDefinitionModel = opts.layerDefinitionModel;
|
||||
this._styleModel = opts.styleModel;
|
||||
this._modals = opts.modals;
|
||||
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this.$el.empty();
|
||||
if (this._styleModel.get('type') === 'none') {
|
||||
this._renderNoneMessage();
|
||||
} else {
|
||||
this._initFormViews();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this._styleModel.bind('change:type', this.render, this);
|
||||
this.add_related_model(this._styleModel);
|
||||
},
|
||||
|
||||
_renderNoneMessage: function () {
|
||||
this.$el.append(noneFormMessage());
|
||||
},
|
||||
|
||||
_initFormViews: function () {
|
||||
if (this._styleModel.isAggregatedType()) {
|
||||
var aggregationFormView = new StyleAggregationFormView({
|
||||
styleModel: this._styleModel,
|
||||
queryGeometryModel: this._queryGeometryModel,
|
||||
querySchemaModel: this._querySchemaModel,
|
||||
configModel: this._configModel,
|
||||
userModel: this._userModel,
|
||||
modals: this._modals
|
||||
});
|
||||
|
||||
this.addView(aggregationFormView);
|
||||
this.$el.append(aggregationFormView.render().el);
|
||||
}
|
||||
|
||||
var propertiesFormView = new StylePropertiesFormView({
|
||||
styleModel: this._styleModel,
|
||||
layerDefinitionsCollection: this._layerDefinitionsCollection,
|
||||
configModel: this._configModel,
|
||||
userModel: this._userModel,
|
||||
layerDefinitionModel: this._layerDefinitionModel,
|
||||
queryGeometryModel: this._queryGeometryModel,
|
||||
querySchemaModel: this._querySchemaModel,
|
||||
modals: this._modals
|
||||
});
|
||||
|
||||
this.addView(propertiesFormView);
|
||||
this.$el.append(propertiesFormView.render().el);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
var _ = require('underscore');
|
||||
var StyleFormDefaultModel = require('builder/editor/style/style-form/style-form-default-model');
|
||||
var StyleFormComponents = require('builder/editor/style/style-form/style-form-components-dictionary');
|
||||
var StyleConstants = require('builder/components/form-components/_constants/_style');
|
||||
|
||||
module.exports = StyleFormDefaultModel.extend({
|
||||
|
||||
_FORM_NAME: 'animated',
|
||||
|
||||
parse: function (r, opts) {
|
||||
var columnAnimatable = opts.querySchemaModel.columnsCollection.findWhere(function (colModel) {
|
||||
return colModel.get('type') === 'number' || colModel.get('type') === 'date';
|
||||
});
|
||||
|
||||
return _.extend(
|
||||
r,
|
||||
{
|
||||
attribute: r.attribute || (columnAnimatable && columnAnimatable.get('name')),
|
||||
overlap: r.overlap && r.overlap.toString()
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
initialize: function (attrs, opts) {
|
||||
StyleFormDefaultModel.prototype.initialize.apply(this, arguments);
|
||||
|
||||
this.listenTo(this._styleModel, 'change', this._onStyleChanged);
|
||||
},
|
||||
|
||||
_setSchema: function () {
|
||||
this.schema = this._generateSchema();
|
||||
this.trigger('changeSchema', this);
|
||||
},
|
||||
|
||||
_onStyleChanged: function () {
|
||||
this._replaceAttrs();
|
||||
this._setSchema();
|
||||
},
|
||||
|
||||
_replaceAttrs: function () {
|
||||
this.set('overlap', this._isTorqueCategory() ? 'false' : this.get('overlap'));
|
||||
},
|
||||
|
||||
_onChange: function () {
|
||||
var animatedData = _.extend(
|
||||
{},
|
||||
this.attributes,
|
||||
{
|
||||
overlap: this.get('overlap') === 'true'
|
||||
}
|
||||
);
|
||||
|
||||
// Don't update style model if there is no attribute selected
|
||||
if (!animatedData.attribute) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._styleModel.set('animated', animatedData);
|
||||
},
|
||||
|
||||
_generateSchema: function () {
|
||||
var styleType = this._styleModel.get('type');
|
||||
|
||||
if (styleType === StyleConstants.Type.HEATMAP) {
|
||||
return {
|
||||
resolution: StyleFormComponents['animated-resolution']()
|
||||
};
|
||||
} else {
|
||||
return StyleFormDefaultModel.prototype._generateSchema.call(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
var Backbone = require('backbone');
|
||||
var CoreView = require('backbone/core-view');
|
||||
require('builder/components/form-components/index');
|
||||
var StyleAnimatedFormModel = require('./style-animated-properties-form-model');
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
module: 'editor/style/style-form/style-properties-form/style-animated-properties-form-view',
|
||||
|
||||
initialize: function (opts) {
|
||||
if (!opts.layerDefinitionsCollection) throw new Error('layerDefinitionsCollection is required');
|
||||
if (!opts.layerDefinitionModel) throw new Error('layerDefinitionModel is required');
|
||||
if (!opts.querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
if (!opts.queryGeometryModel) throw new Error('queryGeometryModel is required');
|
||||
if (!opts.styleModel) throw new Error('styleModel is required');
|
||||
if (!opts.userModel) throw new Error('userModel is required');
|
||||
if (!opts.modals) throw new Error('modals is required');
|
||||
|
||||
this._userModel = opts.userModel;
|
||||
this._modals = opts.modals;
|
||||
|
||||
this._querySchemaModel = opts.querySchemaModel;
|
||||
this._queryGeometryModel = opts.queryGeometryModel;
|
||||
this._layerDefinitionsCollection = opts.layerDefinitionsCollection;
|
||||
this._layerDefinitionModel = opts.layerDefinitionModel;
|
||||
this._styleModel = opts.styleModel;
|
||||
|
||||
this._animatedFormModel = new StyleAnimatedFormModel(
|
||||
this._styleModel.get('animated'),
|
||||
{
|
||||
parse: true,
|
||||
querySchemaModel: this._querySchemaModel,
|
||||
queryGeometryModel: this._queryGeometryModel,
|
||||
styleModel: this._styleModel,
|
||||
userModel: this._userModel,
|
||||
modals: this._modals
|
||||
}
|
||||
);
|
||||
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
|
||||
this._genAnimatedFormView();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this._animatedFormModel.on('changeSchema', this.render, this);
|
||||
},
|
||||
|
||||
_genAnimatedFormView: function () {
|
||||
this._animatedFormView = new Backbone.Form({
|
||||
model: this._animatedFormModel
|
||||
});
|
||||
|
||||
this._animatedFormView.bind('change', function () {
|
||||
this.commit();
|
||||
});
|
||||
|
||||
this.$el.append(this._animatedFormView.render().el);
|
||||
},
|
||||
|
||||
clearSubViews: function () {
|
||||
if (this._animatedFormView) {
|
||||
this._animatedFormView.remove(); // the Backbone.Form equivalent to 'view.clean()'
|
||||
}
|
||||
|
||||
return CoreView.prototype.clearSubViews.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
var _ = require('underscore');
|
||||
var StyleFormDefaultModel = require('builder/editor/style/style-form/style-form-default-model');
|
||||
|
||||
var FILL_PROPERTIES = [
|
||||
{ source: 'size', value: 'fillSize' },
|
||||
{ source: 'color', value: 'fillColor' }
|
||||
];
|
||||
|
||||
var HALO_PROPERTIES = [
|
||||
{ source: 'size', value: 'haloSize' },
|
||||
{ source: 'color', value: 'haloColor' }
|
||||
];
|
||||
|
||||
module.exports = StyleFormDefaultModel.extend({
|
||||
|
||||
_FORM_NAME: 'labels',
|
||||
|
||||
parse: function (response) {
|
||||
return {
|
||||
enabled: response.enabled,
|
||||
attribute: response.attribute,
|
||||
font: response.font,
|
||||
fillSize: response.fill.size,
|
||||
fillColor: response.fill.color,
|
||||
haloSize: response.halo.size,
|
||||
haloColor: response.halo.color,
|
||||
offset: response.offset,
|
||||
overlap: response.overlap,
|
||||
placement: response.placement
|
||||
};
|
||||
},
|
||||
|
||||
_onChange: function () {
|
||||
var attrs = _.clone(this.attributes);
|
||||
|
||||
if (attrs.enabled && !attrs.attribute) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._updatePartialProperties(attrs);
|
||||
|
||||
this._styleModel.set('labels', attrs);
|
||||
},
|
||||
|
||||
_updatePartialProperties: function (attrs) {
|
||||
this._setProperties(FILL_PROPERTIES, 'fill', attrs);
|
||||
this._setProperties(HALO_PROPERTIES, 'halo', attrs);
|
||||
|
||||
return attrs;
|
||||
},
|
||||
|
||||
_setProperties: function (properties, propertyName, attrs) {
|
||||
attrs[propertyName] = _.extend(this._styleModel.get('labels')[propertyName]);
|
||||
|
||||
properties.forEach(function (property) {
|
||||
if (attrs[property.value]) {
|
||||
attrs[propertyName][property.source] = attrs[property.value];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,120 @@
|
||||
var Backbone = require('backbone');
|
||||
var CoreView = require('backbone/core-view');
|
||||
var StyleLabelsFormModel = require('./style-labels-properties-form-model');
|
||||
|
||||
require('builder/components/form-components/index');
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
|
||||
className: 'u-tSpace-xl',
|
||||
|
||||
initialize: function (opts) {
|
||||
if (!opts.queryGeometryModel) throw new Error('queryGeometryModel is required');
|
||||
if (!opts.querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
if (!opts.styleModel) throw new Error('styleModel is required');
|
||||
if (!opts.modals) throw new Error('modals is required');
|
||||
if (!opts.configModel) throw new Error('configModel is required');
|
||||
if (!opts.userModel) throw new Error('userModel is required');
|
||||
|
||||
this._queryGeometryModel = opts.queryGeometryModel;
|
||||
this._querySchemaModel = opts.querySchemaModel;
|
||||
this._styleModel = opts.styleModel;
|
||||
this._configModel = opts.configModel;
|
||||
this._userModel = opts.userModel;
|
||||
this._modals = opts.modals;
|
||||
|
||||
var attributes = this._styleModel.get('labels');
|
||||
|
||||
this._labelsFormModel = new StyleLabelsFormModel(
|
||||
attributes,
|
||||
{
|
||||
parse: true,
|
||||
queryGeometryModel: this._queryGeometryModel,
|
||||
querySchemaModel: this._querySchemaModel,
|
||||
styleModel: this._styleModel,
|
||||
configModel: this._configModel,
|
||||
userModel: this._userModel,
|
||||
modals: this._modals
|
||||
}
|
||||
);
|
||||
|
||||
this._enablerModel = new Backbone.Model({
|
||||
enabler: this._styleModel.get('labels').enabled
|
||||
});
|
||||
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.empty();
|
||||
this._initLabelsEnablerView();
|
||||
return this;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this._styleModel.bind('change:type', function () {
|
||||
var isAnimatedEnabled = this._styleModel.get('type') === 'animation';
|
||||
if (isAnimatedEnabled) {
|
||||
this._enablerView.setValue(false);
|
||||
}
|
||||
}, this);
|
||||
this.add_related_model(this._styleModel);
|
||||
},
|
||||
|
||||
_initLabelsEnablerView: function () {
|
||||
var helpMessage = _t('editor.style.components.labels-enabled.not-with-animated');
|
||||
var isAnimatedVisible = this._queryGeometryModel.get('simple_geom') === 'point';
|
||||
|
||||
this._enablerView = new Backbone.Form.editors.Enabler({
|
||||
model: this._enablerModel,
|
||||
title: _t('editor.style.components.labels-enabled.label'),
|
||||
help: isAnimatedVisible ? helpMessage : '',
|
||||
key: 'enabler'
|
||||
});
|
||||
|
||||
this._enablerModel.bind('change', this._setLabelsFormView, this);
|
||||
this.add_related_model(this._enablerModel);
|
||||
this.$el.append(this._enablerView.render().el);
|
||||
|
||||
this._setLabelsFormView();
|
||||
},
|
||||
|
||||
_setLabelsFormView: function () {
|
||||
var isEnabled = this._enablerModel.get('enabler');
|
||||
this._updateFormModel();
|
||||
if (isEnabled) {
|
||||
this._genLabelsFormView();
|
||||
} else {
|
||||
this._removeLabelsFormView();
|
||||
}
|
||||
},
|
||||
|
||||
_updateFormModel: function () {
|
||||
this._labelsFormModel.set('enabled', this._enablerModel.get('enabler'));
|
||||
},
|
||||
|
||||
_genLabelsFormView: function () {
|
||||
this._labelsFormView = new Backbone.Form({
|
||||
className: 'Editor-formInner--nested',
|
||||
model: this._labelsFormModel
|
||||
});
|
||||
|
||||
this._labelsFormView.bind('change', function () {
|
||||
this.commit();
|
||||
});
|
||||
|
||||
this.$el.append(this._labelsFormView.render().el);
|
||||
},
|
||||
|
||||
_removeLabelsFormView: function () {
|
||||
if (this._labelsFormView) {
|
||||
this._labelsFormView.remove();
|
||||
this._labelsFormView.$el.empty();
|
||||
}
|
||||
},
|
||||
|
||||
clean: function () {
|
||||
this._removeLabelsFormView();
|
||||
CoreView.prototype.clean.call(this);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,112 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var StyleLabelsPropertiesFormView = require('./style-labels-properties-form-view');
|
||||
var StyleAnimatedPropertiesFormView = require('./style-animated-properties-form-view');
|
||||
var StyleShapePropertiesFormView = require('./style-shape-properties-form-view');
|
||||
var StyleNotAnimatableView = require('./style-unanimatable-view');
|
||||
var StyleConstants = require('builder/components/form-components/_constants/_style');
|
||||
var template = require('./style-properties-form.tpl');
|
||||
|
||||
var checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
var REQUIRED_OPTS = [
|
||||
'layerDefinitionsCollection',
|
||||
'querySchemaModel',
|
||||
'queryGeometryModel',
|
||||
'styleModel',
|
||||
'configModel',
|
||||
'userModel',
|
||||
'userModel',
|
||||
'layerDefinitionModel',
|
||||
'modals'
|
||||
];
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
var stepNumber = this._styleModel.isAggregatedType() ? 3 : 2;
|
||||
var simpleGeometry = this._queryGeometryModel.get('simple_geom');
|
||||
|
||||
if (simpleGeometry !== 'point') {
|
||||
stepNumber--;
|
||||
}
|
||||
|
||||
this.$el.html(
|
||||
template({
|
||||
stepNumber: stepNumber,
|
||||
simpleGeometry: simpleGeometry
|
||||
})
|
||||
);
|
||||
this._initViews();
|
||||
return this;
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
var styleType = this._styleModel.get('type');
|
||||
var animatedFormView;
|
||||
var shapeFormView;
|
||||
var labelsFormView;
|
||||
|
||||
if (this._isUnanimatable()) {
|
||||
shapeFormView = new StyleNotAnimatableView({
|
||||
layerDefinitionModel: this._layerDefinitionModel,
|
||||
userModel: this._userModel,
|
||||
configModel: this._configModel,
|
||||
modals: this._modals
|
||||
});
|
||||
this.addView(shapeFormView);
|
||||
this.$('.js-propertiesForm').append(shapeFormView.render().el);
|
||||
} else {
|
||||
shapeFormView = new StyleShapePropertiesFormView({
|
||||
styleModel: this._styleModel,
|
||||
queryGeometryModel: this._queryGeometryModel,
|
||||
querySchemaModel: this._querySchemaModel,
|
||||
configModel: this._configModel,
|
||||
userModel: this._userModel,
|
||||
modals: this._modals
|
||||
});
|
||||
this.addView(shapeFormView);
|
||||
this.$('.js-propertiesForm').append(shapeFormView.render().el);
|
||||
|
||||
if (styleType !== StyleConstants.Type.HEATMAP && styleType !== StyleConstants.Type.ANIMATION) {
|
||||
labelsFormView = new StyleLabelsPropertiesFormView({
|
||||
styleModel: this._styleModel,
|
||||
queryGeometryModel: this._queryGeometryModel,
|
||||
querySchemaModel: this._querySchemaModel,
|
||||
configModel: this._configModel,
|
||||
userModel: this._userModel,
|
||||
modals: this._modals
|
||||
});
|
||||
this.addView(labelsFormView);
|
||||
this.$('.js-propertiesForm').append(labelsFormView.render().el);
|
||||
}
|
||||
|
||||
if (this._queryGeometryModel.get('simple_geom') === 'point' &&
|
||||
(styleType === StyleConstants.Type.ANIMATION || styleType === StyleConstants.Type.HEATMAP)) {
|
||||
animatedFormView = new StyleAnimatedPropertiesFormView({
|
||||
layerDefinitionsCollection: this._layerDefinitionsCollection,
|
||||
layerDefinitionModel: this._layerDefinitionModel,
|
||||
styleModel: this._styleModel,
|
||||
queryGeometryModel: this._queryGeometryModel,
|
||||
querySchemaModel: this._querySchemaModel,
|
||||
userModel: this._userModel,
|
||||
configModel: this._configModel,
|
||||
modals: this._modals
|
||||
});
|
||||
|
||||
this.addView(animatedFormView);
|
||||
this.$('.js-propertiesForm').append(animatedFormView.render().el);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_isUnanimatable: function () {
|
||||
return this._querySchemaModel.columnsCollection.filter(function (colModel) {
|
||||
return colModel.get('type') === 'number' || colModel.get('type') === 'date';
|
||||
}).length === 0 && this._styleModel.get('type') === 'animated';
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
<div class="Editor-HeaderInfo js-styleProperties">
|
||||
<div class="Editor-HeaderNumeration CDB-Text is-semibold u-rSpace--m"><%- stepNumber %></div>
|
||||
<div class="Editor-HeaderInfo-inner CDB-Text js-selector">
|
||||
<div class="Editor-HeaderInfo-title u-bSpace--m">
|
||||
<h2 class="CDB-Text CDB-HeaderInfo-titleText CDB-Size-large">
|
||||
<%- _t('editor.style.style-form.properties.title-label-' + simpleGeometry) %>
|
||||
</h2>
|
||||
</div>
|
||||
<p class="CDB-Text u-upperCase CDB-FontSize-small u-altTextColor u-bSpace--m js-highlight"><%- _t('editor.style.style-form.properties.desc') %></p>
|
||||
<div class="js-propertiesForm"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,80 @@
|
||||
var _ = require('underscore');
|
||||
var StylesFactory = require('builder/editor/style/styles-factory');
|
||||
var StyleFormDefaultModel = require('builder/editor/style/style-form/style-form-default-model');
|
||||
var StyleConstants = require('builder/components/form-components/_constants/_style');
|
||||
var MetricsTracker = require('builder/components/metrics/metrics-tracker');
|
||||
var MetricsTypes = require('builder/components/metrics/metrics-types');
|
||||
|
||||
var FILL_PROPERTIES = [
|
||||
{ source: 'size', value: 'fillSize' },
|
||||
{ source: 'color', value: 'fillColor' }
|
||||
];
|
||||
|
||||
var STROKE_PROPERTIES = [
|
||||
{ source: 'size', value: 'strokeSize' },
|
||||
{ source: 'color', value: 'strokeColor' }
|
||||
];
|
||||
|
||||
module.exports = StyleFormDefaultModel.extend({
|
||||
|
||||
parse: function (response) {
|
||||
var geom = response.geom;
|
||||
|
||||
var fields = {
|
||||
style: response.style,
|
||||
fillSize: response.fill && response.fill.size,
|
||||
fillColor: response.fill && response.fill.color,
|
||||
strokeSize: response.stroke && response.stroke.size,
|
||||
strokeColor: response.stroke && response.stroke.color,
|
||||
blending: response.blending
|
||||
};
|
||||
|
||||
var isAggregatedType = _.contains(StylesFactory.getAggregationTypes(), response.type);
|
||||
if (isAggregatedType || geom === 'polygon') {
|
||||
fields = _.omit(fields, 'fillSize');
|
||||
}
|
||||
|
||||
if (geom === 'line') {
|
||||
fields = _.omit(fields, 'fillSize');
|
||||
fields = _.omit(fields, 'fillColor');
|
||||
}
|
||||
|
||||
if (response.type === StyleConstants.Type.HEATMAP || response.type === StyleConstants.Type.ANIMATION && response.style === StyleConstants.Type.HEATMAP) {
|
||||
fields = _.omit(fields, 'strokeSize', 'strokeColor', 'blending');
|
||||
}
|
||||
|
||||
if (response.type !== StyleConstants.Type.ANIMATION) {
|
||||
fields = _.omit(fields, 'style');
|
||||
}
|
||||
|
||||
return fields;
|
||||
},
|
||||
|
||||
_onChange: function () {
|
||||
var attrs = this._getUpdatedPartialProperties();
|
||||
|
||||
this._styleModel.set(attrs);
|
||||
|
||||
MetricsTracker.track(MetricsTypes.CHANGED_DEFAULT_GEOMETRY);
|
||||
},
|
||||
|
||||
_getUpdatedPartialProperties: function () {
|
||||
var attrs = _.clone(this.attributes);
|
||||
|
||||
this._setProperties(FILL_PROPERTIES, 'fill', attrs);
|
||||
this._setProperties(STROKE_PROPERTIES, 'stroke', attrs);
|
||||
|
||||
return attrs;
|
||||
},
|
||||
|
||||
_setProperties: function (properties, propertyName, attrs) {
|
||||
attrs[propertyName] = _.extend(this._styleModel.get(propertyName));
|
||||
properties.forEach(function (property) {
|
||||
if (attrs[property.value]) {
|
||||
attrs[propertyName][property.source] = attrs[property.value];
|
||||
}
|
||||
});
|
||||
|
||||
return attrs;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,87 @@
|
||||
var Backbone = require('backbone');
|
||||
var CoreView = require('backbone/core-view');
|
||||
require('builder/components/form-components/index');
|
||||
var StyleShapeFormModel = require('./style-shape-properties-form-model');
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
|
||||
className: 'u-tSpace--m',
|
||||
|
||||
initialize: function (opts) {
|
||||
if (!opts.queryGeometryModel) throw new Error('queryGeometryModel is required');
|
||||
if (!opts.querySchemaModel) throw new Error('querySchemaModel is required');
|
||||
if (!opts.styleModel) throw new Error('styleModel is required');
|
||||
if (!opts.configModel) throw new Error('configModel is required');
|
||||
if (!opts.userModel) throw new Error('userModel is required');
|
||||
if (!opts.modals) throw new Error('modals is required');
|
||||
|
||||
this._queryGeometryModel = opts.queryGeometryModel;
|
||||
this._querySchemaModel = opts.querySchemaModel;
|
||||
this._styleModel = opts.styleModel;
|
||||
this._configModel = opts.configModel;
|
||||
this._userModel = opts.userModel;
|
||||
this._modals = opts.modals;
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this._removeFormView();
|
||||
this.$el.empty();
|
||||
this._initViews();
|
||||
return this;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this._styleModel.bind('change:style', function () {
|
||||
var style = this._styleModel.get('style');
|
||||
this._styleModel.setFill(style);
|
||||
this.render();
|
||||
}, this);
|
||||
|
||||
this.add_related_model(this._styleModel);
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
this._shapeFormModel = new StyleShapeFormModel(
|
||||
{
|
||||
type: this._styleModel.get('type'),
|
||||
geom: this._queryGeometryModel.get('simple_geom'),
|
||||
style: this._styleModel.get('style'),
|
||||
fill: this._styleModel.get('fill'),
|
||||
stroke: this._styleModel.get('stroke'),
|
||||
blending: this._styleModel.get('blending')
|
||||
},
|
||||
{
|
||||
parse: true,
|
||||
queryGeometryModel: this._queryGeometryModel,
|
||||
querySchemaModel: this._querySchemaModel,
|
||||
configModel: this._configModel,
|
||||
userModel: this._userModel,
|
||||
modals: this._modals,
|
||||
styleModel: this._styleModel
|
||||
}
|
||||
);
|
||||
|
||||
this._shapeFormView = new Backbone.Form({
|
||||
model: this._shapeFormModel
|
||||
});
|
||||
|
||||
this._shapeFormView.bind('change', function () {
|
||||
this.commit();
|
||||
});
|
||||
|
||||
this.$el.append(this._shapeFormView.render().el);
|
||||
},
|
||||
|
||||
_removeFormView: function () {
|
||||
if (this._shapeFormView) {
|
||||
this._shapeFormView.remove();
|
||||
}
|
||||
},
|
||||
|
||||
clean: function () {
|
||||
this._removeFormView();
|
||||
CoreView.prototype.clean.call(this);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var _ = require('underscore');
|
||||
var template = require('./style-unanimatable.tpl');
|
||||
var VisTableModel = require('builder/data/visualization-table-model');
|
||||
var linkTemplate = _.template('<a href="<%- url %>" target="_blank" title="<%- tableName %>"><%- label %></a>');
|
||||
|
||||
var REQUIRED_OPTS = [
|
||||
'layerDefinitionModel',
|
||||
'configModel'
|
||||
];
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
initialize: function (opts) {
|
||||
var tableName;
|
||||
|
||||
_.each(REQUIRED_OPTS, function (item) {
|
||||
if (!opts[item]) throw new Error(item + ' is required');
|
||||
this['_' + item] = opts[item];
|
||||
}, this);
|
||||
|
||||
this._sourceNode = this._getSourceNode();
|
||||
|
||||
if (this._sourceNode) {
|
||||
tableName = this._sourceNode.get('table_name');
|
||||
this._visTableModel = new VisTableModel({
|
||||
id: tableName,
|
||||
table: {
|
||||
name: tableName
|
||||
}
|
||||
}, {
|
||||
configModel: this._configModel
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var desc = this._getDescTemplate();
|
||||
|
||||
this.clearSubViews();
|
||||
this.$el.html(template({
|
||||
title: _t('editor.style.style-form.unanimatable.desc'),
|
||||
desc: desc
|
||||
}));
|
||||
return this;
|
||||
},
|
||||
|
||||
_getDescTemplate: function () {
|
||||
var tableName = '';
|
||||
var url = '';
|
||||
var tableModel;
|
||||
|
||||
if (this._visTableModel) {
|
||||
tableModel = this._visTableModel.getTableModel();
|
||||
tableName = tableModel.getUnquotedName();
|
||||
url = this._visTableModel && this._visTableModel.datasetURL();
|
||||
}
|
||||
|
||||
var linkHTML = linkTemplate({
|
||||
url: url,
|
||||
tableName: tableName,
|
||||
label: _t('editor.style.style-form.unanimatable.label')
|
||||
});
|
||||
|
||||
return _t('editor.style.style-form.unanimatable.body', {
|
||||
link: linkHTML
|
||||
});
|
||||
},
|
||||
|
||||
_getSourceNode: function () {
|
||||
var node = this._layerDefinitionModel.getAnalysisDefinitionNodeModel();
|
||||
var source;
|
||||
var primarySource;
|
||||
if (node.get('type') === 'source') {
|
||||
source = node;
|
||||
} else {
|
||||
primarySource = node.getPrimarySource();
|
||||
if (primarySource && primarySource.get('type') === 'source') {
|
||||
source = primarySource;
|
||||
}
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
<h2 class="CDB-Text CDB-Size-huge is-light u-secondaryTextColor"><%- title %></h2>
|
||||
<p class="CDB-Text u-tSpace--m CDB-Size-medium u-altTextColor"><%= desc %></p>
|
||||
9
lib/assets/javascripts/builder/editor/style/style-icons/animated.tpl
Executable file
9
lib/assets/javascripts/builder/editor/style/style-icons/animated.tpl
Executable file
@@ -0,0 +1,9 @@
|
||||
<svg width="56px" height="16px" viewBox="718 455 56 16">
|
||||
<g id="animated" transform="translate(718.000000, 455.000000)" class="Style-fill">
|
||||
<rect id="Rectangle-649" x="40" y="0" width="16" height="16" rx="8"></rect>
|
||||
<rect id="Rectangle-649" opacity="0.8" x="30" y="0" width="16" height="16" rx="8"></rect>
|
||||
<rect id="Rectangle-649" opacity="0.6" x="20" y="0" width="16" height="16" rx="8"></rect>
|
||||
<rect id="Rectangle-649" opacity="0.4" x="10" y="0" width="16" height="16" rx="8"></rect>
|
||||
<rect id="Rectangle-649" opacity="0.2" x="0" y="0" width="16" height="16" rx="8"></rect>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 634 B |
46
lib/assets/javascripts/builder/editor/style/style-icons/heatmap.tpl
Executable file
46
lib/assets/javascripts/builder/editor/style/style-icons/heatmap.tpl
Executable file
@@ -0,0 +1,46 @@
|
||||
<svg width="56px" height="25px" viewBox="0 0 56 25" style="will-change: opacity;">
|
||||
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Aggregation-/-Heatmap" transform="translate(-15.000000, -16.000000)">
|
||||
<g id="Group-7">
|
||||
<g transform="translate(15.000000, 16.000000)">
|
||||
<g id="Group-2" style="mix-blend-mode: luminosity;" transform="translate(28.000000, 12.500000) rotate(-90.000000) translate(-28.000000, -12.500000) translate(15.500000, -15.500000)" class="Style-fill">
|
||||
<g id="heat-copy-2" transform="translate(0.000000, 36.000000)">
|
||||
<circle id="Oval-120" opacity="0.4" cx="6" cy="6" r="6"></circle>
|
||||
<circle id="Oval-120-Copy" opacity="0.6" cx="6.5" cy="5.5" r="4.03333333"></circle>
|
||||
<path d="M6.5,8.06666667 C7.91753086,8.06666667 9.06666667,6.91753086 9.06666667,5.5 C9.06666667,4.08246914 7.91753086,2.93333333 6.5,2.93333333 C5.08246914,2.93333333 3.93333333,4.08246914 3.93333333,5.5 C3.93333333,6.91753086 5.08246914,8.06666667 6.5,8.06666667 Z" id="Oval-120-Copy-2" opacity="0.8"></path>
|
||||
<circle id="Oval-120-Copy-3" cx="6.5" cy="5.5" r="1.1"></circle>
|
||||
</g>
|
||||
<g id="heat-copy-2" transform="translate(13.000000, 48.000000)">
|
||||
<circle id="Oval-120" opacity="0.4" cx="4" cy="4" r="4"></circle>
|
||||
<circle id="Oval-120-Copy" opacity="0.6" cx="4" cy="4" r="2.93333333"></circle>
|
||||
<path d="M4,5.86666667 C5.03093153,5.86666667 5.86666667,5.03093153 5.86666667,4 C5.86666667,2.96906847 5.03093153,2.13333333 4,2.13333333 C2.96906847,2.13333333 2.13333333,2.96906847 2.13333333,4 C2.13333333,5.03093153 2.96906847,5.86666667 4,5.86666667 Z" id="Oval-120-Copy-2" opacity="0.8"></path>
|
||||
<circle id="Oval-120-Copy-3" cx="4" cy="4" r="0.8"></circle>
|
||||
</g>
|
||||
<g id="heat-copy-3" transform="translate(0.500000, 0.500000)">
|
||||
<circle id="Oval-120" opacity="0.4" cx="12" cy="12" r="12"></circle>
|
||||
<ellipse id="Oval-120-Copy" opacity="0.6" cx="12" cy="12" rx="8.8" ry="8.8"></ellipse>
|
||||
<path d="M12,17.6 C15.0927946,17.6 17.6,15.0927946 17.6,12 C17.6,8.9072054 15.0927946,6.4 12,6.4 C8.9072054,6.4 6.4,8.9072054 6.4,12 C6.4,15.0927946 8.9072054,17.6 12,17.6 Z" id="Oval-120-Copy-2" opacity="0.8"></path>
|
||||
<circle id="Oval-120-Copy-3" cx="12" cy="12" r="2.4"></circle>
|
||||
</g>
|
||||
<g id="heat" transform="translate(8.000000, 25.000000)">
|
||||
<path d="M0.0682602115,8.5161863 C0.564222232,12.1776805 3.7025171,15 7.5,15 C11.6421356,15 15,11.6421356 15,7.5 C15,3.35786438 11.6421356,0 7.5,0 C3.35786438,0 0,3.35786438 0,7.5 C0,7.84465272 0.0232475903,8.18387567 0.0682602115,8.5161863 Z" id="Oval-120" opacity="0.4"></path>
|
||||
<circle id="Oval-120-Copy" opacity="0.6" cx="7.5" cy="7.5" r="5.5"></circle>
|
||||
<path d="M7.5,11 C9.43299662,11 11,9.43299662 11,7.5 C11,5.56700338 9.43299662,4 7.5,4 C5.56700338,4 4,5.56700338 4,7.5 C4,9.43299662 5.56700338,11 7.5,11 Z" id="Oval-120-Copy-2" opacity="0.8"></path>
|
||||
<circle id="Oval-120-Copy-3" cx="7.5" cy="7.5" r="1.5"></circle>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-8" style="mix-blend-mode: luminosity;" transform="translate(15.000000, 4.000000)">
|
||||
<path opacity="0.4" d="M6,0.5 C6,0.5 10,4 13,0 C12,2.5 11.5,4.5 11.5,4.5 L10.5,6.5 L7,3.5 L6,0.5 Z" id="Path-494" class="Style-fill"></path>
|
||||
<path opacity="0.4" d="M21.2158501,6.00893743 C21.2158501,6.00893743 25.2158501,9.50893743 28.2158501,5.50893743 C27.2158501,8.00893743 26.7158501,10.0089374 26.7158501,10.0089374 L25.7158501,12.0089374 L22.2158501,9.00893743 L21.2158501,6.00893743 Z" id="Path-494" class="Style-fill" transform="translate(24.715850, 8.758937) rotate(52.000000) translate(-24.715850, -8.758937) "></path>
|
||||
<path opacity="0.4" d="M16.9683476,9.30864826 C16.9683476,9.30864826 22.1000758,13.6622016 25.1000758,9.66220164 C24.1000758,12.1622016 23.8307892,14.1229281 23.8307892,14.1229281 L22.8307892,16.1229281 L17.6754544,11.4299685 L16.9683476,9.30864826 Z" id="Path-494" class="Style-fill" transform="translate(21.034212, 12.715788) rotate(-135.000000) translate(-21.034212, -12.715788) "></path>
|
||||
<path opacity="0.4" d="M6.01244045,6.22463473 C6.01244045,6.22463473 9.69418934,8.6717337 12.6941893,4.6717337 C11.6941893,7.1717337 11.1941893,9.1717337 11.1941893,9.1717337 L10.8665273,11.557349 L9.7765744,13.8621271 L6.01244045,6.22463473 Z" id="Path-494" class="Style-fill" transform="translate(9.353315, 9.266930) rotate(-194.000000) translate(-9.353315, -9.266930) "></path>
|
||||
<path opacity="0.6" d="M6,7.5 C5.85295664,5.882523 3.5,2.5 3.5,2.5 C3.5,2.5 6.5,5 9,5 C11.5,5 14.5,1 14.5,1 C14.5,1 12.5,4.25504557 12.5,6 C12.5,7.25504557 14.5,10 14.5,10 C14.5,10 12,8 9.5,8 C7,8 4.5,13.5 4.5,13.5 C4.5,13.5 6.18628997,9.54918967 6,7.5 Z" id="Path-497" class="Style-fill"></path>
|
||||
<path opacity="0.6" d="M19.7830175,9.69012543 C19.6894445,8.07264843 16.7664559,5.429802 16.7664559,5.429802 C16.7664559,5.429802 20.2086087,8.27970692 21.7995178,8.27970692 C23.3904269,8.27970692 26.4566805,5.77970692 26.4566805,5.77970692 C26.4566805,5.77970692 24.4742142,8.43779004 24.4742142,10.1827445 C24.4742142,11.43779 25.8285796,12.5099091 25.8285796,12.5099091 C25.8285796,12.5099091 23.7086087,11.2797069 22.1176996,11.2797069 C20.5267905,11.2797069 17.9729009,15.2555074 17.9729009,15.2555074 C17.9729009,15.2555074 19.9015657,11.7393151 19.7830175,9.69012543 Z" id="Path-497" class="Style-fill" transform="translate(21.611568, 10.342655) rotate(52.000000) translate(-21.611568, -10.342655) "></path>
|
||||
<path id="Path-499" stroke="#979797"></path>
|
||||
<polygon id="Path-500" class="Style-fill" points="0.5 12.5 5 7.5 1 4"></polygon>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.3 KiB |
17
lib/assets/javascripts/builder/editor/style/style-icons/hexabins.tpl
Executable file
17
lib/assets/javascripts/builder/editor/style/style-icons/hexabins.tpl
Executable file
@@ -0,0 +1,17 @@
|
||||
<svg width="52px" height="23px" viewBox="0 0 52 23">
|
||||
<g id="Symbols">
|
||||
<g id="Aggregation-/-Hexabins" transform="translate(-15.000000, -17.000000)" class="Style-fill">
|
||||
<g id="Hexabins">
|
||||
<g transform="translate(15.000000, 17.000000)">
|
||||
<polygon id="Polygon-1-Copy-4" points="23 11 28 14 28 20 23 23 18 20 18 14"></polygon>
|
||||
<polygon id="Polygon-1-Copy-8" points="17 0 22 3 22 9 17 12 12 9 12 3"></polygon>
|
||||
<polygon id="Polygon-1-Copy-8" points="5 0 10 3 10 9 5 12 -1.15463195e-13 9 3.85466323e-09 3"></polygon>
|
||||
<polygon id="Polygon-1-Copy-13" points="29 0 34 3 34 9 29 12 24 9 24 3"></polygon>
|
||||
<polygon id="Polygon-1-Copy-15" points="41 0 46 3 46 9 41 12 36 9 36 3"></polygon>
|
||||
<polygon id="Polygon-1-Copy-14" points="35 11 40 14 40 20 35 23 30 20 30 14"></polygon>
|
||||
<polygon id="Polygon-1-Copy-14" points="47 11 52 14 52 20 47 23 42 20 42 14"></polygon>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
12
lib/assets/javascripts/builder/editor/style/style-icons/points.tpl
Executable file
12
lib/assets/javascripts/builder/editor/style/style-icons/points.tpl
Executable file
@@ -0,0 +1,12 @@
|
||||
<svg width="56px" height="24px" viewBox="16 16 56 24">
|
||||
<g id="points" transform="translate(16.000000, 16.000000)" class="Style-fill">
|
||||
<path d="M6,10 C8.209139,10 10,8.209139 10,6 C10,3.790861 8.209139,2 6,2 C3.790861,2 2,3.790861 2,6 C2,8.209139 3.790861,10 6,10 Z" id="Oval-59"></path>
|
||||
<path d="M52,8 C54.209139,8 56,6.209139 56,4 C56,1.790861 54.209139,0 52,0 C49.790861,0 48,1.790861 48,4 C48,6.209139 49.790861,8 52,8 Z" id="Oval-59-Copy-2"></path>
|
||||
<path d="M52,22 C54.209139,22 56,20.209139 56,18 C56,15.790861 54.209139,14 52,14 C49.790861,14 48,15.790861 48,18 C48,20.209139 49.790861,22 52,22 Z" id="Oval-59-Copy-3"></path>
|
||||
<path d="M4,24 C6.209139,24 8,22.209139 8,20 C8,17.790861 6.209139,16 4,16 C1.790861,16 0,17.790861 0,20 C0,22.209139 1.790861,24 4,24 Z" id="Oval-59-Copy"></path>
|
||||
<path d="M28,8 C30.209139,8 32,6.209139 32,4 C32,1.790861 30.209139,0 28,0 C25.790861,0 24,1.790861 24,4 C24,6.209139 25.790861,8 28,8 Z" id="Oval-59-Copy-4"></path>
|
||||
<path d="M24,20 C26.209139,20 28,18.209139 28,16 C28,13.790861 26.209139,12 24,12 C21.790861,12 20,13.790861 20,16 C20,18.209139 21.790861,20 24,20 Z" id="Oval-59-Copy-4"></path>
|
||||
<path d="M16,16 C18.209139,16 20,14.209139 20,12 C20,9.790861 18.209139,8 16,8 C13.790861,8 12,9.790861 12,12 C12,14.209139 13.790861,16 16,16 Z" id="Oval-59-Copy-4"></path>
|
||||
<path d="M44,12 C46.209139,12 48,10.209139 48,8 C48,5.790861 46.209139,4 44,4 C41.790861,4 40,5.790861 40,8 C40,10.209139 41.790861,12 44,12 Z" id="Oval-59-Copy-4"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
14
lib/assets/javascripts/builder/editor/style/style-icons/regions.tpl
Executable file
14
lib/assets/javascripts/builder/editor/style/style-icons/regions.tpl
Executable file
@@ -0,0 +1,14 @@
|
||||
<svg width="56px" height="24px" viewBox="0 0 56 24">
|
||||
<g id="Symbols">
|
||||
<g id="Aggregation-/-Admin-Regions" transform="translate(-16.000000, -16.000000)" class="Style-fill">
|
||||
<g id="regions">
|
||||
<g transform="translate(16.000000, 16.000000)">
|
||||
<polygon id="Rectangle-649" points="9 8 1 0 27 0 27 17 36 17 36.0065918 23.9934082 25 24 9 16"></polygon>
|
||||
<polygon id="Rectangle-649" points="0 2 7 9 7 17 21 24 0 24 0 15"></polygon>
|
||||
<polygon id="Rectangle-649" points="29 0 50 0 50 6 56 6 56 24 48 24 38 24 38 15 29 15"></polygon>
|
||||
<rect id="Rectangle-1933" x="52" y="0" width="4" height="4"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 772 B |
21
lib/assets/javascripts/builder/editor/style/style-icons/squares.tpl
Executable file
21
lib/assets/javascripts/builder/editor/style/style-icons/squares.tpl
Executable file
@@ -0,0 +1,21 @@
|
||||
<svg width="58px" height="28px" viewBox="0 0 58 28">
|
||||
<g id="Symbols">
|
||||
<g id="Aggregation-/-Squares" transform="translate(-15.000000, -14.000000)" class="Style-fill">
|
||||
<g id="squares">
|
||||
<g transform="translate(15.000000, 14.000000)">
|
||||
<rect id="Rectangle-847-Copy-2" x="10" y="0" width="8" height="8" rx="1"></rect>
|
||||
<rect id="Rectangle-847-Copy-5" x="30" y="20" width="8" height="8" rx="1"></rect>
|
||||
<rect id="Rectangle-847-Copy-12" x="40" y="20" width="8" height="8" rx="1"></rect>
|
||||
<rect id="Rectangle-847-Copy-13" x="40" y="10" width="8" height="8" rx="1"></rect>
|
||||
<rect id="Rectangle-847-Copy-8" x="20" y="10" width="8" height="8" rx="1"></rect>
|
||||
<rect id="Rectangle-847-Copy-6" x="30" y="10" width="8" height="8" rx="1"></rect>
|
||||
<rect id="Rectangle-847-Copy-9" x="20" y="20" width="8" height="8" rx="1"></rect>
|
||||
<rect id="Rectangle-847-Copy-10" x="10" y="10" width="8" height="8" rx="1"></rect>
|
||||
<rect id="Rectangle-847-Copy-10" x="0" y="10" width="8" height="8" rx="1"></rect>
|
||||
<rect id="Rectangle-847-Copy-10" x="50" y="20" width="8" height="8" rx="1"></rect>
|
||||
<rect id="Rectangle-847-Copy-11" x="20" y="0" width="8" height="8" rx="1"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
89
lib/assets/javascripts/builder/editor/style/style-manager.js
Executable file
89
lib/assets/javascripts/builder/editor/style/style-manager.js
Executable file
@@ -0,0 +1,89 @@
|
||||
var StyleGenerator = require('./style-converter');
|
||||
var _ = require('underscore');
|
||||
|
||||
/**
|
||||
* this class manages the changes in layerdef styles and generate the proper cartocss and sql
|
||||
*/
|
||||
function StyleManager (layerDefinitionsCollection, map, configModel) {
|
||||
this.layerDefinitionsCollection = layerDefinitionsCollection;
|
||||
this.map = map;
|
||||
this._configModel = configModel;
|
||||
this._initBinds();
|
||||
}
|
||||
|
||||
StyleManager.prototype = {
|
||||
_initBinds: function () {
|
||||
var self = this;
|
||||
|
||||
function _generate (layerDef) {
|
||||
return function () {
|
||||
self.generate(layerDef);
|
||||
};
|
||||
}
|
||||
|
||||
function _bind (layerDef) {
|
||||
if (layerDef && layerDef.styleModel) {
|
||||
layerDef.styleModel.bind('change', _generate(layerDef), this);
|
||||
layerDef.bind('change:autoStyle', _generate(layerDef), this);
|
||||
}
|
||||
}
|
||||
|
||||
function _unbind (layerDef) {
|
||||
if (layerDef.styleModel) {
|
||||
layerDef.styleModel.unbind('change', _generate(layerDef), this);
|
||||
layerDef.unbind('change:autoStyle', _generate(layerDef), this);
|
||||
}
|
||||
}
|
||||
|
||||
function _bindAll () {
|
||||
this.layerDefinitionsCollection.each(_bind, this);
|
||||
}
|
||||
|
||||
this.layerDefinitionsCollection.bind('reset', _bindAll, this);
|
||||
this.layerDefinitionsCollection.bind('add', _bind, this);
|
||||
this.layerDefinitionsCollection.bind('remove', _unbind, this);
|
||||
|
||||
_bindAll.call(this);
|
||||
},
|
||||
|
||||
generate: function (layerDef) {
|
||||
var isAutoStyleApplied = layerDef.get('autoStyle');
|
||||
var stylesChanged = layerDef.styleModel.changed;
|
||||
|
||||
if (isAutoStyleApplied) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stylesChanged.type && _.size(stylesChanged) === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var simpleGeometryType = layerDef.getAnalysisDefinitionNodeModel().queryGeometryModel.get('simple_geom') || 'point';
|
||||
var generated = StyleGenerator.generateStyle(
|
||||
layerDef.styleModel.toJSON(),
|
||||
simpleGeometryType,
|
||||
{
|
||||
zoom: this.map.get('zoom')
|
||||
},
|
||||
this._configModel
|
||||
);
|
||||
|
||||
var properties = {
|
||||
cartocss: generated.cartoCSS,
|
||||
sql_wrap: generated.sql,
|
||||
type: generated.layerType
|
||||
};
|
||||
|
||||
if (layerDef.get('previousCartoCSSCustom')) {
|
||||
properties = _.extend(properties, {
|
||||
cartocss: layerDef.get('previousCartoCSS'),
|
||||
cartocss_custom: layerDef.get('previousCartoCSSCustom'),
|
||||
previousCartoCSSCustom: false
|
||||
});
|
||||
}
|
||||
|
||||
layerDef.set(properties);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = StyleManager;
|
||||
9
lib/assets/javascripts/builder/editor/style/style-redo-buttons.tpl
Executable file
9
lib/assets/javascripts/builder/editor/style/style-redo-buttons.tpl
Executable file
@@ -0,0 +1,9 @@
|
||||
<button class="u-actionTextColor js-undo <% if (!canUndo) { %>is-disabled<% } %>">
|
||||
<i class="CDB-IconFont CDB-IconFont-undo Size-large"></i>
|
||||
</button>
|
||||
<button class="u-actionTextColor u-lSpace--xl js-redo <% if (!canRedo) { %>is-disabled<% } %>">
|
||||
<i class="CDB-IconFont CDB-IconFont-redo Size-large"></i>
|
||||
</button>
|
||||
<button class="CDB-Button CDB-Button--primary CDB-Button--small">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small">APPLY</span>
|
||||
</button>
|
||||
474
lib/assets/javascripts/builder/editor/style/style-view.js
Executable file
474
lib/assets/javascripts/builder/editor/style/style-view.js
Executable file
@@ -0,0 +1,474 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var CoreView = require('backbone/core-view');
|
||||
var PanelWithOptionsView = require('builder/components/view-options/panel-with-options-view');
|
||||
var StyleContentView = require('./style-content-view');
|
||||
var StyleCartoCSSView = require('./style-cartocss-view');
|
||||
var ScrollView = require('builder/components/scroll/scroll-view');
|
||||
var TabPaneView = require('builder/components/tab-pane/tab-pane-view');
|
||||
var TabPaneCollection = require('builder/components/tab-pane/tab-pane-collection');
|
||||
var Toggler = require('builder/components/toggler/toggler-view');
|
||||
var UndoButtons = require('builder/components/undo-redo/undo-redo-view');
|
||||
var ParserCSS = require('builder/helpers/parser-css');
|
||||
var Infobox = require('builder/components/infobox/infobox-factory');
|
||||
var InfoboxModel = require('builder/components/infobox/infobox-model');
|
||||
var InfoboxCollection = require('builder/components/infobox/infobox-collection');
|
||||
var Notifier = require('builder/components/notifier/notifier');
|
||||
var CartoCSSNotifications = require('builder/cartocss-notifications');
|
||||
var MetricsTracker = require('builder/components/metrics/metrics-tracker');
|
||||
var MetricsTypes = require('builder/components/metrics/metrics-types');
|
||||
|
||||
var OnboardingLauncher = require('builder/components/onboardings/generic/generic-onboarding-launcher');
|
||||
var OnboardingView = require('builder/components/onboardings/layers/style-onboarding/style-onboarding-view');
|
||||
var checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
var ONBOARDING_KEY = 'layer-style-onboarding';
|
||||
|
||||
var REQUIRED_OPTS = [
|
||||
'layerDefinitionsCollection',
|
||||
'layerDefinitionModel',
|
||||
'userActions',
|
||||
'queryGeometryModel',
|
||||
'querySchemaModel',
|
||||
'queryRowsCollection',
|
||||
'modals',
|
||||
'editorModel',
|
||||
'configModel',
|
||||
'userModel',
|
||||
'onboardings',
|
||||
'onboardingNotification',
|
||||
'layerContentModel'
|
||||
];
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
|
||||
initialize: function (opts) {
|
||||
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
|
||||
|
||||
this._styleModel = this._layerDefinitionModel.styleModel;
|
||||
this._cartocssModel = this._layerDefinitionModel.cartocssModel;
|
||||
this._codemirrorModel = new Backbone.Model({
|
||||
content: this._layerDefinitionModel.get('cartocss')
|
||||
});
|
||||
|
||||
// Set edition attribute in case custom cartocss is applied
|
||||
this._editorModel.set({
|
||||
edition: !!this._layerDefinitionModel.get('cartocss_custom'),
|
||||
disabled: false
|
||||
});
|
||||
|
||||
this._infoboxModel = new InfoboxModel({
|
||||
state: this._isLayerHidden() ? 'layer-hidden' : ''
|
||||
});
|
||||
|
||||
this._overlayModel = new Backbone.Model({
|
||||
visible: this._isLayerHidden()
|
||||
});
|
||||
|
||||
this._applyButtonStatusModel = new Backbone.Model({
|
||||
loading: false
|
||||
});
|
||||
|
||||
this._togglerModel = new Backbone.Model({
|
||||
labels: [_t('editor.style.style-toggle.values'), _t('editor.style.style-toggle.cartocss')],
|
||||
active: this._editorModel.isEditing(),
|
||||
disabled: this._editorModel.isDisabled(),
|
||||
isDisableable: true,
|
||||
tooltip: _t('editor.style.style-toggle.tooltip')
|
||||
});
|
||||
|
||||
this._appendMapsAPIError();
|
||||
|
||||
CartoCSSNotifications.track(this);
|
||||
|
||||
this._onboardingLauncher = new OnboardingLauncher({
|
||||
view: OnboardingView,
|
||||
onboardingNotification: this._onboardingNotification,
|
||||
notificationKey: ONBOARDING_KEY,
|
||||
onboardings: this._onboardings
|
||||
}, {
|
||||
editorModel: this._editorModel,
|
||||
selector: 'LayerOnboarding'
|
||||
});
|
||||
|
||||
this._configPanes();
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this._launchOnboarding();
|
||||
this.clearSubViews();
|
||||
this.$el.empty();
|
||||
|
||||
this._initViews();
|
||||
this._infoboxState();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_launchOnboarding: function () {
|
||||
if (this._onboardingNotification.getKey(ONBOARDING_KEY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var georeferencePromise = this._layerDefinitionModel.canBeGeoreferenced();
|
||||
var hasGeomPromise = this._queryGeometryModel.hasValueAsync();
|
||||
var launchOnboarding = function (canBeGeoreferenced, hasGeom) {
|
||||
if (!this._editorModel.isEditing() && !canBeGeoreferenced && hasGeom) {
|
||||
this._onboardingLauncher.launch({
|
||||
geom: this._queryGeometryModel.get('simple_geom'),
|
||||
type: this._styleModel.get('type')
|
||||
});
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
Promise.all([georeferencePromise, hasGeomPromise])
|
||||
.then(function (values) {
|
||||
launchOnboarding(values[0], values[1]);
|
||||
});
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this._layerDefinitionModel, 'change:error', this._appendMapsAPIError);
|
||||
this.listenTo(this._layerDefinitionModel, 'change:cartocss', this._onCartocssChanged);
|
||||
this.listenTo(this._layerDefinitionModel, 'change:visible', this._infoboxState);
|
||||
this.listenTo(this._layerDefinitionModel, 'change:autoStyle', this._infoboxState);
|
||||
|
||||
this.listenTo(this._editorModel, 'change:edition', this._onChangeEdition);
|
||||
this.listenTo(this._editorModel, 'change:disabled', this._onChangeDisabled);
|
||||
this.listenTo(this._togglerModel, 'change:active', this._onTogglerChanged);
|
||||
|
||||
this.listenTo(this._querySchemaModel, 'change:query_errors', this._updateEditor);
|
||||
|
||||
this.listenTo(this._styleModel, 'change', this._onCartocssChanged);
|
||||
this.listenTo(this._cartocssModel, 'undo redo', this._onUndoRedo);
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
var self = this;
|
||||
|
||||
var infoboxSstates = [
|
||||
{
|
||||
state: 'confirm',
|
||||
createContentView: function () {
|
||||
return Infobox.createWithAction({
|
||||
type: 'alert',
|
||||
title: _t('editor.style.messages.cartocss-applied.title'),
|
||||
body: _t('editor.style.messages.cartocss-applied.body'),
|
||||
action: {
|
||||
label: _t('editor.style.messages.cartocss-applied.clear')
|
||||
}
|
||||
});
|
||||
},
|
||||
onAction: self._clearCustomStyles.bind(self),
|
||||
onClose: self._cancelClearStyles.bind(self)
|
||||
}, {
|
||||
state: 'layer-hidden',
|
||||
createContentView: function () {
|
||||
return Infobox.createWithAction({
|
||||
type: self._layerDefinitionModel.get('cartocss_custom') ? 'code' : 'alert',
|
||||
title: _t('editor.messages.layer-hidden.title'),
|
||||
body: _t('editor.messages.layer-hidden.body'),
|
||||
action: {
|
||||
label: _t('editor.messages.layer-hidden.show')
|
||||
}
|
||||
});
|
||||
},
|
||||
onAction: self._showHiddenLayer.bind(self)
|
||||
}, {
|
||||
state: 'torque-exists',
|
||||
createContentView: function () {
|
||||
return Infobox.createWithAction({
|
||||
type: 'alert',
|
||||
title: _t('editor.style.messages.torque-exists.title'),
|
||||
body: _t('editor.style.messages.torque-exists.body'),
|
||||
action: {
|
||||
label: _t('editor.style.messages.torque-exists.continue')
|
||||
}
|
||||
});
|
||||
},
|
||||
onAction: self._applyTorqueAggregation.bind(self),
|
||||
onClose: self._cancelTorqueAggregation.bind(self)
|
||||
}
|
||||
];
|
||||
|
||||
var infoboxCollection = new InfoboxCollection(infoboxSstates);
|
||||
|
||||
var panelWithOptionsView = new PanelWithOptionsView({
|
||||
className: 'Editor-content',
|
||||
editorModel: self._editorModel,
|
||||
infoboxModel: self._infoboxModel,
|
||||
infoboxCollection: infoboxCollection,
|
||||
createContentView: function () {
|
||||
return new TabPaneView({
|
||||
collection: self._collectionPane
|
||||
});
|
||||
},
|
||||
createControlView: function () {
|
||||
return new Toggler({
|
||||
model: self._togglerModel
|
||||
});
|
||||
},
|
||||
createActionView: function () {
|
||||
return new TabPaneView({
|
||||
collection: self._collectionPane,
|
||||
createContentKey: 'createActionView'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.$el.append(panelWithOptionsView.render().el);
|
||||
this.addView(panelWithOptionsView);
|
||||
},
|
||||
|
||||
_onCartocssChanged: function () {
|
||||
this._codemirrorModel.set('content', this._layerDefinitionModel.get('cartocss'));
|
||||
},
|
||||
|
||||
_onUndoRedo: function () {
|
||||
this._codemirrorModel.set('content', this._cartocssModel.get('content'));
|
||||
},
|
||||
|
||||
_appendMapsAPIError: function () {
|
||||
var error = this._layerDefinitionModel.get('error');
|
||||
if (error) {
|
||||
if (error.subtype === 'turbo-carto') {
|
||||
var newErrors = _.clone(this._codemirrorModel.get('errors')) || [];
|
||||
newErrors.push({ line: error.line, message: error.message });
|
||||
this._codemirrorModel.set('errors', newErrors);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_updateEditor: function (model) {
|
||||
var errors = this._querySchemaModel.get('query_errors');
|
||||
var hasErrors = errors && errors.length > 0;
|
||||
this._editorModel.set('disabled', hasErrors);
|
||||
},
|
||||
|
||||
_saveCartoCSS: function (cb) {
|
||||
var content = this._codemirrorModel.get('content');
|
||||
var parser = new ParserCSS(content);
|
||||
var errors = parser.errors();
|
||||
|
||||
if (!content) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._applyButtonStatusModel.set('loading', true);
|
||||
this._codemirrorModel.set('errors', parser.parseError(errors));
|
||||
|
||||
if (errors.length === 0) {
|
||||
this._cartocssModel.set('content', content);
|
||||
|
||||
// Disable auto-style before saving, in order to not reset styles
|
||||
this._layerDefinitionModel.set('autoStyle', false);
|
||||
|
||||
this._layerDefinitionModel.save({
|
||||
cartocss_custom: true,
|
||||
cartocss: content
|
||||
}, {
|
||||
complete: cb
|
||||
});
|
||||
|
||||
MetricsTracker.track(MetricsTypes.APPLIED_CARTOCSS, {
|
||||
layer_id: this._layerDefinitionModel.get('id'),
|
||||
cartocss: this._layerDefinitionModel.get('cartocss')
|
||||
});
|
||||
|
||||
MetricsTracker.track(MetricsTypes.USED_ADVANCED_MODE, {
|
||||
mode_type: 'cartocss'
|
||||
});
|
||||
} else {
|
||||
this._editorModel.get('edition') === false && CartoCSSNotifications.showErrorNotification(parser.parseError(errors));
|
||||
this._applyButtonStatusModel.set('loading', false);
|
||||
}
|
||||
},
|
||||
|
||||
_onSaveComplete: function () {
|
||||
CartoCSSNotifications.showSuccessNotification();
|
||||
this._applyButtonStatusModel.set('loading', false);
|
||||
},
|
||||
|
||||
_cancelClearStyles: function () {
|
||||
this._infoboxModel.set({ state: '' });
|
||||
this._overlayModel.set({ visible: false });
|
||||
|
||||
this._editorModel.set({
|
||||
edition: true
|
||||
});
|
||||
},
|
||||
|
||||
_clearCustomStyles: function () {
|
||||
this._layerDefinitionModel.set('cartocss_custom', false);
|
||||
this._styleModel.applyLastState();
|
||||
this._infoboxModel.set({ state: '' });
|
||||
this._overlayModel.set({ visible: false });
|
||||
this.render();
|
||||
},
|
||||
|
||||
_cancelTorqueAggregation: function () {
|
||||
this._styleModel.applyLastState();
|
||||
this._infoboxModel.set({ state: '' });
|
||||
this._overlayModel.set({ visible: false });
|
||||
this.render();
|
||||
},
|
||||
|
||||
_applyTorqueAggregation: function () {
|
||||
if (this._layerDefinitionsCollection.isThereAnyTorqueLayer()) {
|
||||
var torqueLayer = this._layerDefinitionsCollection.findWhere({ type: 'torque' });
|
||||
torqueLayer.styleModel.setDefaultPropertiesByType('simple', 'point');
|
||||
}
|
||||
|
||||
this._infoboxModel.set({ state: 'unfreeze' });
|
||||
},
|
||||
|
||||
_onChangeEdition: function () {
|
||||
this._infoboxState();
|
||||
|
||||
var edition = this._editorModel.get('edition');
|
||||
var index = edition ? 1 : 0;
|
||||
this._collectionPane.at(index).set({ selected: true });
|
||||
this._togglerModel.set({ active: edition });
|
||||
},
|
||||
|
||||
_onChangeDisabled: function () {
|
||||
var disabled = this._editorModel.get('disabled');
|
||||
this._togglerModel.set({ disabled: disabled });
|
||||
},
|
||||
|
||||
_onTogglerChanged: function () {
|
||||
var checked = this._togglerModel.get('active');
|
||||
this._editorModel.set({ edition: checked });
|
||||
},
|
||||
|
||||
_freezeTorgeAggregation: function (styleType, currentGeometryType) {
|
||||
this._infoboxModel.set({ state: 'torque-exists' });
|
||||
this._overlayModel.set({ visible: true });
|
||||
|
||||
// Apply the previously selected style
|
||||
this._infoboxModel.once('change:state', function (mdl, state) {
|
||||
if (state === 'unfreeze') {
|
||||
this._moveTorqueLayerToTop(function () {
|
||||
this._overlayModel.set({ visible: false });
|
||||
this._styleModel.setDefaultPropertiesByType(styleType, currentGeometryType);
|
||||
}.bind(this));
|
||||
this._infoboxModel.set({ state: '' });
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
_moveTorqueLayerToTop: function (callback) {
|
||||
var notification = Notifier.addNotification({
|
||||
status: 'loading',
|
||||
info: _t('editor.layers.moveTorqueLayer.loading'),
|
||||
closable: true
|
||||
});
|
||||
|
||||
this._layerDefinitionsCollection.once('layerMoved', function () {
|
||||
callback && callback();
|
||||
notification.set({
|
||||
status: 'success',
|
||||
info: _t('editor.layers.moveTorqueLayer.success'),
|
||||
delay: Notifier.DEFAULT_DELAY
|
||||
});
|
||||
}, this);
|
||||
|
||||
this._userActions.moveLayer({
|
||||
from: this._layerDefinitionModel.get('order'),
|
||||
to: this._layerDefinitionsCollection.getTopDataLayerIndex()
|
||||
});
|
||||
},
|
||||
|
||||
_configPanes: function () {
|
||||
var self = this;
|
||||
var tabPaneTabs = [{
|
||||
selected: !this._layerDefinitionModel.get('cartocss_custom'),
|
||||
createContentView: function () {
|
||||
return new ScrollView({
|
||||
createContentView: function () {
|
||||
return new StyleContentView({
|
||||
className: 'Editor-content',
|
||||
userActions: self._userActions,
|
||||
layerDefinitionsCollection: self._layerDefinitionsCollection,
|
||||
layerDefinitionModel: self._layerDefinitionModel,
|
||||
styleModel: self._styleModel,
|
||||
modals: self._modals,
|
||||
configModel: self._configModel,
|
||||
userModel: self._userModel,
|
||||
queryGeometryModel: self._queryGeometryModel,
|
||||
querySchemaModel: self._querySchemaModel,
|
||||
editorModel: self._editorModel,
|
||||
overlayModel: self._overlayModel,
|
||||
freezeTorgeAggregation: self._freezeTorgeAggregation.bind(self),
|
||||
layerContentModel: self._layerContentModel
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
createActionView: function () {
|
||||
return new UndoButtons({
|
||||
trackModel: self._styleModel,
|
||||
editorModel: self._editorModel,
|
||||
applyButton: false
|
||||
});
|
||||
}
|
||||
}, {
|
||||
selected: this._layerDefinitionModel.get('cartocss_custom'),
|
||||
createContentView: function () {
|
||||
return new StyleCartoCSSView({
|
||||
layerDefinitionModel: self._layerDefinitionModel,
|
||||
querySchemaModel: self._querySchemaModel,
|
||||
styleModel: self._styleModel,
|
||||
editorModel: self._editorModel,
|
||||
codemirrorModel: self._codemirrorModel,
|
||||
onApplyEvent: self._saveCartoCSS.bind(self, self._onSaveComplete.bind(self)),
|
||||
overlayModel: self._overlayModel
|
||||
});
|
||||
},
|
||||
createActionView: function () {
|
||||
return new UndoButtons({
|
||||
trackModel: self._cartocssModel,
|
||||
editorModel: self._editorModel,
|
||||
applyStatusModel: self._applyButtonStatusModel,
|
||||
applyButton: true,
|
||||
onApplyClick: self._saveCartoCSS.bind(self, self._onSaveComplete.bind(self)),
|
||||
overlayModel: self._overlayModel
|
||||
});
|
||||
}
|
||||
}];
|
||||
|
||||
this._collectionPane = new TabPaneCollection(tabPaneTabs);
|
||||
},
|
||||
|
||||
_isLayerHidden: function () {
|
||||
return this._layerDefinitionModel.get('visible') === false;
|
||||
},
|
||||
|
||||
_infoboxState: function () {
|
||||
var edition = this._editorModel.get('edition');
|
||||
var cartocss_custom = this._layerDefinitionModel.get('cartocss_custom');
|
||||
var isAutoStyleApplied = this._layerDefinitionModel.get('autoStyle');
|
||||
|
||||
if (!edition && cartocss_custom && !isAutoStyleApplied) {
|
||||
this._infoboxModel.set({ state: 'confirm' });
|
||||
this._overlayModel.set({ visible: true });
|
||||
} else if (this._isLayerHidden()) {
|
||||
this._infoboxModel.set({ state: 'layer-hidden' });
|
||||
this._overlayModel.set({ visible: true });
|
||||
this._togglerModel.set({ disabled: true });
|
||||
} else {
|
||||
this._infoboxModel.set({ state: '' });
|
||||
this._overlayModel.set({ visible: false });
|
||||
this._togglerModel.set({ disabled: false });
|
||||
}
|
||||
},
|
||||
|
||||
_showHiddenLayer: function () {
|
||||
var savingOptions = {
|
||||
shouldPreserveAutoStyle: true
|
||||
};
|
||||
this._layerDefinitionModel.toggleVisible();
|
||||
this._userActions.saveLayer(this._layerDefinitionModel, savingOptions);
|
||||
}
|
||||
});
|
||||
102
lib/assets/javascripts/builder/editor/style/styles-factory.js
Executable file
102
lib/assets/javascripts/builder/editor/style/styles-factory.js
Executable file
@@ -0,0 +1,102 @@
|
||||
var _ = require('underscore');
|
||||
var StyleDefaults = require('./style-defaults/style-defaults');
|
||||
var SimpleStyleDefaults = require('./style-defaults/simple-style-defaults');
|
||||
var HeatmapDefaults = require('./style-defaults/heatmap-style-defaults');
|
||||
var AnimationDefaults = require('./style-defaults/animation-style-defaults');
|
||||
var SquareAggregationDefaults = require('./style-defaults/squares-aggregation-style-defaults');
|
||||
var HexabinsAggregationDefaults = require('./style-defaults/hexabins-aggregation-style-defaults');
|
||||
var RegionsAggregationDefaults = require('./style-defaults/regions-aggregation-style-defaults');
|
||||
|
||||
var STYLE_MAP = {
|
||||
'none': {
|
||||
tooltipTranslationKey: 'editor.style.tooltip.none',
|
||||
labelTranslationKey: 'editor.style.types.none',
|
||||
checkIfValid: function (geometryType) {
|
||||
return !geometryType;
|
||||
},
|
||||
defaultStyles: StyleDefaults
|
||||
},
|
||||
'simple': {
|
||||
tooltipTranslationKey: 'editor.style.style-form.aggregation.tooltips.simple',
|
||||
labelTranslationKey: 'editor.style.types.simple',
|
||||
iconTemplate: require('./style-icons/points.tpl'),
|
||||
checkIfValid: function (geometryType) {
|
||||
return !!geometryType;
|
||||
},
|
||||
defaultStyles: SimpleStyleDefaults
|
||||
},
|
||||
'squares': {
|
||||
tooltipTranslationKey: 'editor.style.style-form.aggregation.tooltips.squares',
|
||||
labelTranslationKey: 'editor.style.types.squares',
|
||||
iconTemplate: require('./style-icons/squares.tpl'),
|
||||
checkIfValid: function (geometryType) {
|
||||
return geometryType === 'point';
|
||||
},
|
||||
defaultStyles: SquareAggregationDefaults
|
||||
},
|
||||
'hexabins': {
|
||||
tooltipTranslationKey: 'editor.style.style-form.aggregation.tooltips.hexabins',
|
||||
labelTranslationKey: 'editor.style.types.hexabins',
|
||||
iconTemplate: require('./style-icons/hexabins.tpl'),
|
||||
checkIfValid: function (geometryType) {
|
||||
return geometryType === 'point';
|
||||
},
|
||||
defaultStyles: HexabinsAggregationDefaults
|
||||
},
|
||||
'regions': {
|
||||
tooltipTranslationKey: 'editor.style.style-form.aggregation.tooltips.regions',
|
||||
labelTranslationKey: 'editor.style.types.regions',
|
||||
iconTemplate: require('./style-icons/regions.tpl'),
|
||||
checkIfValid: function (geometryType) {
|
||||
return geometryType === 'point';
|
||||
},
|
||||
defaultStyles: RegionsAggregationDefaults
|
||||
},
|
||||
'animation': {
|
||||
tooltipTranslationKey: 'editor.style.style-form.aggregation.tooltips.animation',
|
||||
labelTranslationKey: 'editor.style.types.animation',
|
||||
iconTemplate: require('./style-icons/animated.tpl'),
|
||||
checkIfValid: function (geometryType) {
|
||||
return geometryType === 'point';
|
||||
},
|
||||
defaultStyles: AnimationDefaults
|
||||
},
|
||||
'heatmap': {
|
||||
tooltipTranslationKey: 'editor.style.style-form.aggregation.tooltips.heatmap',
|
||||
labelTranslationKey: 'editor.style.types.heatmap',
|
||||
iconTemplate: require('./style-icons/heatmap.tpl'),
|
||||
checkIfValid: function (geometryType) {
|
||||
return geometryType === 'point';
|
||||
},
|
||||
defaultStyles: HeatmapDefaults
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getDefaultStyleAttrsByType: function (styleType, geometryType) {
|
||||
var StyleDefaultsKlass = STYLE_MAP[styleType].defaultStyles;
|
||||
return StyleDefaultsKlass.generateAttributes(geometryType);
|
||||
},
|
||||
|
||||
getStyleTypes: function (currentType, geometryType) {
|
||||
return _.reduce(STYLE_MAP, function (memo, val, key) {
|
||||
if (currentType === key || (val.checkIfValid ? val.checkIfValid(geometryType) : true)) {
|
||||
memo.push({
|
||||
value: key,
|
||||
label: _t(val.labelTranslationKey),
|
||||
tooltip: _t(val.tooltipTranslationKey),
|
||||
iconTemplate: val.iconTemplate
|
||||
});
|
||||
}
|
||||
return memo;
|
||||
}, []);
|
||||
},
|
||||
|
||||
getFormTemplateByType: function (styleType) {
|
||||
return STYLE_MAP[styleType].formTemplate;
|
||||
},
|
||||
|
||||
getAggregationTypes: function () {
|
||||
return ['squares', 'hexabins', 'regions'];
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user