Initial commit

This commit is contained in:
zhongjin
2020-06-15 10:58:47 +08:00
commit 4f1dfe7564
8590 changed files with 1516878 additions and 0 deletions
@@ -0,0 +1,42 @@
var cdb = require('internal-carto.js');
var StyleUtils = require('./style-utils');
var CategoryColors = require('./category-colors');
var getValue = require('../../util/get-object-value');
var AutoStyler = cdb.core.Model.extend({
initialize: function (dataviewModel, layerModel, options) {
this.options = options || {};
this.styles = options && options.auto_style;
this.dataviewModel = dataviewModel;
this.colors = new CategoryColors(this.styles);
this.layer = layerModel;
},
getStyle: function () {
var style = this.layer.get('initialStyle');
if (!style) return;
AutoStyler.FILL_SELECTORS.forEach(function (item) {
style = StyleUtils.changeStyle(style, item, this._getFillColor(item));
}.bind(this));
AutoStyler.OPACITY_SELECTORS.forEach(function (item) {
style = StyleUtils.changeStyle(style, item, this._getOpacity());
}.bind(this));
return StyleUtils.replaceWrongSpaceChar(style);
},
_getColor: function () {
return getValue(this.styles, 'definition.color');
},
_getOpacity: function () {
return getValue(this.styles, 'definition.color.opacity');
}
});
AutoStyler.FILL_SELECTORS = ['marker-fill', 'polygon-fill', 'line-color'];
AutoStyler.OPACITY_SELECTORS = ['marker-fill-opacity', 'polygon-opacity', 'line-opacity'];
module.exports = AutoStyler;
@@ -0,0 +1,79 @@
var _ = require('underscore');
var colorScales = [
'#7F3C8D',
'#11A579',
'#3969AC',
'#F2B701',
'#E73F74'
]; // Demo colors
function getColorRange (styles) {
var colorRange = styles && styles.definition &&
styles.definition.color &&
styles.definition.color.range;
return colorRange || colorScales;
}
/**
* Class to set categories to each color
* - Right now, there is a relation 1 color to 1 category.
* - If that category is not available in the new data, that
* color will be freed.
*
*/
function CategoryColors (styles) {
this.updateColors(styles);
}
CategoryColors.prototype.updateColors = function (styles) {
var colorRange = getColorRange(styles);
this.colors = {};
_.each(colorRange, function (c) {
this.colors[c] = null;
}, this);
};
CategoryColors.prototype.updateData = function (d) {
// Remove categories from colors where they are not present anymore
_.each(this.colors, function (value, key) {
if (!_.contains(d, value)) {
this.colors[key] = null;
} else {
d = _.without(d, value);
}
}, this);
// Set colors by new categories
_.each(d, function (category) {
var nextFreeColor = this.getNextAvailableColor();
if (nextFreeColor) {
this.colors[nextFreeColor] = category;
}
}, this);
};
CategoryColors.prototype.getNextAvailableColor = function () {
for (var i in this.colors) {
if (this.colors[i] === null) {
return i;
}
}
return null;
};
CategoryColors.prototype.getColorByCategory = function (category) {
for (var i in this.colors) {
if (this.colors[i] === category) {
return i;
}
}
return '#A5AA99';
};
CategoryColors.prototype.getCategoryByColor = function (color) {
return this.colors[color];
};
module.exports = CategoryColors;
@@ -0,0 +1,67 @@
var _ = require('underscore');
var AutoStyler = require('./auto-styler');
module.exports = AutoStyler.extend({
updateStyle: function (style) {
this.styles = style.auto_style;
this.colors.updateColors(style.auto_style);
this.colors.updateData(_.pluck(this.dataviewModel.get('data'), 'name'));
},
_getRange: function () {
return _.map(this.dataviewModel.get('data'), function (category) {
return this.colors.getColorByCategory(category.name);
}, this);
},
getDef: function () {
var model = this.dataviewModel;
var categories = model.get('data');
var range = this._getRange();
var definitions = {};
AutoStyler.FILL_SELECTORS.forEach(function (item) {
var definition = {};
var geom = item.substring(0, item.indexOf('-'));
definition = { color:
{ domain: _.pluck(categories, 'name'), range: range, attribute: model.get('column') }
};
definitions[geom === 'marker' ? 'point' : geom] = definition;
});
return definitions;
},
_getFillColor: function () {
var model = this.dataviewModel;
var categories = model.get('data');
var column = model.get('column');
return this._getCategoryRamp(categories, column);
},
_getCategoryRamp: function (categories, column) {
var ramp = 'ramp([' + column + '], ';
var catListColors = '';
var catListValues = '';
for (var i = 0; i < categories.length; i++) {
var cat = categories[i];
var next = i !== categories.length - 1 ? ', ' : '';
catListColors += '"' + this.colors.getColorByCategory(cat.name) + '"' + next;
if (!cat.agg) {
if (typeof cat.name !== 'string') {
catListValues += cat.name + next;
} else {
catListValues += '"' + String(cat.name).replace(/"/g, '\\"') + '"' + next;
}
} else if (i === categories.length - 1) {
catListValues = catListValues.substring(0, catListValues.length - 2);
}
}
return ramp + '(' + catListColors + '), (' + catListValues + '), \'=\')';
}
});
@@ -0,0 +1,15 @@
var Stylers = {
category: require('./category'),
histogram: require('./histogram')
};
module.exports = {
get: function (dataviewModel, layerModel, style) {
var AutoStyler = Stylers[dataviewModel.get('type')];
if (AutoStyler) {
return new AutoStyler(dataviewModel, layerModel, style);
} else {
throw new Error('dataview type not supported');
}
}
};
@@ -0,0 +1,152 @@
var _ = require('underscore');
var cartocolor = require('cartocolor');
var AutoStyler = require('./auto-styler');
var StyleUtils = require('./style-utils');
var HistogramAutoStyler = AutoStyler.extend({
updateStyle: function (style) {
this.styles = style.auto_style;
},
_getFillColor: function (sym) {
var custom = this._getColor();
var scales = custom || {};
if (!custom) {
var shape = this.dataviewModel.getDistributionType(
this.dataviewModel.getUnfilteredDataModel().get('data')
);
scales = HistogramAutoStyler.SCALES_MAP[sym][shape];
}
var ramp = 'ramp([' + this.dataviewModel.get('column') + '], ';
var colors = custom
? "('" + scales.range.join("', '") + "'), "
: 'cartocolor(' + scales.palette + ', ' + this.dataviewModel.get('bins') + '), ';
var cuantification = scales.quantification + ')';
return ramp + colors + cuantification;
},
getDef: function (cartocss) {
var definitions = {};
var shape = this.dataviewModel.getDistributionType(
this.dataviewModel.getUnfilteredDataModel().get('data')
);
var bins = this.dataviewModel.get('bins');
var attr = this.dataviewModel.get('column');
var styles = this.styles;
var isCustomDefinition = (this.styles && this.styles.custom) || false;
AutoStyler.FILL_SELECTORS.forEach(function (item) {
if (StyleUtils.isPropertyIncluded(cartocss, item)) {
var scales = HistogramAutoStyler.SCALES_MAP[item][shape];
var geom = item.substring(0, item.indexOf('-'));
var definition = {};
if (scales) {
if (isCustomDefinition === true) {
definition = _.extend(definition, styles.definition);
} else {
definition = {
color: {
range: cartocolor[scales.palette][bins] || cartocolor[scales.palette][Object.keys(cartocolor[scales.palette]).length],
quantification: scales.quantification,
attribute: attr
}
};
}
}
definitions[geom === 'marker' ? 'point' : geom] = definition;
}
});
return definitions;
}
});
HistogramAutoStyler.SCALES_MAP = {
'polygon-fill': {
'F': {
palette: 'PinkYl',
quantification: 'equal'
},
'L': {
palette: 'Emrld',
quantification: 'headtails'
},
'J': {
palette: 'Emrld',
quantification: 'headtails'
},
'A': {
palette: 'Geyser',
quantification: 'quantiles'
},
'C': {
palette: 'Sunset',
quantification: 'jenks'
},
'U': {
palette: 'Sunset',
quantification: 'jenks'
}
},
'line-color': {
'F': {
palette: 'PinkYl',
quantification: 'equal'
},
'L': {
palette: 'Emrld',
quantification: 'headtails'
},
'J': {
palette: 'Emrld',
quantification: 'headtails'
},
'A': {
palette: 'Geyser',
quantification: 'quantiles'
},
'C': {
palette: 'Sunset',
quantification: 'jenks'
},
'U': {
palette: 'Sunset',
quantification: 'jenks'
}
},
'marker-fill': {
'F': {
palette: 'RedOr',
quantification: 'equal'
},
'L': {
palette: 'BluYl',
quantification: 'headtails'
},
'J': {
palette: 'BluYl',
quantification: 'headtails'
},
'A': {
palette: 'Geyser',
quantification: 'quantiles'
},
'C': {
palette: 'SunsetDark',
quantification: 'jenks'
},
'U': {
palette: 'SunsetDark',
quantification: 'jenks'
}
}
};
module.exports = HistogramAutoStyler;
@@ -0,0 +1,91 @@
var _ = require('underscore');
var postcss = require('postcss');
var stripInlineComments = require('postcss-strip-inline-comments');
var SCSSsyntax = require('postcss-scss');
var OUTLINE_ATTRS = ['line-color', 'line-opacity'];
function generateCSSTreeFromCartoCSS (cartocss) {
return postcss()
.use(stripInlineComments)
.process(cartocss, { syntax: SCSSsyntax });
}
function isPropertyIncluded (cartocss, attr) {
var cssTree = generateCSSTreeFromCartoCSS(cartocss);
var root = cssTree.result.root;
var propertyIncluded = false;
if (root) {
root.walkDecls(attr, function (node) {
var parentNode = node.parent;
if (!isSelectorRule(parentNode) || isMapnikGeometrySelectorRule(parentNode)) {
propertyIncluded = true;
}
});
}
return propertyIncluded;
}
function isSelectorRule (node) {
return node.type === 'rule' && node.selector.search(/\[(.)+\]/g) !== -1;
}
function isMapnikGeometrySelectorRule (node) {
return isSelectorRule(node) && node.selector.search('mapnik::geometry_type') !== -1;
}
function isOutlineRule (node) {
return node.type === 'rule' && node.selector.search('::outline') !== -1;
}
function replaceWrongSpaceChar (cartocss) {
return cartocss.replace(new RegExp(String.fromCharCode(160), 'g'), ' ');
}
/**
* Change attr style and remove all the duplicates
* @param {String} cartocss cartocss original String
* @param {String} attr CSS Attribute ex, polygon-fill
* @param {String} newStyle New style value ex, red;
* @return {String} Cartocss modified String
*/
function changeStyle (cartocss, attr, newStyle) {
if (_.isUndefined(newStyle)) return cartocss;
var cssTree = generateCSSTreeFromCartoCSS(cartocss);
var root = cssTree.result.root;
var attributeAlreadyChanged = false;
if (root) {
root.walkDecls(attr, function (node) {
var parentNode = node.parent;
if (!(isOutlineRule(parentNode) && _.contains(OUTLINE_ATTRS, attr))) {
if (isSelectorRule(parentNode) || attributeAlreadyChanged) {
// If the attribute is inside a conditional selection, it has to be removed
node.remove();
} else {
// If the attribute is inside a regular root (or symbolizer), it just
// changes the value
node.value = newStyle;
attributeAlreadyChanged = true;
}
}
});
return cssTree.css;
}
return cartocss;
}
module.exports = {
changeStyle: _.memoize(changeStyle, function (css, attr, style) {
return css + attr + style;
}),
isPropertyIncluded: isPropertyIncluded,
replaceWrongSpaceChar: replaceWrongSpaceChar
};