Initial commit
This commit is contained in:
Executable
+14
@@ -0,0 +1,14 @@
|
||||
<svg width="42px" height="18px" viewBox="7 7 42 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="Group" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(7.000000, 7.000000)">
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="0" y="0" width="11" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="0" y="4" width="9" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="0" y="8" width="16" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="0" y="12" width="13" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="0" y="16" width="16" height="2"></rect>
|
||||
<ellipse id="Oval-1585" fill-opacity="0.2" fill="#9DE0AD" cx="33" cy="9" rx="9" ry="9"></ellipse>
|
||||
<ellipse id="Oval-1585" fill-opacity="0.4" fill="#9DE0AD" cx="33" cy="11" rx="7" ry="7"></ellipse>
|
||||
<ellipse id="Oval-1585" fill-opacity="0.5" fill="#9DE0AD" cx="33" cy="13" rx="5" ry="5"></ellipse>
|
||||
<ellipse id="Oval-1585" fill-opacity="0.8" fill="#9DE0AD" cx="33" cy="15" rx="3" ry="3"></ellipse>
|
||||
<ellipse id="Oval-1585" fill="#9DE0AD" cx="33" cy="17" rx="1" ry="1"></ellipse>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
Executable
+21
@@ -0,0 +1,21 @@
|
||||
<svg width="56px" height="32px" viewBox="529 429 56 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<rect id="path-1" x="0" y="0" width="56" height="32" rx="2"></rect>
|
||||
<mask id="mask-2" maskContentUnits="userSpaceOnUse" maskUnits="objectBoundingBox" x="0" y="0" width="56" height="32" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
</defs>
|
||||
<g id="category" transform="translate(529.000000, 429.000000)">
|
||||
<use id="Rectangle-2" stroke="#EEEEEE" mask="url(#mask-2)" stroke-width="2" fill="#FFFFFF" xlink:href="#path-1"></use>
|
||||
<rect id="Rectangle-679" fill="#DDDDDD" x="7" y="15" width="23" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="7" y="19" width="13" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="7" y="23" width="10" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="7" y="11" width="13" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="7" y="7" width="19" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#9CE0AC" x="45" y="7" width="3" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#F4F1DE" x="45" y="11" width="3" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#E17C60" x="45" y="15" width="3" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#3D3F5B" x="45" y="19" width="3" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#F2CD8F" x="45" y="23" width="3" height="2"></rect>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
Executable
+21
@@ -0,0 +1,21 @@
|
||||
<svg width="56px" height="32px" viewBox="529 429 56 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<rect id="path-1" x="0" y="0" width="56" height="32" rx="2"></rect>
|
||||
<mask id="mask-2" maskContentUnits="userSpaceOnUse" maskUnits="objectBoundingBox" x="0" y="0" width="56" height="32" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
</defs>
|
||||
<g id="category" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(529.000000, 429.000000)">
|
||||
<use id="Rectangle-2" stroke="#EEEEEE" mask="url(#mask-2)" stroke-width="2" fill="#FFFFFF" xlink:href="#path-1"></use>
|
||||
<rect id="Rectangle-679" fill="#DDDDDD" x="14" y="15" width="23" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="14" y="19" width="13" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="14" y="23" width="10" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="14" y="11" width="13" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="14" y="7" width="19" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#9CE0AC" x="7" y="7" width="3" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#F4F1DE" x="7" y="11" width="3" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#E17C60" x="7" y="15" width="3" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#3D3F5B" x="7" y="19" width="3" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#F2CD8F" x="7" y="23" width="3" height="2"></rect>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
Executable
+18
@@ -0,0 +1,18 @@
|
||||
<svg width="54px" height="24px" viewBox="519 458 54 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<linearGradient x1="90.736547%" y1="49.7500002%" x2="9.63471511%" y2="49.7500002%" id="linearGradient-1">
|
||||
<stop stop-color="#C11F22" offset="0%"></stop>
|
||||
<stop stop-color="#F53F15" offset="23.9588524%"></stop>
|
||||
<stop stop-color="#FF9030" offset="49.5142003%"></stop>
|
||||
<stop stop-color="#FFCF52" offset="75.4982561%"></stop>
|
||||
<stop stop-color="#FFFEAE" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g id="color" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(519.000000, 458.000000)">
|
||||
<rect id="bg" fill="#FFFFFF" x="0" y="0" width="54" height="23" rx="2"></rect>
|
||||
<path d="M1,20.9991358 C1,21.5484057 1.45096651,22 2.00209026,22 L51.9979097,22 C52.5538814,22 53,21.5535154 53,20.9991358 L53,2.00086422 C53,1.45159429 52.5490335,1 51.9979097,1 L2.00209026,1 C1.44611861,1 1,1.44648455 1,2.00086422 L1,20.9991358 Z M2.00209026,0 L51.9979097,0 C53.1036337,0 54,0.901627257 54,2.00086422 L54,20.9991358 C54,22.1041826 53.1077828,23 51.9979097,23 L2.00209026,23 C0.896366344,23 0,22.0983727 0,20.9991358 L0,2.00086422 C0,0.895817426 0.892217249,0 2.00209026,0 Z" id="Rectangle-2087-Copy" fill="#EEEEEE"></path>
|
||||
<rect id="Rectangle-680" fill="url(#linearGradient-1)" x="6" y="12" width="42" height="5"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="6" y="6" width="6" height="2"></rect>
|
||||
<rect id="Rectangle-680" fill="#DDDDDD" x="42" y="6" width="6" height="2"></rect>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
Executable
+1
@@ -0,0 +1 @@
|
||||
<p class="CDB-Text CDB-Size-small u-upperCase u-altTextColor">None</p>
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
<ul class="CodeMirror-error">
|
||||
<li class="CodeMirror-errorMessage u-lSpace--xl u-rSpace--xl">
|
||||
<%- _t('components.codemirror.syntax-error') %>. <%- _t('components.codemirror.line') %> <%- line %>: <span><%- message %></span>
|
||||
</li>
|
||||
</ul>
|
||||
Executable
+89
@@ -0,0 +1,89 @@
|
||||
var LegendTypes = require('builder/editor/layers/layer-content-views/legend/legend-types');
|
||||
var styleHelper = require('builder/helpers/style');
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
value: LegendTypes.NONE,
|
||||
tooltipTranslationKey: 'editor.legend.tooltips.style.none',
|
||||
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/none.tpl'),
|
||||
label: _t('editor.legend.types.none')
|
||||
}, {
|
||||
value: LegendTypes.CATEGORY,
|
||||
tooltipTranslationKey: 'editor.legend.tooltips.style.category',
|
||||
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/category.tpl'),
|
||||
label: _t('editor.legend.types.category'),
|
||||
isStyleCompatible: function (styleModel) {
|
||||
var color = styleHelper.getColor(styleModel);
|
||||
|
||||
if (color == null || styleModel.isAnimation()) return false;
|
||||
|
||||
var usesCategory = (color && color.quantification === 'category');
|
||||
var hasStringAttribute = (color && color.attribute &&
|
||||
color.attribute_type && color.attribute_type === 'string');
|
||||
var hasBooleanAttribute = (color && color.attribute &&
|
||||
color.attribute_type && color.attribute_type === 'boolean');
|
||||
|
||||
return (usesCategory || hasStringAttribute || hasBooleanAttribute);
|
||||
}
|
||||
}, {
|
||||
value: LegendTypes.TORQUE,
|
||||
tooltipTranslationKey: 'editor.legend.tooltips.style.torque',
|
||||
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/category.tpl'),
|
||||
label: _t('editor.legend.types.category'),
|
||||
isStyleCompatible: function (styleModel) {
|
||||
var color = styleHelper.getColor(styleModel);
|
||||
|
||||
if (color == null || !styleModel.isAnimation()) return false;
|
||||
|
||||
var usesCategory = (color && color.quantification === 'category');
|
||||
var hasStringAttribute = (color && color.attribute &&
|
||||
color.attribute_type && color.attribute_type === 'string');
|
||||
|
||||
return (usesCategory || hasStringAttribute);
|
||||
}
|
||||
}, {
|
||||
value: LegendTypes.CHOROPLETH,
|
||||
tooltipTranslationKey: 'editor.legend.tooltips.style.choropleth',
|
||||
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/gradient.tpl'),
|
||||
label: _t('editor.legend.types.gradient'),
|
||||
isStyleCompatible: function (styleModel) {
|
||||
var color = styleHelper.getColor(styleModel);
|
||||
if (color == null) return false;
|
||||
|
||||
if (styleModel.isAnimation() || styleModel.isHeatmap()) return false;
|
||||
|
||||
var usesCategory = (color && color.quantification === 'category');
|
||||
if (usesCategory) return false;
|
||||
|
||||
var attributeTypeIsBoolean = (color.attribute_type && color.attribute_type === 'boolean');
|
||||
if (attributeTypeIsBoolean) return false;
|
||||
|
||||
var hasAttribute = color && color.attribute;
|
||||
var attributeTypeIsUndef = (color.attribute_type === undefined);
|
||||
var attributeTypeIsNotString = (color.attribute_type && color.attribute_type !== 'string');
|
||||
|
||||
return hasAttribute && (attributeTypeIsUndef || attributeTypeIsNotString);
|
||||
}
|
||||
}, {
|
||||
value: LegendTypes.CUSTOM_CHOROPLETH,
|
||||
tooltipTranslationKey: 'editor.legend.tooltips.style.custom_choropleth',
|
||||
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/gradient.tpl'),
|
||||
label: _t('editor.legend.types.gradient'),
|
||||
isStyleCompatible: function (styleModel) {
|
||||
var color = styleHelper.getColor(styleModel);
|
||||
|
||||
if (color == null || !styleModel.isHeatmap()) return false;
|
||||
|
||||
var hasAttribute = color && color.attribute;
|
||||
var attributeTypeIsUndef = (color.attribute_type === undefined);
|
||||
var attributeTypeIsNotString = (color.attribute_type && color.attribute_type !== 'string');
|
||||
|
||||
return hasAttribute && (attributeTypeIsUndef || attributeTypeIsNotString);
|
||||
}
|
||||
}, {
|
||||
value: LegendTypes.CUSTOM,
|
||||
tooltipTranslationKey: 'editor.legend.tooltips.style.custom',
|
||||
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/custom.tpl'),
|
||||
label: _t('editor.legend.types.custom')
|
||||
}
|
||||
];
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
var LegendTypes = require('./legend-color-types');
|
||||
var LegendTypeBaseView = require('builder/editor/layers/layer-content-views/legend/legend-base-type-view');
|
||||
|
||||
module.exports = LegendTypeBaseView.extend({
|
||||
initialize: function (opts) {
|
||||
this.legendTypes = LegendTypes;
|
||||
LegendTypeBaseView.prototype.initialize.call(this, opts);
|
||||
}
|
||||
});
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<ul>
|
||||
<% for(var i in items) { %>
|
||||
<li class="Legend-categoryListItem u-flex u-alignCenter">
|
||||
<% if (items[i].icon) { %>
|
||||
<span class="Legend-categoryIcon js-image-container" data-icon="<%= items[i].icon %>" <% if (items[i].color) { %>data-color="<%= items[i].color %>"<% } %>></span>
|
||||
<% } else if (items[i].color) { %>
|
||||
<span class="Legend-categoryCircle" style="opacity:1; background: <%= items[i].color %>;"></span>
|
||||
<% } %>
|
||||
|
||||
<p class="Legend-categoryTitle CDB-Text CDB-Size-small u-upperCase u-ellipsis" title="<%= items[i].title %>"><%= items[i].title %></p>
|
||||
</li>
|
||||
<% } %>
|
||||
</ul>
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
<h2 class="CDB-Text CDB-Size-huge is-light u-secondaryTextColor">
|
||||
<%- _t('editor.legend.message') %>
|
||||
</h2>
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
var Backbone = require('backbone');
|
||||
var _ = require('underscore');
|
||||
|
||||
/*
|
||||
Base model form legend.
|
||||
*/
|
||||
module.exports = Backbone.Model.extend({
|
||||
defaults: {
|
||||
type: 'none',
|
||||
title: ''
|
||||
},
|
||||
|
||||
initialize: function (attrs, opts) {
|
||||
if (!opts.legendDefinitionModel) throw new Error('legendDefinitionModel is required');
|
||||
this.legendDefinitionModel = opts.legendDefinitionModel;
|
||||
|
||||
this.schema = this._generateSchema();
|
||||
},
|
||||
|
||||
_generateSchema: function () {
|
||||
return {
|
||||
title: {
|
||||
type: 'EnablerEditor',
|
||||
title: '',
|
||||
label: _t('editor.legend.legend-form.title.label'),
|
||||
defaultValue: this._titlePlaceholder,
|
||||
editor: {
|
||||
type: 'Text',
|
||||
editorAttrs: {
|
||||
placeholder: this._titlePlaceholder,
|
||||
help: _t('editor.legend.legend-form.title.help')
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
toJSON: function () {
|
||||
return _.extend(
|
||||
this.attributes,
|
||||
{
|
||||
type: this.get('type')
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
var _ = require('underscore');
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
var LegendBaseDefModel = require('./legend-base-definition-form-model');
|
||||
var LegendColorHelper = require('./legend-color-helper');
|
||||
|
||||
module.exports = LegendBaseDefModel.extend({
|
||||
defaults: _.extend({}, LegendBaseDefModel.prototype.defaults,
|
||||
{
|
||||
type: 'bubble',
|
||||
fillColor: null
|
||||
}
|
||||
),
|
||||
|
||||
initialize: function (attrs, opts) {
|
||||
this._titlePlaceholder = _t('editor.legend.legend-form.by-size');
|
||||
LegendBaseDefModel.prototype.initialize.call(this, attrs, opts);
|
||||
|
||||
this.on('change:fill', function () {
|
||||
this.set('fillColor', this.get('fill').color.fixed);
|
||||
}, this);
|
||||
|
||||
this._initialColor();
|
||||
},
|
||||
|
||||
toJSON: function () {
|
||||
return _.extend(
|
||||
{},
|
||||
_.omit(this.attributes, 'fill')
|
||||
);
|
||||
},
|
||||
|
||||
_initialColor: function () {
|
||||
var color = this.legendDefinitionModel.get('fillColor');
|
||||
var fill = LegendColorHelper.getBubbles(color);
|
||||
this.set({fill: fill});
|
||||
},
|
||||
|
||||
_generateSchema: function () {
|
||||
var schema = LegendBaseDefModel.prototype._generateSchema.call(this);
|
||||
return _.extend(
|
||||
schema,
|
||||
{
|
||||
fill: {
|
||||
type: 'Fill',
|
||||
title: _t('editor.legend.legend-form.fill'),
|
||||
options: [],
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
color: {
|
||||
hidePanes: ['value']
|
||||
}
|
||||
}
|
||||
},
|
||||
topLabel: {
|
||||
type: 'EnablerEditor',
|
||||
title: '',
|
||||
label: _t('editor.legend.legend-form.top-label'),
|
||||
editor: {
|
||||
type: 'Text',
|
||||
editorAttrs: {
|
||||
placeholder: _t('editor.legend.legend-form.custom-label-placeholder')
|
||||
}
|
||||
}
|
||||
},
|
||||
bottomLabel: {
|
||||
type: 'EnablerEditor',
|
||||
title: '',
|
||||
label: _t('editor.legend.legend-form.bottom-label'),
|
||||
editor: {
|
||||
type: 'Text',
|
||||
editorAttrs: {
|
||||
placeholder: _t('editor.legend.legend-form.custom-label-placeholder')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
var _ = require('underscore');
|
||||
var LegendBaseDefModel = require('./legend-base-definition-form-model');
|
||||
|
||||
module.exports = LegendBaseDefModel.extend({
|
||||
defaults: _.extend({}, LegendBaseDefModel.prototype.defaults,
|
||||
{
|
||||
type: 'category'
|
||||
}
|
||||
),
|
||||
|
||||
initialize: function (attrs, opts) {
|
||||
this._titlePlaceholder = _t('editor.legend.legend-form.by-color');
|
||||
LegendBaseDefModel.prototype.initialize.call(this, attrs, opts);
|
||||
}
|
||||
});
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
var _ = require('underscore');
|
||||
var LegendBaseDefModel = require('./legend-base-definition-form-model');
|
||||
|
||||
module.exports = LegendBaseDefModel.extend({
|
||||
defaults: _.extend({}, LegendBaseDefModel.prototype.defaults,
|
||||
{
|
||||
type: 'choropleth',
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
leftLabel: '',
|
||||
rightLabel: ''
|
||||
}
|
||||
),
|
||||
|
||||
initialize: function (attrs, opts) {
|
||||
this._titlePlaceholder = _t('editor.legend.legend-form.by-color');
|
||||
LegendBaseDefModel.prototype.initialize.call(this, attrs, opts);
|
||||
},
|
||||
|
||||
_generateSchema: function () {
|
||||
var schema = LegendBaseDefModel.prototype._generateSchema.call(this);
|
||||
return _.extend(
|
||||
schema,
|
||||
{
|
||||
leftLabel: {
|
||||
type: 'EnablerEditor',
|
||||
title: '',
|
||||
label: _t('editor.legend.legend-form.left-label'),
|
||||
editor: {
|
||||
type: 'Text',
|
||||
editorAttrs: {
|
||||
placeholder: _t('editor.legend.legend-form.custom-label-placeholder')
|
||||
}
|
||||
}
|
||||
},
|
||||
rightLabel: {
|
||||
type: 'EnablerEditor',
|
||||
title: '',
|
||||
label: _t('editor.legend.legend-form.right-label'),
|
||||
editor: {
|
||||
type: 'Text',
|
||||
editorAttrs: {
|
||||
placeholder: _t('editor.legend.legend-form.custom-label-placeholder')
|
||||
}
|
||||
}
|
||||
},
|
||||
suffix: {
|
||||
type: 'EnablerEditor',
|
||||
title: '',
|
||||
label: _t('editor.legend.legend-form.suffix'),
|
||||
editor: {
|
||||
type: 'Text'
|
||||
}
|
||||
},
|
||||
prefix: {
|
||||
type: 'EnablerEditor',
|
||||
title: '',
|
||||
label: _t('editor.legend.legend-form.prefix'),
|
||||
editor: {
|
||||
type: 'Text'
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
var _ = require('underscore');
|
||||
|
||||
function buildSwatch (color, name, icon) {
|
||||
if (_.isString(color)) {
|
||||
color = {
|
||||
fixed: color,
|
||||
opacity: 1,
|
||||
image: icon
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
fill: {
|
||||
color: color
|
||||
},
|
||||
title: name
|
||||
};
|
||||
}
|
||||
|
||||
function _unquote (c) {
|
||||
return c && c.replace && c.replace(/^"(.+(?="$))"$/, '$1') || c;
|
||||
}
|
||||
|
||||
function simpleColor (color) {
|
||||
return [buildSwatch(color, '', color.image || '')];
|
||||
}
|
||||
|
||||
function collectionColor (color) {
|
||||
var range = color.range.length;
|
||||
return _.range(range).map(function (v, index) {
|
||||
// if style attribute is number there is no domain (choropleth)
|
||||
return buildSwatch(
|
||||
color.range[index],
|
||||
color.domain && _unquote(color.domain[index]) || '',
|
||||
color.images && color.images[index]);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildSwatch: buildSwatch,
|
||||
getCategories: function (color) {
|
||||
if (color.fixed !== undefined) {
|
||||
return simpleColor(color);
|
||||
} else if (color.attribute) {
|
||||
return collectionColor(color);
|
||||
}
|
||||
},
|
||||
|
||||
unquoteColor: _unquote,
|
||||
getBubbles: function (color) {
|
||||
return _.omit(_.first(this.getCategories(color)), 'title').fill;
|
||||
}
|
||||
};
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
var _ = require('underscore');
|
||||
|
||||
function rotateCollection (array) {
|
||||
var first = _.first(array);
|
||||
array = _.rest(array);
|
||||
return array.concat([first]);
|
||||
}
|
||||
|
||||
var COLORS = [
|
||||
'#66B79E',
|
||||
'#E65176',
|
||||
'#528995',
|
||||
'#FF710F',
|
||||
'#305482',
|
||||
'#CCD859',
|
||||
'#565175',
|
||||
'#FFB927',
|
||||
'#3EBCAE',
|
||||
'#E54C1F'
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
getNextColor: function () {
|
||||
COLORS = rotateCollection(COLORS);
|
||||
return _.first(COLORS);
|
||||
},
|
||||
|
||||
getColors: function () {
|
||||
return COLORS;
|
||||
},
|
||||
|
||||
setColors: function (collection) {
|
||||
COLORS = collection;
|
||||
}
|
||||
};
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
var _ = require('underscore');
|
||||
var LegendBaseDefModel = require('./legend-choropleth-definition-form-model');
|
||||
|
||||
module.exports = LegendBaseDefModel.extend({
|
||||
defaults: _.extend({}, LegendBaseDefModel.prototype.defaults,
|
||||
{
|
||||
type: 'custom_choropleth'
|
||||
}
|
||||
)
|
||||
});
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
var _ = require('underscore');
|
||||
var LegendBaseDefModel = require('./legend-base-definition-form-model');
|
||||
var NestedCategory = require('./legend-nested-category-definition-form-model');
|
||||
var templateItem = require('./legend-list-item.tpl');
|
||||
var templateList = require('./legend-list.tpl');
|
||||
var LegendColorHelper = require('./legend-color-helper');
|
||||
|
||||
module.exports = LegendBaseDefModel.extend({
|
||||
defaults: _.extend({}, LegendBaseDefModel.prototype.defaults,
|
||||
{
|
||||
type: 'custom',
|
||||
items: []
|
||||
}
|
||||
),
|
||||
|
||||
initialize: function (attrs, opts) {
|
||||
if (!opts.userModel) throw new Error('userModel is required');
|
||||
if (!opts.configModel) throw new Error('configModel is required');
|
||||
if (!opts.modals) throw new Error('configModel is required');
|
||||
|
||||
this._userModel = opts.userModel;
|
||||
this._configModel = opts.configModel;
|
||||
this._modals = opts.modals;
|
||||
|
||||
this._titlePlaceholder = _t('editor.legend.legend-form.by-color');
|
||||
LegendBaseDefModel.prototype.initialize.call(this, attrs, opts);
|
||||
|
||||
this._initialItems();
|
||||
},
|
||||
|
||||
_initialItems: function () {
|
||||
var items;
|
||||
var categories = this.legendDefinitionModel.get('items');
|
||||
items = categories.map(function (v, index) {
|
||||
return LegendColorHelper.buildSwatch(v.color, v.title, v.icon);
|
||||
});
|
||||
this.set({items: items});
|
||||
},
|
||||
|
||||
_generateSchema: function () {
|
||||
var schema = LegendBaseDefModel.prototype._generateSchema.call(this);
|
||||
return _.extend(
|
||||
schema,
|
||||
{
|
||||
items: {
|
||||
type: 'SortableList',
|
||||
itemType: 'CategoryModel',
|
||||
model: NestedCategory,
|
||||
title: '',
|
||||
itemTemplate: templateItem,
|
||||
listTemplate: templateList,
|
||||
editorAttrs: {
|
||||
className: 'u-flex',
|
||||
userModel: this._userModel,
|
||||
configModel: this._configModel,
|
||||
modals: this._modals
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
toJSON: function () {
|
||||
return _.extend(
|
||||
{},
|
||||
_.omit(this.attributes, 'items'),
|
||||
{
|
||||
items: this.get('items').map(function (item) {
|
||||
return {
|
||||
title: item.title,
|
||||
color: item.fill.color.fixed,
|
||||
image: item.fill.color.image
|
||||
};
|
||||
})
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
<div class="LegendItem js-sortable">
|
||||
<div class="LegendItem-listFieldsOrder CDB-Shape js-editable">
|
||||
<div class="CDB-Shape-rectsHandle is-small">
|
||||
<div class="CDB-Shape-rectsHandleItem CDB-Shape-rectsHandleItem--grey is-first"></div>
|
||||
<div class="CDB-Shape-rectsHandleItem CDB-Shape-rectsHandleItem--grey is-second"></div>
|
||||
<div class="CDB-Shape-rectsHandleItem CDB-Shape-rectsHandleItem--grey is-third"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-editor class="u-grow">
|
||||
</div>
|
||||
<button class="LegendItem-deleteButton js-editable js-remove-help" type="button" data-action="remove">
|
||||
<svg width="8px" height="8px" viewBox="0 0 8 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<polygon fill="#1181FB" points="4 3.435128 0.564872 0 0 0.564872 3.435128 4 0 7.435128 0.564872 8 4 4.564872 7.435128 8 8 7.435128 4.564872 4 8 0.564872 7.435128 0"></polygon>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
<div class="u-grow LegendItems-container">
|
||||
<div data-items class="u-bSpace--xl">
|
||||
|
||||
</div>
|
||||
<div class="u-flex u-justifyEnd" style="width: 100%;"> <!-- We need a fucking u-full helper -->
|
||||
<button class="CDB-Text CDB-Size-small u-actionTextColor u-upperCase" type="button" data-action="add">
|
||||
<%- _t('editor.legend.legend-form.add') %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
|
||||
var LegendColors = require('./legend-color-range');
|
||||
|
||||
var defaultFill = {
|
||||
color: {
|
||||
fixed: '#fabada',
|
||||
opacity: 0.9
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Backbone.Model.extend({
|
||||
schema: {
|
||||
fill: {
|
||||
type: 'Fill',
|
||||
title: '',
|
||||
options: [],
|
||||
dialogMode: DialogConstants.Mode.FLOAT,
|
||||
editorAttrs: {
|
||||
color: {
|
||||
hidePanes: ['value'],
|
||||
imageEnabled: true,
|
||||
help: _t('editor.legend.tooltips.item.fill')
|
||||
},
|
||||
className: 'LegendItem-inner'
|
||||
}
|
||||
},
|
||||
title: {
|
||||
type: 'Text',
|
||||
title: '',
|
||||
editorAttrs: {
|
||||
className: 'LegendItem-inner',
|
||||
placeholder: _t('editor.legend.legend-form.untitled'),
|
||||
help: _t('editor.legend.tooltips.item.title')
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
initialize: function (attrs, opts) {
|
||||
this._userModel = opts.userModel;
|
||||
this._configModel = opts.configModel;
|
||||
this._modals = opts.modals;
|
||||
|
||||
this._setOptions();
|
||||
|
||||
var fill = _.clone(defaultFill);
|
||||
if (attrs.fill === undefined) {
|
||||
fill.color.fixed = LegendColors.getNextColor();
|
||||
this.set({fill: fill}, {silent: true});
|
||||
}
|
||||
},
|
||||
|
||||
_setOptions: function () {
|
||||
this.schema.fill.editorAttrs.userModel = this._userModel;
|
||||
this.schema.fill.editorAttrs.configModel = this._configModel;
|
||||
this.schema.fill.editorAttrs.modals = this._modals;
|
||||
}
|
||||
});
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
var _ = require('underscore');
|
||||
var LegendBaseDefModel = require('./legend-category-definition-form-model');
|
||||
|
||||
module.exports = LegendBaseDefModel.extend({
|
||||
defaults: _.extend({}, LegendBaseDefModel.prototype.defaults,
|
||||
{
|
||||
type: 'torque'
|
||||
}
|
||||
)
|
||||
});
|
||||
Executable
+401
@@ -0,0 +1,401 @@
|
||||
var cdb = require('internal-carto.js');
|
||||
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 LegendContentView = require('./legend-content-view');
|
||||
var LegendEditorView = require('./legend-editor-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 ApplyButtonView = require('builder/components/apply-button/apply-button-view');
|
||||
var Infobox = require('builder/components/infobox/infobox-factory');
|
||||
var InfoboxCollection = require('builder/components/infobox/infobox-collection');
|
||||
var LegendDefinitionModel = require('builder/data/legends/legend-base-definition-model');
|
||||
var LegendFactory = require('./legend-factory');
|
||||
var htmlTemplate = require('./color/legend-custom-template.tpl');
|
||||
var checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
var MetricsTracker = require('builder/components/metrics/metrics-tracker');
|
||||
var MetricsTypes = require('builder/components/metrics/metrics-types');
|
||||
|
||||
var REQUIRED_OPTS = [
|
||||
'mapDefinitionModel',
|
||||
'layerDefinitionModel',
|
||||
'editorModel',
|
||||
'layerContentModel',
|
||||
'legendDefinitionsCollection',
|
||||
'type',
|
||||
'userActions',
|
||||
'userModel',
|
||||
'configModel',
|
||||
'modals',
|
||||
'overlayModel',
|
||||
'infoboxModel'
|
||||
];
|
||||
|
||||
var PLACEHOLDER = '[[Legend]]';
|
||||
var HTML_TEMPLATE = _.template('<%= preSnippet %>\r\n<%- placeholder %>\r\n<%= postSnippet %>');
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
initialize: function (opts) {
|
||||
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
|
||||
|
||||
// this.legendTypes is defined in the subview
|
||||
this._legendDefinitionModel = this._getUserLegend(this.legendTypes);
|
||||
|
||||
this._codemirrorModel = new Backbone.Model({
|
||||
content: this._getEditorContent()
|
||||
});
|
||||
|
||||
this._editorModel.set({
|
||||
edition: this._legendDefinitionModel.hasCustomHtml(),
|
||||
disabled: this._isToggleDisable() // if there is an sql error or none style is selected, set to true
|
||||
});
|
||||
|
||||
this._overlayModel.set({
|
||||
visible: this._isLayerHidden() || this._legendDefinitionModel.hasCustomHtml()
|
||||
}, {
|
||||
silent: true
|
||||
});
|
||||
|
||||
this._togglerModel = new Backbone.Model({
|
||||
labels: [_t('editor.legend.data-toggle.values'), _t('editor.legend.data-toggle.html')],
|
||||
active: this._editorModel.isEditing(),
|
||||
disabled: this._editorModel.isDisabled(),
|
||||
isDisableable: true,
|
||||
tooltip: _t('editor.legend.data-toggle.tooltip')
|
||||
});
|
||||
|
||||
this._configPanes();
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this.$el.empty();
|
||||
|
||||
this._initViews();
|
||||
this._infoboxState();
|
||||
this._toggleOverlay();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this._layerContentModel, 'change:state', this._infoboxState);
|
||||
this.listenTo(this._layerDefinitionModel, 'change:visible', this._infoboxState);
|
||||
this.listenTo(this._mapDefinitionModel, 'change:legends', 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._overlayModel, 'change:visible', this._toggleOverlay);
|
||||
},
|
||||
|
||||
_getEditorContent: function () {
|
||||
var content;
|
||||
var type = this._legendDefinitionModel.get('type');
|
||||
|
||||
if (type === 'custom') {
|
||||
if (this._legendDefinitionModel.hasCustomHtml()) {
|
||||
content = this._legendDefinitionModel.get('html');
|
||||
} else {
|
||||
content = '';
|
||||
}
|
||||
} else {
|
||||
content = this._getReadOnlyContent();
|
||||
}
|
||||
|
||||
return content;
|
||||
},
|
||||
|
||||
_getReadOnlyContent: function () {
|
||||
var content = HTML_TEMPLATE({
|
||||
preSnippet: this._legendDefinitionModel.get('preHTMLSnippet') || _t('editor.legend.code-mirror.pre-html'),
|
||||
placeholder: PLACEHOLDER,
|
||||
postSnippet: this._legendDefinitionModel.get('postHTMLSnippet') || _t('editor.legend.code-mirror.post-html')
|
||||
});
|
||||
|
||||
return content;
|
||||
},
|
||||
|
||||
_getCustomContent: function () {
|
||||
var items;
|
||||
var result = this._legendDefinitionModel.get('html');
|
||||
|
||||
if (result === '') {
|
||||
items = this._legendDefinitionModel.get('items');
|
||||
|
||||
result = htmlTemplate({ items: items });
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
_handleEditorContent: function (expertMode) {
|
||||
var type = this._legendDefinitionModel.get('type');
|
||||
if (expertMode) {
|
||||
this._codemirrorModel.set({ content: type === 'custom' ? this._getCustomContent() : this._getReadOnlyContent() });
|
||||
}
|
||||
},
|
||||
|
||||
_getUserLegend: function (types) {
|
||||
var self = this;
|
||||
var values = _.map(types, function (type) { return type.value; });
|
||||
var selected = this._legendDefinitionsCollection.find(function (legendDefModel) {
|
||||
return values.indexOf(legendDefModel.get('type')) !== -1 && legendDefModel.layerDefinitionModel.id === self._layerDefinitionModel.id;
|
||||
});
|
||||
|
||||
if (selected === undefined) {
|
||||
selected = new LegendDefinitionModel(null, {
|
||||
layerDefinitionModel: this._layerDefinitionModel,
|
||||
configModel: this._legendDefinitionsCollection.configModel,
|
||||
vizId: this._legendDefinitionsCollection.vizId
|
||||
});
|
||||
}
|
||||
|
||||
return selected;
|
||||
},
|
||||
|
||||
_isToggleDisable: function () {
|
||||
return this._isErrored() || this._legendDefinitionModel.get('type') === 'none' || this._areLegendsDisabled();
|
||||
},
|
||||
|
||||
_isLayerHidden: function () {
|
||||
return this._layerDefinitionModel.get('visible') === false;
|
||||
},
|
||||
|
||||
_isErrored: function () {
|
||||
return this._layerContentModel.isErrored();
|
||||
},
|
||||
|
||||
_toggleOverlay: function () {
|
||||
var isDisabled = this._overlayModel.get('visible');
|
||||
this.$('.js-overlay').toggleClass('is-disabled', isDisabled);
|
||||
},
|
||||
|
||||
_onChangeState: function () {
|
||||
this._editorModel.set({ disabled: this._isErrored() });
|
||||
},
|
||||
|
||||
_onChangeEdition: function () {
|
||||
this._infoboxState();
|
||||
|
||||
var edition = this._editorModel.get('edition');
|
||||
this._handleEditorContent(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 });
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
var self = this;
|
||||
|
||||
var infoboxSstates = [
|
||||
{
|
||||
state: 'html-legend',
|
||||
createContentView: function () {
|
||||
return Infobox.createWithAction({
|
||||
type: 'alert',
|
||||
title: _t('editor.legend.messages.custom-legend.title'),
|
||||
body: _t('editor.legend.messages.custom-legend.body'),
|
||||
action: {
|
||||
label: _t('editor.legend.messages.custom-legend.accept')
|
||||
}
|
||||
});
|
||||
},
|
||||
onAction: self._deleteCustomHtmlLegend.bind(self)
|
||||
}, {
|
||||
state: 'layer-hidden',
|
||||
createContentView: function () {
|
||||
return Infobox.createWithAction({
|
||||
type: '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: 'legends-disabled',
|
||||
createContentView: function () {
|
||||
return Infobox.createWithAction({
|
||||
type: 'alert',
|
||||
title: _t('editor.legend.messages.legends-disabled.title'),
|
||||
body: _t('editor.legend.messages.legends-disabled.body'),
|
||||
action: {
|
||||
label: _t('editor.legend.messages.legends-disabled.show')
|
||||
}
|
||||
});
|
||||
},
|
||||
onAction: self._enableLegends.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);
|
||||
},
|
||||
|
||||
_showHiddenLayer: function () {
|
||||
var savingOptions = {
|
||||
shouldPreserveAutoStyle: true
|
||||
};
|
||||
this._layerDefinitionModel.toggleVisible();
|
||||
this._userActions.saveLayer(this._layerDefinitionModel, savingOptions);
|
||||
},
|
||||
|
||||
_deleteCustomHtmlLegend: function () {
|
||||
var type = this._legendDefinitionModel.get('type');
|
||||
this._legendDefinitionModel && this._legendDefinitionModel.set({
|
||||
html: ''
|
||||
});
|
||||
LegendFactory.createLegend(this._layerDefinitionModel, type);
|
||||
this._infoboxState();
|
||||
},
|
||||
|
||||
_saveLegendHTML: function () {
|
||||
var content = this._codemirrorModel.get('content');
|
||||
var type = this._legendDefinitionModel.get('type');
|
||||
var parts;
|
||||
|
||||
if (type === 'custom') {
|
||||
this._legendDefinitionModel && this._legendDefinitionModel.set({
|
||||
html: content
|
||||
});
|
||||
} else {
|
||||
parts = content.split(PLACEHOLDER).map(function (part) {
|
||||
return cdb.core.sanitize.html(part);
|
||||
});
|
||||
|
||||
this._legendDefinitionModel && this._legendDefinitionModel.set({
|
||||
preHTMLSnippet: parts[0],
|
||||
postHTMLSnippet: parts[1]
|
||||
});
|
||||
}
|
||||
|
||||
MetricsTracker.track(MetricsTypes.USED_ADVANCED_MODE, {
|
||||
mode_type: 'legend'
|
||||
});
|
||||
|
||||
LegendFactory.createLegend(this._layerDefinitionModel, type);
|
||||
},
|
||||
|
||||
_infoboxState: function () {
|
||||
var edition = this._editorModel.get('edition');
|
||||
|
||||
if (!edition && this._areLegendsDisabled()) {
|
||||
this._infoboxModel.set({ state: 'legends-disabled' });
|
||||
this._overlayModel.set({ visible: true });
|
||||
this._togglerModel.set({ disabled: true });
|
||||
} else if (!edition && this._legendDefinitionModel.hasCustomHtml()) {
|
||||
this._infoboxModel.set({ state: 'html-legend' });
|
||||
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 });
|
||||
}
|
||||
},
|
||||
|
||||
_areLegendsDisabled: function () {
|
||||
return this._mapDefinitionModel.get('legends') === false;
|
||||
},
|
||||
|
||||
_enableLegends: function () {
|
||||
this._mapDefinitionModel.save({ legends: true });
|
||||
},
|
||||
|
||||
// we need to update the reference to the model
|
||||
_updateLegend: function (newLegendDefModel) {
|
||||
this._legendDefinitionModel = newLegendDefModel;
|
||||
},
|
||||
|
||||
_configPanes: function () {
|
||||
var self = this;
|
||||
var tabPaneTabs = [{
|
||||
selected: !self._legendDefinitionModel.hasCustomHtml(),
|
||||
createContentView: function () {
|
||||
return new ScrollView({
|
||||
createContentView: function () {
|
||||
return new LegendContentView({
|
||||
className: 'Editor-content',
|
||||
editorModel: self._editorModel,
|
||||
legendTypes: self.legendTypes,
|
||||
layerDefinitionModel: self._layerDefinitionModel,
|
||||
legendDefinitionModel: self._getUserLegend(self.legendTypes),
|
||||
legendDefinitionsCollection: self._legendDefinitionsCollection,
|
||||
updateLegend: self._updateLegend.bind(self),
|
||||
type: self._type,
|
||||
userModel: self._userModel,
|
||||
configModel: self._configModel,
|
||||
modals: self._modals
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
createActionView: function () {
|
||||
return new CoreView();
|
||||
}
|
||||
}, {
|
||||
selected: self._legendDefinitionModel.hasCustomHtml(),
|
||||
createContentView: function () {
|
||||
return new LegendEditorView({
|
||||
isCustom: self._legendDefinitionModel.get('type') === 'custom',
|
||||
codemirrorModel: self._codemirrorModel,
|
||||
onApplyEvent: self._saveLegendHTML.bind(self)
|
||||
});
|
||||
},
|
||||
createActionView: function () {
|
||||
return new ApplyButtonView({
|
||||
onApplyClick: self._saveLegendHTML.bind(self),
|
||||
overlayModel: self._overlayModel
|
||||
});
|
||||
}
|
||||
}];
|
||||
|
||||
this._collectionPane = new TabPaneCollection(tabPaneTabs);
|
||||
}
|
||||
});
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
var _ = require('underscore');
|
||||
|
||||
var LEGEND_TYPES_PER_ATTRIBUTE = {
|
||||
color: ['category', 'choropleth', 'custom', 'custom_choropleth', 'torque'],
|
||||
size: ['bubble']
|
||||
};
|
||||
|
||||
function LegendBuffer (opts) {
|
||||
this.queue = [];
|
||||
this.running = false;
|
||||
this._legendDefinitionsCollection = opts.legendDefinitionsCollection;
|
||||
}
|
||||
|
||||
LegendBuffer.prototype.add = function (model, callback) {
|
||||
this._cleanQueue(model.get('layer_id'), model.get('type'));
|
||||
this.queue.push(model);
|
||||
|
||||
if (!this.running) {
|
||||
this.running = true;
|
||||
this._run(callback);
|
||||
}
|
||||
};
|
||||
|
||||
LegendBuffer.prototype._run = function (callback) {
|
||||
if (this.running === false || this.queue.length === 0) {
|
||||
this.running = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var model = this.queue.shift();
|
||||
|
||||
this._removePrevious(model.layerDefinitionModel.get('id'), model.get('type'), function () {
|
||||
model.save(null, {
|
||||
success: function (model) {
|
||||
this._legendDefinitionsCollection.add(model);
|
||||
this._run();
|
||||
}.bind(this),
|
||||
complete: function () {
|
||||
callback && callback();
|
||||
}
|
||||
});
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
LegendBuffer.prototype._removePrevious = function (layer_id, type, callback) {
|
||||
var types = this._findSameType(type);
|
||||
|
||||
var removeLegends = this._legendDefinitionsCollection.filter(function (legend) {
|
||||
return legend.get('layer_id') === layer_id && _.includes(types, legend.get('type'));
|
||||
});
|
||||
var legendsLeft = removeLegends.length;
|
||||
|
||||
if (this._legendDefinitionsCollection.size() === 0 || removeLegends.length === 0) {
|
||||
callback && callback();
|
||||
return;
|
||||
}
|
||||
|
||||
_.each(removeLegends, function (legend) {
|
||||
legend.destroy({
|
||||
complete: function () {
|
||||
// In case there's more than one legend to be removed (shouldn't be possible), we should wait for all to be removed
|
||||
legendsLeft = legendsLeft - 1;
|
||||
if (legendsLeft === 0) {
|
||||
callback && callback();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
LegendBuffer.prototype._cleanQueue = function (layer_id, type) {
|
||||
var types = this._findSameType(type);
|
||||
|
||||
this.queue = _.reject(this.queue, function (legend) {
|
||||
return legend.get('layer_id') === layer_id && _.includes(types, legend.get('type'));
|
||||
});
|
||||
};
|
||||
|
||||
LegendBuffer.prototype._findSameType = function (type) {
|
||||
return _.find(LEGEND_TYPES_PER_ATTRIBUTE, function (collection, name) {
|
||||
return _.include(collection, type);
|
||||
});
|
||||
};
|
||||
|
||||
LegendBuffer.prototype.findLegend = function (layer_id, type) {
|
||||
return _.findWhere(this.queue, { layer_id: layer_id, type: type });
|
||||
};
|
||||
|
||||
module.exports = LegendBuffer;
|
||||
lib/assets/javascripts/builder/editor/layers/layer-content-views/legend/legend-content-sql-error.tpl
Executable
+3
@@ -0,0 +1,3 @@
|
||||
<h2 class="CDB-Text CDB-Size-huge is-light u-secondaryTextColor">
|
||||
<%= body %>
|
||||
</h2>
|
||||
Executable
+217
@@ -0,0 +1,217 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var _ = require('underscore');
|
||||
var checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
var styleHelper = require('builder/helpers/style');
|
||||
|
||||
var CarouselFormView = require('builder/components/carousel-form-view');
|
||||
var CarouselCollection = require('builder/components/custom-carousel/custom-carousel-collection');
|
||||
var FormView = require('./legend-properties-form');
|
||||
|
||||
var CustomFormModel = require('./form/legend-custom-definition-form-model');
|
||||
var CategoryFormModel = require('./form/legend-category-definition-form-model');
|
||||
var BubbleFormModel = require('./form/legend-bubble-definition-form-model');
|
||||
var ChoroplethFormModel = require('./form/legend-choropleth-definition-form-model');
|
||||
var CustomChoroplethFormModel = require('./form/legend-custom-choropleth-definition-form-model');
|
||||
var TorqueFormModel = require('./form/legend-torque-definition-form-model');
|
||||
|
||||
var template = require('./legend-content.tpl');
|
||||
var LegendFactory = require('./legend-factory');
|
||||
|
||||
var DEBOUNCE_TIME = 350;
|
||||
|
||||
var REQUIRED_OPTS = [
|
||||
'editorModel',
|
||||
'legendTypes',
|
||||
'updateLegend',
|
||||
'layerDefinitionModel',
|
||||
'legendDefinitionModel',
|
||||
'legendDefinitionsCollection',
|
||||
'type',
|
||||
'userModel',
|
||||
'configModel',
|
||||
'modals'
|
||||
];
|
||||
|
||||
var LEGEND_MODEL_TYPE = {
|
||||
bubble: BubbleFormModel,
|
||||
custom: CustomFormModel,
|
||||
category: CategoryFormModel,
|
||||
choropleth: ChoroplethFormModel,
|
||||
custom_choropleth: CustomChoroplethFormModel,
|
||||
torque: TorqueFormModel
|
||||
};
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
|
||||
initialize: function (opts) {
|
||||
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
|
||||
|
||||
var type = this._legendDefinitionModel.get('type');
|
||||
|
||||
this._onDebouncedChange = _.debounce(this._updateChanges.bind(this), DEBOUNCE_TIME);
|
||||
this._lastType = type || 'none';
|
||||
|
||||
this._createFormModel(type);
|
||||
|
||||
var styleModel = this._layerDefinitionModel.styleModel;
|
||||
this._carouselCollection = new CarouselCollection(
|
||||
_.chain(this._legendTypes).filter(function (legend) {
|
||||
return legend.isStyleCompatible ? legend.isStyleCompatible(styleModel) : true;
|
||||
}, this).map(function (legend) {
|
||||
return {
|
||||
selected: type === legend.value,
|
||||
val: legend.value,
|
||||
label: legend.label,
|
||||
template: function () {
|
||||
return (legend.legendIcon && legend.legendIcon()) || legend.value;
|
||||
},
|
||||
tooltip: _t(legend.tooltipTranslationKey)
|
||||
};
|
||||
}, this).value()
|
||||
);
|
||||
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this.$el.empty();
|
||||
|
||||
this.$el.html(template());
|
||||
|
||||
this._initViews();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this._carouselCollection, 'change:selected', this._onCarouselChange);
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
var type = this._legendDefinitionModel.get('type');
|
||||
this._renderCarousel();
|
||||
this._renderForm(type);
|
||||
this._updateToggle(type);
|
||||
},
|
||||
|
||||
_createFormModel: function (type) {
|
||||
var Klass;
|
||||
var attrs;
|
||||
|
||||
if (this._formModel) {
|
||||
this._unBindFormModel(this._formModel);
|
||||
delete this._formModel;
|
||||
}
|
||||
|
||||
if (type && type !== 'none') {
|
||||
Klass = LEGEND_MODEL_TYPE[type];
|
||||
attrs = this._pickAttrs(this._legendDefinitionModel);
|
||||
this._formModel = new Klass(attrs, {
|
||||
legendDefinitionModel: this._legendDefinitionModel,
|
||||
userModel: this._userModel,
|
||||
configModel: this._configModel,
|
||||
modals: this._modals
|
||||
});
|
||||
|
||||
this._bindFormModel(this._formModel);
|
||||
}
|
||||
},
|
||||
|
||||
_pickAttrs: function (legendDefinitionModel) {
|
||||
var attrs = _.pick(legendDefinitionModel.attributes, 'title', 'prefix', 'suffix', 'leftLabel', 'rightLabel', 'topLabel', 'bottomLabel', 'items');
|
||||
return attrs;
|
||||
},
|
||||
|
||||
_onCarouselChange: function (model) {
|
||||
var type = model.getValue();
|
||||
|
||||
if (model.get('selected') === true) {
|
||||
this._updateLegendModel(type);
|
||||
this._createFormModel(type);
|
||||
this._renderForm(type);
|
||||
this._updateToggle(type);
|
||||
}
|
||||
},
|
||||
|
||||
_updateLegendModel: function (type) {
|
||||
var attrs;
|
||||
|
||||
if (type && type !== 'none') {
|
||||
attrs = this._getDefaultAttributes(this._layerDefinitionModel, type);
|
||||
LegendFactory.enableLegend(this._type);
|
||||
this._legendDefinitionModel = LegendFactory.createLegend(this._layerDefinitionModel, type, attrs);
|
||||
this._updateLegend(this._legendDefinitionModel);
|
||||
} else {
|
||||
LegendFactory.disableLegend(type);
|
||||
LegendFactory.removeLegend(this._layerDefinitionModel, this._lastType);
|
||||
this._updateLegend(null);
|
||||
delete this._legendDefinitionModel;
|
||||
}
|
||||
|
||||
this._lastType = type;
|
||||
},
|
||||
|
||||
_getDefaultAttributes: function (layerDefModel, type) {
|
||||
if (type === 'torque' || type === 'choropleth') {
|
||||
return {
|
||||
title: styleHelper.getColorAttribute(layerDefModel.styleModel)
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
_renderForm: function (type) {
|
||||
this._removeForm();
|
||||
|
||||
if (type && type !== 'none') {
|
||||
this._addForm();
|
||||
}
|
||||
},
|
||||
|
||||
_addForm: function () {
|
||||
this._formView = new FormView({
|
||||
formModel: this._formModel
|
||||
});
|
||||
this.addView(this._formView);
|
||||
this.$('.js-form').html(this._formView.render().el);
|
||||
},
|
||||
|
||||
_removeForm: function () {
|
||||
if (this._formView) {
|
||||
this.removeView(this._formView);
|
||||
this._formView.clean();
|
||||
}
|
||||
},
|
||||
|
||||
_updateToggle: function (type) {
|
||||
var isDisabled = type === 'none';
|
||||
this._editorModel.set({disabled: isDisabled});
|
||||
},
|
||||
|
||||
_renderCarousel: function () {
|
||||
var view = new CarouselFormView({
|
||||
collection: this._carouselCollection,
|
||||
template: require('./legend-form-types.tpl')
|
||||
});
|
||||
this.addView(view);
|
||||
this.$('.js-carousel').html(view.render().el);
|
||||
},
|
||||
|
||||
_bindFormModel: function (model) {
|
||||
if (model) {
|
||||
model.on('change', this._onDebouncedChange, this);
|
||||
this.add_related_model(model);
|
||||
}
|
||||
},
|
||||
|
||||
_unBindFormModel: function (model) {
|
||||
model && model.off('change', this._onDebouncedChange, this);
|
||||
},
|
||||
|
||||
_updateChanges: function () {
|
||||
if (this._legendDefinitionModel) {
|
||||
this._legendDefinitionModel.setAttributes(this._formModel.toJSON());
|
||||
LegendFactory.createLegend(this._layerDefinitionModel, this._legendDefinitionModel.get('type'));
|
||||
}
|
||||
}
|
||||
});
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
<div class="js-carousel"></div>
|
||||
<div class="js-form"></div>
|
||||
Executable
+56
@@ -0,0 +1,56 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var CodeMirrorView = require('builder/components/code-mirror/code-mirror-view');
|
||||
var ErrorTemplate = require('./code-mirror-error.tpl');
|
||||
var checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
var REQUIRED_OPTS = [
|
||||
'codemirrorModel',
|
||||
'onApplyEvent',
|
||||
'isCustom'
|
||||
];
|
||||
|
||||
var PLACEHOLDER = '[[Legend]]';
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
module: 'editor:layers:layer-content-views:legend:legend-editor-view',
|
||||
|
||||
className: 'Editor-content',
|
||||
|
||||
initialize: function (opts) {
|
||||
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this.$el.empty();
|
||||
this._initViews();
|
||||
return this;
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
this.codeMirrorView = new CodeMirrorView({
|
||||
model: this._codemirrorModel,
|
||||
tips: [
|
||||
_t('editor.legend.code-mirror.save')
|
||||
],
|
||||
errorTemplate: ErrorTemplate
|
||||
});
|
||||
|
||||
this.codeMirrorView.bind('codeSaved', this._triggerCodeSaved, this);
|
||||
this.addView(this.codeMirrorView);
|
||||
this.$el.append(this.codeMirrorView.render().el);
|
||||
|
||||
if (!this._isCustom) {
|
||||
this._markReadOnly();
|
||||
}
|
||||
},
|
||||
|
||||
_markReadOnly: function () {
|
||||
var cursor = this.codeMirrorView.search(PLACEHOLDER);
|
||||
this.codeMirrorView.markReadOnly(cursor.from, cursor.to);
|
||||
},
|
||||
|
||||
_triggerCodeSaved: function (code, view) {
|
||||
this.options.onApplyEvent && this.options.onApplyEvent();
|
||||
}
|
||||
});
|
||||
Executable
+126
@@ -0,0 +1,126 @@
|
||||
var _ = require('underscore');
|
||||
var CategoryModel = require('builder/data/legends/legend-category-definition-model');
|
||||
var BubbleModel = require('builder/data/legends/legend-bubble-definition-model');
|
||||
var ChoroplethModel = require('builder/data/legends/legend-choropleth-definition-model');
|
||||
var CustomChoroplethModel = require('builder/data/legends/legend-custom-choropleth-definition-model');
|
||||
var CustomModel = require('builder/data/legends/legend-custom-definition-model');
|
||||
var TorqueModel = require('builder/data/legends/legend-torque-definition-model');
|
||||
var Validations = require('./legend-validations');
|
||||
var Buffer = require('./legend-buffer');
|
||||
|
||||
var LEGEND_MODEL_TYPE = {
|
||||
'bubble': BubbleModel,
|
||||
'category': CategoryModel,
|
||||
'choropleth': ChoroplethModel,
|
||||
'custom_choropleth': CustomChoroplethModel,
|
||||
'custom': CustomModel,
|
||||
'torque': TorqueModel
|
||||
};
|
||||
|
||||
var manager = (function () {
|
||||
return {
|
||||
init: function (legendDefinitionsCollection) {
|
||||
if (!legendDefinitionsCollection) {
|
||||
throw new Error('legendDefinitionsCollection is required');
|
||||
}
|
||||
this.legendDefinitionsCollection = legendDefinitionsCollection;
|
||||
this.legendBuffer = new Buffer({
|
||||
legendDefinitionsCollection: this.legendDefinitionsCollection
|
||||
});
|
||||
},
|
||||
|
||||
getLegendsCollection: function () {
|
||||
return this.legendDefinitionsCollection;
|
||||
},
|
||||
|
||||
save: function (model, callback) {
|
||||
model.save(null, {complete: function (model) {
|
||||
callback && callback();
|
||||
}});
|
||||
},
|
||||
|
||||
remove: function (model, callback) {
|
||||
var self = this;
|
||||
model.destroy({
|
||||
success: function (model) {
|
||||
self.legendDefinitionsCollection.remove(model);
|
||||
},
|
||||
complete: function () {
|
||||
callback && callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
createLegend: function (layerDefModel, type, attrs, callback) {
|
||||
var model = this.legendDefinitionsCollection.findByLayerDefModelAndType(layerDefModel, type);
|
||||
var Klass;
|
||||
var validation = Validations[type];
|
||||
var isValid = validation(layerDefModel.styleModel);
|
||||
attrs = attrs || {};
|
||||
|
||||
if (!model) {
|
||||
Klass = LEGEND_MODEL_TYPE[type];
|
||||
model = new Klass(attrs, {
|
||||
layerDefinitionModel: layerDefModel,
|
||||
configModel: this.legendDefinitionsCollection.configModel,
|
||||
vizId: this.legendDefinitionsCollection.vizId,
|
||||
parse: true
|
||||
});
|
||||
|
||||
if (isValid) {
|
||||
this.legendBuffer.add(model, callback);
|
||||
}
|
||||
} else {
|
||||
if (!isValid) {
|
||||
this.remove(model, callback);
|
||||
} else {
|
||||
model.set(attrs);
|
||||
this.save(model, callback);
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
},
|
||||
|
||||
removeLegend: function (layerDefModel, type, cb) {
|
||||
var legend = this.legendDefinitionsCollection.findByLayerDefModelAndType(layerDefModel, type);
|
||||
if (legend) {
|
||||
this.remove(legend, cb);
|
||||
} else {
|
||||
cb && cb();
|
||||
}
|
||||
return legend;
|
||||
},
|
||||
|
||||
find: function (layerDefModel, type) {
|
||||
return this.legendDefinitionsCollection.findByLayerDefModelAndType(layerDefModel, type);
|
||||
},
|
||||
|
||||
removeAllLegend: function (layerDefModel) {
|
||||
var legends = this.legendDefinitionsCollection.findByLayerDefModel(layerDefModel);
|
||||
_.each(legends, function (legend) {
|
||||
legend.get('type') !== 'custom' && this.remove(legend);
|
||||
}, this);
|
||||
},
|
||||
|
||||
hasMigratedLegend: function (layerDefModel) {
|
||||
var legend = this.legendDefinitionsCollection.findByLayerDefModelAndType(layerDefModel, 'html');
|
||||
return !!legend;
|
||||
},
|
||||
|
||||
disableLegend: function (type) {
|
||||
this[type] = false;
|
||||
},
|
||||
|
||||
enableLegend: function (type) {
|
||||
this[type] = true;
|
||||
},
|
||||
|
||||
// By default, it's undefined so we are removing this condition from the equation
|
||||
isEnabledType: function (type) {
|
||||
return this[type] === undefined ? true : !!this[type];
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
module.exports = manager;
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
<div class="Editor-HeaderInfo">
|
||||
<div class="Editor-HeaderNumeration CDB-Text is-semibold u-rSpace--m">1</div>
|
||||
<div class="Editor-HeaderInfo-inner CDB-Text">
|
||||
<div class="Editor-HeaderInfo-title u-bSpace--m">
|
||||
<h2 class="CDB-Text CDB-HeaderInfo-titleText CDB-Size-large"><%- _t('editor.legend.legend-form.type.title') %></h2>
|
||||
</div>
|
||||
<div class="js-selector u-bSpace--xl">
|
||||
<p class="CDB-Text u-upperCase CDB-FontSize-small u-altTextColor u-bSpace--m js-highlight"><%- name %></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
var Backbone = require('backbone');
|
||||
var CoreView = require('backbone/core-view');
|
||||
var template = require('./legend-properties-form.tpl');
|
||||
require('builder/components/form-components/index');
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
|
||||
initialize: function (opts) {
|
||||
if (!opts.formModel) throw new Error('formModel is required');
|
||||
this._formModel = opts.formModel;
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this._removeFormView();
|
||||
this.$el.html(template());
|
||||
this._initViews();
|
||||
return this;
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
this._formView = new Backbone.Form({
|
||||
model: this._formModel
|
||||
});
|
||||
|
||||
this.listenTo(this._formView, 'change', this._updateChanges, this);
|
||||
|
||||
this.$('.js-propertiesForm').append(this._formView.render().el);
|
||||
|
||||
this.$('form').on('submit', function (event) {
|
||||
event.preventDefault();
|
||||
});
|
||||
},
|
||||
|
||||
_updateChanges: function () {
|
||||
this._formView.commit();
|
||||
},
|
||||
|
||||
_removeFormView: function () {
|
||||
this._formView && this._formView.remove();
|
||||
},
|
||||
|
||||
clean: function () {
|
||||
this.$('form').off('submit');
|
||||
this._removeFormView();
|
||||
CoreView.prototype.clean.call(this);
|
||||
}
|
||||
|
||||
});
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
<div class="Editor-HeaderInfo">
|
||||
<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.legend.legend-form.properties.title') %></h2>
|
||||
</div>
|
||||
<p class="CDB-Text u-upperCase CDB-FontSize-small u-altTextColor u-bSpace--m"><%- _t('editor.legend.legend-form.properties.subtitle') %></p>
|
||||
<div class="js-propertiesForm"></div>
|
||||
</div>
|
||||
</div>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
var LEGEND_TYPES = {
|
||||
NONE: 'none',
|
||||
BUBBLE: 'bubble',
|
||||
CATEGORY: 'category',
|
||||
CHOROPLETH: 'choropleth',
|
||||
TORQUE: 'torque',
|
||||
CUSTOM: 'custom',
|
||||
CUSTOM_CHOROPLETH: 'custom_choropleth'
|
||||
};
|
||||
|
||||
module.exports = LEGEND_TYPES;
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
var _ = require('underscore');
|
||||
|
||||
var noOp = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
var getStyleAttrs = function (styleModel) {
|
||||
var fill = styleModel.get('fill');
|
||||
var stroke = styleModel.get('stroke');
|
||||
if (!fill && !stroke || _.isEmpty(fill) && _.isEmpty(stroke)) return false;
|
||||
|
||||
return {
|
||||
fill: fill,
|
||||
stroke: stroke
|
||||
};
|
||||
};
|
||||
|
||||
var validateColorRange = function (styleModel) {
|
||||
var attributes = getStyleAttrs(styleModel);
|
||||
if (!attributes) return false;
|
||||
|
||||
var color = attributes.fill && attributes.fill.color || attributes.stroke && attributes.stroke.color;
|
||||
return color.range && color.range.length > 0;
|
||||
};
|
||||
|
||||
var validateSizeRange = function (styleModel) {
|
||||
var attributes = getStyleAttrs(styleModel);
|
||||
if (!attributes) return false;
|
||||
|
||||
var size = attributes.fill && attributes.fill.size || attributes.stroke && attributes.stroke.size;
|
||||
return size.range && size.range.length > 0;
|
||||
};
|
||||
|
||||
var validateRangeAndDomain = function (styleModel) {
|
||||
var attributes = getStyleAttrs(styleModel);
|
||||
if (!attributes) return false;
|
||||
|
||||
var color = attributes.fill && attributes.fill.color || attributes.stroke && attributes.stroke.color;
|
||||
return color.range && color.range.length > 0 && color.domain && color.domain.length > 0 && color.range && color.range.length > 0;
|
||||
};
|
||||
|
||||
var validations = {
|
||||
bubble: validateSizeRange,
|
||||
category: validateRangeAndDomain,
|
||||
torque: validateRangeAndDomain,
|
||||
choropleth: validateColorRange,
|
||||
custom_choropleth: validateColorRange,
|
||||
custom: noOp
|
||||
};
|
||||
|
||||
module.exports = validations;
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
var Backbone = require('backbone');
|
||||
var _ = require('underscore');
|
||||
var CoreView = require('backbone/core-view');
|
||||
var LegendColorView = require('./color/legend-color-view');
|
||||
var LegendSizeView = require('./size/legend-size-view');
|
||||
var LegendSizeTypes = require('./size/legend-size-types');
|
||||
var createTextLabelsTabPane = require('builder/components/tab-pane/create-text-labels-tab-pane');
|
||||
var TabPaneTemplate = require('builder/editor/tab-pane-submenu.tpl');
|
||||
var sqlErrorTemplate = require('./legend-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 InfoboxModel = require('builder/components/infobox/infobox-model');
|
||||
|
||||
var REQUIRED_OPTS = [
|
||||
'mapDefinitionModel',
|
||||
'userActions',
|
||||
'layerDefinitionModel',
|
||||
'legendDefinitionsCollection',
|
||||
'editorModel',
|
||||
'userModel',
|
||||
'configModel',
|
||||
'modals',
|
||||
'layerContentModel'
|
||||
];
|
||||
|
||||
var LEGEND_TYPES = {
|
||||
color: 'color',
|
||||
size: 'size'
|
||||
};
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
module: 'layer-content-views:legend:legends-view',
|
||||
|
||||
initialize: function (opts) {
|
||||
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
|
||||
|
||||
this._initViewState();
|
||||
this._initModels();
|
||||
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();
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_initViewState: function () {
|
||||
this._viewState = new Backbone.Model({
|
||||
isDataFiltered: false
|
||||
});
|
||||
|
||||
this._setViewValues();
|
||||
},
|
||||
|
||||
_initModels: function () {
|
||||
this._infoboxModel = new InfoboxModel({
|
||||
state: this._isLayerHidden() ? 'layer-hidden' : ''
|
||||
});
|
||||
|
||||
this._overlayModel = new Backbone.Model({
|
||||
visible: this._isLayerHidden()
|
||||
});
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this._editorModel, 'change:edition', this._changeStyle);
|
||||
this.listenTo(this._layerContentModel, 'change:state', this._setViewValues);
|
||||
this.listenTo(this._viewState, 'change:isDataFiltered', this.render);
|
||||
},
|
||||
|
||||
_isLayerHidden: function () {
|
||||
return this._layerDefinitionModel.get('visible') === false;
|
||||
},
|
||||
|
||||
_onQueryChanged: function () {
|
||||
if (this._isErrored()) {
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
|
||||
_isErrored: function () {
|
||||
return this._layerContentModel.isErrored();
|
||||
},
|
||||
|
||||
_renderError: function () {
|
||||
this.$el.append(
|
||||
sqlErrorTemplate({
|
||||
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')
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
var tabPaneTabs = [this._getColorTabPaneOptions(), this._getSizeTabPaneOptions()];
|
||||
|
||||
var tabPaneOptions = {
|
||||
tabPaneOptions: {
|
||||
template: TabPaneTemplate,
|
||||
tabPaneItemOptions: {
|
||||
tagName: 'li',
|
||||
klassName: 'CDB-NavSubmenu-item'
|
||||
}
|
||||
},
|
||||
tabPaneItemLabelOptions: {
|
||||
tagName: 'button',
|
||||
className: 'CDB-NavSubmenu-link u-upperCase'
|
||||
}
|
||||
};
|
||||
|
||||
this._layerTabPaneView = createTextLabelsTabPane(tabPaneTabs, tabPaneOptions);
|
||||
this.$el.append(this._layerTabPaneView.render().$el);
|
||||
this.addView(this._layerTabPaneView);
|
||||
this._changeStyle(this._editorModel);
|
||||
},
|
||||
|
||||
_getColorTabPaneOptions: function () {
|
||||
var self = this;
|
||||
|
||||
return {
|
||||
name: LEGEND_TYPES.color,
|
||||
label: _t('editor.legend.menu-tab-pane-labels.color'),
|
||||
createContentView: function () {
|
||||
return new LegendColorView({
|
||||
className: 'Editor-content js-type',
|
||||
mapDefinitionModel: self._mapDefinitionModel,
|
||||
editorModel: self._editorModel,
|
||||
userActions: self._userActions,
|
||||
layerContentModel: self._layerContentModel,
|
||||
layerDefinitionModel: self._layerDefinitionModel,
|
||||
legendDefinitionsCollection: self._legendDefinitionsCollection,
|
||||
type: LEGEND_TYPES.color,
|
||||
userModel: self._userModel,
|
||||
configModel: self._configModel,
|
||||
modals: self._modals,
|
||||
overlayModel: self._overlayModel,
|
||||
infoboxModel: self._infoboxModel
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
_getSizeTabPaneOptions: function () {
|
||||
var legendType = LEGEND_TYPES.size;
|
||||
var disabled = !this._isStyleCompatible(legendType);
|
||||
var self = this;
|
||||
|
||||
return {
|
||||
name: legendType,
|
||||
label: _t('editor.legend.menu-tab-pane-labels.size'),
|
||||
disabled: disabled,
|
||||
tooltip: disabled && _t('editor.legend.menu-tab-pane-labels.size-disabled'),
|
||||
createContentView: function () {
|
||||
return new LegendSizeView({
|
||||
className: 'Editor-content js-type',
|
||||
mapDefinitionModel: self._mapDefinitionModel,
|
||||
editorModel: self._editorModel,
|
||||
userActions: self._userActions,
|
||||
userModel: self._userModel,
|
||||
configModel: self._configModel,
|
||||
modals: self._modals,
|
||||
layerContentModel: self._layerContentModel,
|
||||
layerDefinitionModel: self._layerDefinitionModel,
|
||||
legendDefinitionsCollection: self._legendDefinitionsCollection,
|
||||
type: legendType,
|
||||
overlayModel: self._overlayModel,
|
||||
infoboxModel: self._infoboxModel
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
_isStyleCompatible: function (legendType) {
|
||||
if (legendType === LEGEND_TYPES.size) {
|
||||
var isCompatible = _.some(LegendSizeTypes, function (type) {
|
||||
var isStyleCompatible = type.isStyleCompatible;
|
||||
|
||||
if (isStyleCompatible) {
|
||||
return isStyleCompatible(this._layerDefinitionModel.styleModel);
|
||||
}
|
||||
|
||||
return false;
|
||||
}, this);
|
||||
|
||||
return isCompatible;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_changeStyle: function (m) {
|
||||
if (this._layerTabPaneView) { this._layerTabPaneView.changeStyleMenu(m); }
|
||||
},
|
||||
|
||||
_showHiddenLayer: function () {
|
||||
var savingOptions = {
|
||||
shouldPreserveAutoStyle: true
|
||||
};
|
||||
this._layerDefinitionModel.toggleVisible();
|
||||
this._userActions.saveLayer(this._layerDefinitionModel, savingOptions);
|
||||
},
|
||||
|
||||
_setViewValues: function () {
|
||||
this._layerDefinitionModel.isDataFiltered()
|
||||
.then(function (isDataFiltered) {
|
||||
this._viewState.set('isDataFiltered', isDataFiltered);
|
||||
}.bind(this));
|
||||
}
|
||||
});
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
var LegendTypes = require('builder/editor/layers/layer-content-views/legend/legend-types');
|
||||
var styleHelper = require('builder/helpers/style');
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
value: LegendTypes.NONE,
|
||||
tooltipTranslationKey: 'editor.legend.tooltips.style.none',
|
||||
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/none.tpl'),
|
||||
label: _t('editor.legend.types.none')
|
||||
}, {
|
||||
value: LegendTypes.BUBBLE,
|
||||
tooltipTranslationKey: 'editor.legend.tooltips.style.bubble',
|
||||
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/bubble.tpl'),
|
||||
label: _t('editor.legend.types.bubble'),
|
||||
isStyleCompatible: function (styleModel) {
|
||||
var size = styleHelper.getSize(styleModel);
|
||||
if (size == null) return false;
|
||||
|
||||
return size && size.attribute !== undefined;
|
||||
}
|
||||
}
|
||||
];
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
var LegendTypes = require('./legend-size-types');
|
||||
var LegendTypeBaseView = require('builder/editor/layers/layer-content-views/legend/legend-base-type-view');
|
||||
|
||||
module.exports = LegendTypeBaseView.extend({
|
||||
initialize: function (opts) {
|
||||
this.legendTypes = LegendTypes;
|
||||
LegendTypeBaseView.prototype.initialize.call(this, opts);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user