Compare commits
101 Commits
0.15.1-cdb
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
85881d99dd | ||
|
d3a5c97143 | ||
|
8ed3ad15c1 | ||
|
72f79efbdd | ||
|
161516b721 | ||
|
e48d5ff993 | ||
|
31abb8bee0 | ||
|
e2177cf443 | ||
|
664b45cdde | ||
|
368dad0d11 | ||
|
4dfe5361b3 | ||
|
3596991362 | ||
|
bf4c67034a | ||
|
ad5d919139 | ||
|
9fb894181d | ||
|
ffdf2d3c9b | ||
|
cbe66020f9 | ||
|
056081ace6 | ||
|
a48ba58cae | ||
|
9f67f1bdde | ||
|
55c0786130 | ||
|
fef8cb369f | ||
|
d35e54859a | ||
|
daafa9fbf2 | ||
|
34799db0cc | ||
|
41133a65ad | ||
|
1016f6870c | ||
|
72f93abf16 | ||
|
a3538d9007 | ||
|
66cc146a02 | ||
|
aab27e6be8 | ||
|
cea1e7c620 | ||
|
f8a9995050 | ||
|
0de8b82ff9 | ||
|
7d00bfdf23 | ||
|
3db2fa322b | ||
|
f4a2605a23 | ||
|
d95967247d | ||
|
da8707a17f | ||
|
3f9f6ef40d | ||
|
b051ae284e | ||
|
ea880ccf7b | ||
|
ab412165b2 | ||
|
7974fb0a05 | ||
|
59c0208caa | ||
|
9b5fb6a408 | ||
|
945f5efb74 | ||
|
decdcc5d46 | ||
|
34bd0a045d | ||
|
ed819c3b51 | ||
|
a42afef5a8 | ||
|
410ecfd3c7 | ||
|
8c75b4b0c6 | ||
|
fd94fbd2e6 | ||
|
5c4bed9593 | ||
|
2c092f6b39 | ||
|
cc2104eb49 | ||
|
c780998dc8 | ||
|
0063ddba7f | ||
|
510847a3b2 | ||
|
0c1990f655 | ||
|
7315428079 | ||
|
515fbd0991 | ||
|
975abe9b5c | ||
|
b6186d884c | ||
|
e6ba32bc07 | ||
|
fd4caf7595 | ||
|
45e59f6a5b | ||
|
dfecbbb976 | ||
|
50fa97564e | ||
|
8f9982c313 | ||
|
01c6f0c6e5 | ||
|
7e02aac641 | ||
|
4f792fbead | ||
|
9e12a3b0d8 | ||
|
09d6384b1f | ||
|
11ffba0a8e | ||
|
199d41f20d | ||
|
e931f91475 | ||
|
11d597e733 | ||
|
1960aca276 | ||
|
f17aea8657 | ||
|
dfaed546e0 | ||
|
803f0c0a49 | ||
|
0d6f9d4634 | ||
|
c042733845 | ||
|
1fc486b1b9 | ||
|
b50ee48386 | ||
|
cf5886579f | ||
|
72d005a082 | ||
|
9e8c90b6f9 | ||
|
d3e23dcb5d | ||
|
176886f1ad | ||
|
673cf38121 | ||
|
860bc0adeb | ||
|
be56e24d9a | ||
|
27850ed122 | ||
|
0d2dddf978 | ||
|
fba91a0633 | ||
|
1612b5a8b7 | ||
|
4f13aabb6c |
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@
|
||||
test/rendering/layers/
|
||||
test/rendering/cache/
|
||||
test/rendering-mss/npm-debug.log
|
||||
.idea/
|
||||
|
@ -1,7 +1,9 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "0.11"
|
||||
- "0.10"
|
||||
- '6'
|
||||
- '8'
|
||||
- '10'
|
||||
|
||||
script:
|
||||
- npm test
|
||||
|
9
CHANGELOG.carto.md
Normal file
9
CHANGELOG.carto.md
Normal file
@ -0,0 +1,9 @@
|
||||
## CARTO's Changelog
|
||||
|
||||
## 0.15.1-cdb5
|
||||
2018-11-20
|
||||
|
||||
* Support Node.js 6, 8 and, 10
|
||||
* Drop support for Node.js 0.10 and 0.11
|
||||
* Add package-lock.json
|
||||
* Add CHANGELOG.carto.md
|
@ -1,6 +1,6 @@
|
||||
# CartoCSS
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/mapbox/carto.png)](http://travis-ci.org/mapbox/carto)
|
||||
[![Build Status](https://travis-ci.org/CartoDB/carto.png?branch=master)](https://travis-ci.org/CartoDB/carto)
|
||||
|
||||
Is as stylesheet renderer for javascript, It's an evolution of the Mapnik renderer from Mapbox.
|
||||
Please, see original [Mapbox repo](http://github.com/mapbox/carto) for more information and credits
|
||||
|
@ -1,69 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var xml2js = require('xml2js'),
|
||||
fs = require('fs');
|
||||
|
||||
if (!process.argv[2]) {
|
||||
console.log('Please specify a XML file.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
fs.readFile(process.argv[2], 'utf-8', function(err, data) {
|
||||
if (err) throw err;
|
||||
|
||||
// Replace entities.
|
||||
var entities = {};
|
||||
var match = data.match(/<!ENTITY([^>]|"([^"]|\\")*")+>/g)
|
||||
if (match != null) {
|
||||
match.forEach(function(entity) {
|
||||
var parts = entity.match(/^<!ENTITY\s+(\w+)\s+"(.+)">$/);
|
||||
entities['&' + parts[1] + ';'] = parts[2];
|
||||
});
|
||||
}
|
||||
data = data.replace(/&\w+;/g, function(entity) {
|
||||
return entities[entity];
|
||||
});
|
||||
|
||||
function addAttributes(obj) {
|
||||
if (obj['$']) for (var key in obj['$']) obj[key] = obj['$'][key];
|
||||
delete obj['$'];
|
||||
return obj;
|
||||
}
|
||||
|
||||
function simplifyExternal(obj) {
|
||||
if (obj.src) return obj.src;
|
||||
else return obj;
|
||||
}
|
||||
|
||||
var parser = new xml2js.Parser({
|
||||
explicitRoot: false,
|
||||
explicitArray: false
|
||||
});
|
||||
parser.addListener('end', function(json) {
|
||||
console.log(JSON.stringify(json, function(key, value) {
|
||||
if (!key) {
|
||||
return addAttributes(value);
|
||||
}
|
||||
else if (key === 'Stylesheet') {
|
||||
if (Array.isArray(value)) return value.map(addAttributes).map(simplifyExternal);
|
||||
else return [ simplifyExternal(addAttributes(value)) ];
|
||||
}
|
||||
else if (key === 'Layer' || key === 'Stylesheet') {
|
||||
if (Array.isArray(value)) return value.map(addAttributes);
|
||||
else return [ addAttributes(value) ];
|
||||
}
|
||||
else if (key === 'Datasource') {
|
||||
value = addAttributes(value);
|
||||
value.Parameter.forEach(function(parameter) {
|
||||
value[parameter['$'].name] = parameter['_'];
|
||||
});
|
||||
delete value.Parameter;
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
}, 4));
|
||||
});
|
||||
parser.parseString(data);
|
||||
});
|
8
dist/carto.js
vendored
8
dist/carto.js
vendored
File diff suppressed because one or more lines are too long
320
dist/carto.uncompressed.js
vendored
320
dist/carto.uncompressed.js
vendored
@ -268,7 +268,7 @@ var carto = {
|
||||
if (typeof(extract[2]) === 'string') {
|
||||
error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
|
||||
}
|
||||
error = options.indent + error.join('\n' + options.indent) + '\033[0m\n';
|
||||
error = options.indent + error.join('\n' + options.indent) + '\x1B[0m\n';
|
||||
|
||||
message = options.indent + message + stylize(ctx.message, 'red');
|
||||
if (ctx.filename) (message += stylize(' in ', 'red') + ctx.filename);
|
||||
@ -326,12 +326,12 @@ function stylize(str, style) {
|
||||
'red' : [31, 39],
|
||||
'grey' : [90, 39]
|
||||
};
|
||||
return '\033[' + styles[style][0] + 'm' + str +
|
||||
'\033[' + styles[style][1] + 'm';
|
||||
return '\x1B[' + styles[style][0] + 'm' + str +
|
||||
'\x1B[' + styles[style][1] + 'm';
|
||||
}
|
||||
|
||||
}).call(this,require('_process'),"/lib/carto")
|
||||
},{"../../package.json":44,"./functions":1,"./parser":3,"./renderer":4,"./renderer_js":5,"./torque-reference":6,"./tree":7,"./tree/call":8,"./tree/color":9,"./tree/comment":10,"./tree/definition":11,"./tree/dimension":12,"./tree/element":13,"./tree/expression":14,"./tree/field":15,"./tree/filter":16,"./tree/filterset":17,"./tree/fontset":18,"./tree/frame_offset":19,"./tree/imagefilter":20,"./tree/invalid":21,"./tree/keyword":22,"./tree/layer":23,"./tree/literal":24,"./tree/operation":25,"./tree/quoted":26,"./tree/reference":27,"./tree/rule":28,"./tree/ruleset":29,"./tree/selector":30,"./tree/style":31,"./tree/url":32,"./tree/value":33,"./tree/variable":34,"./tree/zoom":35,"_process":40,"fs":36,"path":39,"util":42}],3:[function(require,module,exports){
|
||||
},{"../../package.json":44,"./functions":1,"./parser":3,"./renderer":4,"./renderer_js":5,"./torque-reference":6,"./tree":7,"./tree/call":8,"./tree/color":9,"./tree/comment":10,"./tree/definition":11,"./tree/dimension":12,"./tree/element":13,"./tree/expression":14,"./tree/field":15,"./tree/filter":16,"./tree/filterset":17,"./tree/fontset":18,"./tree/frame_offset":19,"./tree/imagefilter":20,"./tree/invalid":21,"./tree/keyword":22,"./tree/layer":23,"./tree/literal":24,"./tree/operation":25,"./tree/quoted":26,"./tree/reference":27,"./tree/rule":28,"./tree/ruleset":29,"./tree/selector":30,"./tree/style":31,"./tree/url":32,"./tree/value":33,"./tree/variable":34,"./tree/zoom":35,"_process":40,"fs":37,"path":39,"util":43}],3:[function(require,module,exports){
|
||||
(function (global){
|
||||
var carto = exports,
|
||||
tree = require('./tree'),
|
||||
@ -449,8 +449,9 @@ carto.Parser = function Parser(env) {
|
||||
// - `index`: Char. index where the error occurred.
|
||||
function makeError(err) {
|
||||
var einput;
|
||||
var errorTemplate;
|
||||
|
||||
_(err).defaults({
|
||||
_.defaults(err, {
|
||||
index: furthest,
|
||||
filename: env.filename,
|
||||
message: 'Parse error.',
|
||||
@ -468,8 +469,8 @@ carto.Parser = function Parser(env) {
|
||||
for (var n = err.index; n >= 0 && einput.charAt(n) !== '\n'; n--) {
|
||||
err.column++;
|
||||
}
|
||||
|
||||
return new Error(_('<%=filename%>:<%=line%>:<%=column%> <%=message%>').template(err));
|
||||
errorTemplate = _.template('<%=filename%>:<%=line%>:<%=column%> <%=message%>');
|
||||
return new Error(errorTemplate(err));
|
||||
}
|
||||
|
||||
this.env = env = env || {};
|
||||
@ -811,6 +812,7 @@ carto.Parser = function Parser(env) {
|
||||
return new tree.Dimension(value[1], value[2], memo);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// The variable part of a variable definition.
|
||||
@ -1059,10 +1061,22 @@ carto.Parser = function Parser(env) {
|
||||
},
|
||||
// A sub-expression, contained by parenthensis
|
||||
sub: function() {
|
||||
var e;
|
||||
var e, expressions = [];
|
||||
|
||||
if ($('(') && (e = $(this.expression)) && $(')')) {
|
||||
return e;
|
||||
if ($('(')) {
|
||||
while (e = $(this.expression)) {
|
||||
expressions.push(e);
|
||||
if (! $(',')) { break; }
|
||||
}
|
||||
$(')');
|
||||
}
|
||||
|
||||
if (expressions.length > 1) {
|
||||
return new tree.Value(expressions.map(function(e) {
|
||||
return e.value[0];
|
||||
}));
|
||||
} else if (expressions.length === 1) {
|
||||
return new tree.Value(expressions);
|
||||
}
|
||||
},
|
||||
// This is a misnomer because it actually handles multiplication
|
||||
@ -1136,7 +1150,7 @@ carto.Renderer = function Renderer(env, options) {
|
||||
carto.Renderer.prototype.renderMSS = function render(data) {
|
||||
// effects is a container for side-effects, which currently
|
||||
// are limited to FontSets.
|
||||
var env = _(this.env).defaults({
|
||||
var env = _.defaults(this.env, {
|
||||
benchmark: false,
|
||||
validation_data: false,
|
||||
effects: []
|
||||
@ -1190,7 +1204,7 @@ carto.Renderer.prototype.renderMSS = function render(data) {
|
||||
carto.Renderer.prototype.render = function render(m) {
|
||||
// effects is a container for side-effects, which currently
|
||||
// are limited to FontSets.
|
||||
var env = _(this.env).defaults({
|
||||
var env = _.defaults(this.env, {
|
||||
benchmark: false,
|
||||
validation_data: false,
|
||||
effects: [],
|
||||
@ -1204,14 +1218,14 @@ carto.Renderer.prototype.render = function render(m) {
|
||||
var output = [];
|
||||
|
||||
// Transform stylesheets into definitions.
|
||||
var definitions = _(m.Stylesheet).chain()
|
||||
var definitions = _.chain(m.Stylesheet)
|
||||
.map(function(s) {
|
||||
if (typeof s == 'string') {
|
||||
throw new Error("Stylesheet object is expected not a string: '" + s + "'");
|
||||
}
|
||||
// Passing the environment from stylesheet to stylesheet,
|
||||
// allows frames and effects to be maintained.
|
||||
env = _(env).extend({filename:s.id});
|
||||
env = _.extend(env, {filename:s.id});
|
||||
|
||||
var time = +new Date(),
|
||||
root = (carto.Parser(env)).parse(s.data);
|
||||
@ -1272,7 +1286,7 @@ carto.Renderer.prototype.render = function render(m) {
|
||||
if (env.errors) throw env.errors;
|
||||
|
||||
// Pass TileJSON and other custom parameters through to Mapnik XML.
|
||||
var parameters = _(m).reduce(function(memo, v, k) {
|
||||
var parameters = _.reduce(m, function(memo, v, k) {
|
||||
if (!v && v !== 0) return memo;
|
||||
|
||||
switch (k) {
|
||||
@ -1325,7 +1339,7 @@ carto.Renderer.prototype.render = function render(m) {
|
||||
'\n</Parameters>\n'
|
||||
);
|
||||
|
||||
var properties = _(map_properties).map(function(v) { return ' ' + v; }).join('');
|
||||
var properties = _.map(map_properties, function(v) { return ' ' + v; }).join('');
|
||||
|
||||
output.unshift(
|
||||
'<?xml version="1.0" ' +
|
||||
@ -1583,7 +1597,7 @@ CartoCSS.Layer.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* return the symbolizers that need to be rendered with
|
||||
* return the symbolizers that need to be rendered with
|
||||
* this style. The order is the rendering order.
|
||||
* @returns a list with 3 possible values 'line', 'marker', 'polygon'
|
||||
*/
|
||||
@ -1625,7 +1639,7 @@ CartoCSS.Layer.prototype = {
|
||||
|
||||
//
|
||||
// given a geoemtry type returns the transformed one acording the CartoCSS
|
||||
// For points there are two kind of types: point and sprite, the first one
|
||||
// For points there are two kind of types: point and sprite, the first one
|
||||
// is a circle, second one is an image sprite
|
||||
//
|
||||
// the other geometry types are the same than geojson (polygon, linestring...)
|
||||
@ -1728,12 +1742,15 @@ CartoCSS.prototype = {
|
||||
var layer = layers[key] = (layers[key] || {
|
||||
symbolizers: []
|
||||
});
|
||||
|
||||
for(var u = 0; u<def.rules.length; u++){
|
||||
if(def.rules[u].name === "marker-file" || def.rules[u].name === "point-file"){
|
||||
var value = def.rules[u].value.value[0].value[0].value.value;
|
||||
this.imageURLs.push(value);
|
||||
var rule = def.rules[u];
|
||||
if(rule.name === "marker-file" || rule.name === "point-file"){
|
||||
var value = rule.value.value[0].value[0].value.value;
|
||||
this.imageURLs.push(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layer.frames = [];
|
||||
layer.zoom = tree.Zoom.all;
|
||||
var props = def.toJS(parse_env);
|
||||
@ -1752,6 +1769,8 @@ CartoCSS.prototype = {
|
||||
// serach the max index to know rendering order
|
||||
lyr.index = _.max(props[v].map(function(a) { return a.index; }).concat(lyr.index));
|
||||
lyr.constant = !_.any(props[v].map(function(a) { return !a.constant; }));
|
||||
// True when the property is filtered.
|
||||
lyr.filtered = props[v][0].filtered;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1761,6 +1780,14 @@ CartoCSS.prototype = {
|
||||
var done = {};
|
||||
for(var i = 0; i < defs.length; ++i) {
|
||||
var def = defs[i];
|
||||
|
||||
if (this.options.strict) {
|
||||
def.toXML(parse_env, {});
|
||||
if (parse_env.errors.message) {
|
||||
throw new Error(parse_env.errors.message);
|
||||
}
|
||||
}
|
||||
|
||||
var k = defKey(def);
|
||||
var layer = layers[k];
|
||||
if(!done[k]) {
|
||||
@ -1797,12 +1824,13 @@ CartoCSS.prototype = {
|
||||
carto.RendererJS = function (options) {
|
||||
this.options = options || {};
|
||||
this.options.mapnik_version = this.options.mapnik_version || 'latest';
|
||||
this.reference = this.options.reference || require('./torque-reference').version.latest;
|
||||
this.options.strict = this.options.hasOwnProperty('strict') ? this.options.strict : false;
|
||||
};
|
||||
|
||||
// Prepare a javascript object which contains the layers
|
||||
carto.RendererJS.prototype.render = function render(cartocss, callback) {
|
||||
var reference = require('./torque-reference');
|
||||
tree.Reference.setData(reference.version.latest);
|
||||
tree.Reference.setData(this.reference);
|
||||
return new CartoCSS(cartocss, this.options);
|
||||
}
|
||||
|
||||
@ -1842,7 +1870,10 @@ var _mapnik_reference_latest = {
|
||||
["x-gradient", 0],
|
||||
["y-gradient", 0],
|
||||
["invert", 0],
|
||||
["sharpen", 0]
|
||||
["sharpen", 0],
|
||||
["colorize-alpha", -1],
|
||||
["color-to-alpha", 1],
|
||||
["scale-hsla", 8]
|
||||
],
|
||||
"doc": "A list of image filters."
|
||||
},
|
||||
@ -1977,7 +2008,20 @@ var _mapnik_reference_latest = {
|
||||
["x-gradient", 0],
|
||||
["y-gradient", 0],
|
||||
["invert", 0],
|
||||
["sharpen", 0]
|
||||
["sharpen", 0],
|
||||
["colorize-alpha", -1],
|
||||
["color-to-alpha", 1],
|
||||
["scale-hsla", 8],
|
||||
["buckets", -1],
|
||||
["category", -1],
|
||||
["equal", -1],
|
||||
["headtails", -1],
|
||||
["jenks", -1],
|
||||
["quantiles", -1],
|
||||
["cartocolor", -1],
|
||||
["colorbrewer", -1],
|
||||
["range", -1],
|
||||
["ramp", -1]
|
||||
],
|
||||
"doc": "A list of image filters."
|
||||
},
|
||||
@ -2104,14 +2148,16 @@ var _mapnik_reference_latest = {
|
||||
"type": "color",
|
||||
"default-value": "rgba(128,128,128,1)",
|
||||
"default-meaning": "gray and fully opaque (alpha = 1), same as rgb(128,128,128)",
|
||||
"doc": "Fill color to assign to a polygon"
|
||||
"doc": "Fill color to assign to a polygon",
|
||||
"expression": true
|
||||
},
|
||||
"fill-opacity": {
|
||||
"css": "polygon-opacity",
|
||||
"type": "float",
|
||||
"doc": "The opacity of the polygon",
|
||||
"default-value": 1,
|
||||
"default-meaning": "opaque"
|
||||
"default-meaning": "opaque",
|
||||
"expression": true
|
||||
},
|
||||
"gamma": {
|
||||
"css": "polygon-gamma",
|
||||
@ -2212,13 +2258,15 @@ var _mapnik_reference_latest = {
|
||||
"default-value": "rgba(0,0,0,1)",
|
||||
"type": "color",
|
||||
"default-meaning": "black and fully opaque (alpha = 1), same as rgb(0,0,0)",
|
||||
"doc": "The color of a drawn line"
|
||||
"doc": "The color of a drawn line",
|
||||
"expression": true
|
||||
},
|
||||
"stroke-width": {
|
||||
"css": "line-width",
|
||||
"default-value": 1,
|
||||
"type": "float",
|
||||
"doc": "The width of a line in pixels"
|
||||
"doc": "The width of a line in pixels",
|
||||
"expression": true
|
||||
},
|
||||
"stroke-opacity": {
|
||||
"css": "line-opacity",
|
||||
@ -2383,7 +2431,8 @@ var _mapnik_reference_latest = {
|
||||
"doc": "An SVG file that this marker shows at each placement. If no file is given, the marker will show an ellipse.",
|
||||
"default-value": "",
|
||||
"default-meaning": "An ellipse or circle, if width equals height",
|
||||
"type": "uri"
|
||||
"type": "uri",
|
||||
"expression": true
|
||||
},
|
||||
"opacity": {
|
||||
"css": "marker-opacity",
|
||||
@ -2467,7 +2516,8 @@ var _mapnik_reference_latest = {
|
||||
"css": "marker-fill",
|
||||
"default-value": "blue",
|
||||
"doc": "The color of the area of the marker.",
|
||||
"type": "color"
|
||||
"type": "color",
|
||||
"expression": true
|
||||
},
|
||||
"allow-overlap": {
|
||||
"css": "marker-allow-overlap",
|
||||
@ -2842,7 +2892,8 @@ var _mapnik_reference_latest = {
|
||||
"type": "uri",
|
||||
"default-value": "none",
|
||||
"required": true,
|
||||
"doc": "An image file to be repeated and warped along a line"
|
||||
"doc": "An image file to be repeated and warped along a line",
|
||||
"expression": true
|
||||
},
|
||||
"clip": {
|
||||
"css": "line-pattern-clip",
|
||||
@ -2922,7 +2973,8 @@ var _mapnik_reference_latest = {
|
||||
"type": "uri",
|
||||
"default-value": "none",
|
||||
"required": true,
|
||||
"doc": "Image to use as a repeated pattern fill within a polygon"
|
||||
"doc": "Image to use as a repeated pattern fill within a polygon",
|
||||
"expression": true
|
||||
},
|
||||
"alignment": {
|
||||
"css": "polygon-pattern-alignment",
|
||||
@ -4179,48 +4231,37 @@ tree.Definition.prototype.toXML = function(env, existing) {
|
||||
|
||||
tree.Definition.prototype.toJS = function(env) {
|
||||
var shaderAttrs = {};
|
||||
|
||||
// merge conditions from filters with zoom condition of the
|
||||
// definition
|
||||
var zoom = "(" + this.zoom + " & (1 << ctx.zoom))";
|
||||
var frame_offset = this.frame_offset;
|
||||
var _if = this.filters.toJS(env);
|
||||
var filters = [zoom];
|
||||
if(_if) filters.push(_if);
|
||||
if(frame_offset) filters.push('ctx["frame-offset"] === ' + frame_offset);
|
||||
_if = filters.join(" && ");
|
||||
_.each(this.rules, function(rule) {
|
||||
if(rule instanceof tree.Rule) {
|
||||
shaderAttrs[rule.name] = shaderAttrs[rule.name] || [];
|
||||
var zoomFilter = "(" + this.zoom + " & (1 << ctx.zoom))";
|
||||
var filters = [zoomFilter];
|
||||
var originalFilters = this.filters.toJS(env);
|
||||
// Ignore default zoom for filtering (https://github.com/CartoDB/carto/issues/40)
|
||||
var zoomFiltered = this.zoom !== tree.Zoom.all;
|
||||
|
||||
if (originalFilters) {
|
||||
filters.push(originalFilters);
|
||||
}
|
||||
|
||||
var r = {
|
||||
index: rule.index,
|
||||
symbolizer: rule.symbolizer
|
||||
};
|
||||
if (frame_offset) {
|
||||
filters.push('ctx["frame-offset"] === ' + frame_offset);
|
||||
}
|
||||
|
||||
if (_if) {
|
||||
r.js = "if(" + _if + "){" + rule.value.toJS(env) + "}"
|
||||
} else {
|
||||
r.js = rule.value.toJS(env);
|
||||
}
|
||||
_.each(this.rules, function (rule) {
|
||||
var exportedRule = {};
|
||||
|
||||
r.constant = rule.value.ev(env).is !== 'field';
|
||||
r.filtered = !!_if;
|
||||
|
||||
shaderAttrs[rule.name].push(r);
|
||||
} else {
|
||||
throw new Error("Ruleset not supported");
|
||||
//if (rule instanceof tree.Ruleset) {
|
||||
//var sh = rule.toJS(env);
|
||||
//for(var v in sh) {
|
||||
//shaderAttrs[v] = shaderAttrs[v] || [];
|
||||
//for(var attr in sh[v]) {
|
||||
//shaderAttrs[v].push(sh[v][attr]);
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
if (!rule instanceof tree.Rule) {
|
||||
throw new Error("Ruleset not supported");
|
||||
}
|
||||
|
||||
exportedRule.index = rule.index;
|
||||
exportedRule.symbolizer = rule.symbolizer;
|
||||
exportedRule.js = "if(" + filters.join(" && ") + "){" + rule.value.toJS(env) + "}";
|
||||
exportedRule.constant = rule.value.ev(env).is !== 'field';
|
||||
exportedRule.filtered = zoomFiltered || (originalFilters !== '');
|
||||
shaderAttrs[rule.name] = shaderAttrs[rule.name] || [];
|
||||
shaderAttrs[rule.name].push(exportedRule);
|
||||
});
|
||||
|
||||
return shaderAttrs;
|
||||
};
|
||||
|
||||
@ -4228,7 +4269,7 @@ tree.Definition.prototype.toJS = function(env) {
|
||||
})(require('../tree'));
|
||||
|
||||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||
},{"../tree":7,"assert":37,"underscore":undefined}],12:[function(require,module,exports){
|
||||
},{"../tree":7,"assert":36,"underscore":undefined}],12:[function(require,module,exports){
|
||||
(function (global){
|
||||
(function(tree) {
|
||||
var _ = global._ || require('underscore');
|
||||
@ -4576,7 +4617,10 @@ tree.Filterset.prototype.toJS = function(env) {
|
||||
val = filter._val.toString(true);
|
||||
}
|
||||
var attrs = "data";
|
||||
return attrs + "." + filter.key.value + " " + op + " " + (val.is === 'string' ? "'"+ val +"'" : val);
|
||||
if (op === '=~') {
|
||||
return "(" + attrs + "['" + filter.key.value + "'] + '').match(" + (val.is === 'string' ? "'" + val.toString().replace(/'/g, "\\'") + "'" : val) + ")";
|
||||
}
|
||||
return attrs + "['" + filter.key.value + "'] " + op + " " + (val.is === 'string' ? "'" + val.toString().replace(/'/g, "\\'") + "'" : val);
|
||||
}).join(' && ');
|
||||
};
|
||||
|
||||
@ -5295,7 +5339,7 @@ tree.Reference = ref;
|
||||
})(require('../tree'));
|
||||
|
||||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||
},{"../tree":7,"mapnik-reference":43,"underscore":undefined}],28:[function(require,module,exports){
|
||||
},{"../tree":7,"mapnik-reference":38,"underscore":undefined}],28:[function(require,module,exports){
|
||||
(function(tree) {
|
||||
// a rule is a single property and value combination, or variable
|
||||
// name and value combination, like
|
||||
@ -5756,7 +5800,14 @@ tree.Value.prototype = {
|
||||
v = "'" + v + "'";
|
||||
} else if (val.is === 'field') {
|
||||
// replace [variable] by ctx['variable']
|
||||
v = v.replace(/\[(.*)\]/g, "data['$1']");
|
||||
v = v.replace(/\[([^\]]*)\]/g, function(matched) {
|
||||
return matched.replace(/\[(.*)\]/g, "data['$1']");
|
||||
});
|
||||
}else if (val.is === 'call') {
|
||||
v = JSON.stringify({
|
||||
name: val.name,
|
||||
args: val.args
|
||||
})
|
||||
}
|
||||
return "_value = " + v + ";";
|
||||
}
|
||||
@ -5929,8 +5980,6 @@ tree.Zoom.prototype.toString = function() {
|
||||
};
|
||||
|
||||
},{"../tree":7}],36:[function(require,module,exports){
|
||||
|
||||
},{}],37:[function(require,module,exports){
|
||||
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
|
||||
//
|
||||
// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
|
||||
@ -6292,32 +6341,38 @@ var objectKeys = Object.keys || function (obj) {
|
||||
return keys;
|
||||
};
|
||||
|
||||
},{"util/":42}],38:[function(require,module,exports){
|
||||
if (typeof Object.create === 'function') {
|
||||
// implementation from standard node.js 'util' module
|
||||
module.exports = function inherits(ctor, superCtor) {
|
||||
ctor.super_ = superCtor
|
||||
ctor.prototype = Object.create(superCtor.prototype, {
|
||||
constructor: {
|
||||
value: ctor,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
};
|
||||
} else {
|
||||
// old school shim for old browsers
|
||||
module.exports = function inherits(ctor, superCtor) {
|
||||
ctor.super_ = superCtor
|
||||
var TempCtor = function () {}
|
||||
TempCtor.prototype = superCtor.prototype
|
||||
ctor.prototype = new TempCtor()
|
||||
ctor.prototype.constructor = ctor
|
||||
}
|
||||
}
|
||||
},{"util/":43}],37:[function(require,module,exports){
|
||||
|
||||
},{}],39:[function(require,module,exports){
|
||||
},{}],38:[function(require,module,exports){
|
||||
(function (__dirname){
|
||||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
existsSync = require('fs').existsSync || require('path').existsSync;
|
||||
|
||||
// Load all stated versions into the module exports
|
||||
module.exports.version = {};
|
||||
|
||||
var refs = [
|
||||
'2.0.0',
|
||||
'2.0.1',
|
||||
'2.0.2',
|
||||
'2.1.0',
|
||||
'2.1.1',
|
||||
'2.2.0',
|
||||
'2.3.0',
|
||||
'3.0.0'
|
||||
];
|
||||
|
||||
refs.map(function(version) {
|
||||
module.exports.version[version] = require(path.join(__dirname, version, 'reference.json'));
|
||||
var ds_path = path.join(__dirname, version, 'datasources.json');
|
||||
if (existsSync(ds_path)) {
|
||||
module.exports.version[version].datasources = require(ds_path).datasources;
|
||||
}
|
||||
});
|
||||
|
||||
}).call(this,"/node_modules/mapnik-reference")
|
||||
},{"fs":37,"path":39}],39:[function(require,module,exports){
|
||||
(function (process){
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
@ -6634,13 +6689,38 @@ process.chdir = function (dir) {
|
||||
};
|
||||
|
||||
},{}],41:[function(require,module,exports){
|
||||
if (typeof Object.create === 'function') {
|
||||
// implementation from standard node.js 'util' module
|
||||
module.exports = function inherits(ctor, superCtor) {
|
||||
ctor.super_ = superCtor
|
||||
ctor.prototype = Object.create(superCtor.prototype, {
|
||||
constructor: {
|
||||
value: ctor,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
};
|
||||
} else {
|
||||
// old school shim for old browsers
|
||||
module.exports = function inherits(ctor, superCtor) {
|
||||
ctor.super_ = superCtor
|
||||
var TempCtor = function () {}
|
||||
TempCtor.prototype = superCtor.prototype
|
||||
ctor.prototype = new TempCtor()
|
||||
ctor.prototype.constructor = ctor
|
||||
}
|
||||
}
|
||||
|
||||
},{}],42:[function(require,module,exports){
|
||||
module.exports = function isBuffer(arg) {
|
||||
return arg && typeof arg === 'object'
|
||||
&& typeof arg.copy === 'function'
|
||||
&& typeof arg.fill === 'function'
|
||||
&& typeof arg.readUInt8 === 'function';
|
||||
}
|
||||
},{}],42:[function(require,module,exports){
|
||||
},{}],43:[function(require,module,exports){
|
||||
(function (process,global){
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
@ -7230,39 +7310,10 @@ function hasOwnProperty(obj, prop) {
|
||||
}
|
||||
|
||||
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||
},{"./support/isBuffer":41,"_process":40,"inherits":38}],43:[function(require,module,exports){
|
||||
(function (__dirname){
|
||||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
existsSync = require('fs').existsSync || require('path').existsSync;
|
||||
|
||||
// Load all stated versions into the module exports
|
||||
module.exports.version = {};
|
||||
|
||||
var refs = [
|
||||
'2.0.0',
|
||||
'2.0.1',
|
||||
'2.0.2',
|
||||
'2.1.0',
|
||||
'2.1.1',
|
||||
'2.2.0',
|
||||
'2.3.0',
|
||||
'3.0.0'
|
||||
];
|
||||
|
||||
refs.map(function(version) {
|
||||
module.exports.version[version] = require(path.join(__dirname, version, 'reference.json'));
|
||||
var ds_path = path.join(__dirname, version, 'datasources.json');
|
||||
if (existsSync(ds_path)) {
|
||||
module.exports.version[version].datasources = require(ds_path).datasources;
|
||||
}
|
||||
});
|
||||
|
||||
}).call(this,"/node_modules/mapnik-reference")
|
||||
},{"fs":36,"path":39}],44:[function(require,module,exports){
|
||||
},{"./support/isBuffer":42,"_process":40,"inherits":41}],44:[function(require,module,exports){
|
||||
module.exports={
|
||||
"name": "carto",
|
||||
"version": "0.15.1",
|
||||
"version": "0.15.1-cdb4",
|
||||
"description": "CartoCSS Stylesheet Compiler",
|
||||
"url": "https://github.com/cartodb/carto",
|
||||
"repository": {
|
||||
@ -7299,7 +7350,7 @@ module.exports={
|
||||
"node": ">=0.4.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"underscore": "~1.6.0",
|
||||
"underscore": "1.8.3",
|
||||
"mapnik-reference": "~6.0.2",
|
||||
"optimist": "~0.6.0"
|
||||
},
|
||||
@ -7315,6 +7366,7 @@ module.exports={
|
||||
"scripts": {
|
||||
"pretest": "npm install",
|
||||
"test": "mocha -R spec",
|
||||
"tdd" : "env HIDE_LOGS=true mocha -w -R spec",
|
||||
"coverage": "istanbul cover ./node_modules/.bin/_mocha && coveralls < ./coverage/lcov.info"
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ line-color: yellow;
|
||||
}
|
||||
```
|
||||
|
||||
Especially of note is the support for hsl, which can be [easier to reason about than rgb()](http://mothereffinghsl.com/). Carto also includes several color functions [borrowed from less](http://lesscss.org/#-color-functions):
|
||||
Especially of note is the support for hsl, which can be [easier to reason about than rgb()](http://mothereffinghsl.com/). Carto also includes several color operation functions [borrowed from less](http://lesscss.org/functions/#color-operations):
|
||||
|
||||
``` css
|
||||
// lighten and darken colors
|
||||
|
@ -53,7 +53,7 @@ var carto = {
|
||||
if (typeof(extract[2]) === 'string') {
|
||||
error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
|
||||
}
|
||||
error = options.indent + error.join('\n' + options.indent) + '\033[0m\n';
|
||||
error = options.indent + error.join('\n' + options.indent) + '\x1B[0m\n';
|
||||
|
||||
message = options.indent + message + stylize(ctx.message, 'red');
|
||||
if (ctx.filename) (message += stylize(' in ', 'red') + ctx.filename);
|
||||
@ -111,6 +111,6 @@ function stylize(str, style) {
|
||||
'red' : [31, 39],
|
||||
'grey' : [90, 39]
|
||||
};
|
||||
return '\033[' + styles[style][0] + 'm' + str +
|
||||
'\033[' + styles[style][1] + 'm';
|
||||
return '\x1B[' + styles[style][0] + 'm' + str +
|
||||
'\x1B[' + styles[style][1] + 'm';
|
||||
}
|
||||
|
@ -114,8 +114,9 @@ carto.Parser = function Parser(env) {
|
||||
// - `index`: Char. index where the error occurred.
|
||||
function makeError(err) {
|
||||
var einput;
|
||||
var errorTemplate;
|
||||
|
||||
_(err).defaults({
|
||||
_.defaults(err, {
|
||||
index: furthest,
|
||||
filename: env.filename,
|
||||
message: 'Parse error.',
|
||||
@ -133,8 +134,8 @@ carto.Parser = function Parser(env) {
|
||||
for (var n = err.index; n >= 0 && einput.charAt(n) !== '\n'; n--) {
|
||||
err.column++;
|
||||
}
|
||||
|
||||
return new Error(_('<%=filename%>:<%=line%>:<%=column%> <%=message%>').template(err));
|
||||
errorTemplate = _.template('<%=filename%>:<%=line%>:<%=column%> <%=message%>');
|
||||
return new Error(errorTemplate(err));
|
||||
}
|
||||
|
||||
this.env = env = env || {};
|
||||
@ -476,6 +477,7 @@ carto.Parser = function Parser(env) {
|
||||
return new tree.Dimension(value[1], value[2], memo);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// The variable part of a variable definition.
|
||||
@ -724,10 +726,22 @@ carto.Parser = function Parser(env) {
|
||||
},
|
||||
// A sub-expression, contained by parenthensis
|
||||
sub: function() {
|
||||
var e;
|
||||
var e, expressions = [];
|
||||
|
||||
if ($('(') && (e = $(this.expression)) && $(')')) {
|
||||
return e;
|
||||
if ($('(')) {
|
||||
while (e = $(this.expression)) {
|
||||
expressions.push(e);
|
||||
if (! $(',')) { break; }
|
||||
}
|
||||
$(')');
|
||||
}
|
||||
|
||||
if (expressions.length > 1) {
|
||||
return new tree.Value(expressions.map(function(e) {
|
||||
return e.value[0];
|
||||
}));
|
||||
} else if (expressions.length === 1) {
|
||||
return new tree.Value(expressions);
|
||||
}
|
||||
},
|
||||
// This is a misnomer because it actually handles multiplication
|
||||
|
@ -16,7 +16,7 @@ carto.Renderer = function Renderer(env, options) {
|
||||
carto.Renderer.prototype.renderMSS = function render(data) {
|
||||
// effects is a container for side-effects, which currently
|
||||
// are limited to FontSets.
|
||||
var env = _(this.env).defaults({
|
||||
var env = _.defaults(this.env, {
|
||||
benchmark: false,
|
||||
validation_data: false,
|
||||
effects: []
|
||||
@ -70,7 +70,7 @@ carto.Renderer.prototype.renderMSS = function render(data) {
|
||||
carto.Renderer.prototype.render = function render(m) {
|
||||
// effects is a container for side-effects, which currently
|
||||
// are limited to FontSets.
|
||||
var env = _(this.env).defaults({
|
||||
var env = _.defaults(this.env, {
|
||||
benchmark: false,
|
||||
validation_data: false,
|
||||
effects: [],
|
||||
@ -84,14 +84,14 @@ carto.Renderer.prototype.render = function render(m) {
|
||||
var output = [];
|
||||
|
||||
// Transform stylesheets into definitions.
|
||||
var definitions = _(m.Stylesheet).chain()
|
||||
var definitions = _.chain(m.Stylesheet)
|
||||
.map(function(s) {
|
||||
if (typeof s == 'string') {
|
||||
throw new Error("Stylesheet object is expected not a string: '" + s + "'");
|
||||
}
|
||||
// Passing the environment from stylesheet to stylesheet,
|
||||
// allows frames and effects to be maintained.
|
||||
env = _(env).extend({filename:s.id});
|
||||
env = _.extend(env, {filename:s.id});
|
||||
|
||||
var time = +new Date(),
|
||||
root = (carto.Parser(env)).parse(s.data);
|
||||
@ -152,7 +152,7 @@ carto.Renderer.prototype.render = function render(m) {
|
||||
if (env.errors) throw env.errors;
|
||||
|
||||
// Pass TileJSON and other custom parameters through to Mapnik XML.
|
||||
var parameters = _(m).reduce(function(memo, v, k) {
|
||||
var parameters = _.reduce(m, function(memo, v, k) {
|
||||
if (!v && v !== 0) return memo;
|
||||
|
||||
switch (k) {
|
||||
@ -205,7 +205,7 @@ carto.Renderer.prototype.render = function render(m) {
|
||||
'\n</Parameters>\n'
|
||||
);
|
||||
|
||||
var properties = _(map_properties).map(function(v) { return ' ' + v; }).join('');
|
||||
var properties = _.map(map_properties, function(v) { return ' ' + v; }).join('');
|
||||
|
||||
output.unshift(
|
||||
'<?xml version="1.0" ' +
|
||||
|
@ -57,7 +57,7 @@ CartoCSS.Layer.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* return the symbolizers that need to be rendered with
|
||||
* return the symbolizers that need to be rendered with
|
||||
* this style. The order is the rendering order.
|
||||
* @returns a list with 3 possible values 'line', 'marker', 'polygon'
|
||||
*/
|
||||
@ -99,7 +99,7 @@ CartoCSS.Layer.prototype = {
|
||||
|
||||
//
|
||||
// given a geoemtry type returns the transformed one acording the CartoCSS
|
||||
// For points there are two kind of types: point and sprite, the first one
|
||||
// For points there are two kind of types: point and sprite, the first one
|
||||
// is a circle, second one is an image sprite
|
||||
//
|
||||
// the other geometry types are the same than geojson (polygon, linestring...)
|
||||
@ -202,12 +202,15 @@ CartoCSS.prototype = {
|
||||
var layer = layers[key] = (layers[key] || {
|
||||
symbolizers: []
|
||||
});
|
||||
|
||||
for(var u = 0; u<def.rules.length; u++){
|
||||
if(def.rules[u].name === "marker-file" || def.rules[u].name === "point-file"){
|
||||
var value = def.rules[u].value.value[0].value[0].value.value;
|
||||
this.imageURLs.push(value);
|
||||
var rule = def.rules[u];
|
||||
if(rule.name === "marker-file" || rule.name === "point-file"){
|
||||
var value = rule.value.value[0].value[0].value.value;
|
||||
this.imageURLs.push(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layer.frames = [];
|
||||
layer.zoom = tree.Zoom.all;
|
||||
var props = def.toJS(parse_env);
|
||||
@ -226,6 +229,8 @@ CartoCSS.prototype = {
|
||||
// serach the max index to know rendering order
|
||||
lyr.index = _.max(props[v].map(function(a) { return a.index; }).concat(lyr.index));
|
||||
lyr.constant = !_.any(props[v].map(function(a) { return !a.constant; }));
|
||||
// True when the property is filtered.
|
||||
lyr.filtered = props[v][0].filtered;
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,6 +240,14 @@ CartoCSS.prototype = {
|
||||
var done = {};
|
||||
for(var i = 0; i < defs.length; ++i) {
|
||||
var def = defs[i];
|
||||
|
||||
if (this.options.strict) {
|
||||
def.toXML(parse_env, {});
|
||||
if (parse_env.errors.message) {
|
||||
throw new Error(parse_env.errors.message);
|
||||
}
|
||||
}
|
||||
|
||||
var k = defKey(def);
|
||||
var layer = layers[k];
|
||||
if(!done[k]) {
|
||||
@ -271,12 +284,13 @@ CartoCSS.prototype = {
|
||||
carto.RendererJS = function (options) {
|
||||
this.options = options || {};
|
||||
this.options.mapnik_version = this.options.mapnik_version || 'latest';
|
||||
this.reference = this.options.reference || require('./torque-reference').version.latest;
|
||||
this.options.strict = this.options.hasOwnProperty('strict') ? this.options.strict : false;
|
||||
};
|
||||
|
||||
// Prepare a javascript object which contains the layers
|
||||
carto.RendererJS.prototype.render = function render(cartocss, callback) {
|
||||
var reference = require('./torque-reference');
|
||||
tree.Reference.setData(reference.version.latest);
|
||||
tree.Reference.setData(this.reference);
|
||||
return new CartoCSS(cartocss, this.options);
|
||||
}
|
||||
|
||||
|
@ -166,7 +166,17 @@ var _mapnik_reference_latest = {
|
||||
["sharpen", 0],
|
||||
["colorize-alpha", -1],
|
||||
["color-to-alpha", 1],
|
||||
["scale-hsla", 8]
|
||||
["scale-hsla", 8],
|
||||
["buckets", -1],
|
||||
["category", -1],
|
||||
["equal", -1],
|
||||
["headtails", -1],
|
||||
["jenks", -1],
|
||||
["quantiles", -1],
|
||||
["cartocolor", -1],
|
||||
["colorbrewer", -1],
|
||||
["range", -1],
|
||||
["ramp", -1]
|
||||
],
|
||||
"doc": "A list of image filters."
|
||||
},
|
||||
@ -293,14 +303,16 @@ var _mapnik_reference_latest = {
|
||||
"type": "color",
|
||||
"default-value": "rgba(128,128,128,1)",
|
||||
"default-meaning": "gray and fully opaque (alpha = 1), same as rgb(128,128,128)",
|
||||
"doc": "Fill color to assign to a polygon"
|
||||
"doc": "Fill color to assign to a polygon",
|
||||
"expression": true
|
||||
},
|
||||
"fill-opacity": {
|
||||
"css": "polygon-opacity",
|
||||
"type": "float",
|
||||
"doc": "The opacity of the polygon",
|
||||
"default-value": 1,
|
||||
"default-meaning": "opaque"
|
||||
"default-meaning": "opaque",
|
||||
"expression": true
|
||||
},
|
||||
"gamma": {
|
||||
"css": "polygon-gamma",
|
||||
@ -401,13 +413,15 @@ var _mapnik_reference_latest = {
|
||||
"default-value": "rgba(0,0,0,1)",
|
||||
"type": "color",
|
||||
"default-meaning": "black and fully opaque (alpha = 1), same as rgb(0,0,0)",
|
||||
"doc": "The color of a drawn line"
|
||||
"doc": "The color of a drawn line",
|
||||
"expression": true
|
||||
},
|
||||
"stroke-width": {
|
||||
"css": "line-width",
|
||||
"default-value": 1,
|
||||
"type": "float",
|
||||
"doc": "The width of a line in pixels"
|
||||
"doc": "The width of a line in pixels",
|
||||
"expression": true
|
||||
},
|
||||
"stroke-opacity": {
|
||||
"css": "line-opacity",
|
||||
@ -572,7 +586,8 @@ var _mapnik_reference_latest = {
|
||||
"doc": "An SVG file that this marker shows at each placement. If no file is given, the marker will show an ellipse.",
|
||||
"default-value": "",
|
||||
"default-meaning": "An ellipse or circle, if width equals height",
|
||||
"type": "uri"
|
||||
"type": "uri",
|
||||
"expression": true
|
||||
},
|
||||
"opacity": {
|
||||
"css": "marker-opacity",
|
||||
@ -656,7 +671,8 @@ var _mapnik_reference_latest = {
|
||||
"css": "marker-fill",
|
||||
"default-value": "blue",
|
||||
"doc": "The color of the area of the marker.",
|
||||
"type": "color"
|
||||
"type": "color",
|
||||
"expression": true
|
||||
},
|
||||
"allow-overlap": {
|
||||
"css": "marker-allow-overlap",
|
||||
@ -822,6 +838,18 @@ var _mapnik_reference_latest = {
|
||||
"default-value": "point",
|
||||
"doc": "How this shield should be placed. Point placement attempts to place it on top of points, line places along lines multiple times per feature, vertex places on the vertexes of polygons, and interior attempts to place inside of polygons."
|
||||
},
|
||||
"placement-type": {
|
||||
"css": "shield-placement-type",
|
||||
"doc": "Re-position and/or re-size shield to avoid overlaps. \"simple\" for basic algorithm (using shield-placements string,) \"dummy\" to turn this feature off.",
|
||||
"type": [
|
||||
"dummy",
|
||||
"simple",
|
||||
"list"
|
||||
],
|
||||
"expression":true,
|
||||
"default-meaning": "Alternative placements will not be enabled.",
|
||||
"default-value": "dummy"
|
||||
},
|
||||
"avoid-edges": {
|
||||
"css": "shield-avoid-edges",
|
||||
"doc": "Tell positioning algorithm to avoid labeling near intersection edges.",
|
||||
@ -1031,7 +1059,8 @@ var _mapnik_reference_latest = {
|
||||
"type": "uri",
|
||||
"default-value": "none",
|
||||
"required": true,
|
||||
"doc": "An image file to be repeated and warped along a line"
|
||||
"doc": "An image file to be repeated and warped along a line",
|
||||
"expression": true
|
||||
},
|
||||
"clip": {
|
||||
"css": "line-pattern-clip",
|
||||
@ -1111,7 +1140,8 @@ var _mapnik_reference_latest = {
|
||||
"type": "uri",
|
||||
"default-value": "none",
|
||||
"required": true,
|
||||
"doc": "Image to use as a repeated pattern fill within a polygon"
|
||||
"doc": "Image to use as a repeated pattern fill within a polygon",
|
||||
"expression": true
|
||||
},
|
||||
"alignment": {
|
||||
"css": "polygon-pattern-alignment",
|
||||
|
@ -210,48 +210,37 @@ tree.Definition.prototype.toXML = function(env, existing) {
|
||||
|
||||
tree.Definition.prototype.toJS = function(env) {
|
||||
var shaderAttrs = {};
|
||||
|
||||
// merge conditions from filters with zoom condition of the
|
||||
// definition
|
||||
var zoom = "(" + this.zoom + " & (1 << ctx.zoom))";
|
||||
var frame_offset = this.frame_offset;
|
||||
var _if = this.filters.toJS(env);
|
||||
var filters = [zoom];
|
||||
if(_if) filters.push(_if);
|
||||
if(frame_offset) filters.push('ctx["frame-offset"] === ' + frame_offset);
|
||||
_if = filters.join(" && ");
|
||||
_.each(this.rules, function(rule) {
|
||||
if(rule instanceof tree.Rule) {
|
||||
shaderAttrs[rule.name] = shaderAttrs[rule.name] || [];
|
||||
var zoomFilter = "(" + this.zoom + " & (1 << ctx.zoom))";
|
||||
var filters = [zoomFilter];
|
||||
var originalFilters = this.filters.toJS(env);
|
||||
// Ignore default zoom for filtering (https://github.com/CartoDB/carto/issues/40)
|
||||
var zoomFiltered = this.zoom !== tree.Zoom.all;
|
||||
|
||||
if (originalFilters) {
|
||||
filters.push(originalFilters);
|
||||
}
|
||||
|
||||
var r = {
|
||||
index: rule.index,
|
||||
symbolizer: rule.symbolizer
|
||||
};
|
||||
if (frame_offset) {
|
||||
filters.push('ctx["frame-offset"] === ' + frame_offset);
|
||||
}
|
||||
|
||||
if (_if) {
|
||||
r.js = "if(" + _if + "){" + rule.value.toJS(env) + "}"
|
||||
} else {
|
||||
r.js = rule.value.toJS(env);
|
||||
}
|
||||
_.each(this.rules, function (rule) {
|
||||
var exportedRule = {};
|
||||
|
||||
r.constant = rule.value.ev(env).is !== 'field';
|
||||
r.filtered = !!_if;
|
||||
|
||||
shaderAttrs[rule.name].push(r);
|
||||
} else {
|
||||
throw new Error("Ruleset not supported");
|
||||
//if (rule instanceof tree.Ruleset) {
|
||||
//var sh = rule.toJS(env);
|
||||
//for(var v in sh) {
|
||||
//shaderAttrs[v] = shaderAttrs[v] || [];
|
||||
//for(var attr in sh[v]) {
|
||||
//shaderAttrs[v].push(sh[v][attr]);
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
if (!rule instanceof tree.Rule) {
|
||||
throw new Error("Ruleset not supported");
|
||||
}
|
||||
|
||||
exportedRule.index = rule.index;
|
||||
exportedRule.symbolizer = rule.symbolizer;
|
||||
exportedRule.js = "if(" + filters.join(" && ") + "){" + rule.value.toJS(env) + "}";
|
||||
exportedRule.constant = rule.value.ev(env).is !== 'field';
|
||||
exportedRule.filtered = zoomFiltered || (originalFilters !== '');
|
||||
shaderAttrs[rule.name] = shaderAttrs[rule.name] || [];
|
||||
shaderAttrs[rule.name].push(exportedRule);
|
||||
});
|
||||
|
||||
return shaderAttrs;
|
||||
};
|
||||
|
||||
|
@ -92,7 +92,10 @@ tree.Filterset.prototype.toJS = function(env) {
|
||||
val = filter._val.toString(true);
|
||||
}
|
||||
var attrs = "data";
|
||||
return attrs + "." + filter.key.value + " " + op + " " + (val.is === 'string' ? "'"+ val +"'" : val);
|
||||
if (op === '=~') {
|
||||
return "(" + attrs + "['" + filter.key.value + "'] + '').match(" + (val.is === 'string' ? "'" + val.toString().replace(/'/g, "\\'").replace(/&/g, '&') + "'" : val) + ")";
|
||||
}
|
||||
return attrs + "['" + filter.key.value + "'] " + op + " " + (val.is === 'string' ? "'" + val.toString().replace(/'/g, "\\'").replace(/&/g, '&') + "'" : val);
|
||||
}).join(' && ');
|
||||
};
|
||||
|
||||
|
@ -33,10 +33,18 @@ tree.Value.prototype = {
|
||||
var val = this.ev(env);
|
||||
var v = val.toString();
|
||||
if(val.is === "color" || val.is === 'uri' || val.is === 'string' || val.is === 'keyword') {
|
||||
v = "'" + v + "'";
|
||||
v = "'" + v.replace(/&/g, '&') + "'";
|
||||
} else if (Array.isArray(this.value) && this.value.length > 1) {
|
||||
// This covers something like `line-dasharray: 5, 10;`
|
||||
// where the return _value has more than one element.
|
||||
// Without this the generated code will look like:
|
||||
// _value = 5, 10; which will ignore the 10.
|
||||
v = '[' + this.value.join(',') + ']';
|
||||
} else if (val.is === 'field') {
|
||||
// replace [variable] by ctx['variable']
|
||||
v = v.replace(/\[(.*)\]/g, "data['$1']");
|
||||
v = v.replace(/\[([^\]]*)\]/g, function(matched) {
|
||||
return matched.replace(/\[(.*)\]/g, "data['$1']");
|
||||
});
|
||||
}else if (val.is === 'call') {
|
||||
v = JSON.stringify({
|
||||
name: val.name,
|
||||
|
2110
package-lock.json
generated
Normal file
2110
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "carto",
|
||||
"version": "0.15.1-cdb1",
|
||||
"version": "0.15.1-cdb5",
|
||||
"description": "CartoCSS Stylesheet Compiler",
|
||||
"url": "https://github.com/cartodb/carto",
|
||||
"repository": {
|
||||
@ -37,7 +37,7 @@
|
||||
"node": ">=0.4.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"underscore": "~1.6.0",
|
||||
"underscore": "1.8.3",
|
||||
"mapnik-reference": "~6.0.2",
|
||||
"optimist": "~0.6.0"
|
||||
},
|
||||
@ -53,6 +53,11 @@
|
||||
"scripts": {
|
||||
"pretest": "npm install",
|
||||
"test": "mocha -R spec",
|
||||
"coverage": "istanbul cover ./node_modules/.bin/_mocha && coveralls < ./coverage/lcov.info"
|
||||
"tdd": "env HIDE_LOGS=true mocha -w -R spec",
|
||||
"coverage": "istanbul cover ./node_modules/.bin/_mocha && coveralls < ./coverage/lcov.info",
|
||||
"bump": "npm version patch",
|
||||
"bump:major": "npm version major",
|
||||
"bump:minor": "npm version minor",
|
||||
"postversion": "git push origin master --follow-tags"
|
||||
}
|
||||
}
|
||||
|
102
test/filtered.test.js
Normal file
102
test/filtered.test.js
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Test the filtered field.
|
||||
*
|
||||
* When compiled, a rule provides metainformation fields like index, constant...etc
|
||||
* one of this fields is the "filtered field".
|
||||
*
|
||||
* This field gives information about whether a property is filtered or not.
|
||||
*
|
||||
* A property is filtered if it was activated inside a filter. In the following cartocss
|
||||
* code marker-color.filtered will be true because it's inside a population filter.
|
||||
*
|
||||
* #layer {
|
||||
* maker-width: 20;
|
||||
* [population > 100] {
|
||||
* marker-color: red; // this property is filtered
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* "zoom" is a special case, and it only should be considered when its value is not the default.
|
||||
*/
|
||||
var assert = require('assert');
|
||||
var Carto = require('../lib/carto/index.js');
|
||||
var renderer = new Carto.RendererJS({ strict: true });
|
||||
|
||||
describe('property.filtered', function () {
|
||||
it('should be false when the property is not filtered', function () {
|
||||
var style = [
|
||||
'#layer {',
|
||||
' marker-fill: red;',
|
||||
'}'
|
||||
].join('\n');
|
||||
var layers = renderer.render(style).layers[0].shader;
|
||||
assert(!layers['marker-fill'].filtered);
|
||||
});
|
||||
|
||||
it('should be true when the property is filtered', function () {
|
||||
var style = [
|
||||
'#layer {',
|
||||
' [foo > 30] {',
|
||||
' marker-fill: red;',
|
||||
' }',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
var layers = renderer.render(style).layers[0].shader;
|
||||
assert(layers['marker-fill'].filtered);
|
||||
});
|
||||
|
||||
it('should be true when the property is filtered at first level', function () {
|
||||
var style = [
|
||||
'#layer [foo > 30] {',
|
||||
' marker-fill: red;',
|
||||
'}`'
|
||||
].join('\n');
|
||||
|
||||
var layers = renderer.render(style).layers[0].shader;
|
||||
assert(layers['marker-fill'].filtered);
|
||||
});
|
||||
|
||||
it('should be false when the property is not filterd but there is another filtered properties', function () {
|
||||
var style = [
|
||||
'#layer {',
|
||||
' marker-fill: red;',
|
||||
' [bar < 200]{',
|
||||
' marker-allow-overlap: false;',
|
||||
' }',
|
||||
'}`'
|
||||
].join('\n');
|
||||
|
||||
var layers = renderer.render(style).layers[0].shader;
|
||||
|
||||
assert(!layers['marker-fill'].filtered);
|
||||
assert(layers['marker-allow-overlap'].filtered);
|
||||
});
|
||||
|
||||
it('should be true when the property is filtered and have a default value', function () {
|
||||
var style = [
|
||||
'#layer {',
|
||||
' marker-fill: red;',
|
||||
' [bar < 200]{',
|
||||
' marker-fill: blue;',
|
||||
' }',
|
||||
'}`'
|
||||
].join('\n');
|
||||
var layers = renderer.render(style).layers[0].shader;
|
||||
|
||||
assert(layers['marker-fill'].filtered);
|
||||
});
|
||||
|
||||
it('should be true when filtering by zoom', function () {
|
||||
var style = [
|
||||
'#layer {',
|
||||
' [zoom < 5]{',
|
||||
' marker-fill: blue;',
|
||||
' }',
|
||||
'}`'
|
||||
].join('\n');
|
||||
var layers = renderer.render(style).layers[0].shader;
|
||||
|
||||
assert(layers['marker-fill'].filtered);
|
||||
});
|
||||
});
|
@ -54,7 +54,8 @@ var _mapnik_reference_latest = {
|
||||
["x-gradient", 0],
|
||||
["y-gradient", 0],
|
||||
["invert", 0],
|
||||
["sharpen", 0]
|
||||
["sharpen", 0],
|
||||
["ramp", 0]
|
||||
],
|
||||
"doc": "A list of image filters."
|
||||
},
|
||||
|
148
test/rendering_js-strict.test.js
Normal file
148
test/rendering_js-strict.test.js
Normal file
@ -0,0 +1,148 @@
|
||||
var assert = require('assert');
|
||||
var carto = require('../lib/carto');
|
||||
var tree = require('../lib/carto/tree');
|
||||
|
||||
describe('RendererJS Strict Mode', function() {
|
||||
|
||||
var style = [
|
||||
'#world {',
|
||||
'polygon-fill: red;',
|
||||
'line-width: 2;',
|
||||
'line-color: #f00;',
|
||||
'[frame-offset = 1] {',
|
||||
'line-width: 3;',
|
||||
'}',
|
||||
'[frame-offset = 2] {',
|
||||
'line-width: 3;',
|
||||
'}',
|
||||
'}',
|
||||
'',
|
||||
'#worls[frame-offset = 10] {',
|
||||
'line-width: 4;',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
var reference = {
|
||||
version: '1.0.0',
|
||||
style: {},
|
||||
layer: {},
|
||||
colors: {},
|
||||
filter: {},
|
||||
symbolizers: {
|
||||
line: {
|
||||
"stroke": {
|
||||
"css": "line-color",
|
||||
"default-value": "rgba(0,0,0,1)",
|
||||
"type": "color",
|
||||
"default-meaning": "black and fully opaque (alpha = 1), same as rgb(0,0,0)",
|
||||
"doc": "The color of a drawn line"
|
||||
},
|
||||
"stroke-width": {
|
||||
"css": "line-width",
|
||||
"default-value": 1,
|
||||
"type": "float",
|
||||
"doc": "The width of a line in pixels"
|
||||
},
|
||||
"stroke-opacity": {
|
||||
"css": "line-opacity",
|
||||
"default-value": 1,
|
||||
"type": "float",
|
||||
"default-meaning": "opaque",
|
||||
"doc": "The opacity of a line"
|
||||
},
|
||||
"stroke-linejoin": {
|
||||
"css": "line-join",
|
||||
"default-value": "miter",
|
||||
"type": [
|
||||
"miter",
|
||||
"miter-revert",
|
||||
"round",
|
||||
"bevel"
|
||||
],
|
||||
"expression": true,
|
||||
"doc": "The behavior of lines when joining.",
|
||||
"default-meaning": "The line joins will be rendered using a miter look."
|
||||
},
|
||||
"stroke-linecap": {
|
||||
"css": "line-cap",
|
||||
"default-value": "butt",
|
||||
"type": [
|
||||
"butt",
|
||||
"round",
|
||||
"square"
|
||||
],
|
||||
"expression": true,
|
||||
"doc": "The display of line endings.",
|
||||
"default-meaning": "The line endings will be rendered using a butt look."
|
||||
},
|
||||
"comp-op": {
|
||||
"css": "line-comp-op",
|
||||
"default-value": "overlay",
|
||||
"default-meaning": "Add the current symbolizer on top of other symbolizer.",
|
||||
"doc": "Composite operation. This defines how this symbolizer should behave relative to symbolizers atop or below it.",
|
||||
"type": [
|
||||
"multiply",
|
||||
"add",
|
||||
"overlay"
|
||||
],
|
||||
"expression": true
|
||||
},
|
||||
"stroke-dasharray": {
|
||||
"css": "line-dasharray",
|
||||
"type": "numbers",
|
||||
"expression": true,
|
||||
"doc": "A pair of length values [a,b], where (a) is the dash length and (b) is the gap length respectively. More than two values are supported for more complex patterns.",
|
||||
"default-value": "none",
|
||||
"default-meaning": "The line will be drawn without dashes."
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var expectedErrorMessageRegex = /Unrecognized rule: polygon-fill/;
|
||||
|
||||
before(function() {
|
||||
this.referenceData = tree.Reference.data;
|
||||
});
|
||||
|
||||
after(function() {
|
||||
if (this.referenceData) {
|
||||
tree.Reference.setData(this.referenceData);
|
||||
}
|
||||
});
|
||||
|
||||
it('should fail if a feature is not supported and strict is turned on', function () {
|
||||
assert.throws(
|
||||
function () {
|
||||
var RendererJS = new carto.RendererJS({reference: reference, mapnik_version: '1.0.0', strict: true });
|
||||
var shader = RendererJS.render(style);
|
||||
},
|
||||
expectedErrorMessageRegex
|
||||
);
|
||||
});
|
||||
|
||||
function rendererStrictModeOffTest(RendererJS) {
|
||||
return function () {
|
||||
var shader = RendererJS.render(style);
|
||||
|
||||
assert.ok(shader.layers);
|
||||
assert.equal(shader.layers.length, 2);
|
||||
};
|
||||
}
|
||||
|
||||
it('should pass if a feature is not supported but strict mode is not specified', rendererStrictModeOffTest(
|
||||
new carto.RendererJS({reference: reference, mapnik_version: '1.0.0' })
|
||||
));
|
||||
|
||||
it('should pass if a feature is not supported but strict is turned off', function () {
|
||||
new carto.RendererJS({reference: reference, mapnik_version: '1.0.0', strict: false })
|
||||
});
|
||||
|
||||
it('should pass if a feature is supported and strict is turned on', function () {
|
||||
var RendererJS = new carto.RendererJS({reference: reference, mapnik_version: '1.0.0', strict: true });
|
||||
var cartocss = '#layer { line-width: 10 }';
|
||||
var shader = RendererJS.render(cartocss);
|
||||
assert.ok(shader);
|
||||
});
|
||||
|
||||
});
|
@ -1,27 +1,27 @@
|
||||
|
||||
var SHOW_LOGS = (process.env.HIDE_LOGS !== 'true');
|
||||
var assert = require('assert');
|
||||
var carto = require('../lib/carto');
|
||||
describe('RenderingJS', function() {
|
||||
var shader;
|
||||
var style = [
|
||||
'#world {',
|
||||
'line-width: 2;',
|
||||
'line-color: #f00;',
|
||||
'[frame-offset = 1] {',
|
||||
'line-width: 3;',
|
||||
'}',
|
||||
'[frame-offset = 2] {',
|
||||
'line-width: 3;',
|
||||
'}',
|
||||
'}',
|
||||
'',
|
||||
'#worls[frame-offset = 10] {',
|
||||
'line-width: 4;',
|
||||
'#world {',
|
||||
'line-width: 2;',
|
||||
'line-color: #f00;',
|
||||
'[frame-offset = 1] {',
|
||||
'line-width: 3;',
|
||||
'}',
|
||||
'[frame-offset = 2] {',
|
||||
'line-width: 3;',
|
||||
'}',
|
||||
'}',
|
||||
'',
|
||||
'#worls[frame-offset = 10] {',
|
||||
'line-width: 4;',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
beforeEach(function() {
|
||||
shader = (new carto.RendererJS({ debug: true })).render(style);
|
||||
shader = (new carto.RendererJS({ debug: SHOW_LOGS })).render(style);
|
||||
});
|
||||
|
||||
it ("shold render layers", function() {
|
||||
@ -45,7 +45,7 @@ describe('RenderingJS', function() {
|
||||
|
||||
it ("shold render variables", function() {
|
||||
var style = '#test { marker-width: [testing]; }';
|
||||
shader = (new carto.RendererJS({ debug: true })).render(style);
|
||||
shader = (new carto.RendererJS({ debug: SHOW_LOGS })).render(style);
|
||||
var layer = shader.getLayers()[0];
|
||||
var props = layer.getStyle({testing: 2}, { 'zoom': 0, 'frame-offset': 10 });
|
||||
assert( props['marker-width'] === 2);
|
||||
@ -53,7 +53,7 @@ describe('RenderingJS', function() {
|
||||
|
||||
it ("should allow filter based rendering", function() {
|
||||
var style = '#test { marker-width: 10; [zoom = 1] { marker-width: 1; } }';
|
||||
shader = (new carto.RendererJS({ debug: true })).render(style);
|
||||
shader = (new carto.RendererJS({ debug: SHOW_LOGS })).render(style);
|
||||
var layer = shader.getLayers()[0];
|
||||
var props = layer.getStyle({}, { 'zoom': 0, 'frame-offset': 10 });
|
||||
assert( props['marker-width'] === 10);
|
||||
@ -63,8 +63,8 @@ describe('RenderingJS', function() {
|
||||
|
||||
it ("symbolizers should be in rendering order", function() {
|
||||
var style = '#test { polygon-fill: red; line-color: red; }';
|
||||
style += '#test2 { line-color: red;polygon-fill: red; line-witdh: 10; }';
|
||||
var shader = (new carto.RendererJS({ debug: true })).render(style);
|
||||
style += '#test2 { line-color: red;polygon-fill: red; line-width: 10; }';
|
||||
var shader = (new carto.RendererJS({ debug: SHOW_LOGS })).render(style);
|
||||
var layer0 = shader.getLayers()[0];
|
||||
assert(layer0.getSymbolizers()[0] === 'polygon');
|
||||
assert(layer0.getSymbolizers()[1] === 'line');
|
||||
@ -76,7 +76,7 @@ describe('RenderingJS', function() {
|
||||
|
||||
it ("colorize should return a list of colours in same order", function() {
|
||||
var style = '#test { image-filters: colorize-alpha(blue, cyan, green, yellow, orange, red); }';
|
||||
var shader = (new carto.RendererJS({ debug: true })).render(style);
|
||||
var shader = (new carto.RendererJS({ debug: SHOW_LOGS })).render(style);
|
||||
var layer0 = shader.getLayers()[0];
|
||||
var st = layer0.getStyle({ value: 1 }, {"frame-offset": 0, "zoom": 3});
|
||||
var expectedColours = [[0, 0, 255], [0, 255, 255], [0, 128, 0], [255, 255, 0], [255, 165, 0], [255, 0, 0]];
|
||||
@ -106,7 +106,7 @@ describe('RenderingJS', function() {
|
||||
' [frame-offset = 2] { marker-width: 15; marker-fill-opacity: 0.02;}',
|
||||
'}'
|
||||
].join('\n');
|
||||
var shader = (new carto.RendererJS({ debug: true })).render(css);
|
||||
var shader = (new carto.RendererJS({ debug: SHOW_LOGS })).render(css);
|
||||
var markerURLs = shader.getImageURLs();
|
||||
var against = ["http://localhost:8081/gal.svg", "http://upload.wikimedia.org/wikipedia/commons/4/43/Flag_of_the_Galactic_Empire.svg", "http://upload.wikimedia.org/wikipedia/commons/c/c9/Flag_of_Syldavia.svg"];
|
||||
for(var i = 0; i<against.length; i++){
|
||||
@ -116,20 +116,124 @@ describe('RenderingJS', function() {
|
||||
|
||||
it ("should return variable for styles that change", function() {
|
||||
var style = '#test { marker-width: [prop]; }';
|
||||
var shader = (new carto.RendererJS({ debug: true })).render(style);
|
||||
var shader = (new carto.RendererJS({ debug: SHOW_LOGS })).render(style);
|
||||
var layer0 = shader.getLayers()[0];
|
||||
assert(layer0.isVariable());
|
||||
|
||||
style = '#test { marker-width: 1; }';
|
||||
shader = (new carto.RendererJS({ debug: true })).render(style);
|
||||
shader = (new carto.RendererJS({ debug: SHOW_LOGS })).render(style);
|
||||
layer0 = shader.getLayers()[0];
|
||||
assert(!layer0.isVariable());
|
||||
|
||||
style = '#test { marker-width: [prop]; marker-fill: red; }';
|
||||
shader = (new carto.RendererJS({ debug: true })).render(style);
|
||||
shader = (new carto.RendererJS({ debug: SHOW_LOGS })).render(style);
|
||||
layer0 = shader.getLayers()[0];
|
||||
assert(layer0.isVariable());
|
||||
|
||||
});
|
||||
|
||||
it("should parse styles with string", function() {
|
||||
var style = '#test { [column = "test\'ing"] { marker-width: 10; } }';
|
||||
var shader = (new carto.RendererJS({ debug: SHOW_LOGS })).render(style);
|
||||
var layer = shader.getLayers()[0];
|
||||
var props = layer.getStyle({column: 'test\'ing'}, { 'zoom': 0, 'frame-offset': 10 });
|
||||
assert(props['marker-width'] === 10);
|
||||
});
|
||||
|
||||
it("should parse styles with filters not supported by dot notation", function() {
|
||||
var style = '#test["mapnik::geometry_type"=1] { marker-width: 10; }';
|
||||
var shader = (new carto.RendererJS({ debug: SHOW_LOGS })).render(style);
|
||||
var layer = shader.getLayers()[0];
|
||||
var props = layer.getStyle({"mapnik::geometry_type": 1}, { 'zoom': 0 });
|
||||
assert.equal(props['marker-width'], 10);
|
||||
var emptyFilterProps = layer.getStyle({"mapnik::geometry_type": 2}, { 'zoom': 0 });
|
||||
assert.equal(emptyFilterProps['marker-width'], null);
|
||||
});
|
||||
|
||||
it ("should parse turbocarto", function(){
|
||||
var css = [
|
||||
'#layer {',
|
||||
' marker-width: ramp([cartodb_id], (#fff, #bbb), jenks);',
|
||||
'}'
|
||||
].join('\n');
|
||||
var shader = (new carto.RendererJS({ debug: SHOW_LOGS })).render(css);
|
||||
var layer = shader.getLayers()[0];
|
||||
var st = layer.shader['marker-width'].style({}, {zoom: 1})
|
||||
assert.equal(st.name, "ramp")
|
||||
assert.equal(st.args.length, 3);
|
||||
assert.equal(st.args[1].value[0].rgb[0], 255);
|
||||
assert.equal(st.args[1].value[0].rgb[1], 255);
|
||||
assert.equal(st.args[1].value[0].rgb[2], 255);
|
||||
assert.equal(st.args[2].value, 'jenks');
|
||||
})
|
||||
|
||||
it("should parse turbocarto with inner functions", function(){
|
||||
var css = [
|
||||
'#layer {',
|
||||
' marker-width: ramp([cartodb_id], cartocolor(Bold), category(10));',
|
||||
'}'
|
||||
].join('\n');
|
||||
var shader = (new carto.RendererJS({ debug: SHOW_LOGS })).render(css);
|
||||
var layer = shader.getLayers()[0];
|
||||
var st = layer.shader['marker-width'].style({}, {zoom: 1});
|
||||
assert.equal(st.name, "ramp");
|
||||
assert.equal(st.args.length, 3);
|
||||
assert.equal(st.args[1].name, 'cartocolor');
|
||||
assert.equal(st.args[1].args[0].value, 'Bold');
|
||||
assert.equal(st.args[2].name, 'category');
|
||||
assert.equal(st.args[2].args[0].value, 10);
|
||||
});
|
||||
|
||||
it("should work with multiple operands", function(){
|
||||
var css = [
|
||||
'#layer {',
|
||||
' marker-width: [value] * [value] * 0.5;',
|
||||
'}'
|
||||
].join('\n');
|
||||
var shader = (new carto.RendererJS({ debug: false })).render(css);
|
||||
var layer = shader.getLayers()[0];
|
||||
var width = layer.shader['marker-width'].style({value: 4}, {zoom: 1});
|
||||
assert.equal(width, 8);
|
||||
});
|
||||
|
||||
it("should work with numbers", function(){
|
||||
var css = [
|
||||
'#layer {',
|
||||
' line-dasharray: 5, 10;',
|
||||
'}'
|
||||
].join('\n');
|
||||
var shader = (new carto.RendererJS({ debug: false })).render(css);
|
||||
var layer = shader.getLayers()[0];
|
||||
var dasharray = layer.shader['line-dasharray'].style({value: 4}, {zoom: 1});
|
||||
assert.deepEqual(dasharray, [5, 10]);
|
||||
});
|
||||
|
||||
it("should not throw `ReferenceError` with `=~` operator", function(){
|
||||
var css = [
|
||||
'#layer[name=~".*wadus*"] {',
|
||||
' marker-width: 14;',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
assert.doesNotThrow(function () {
|
||||
var shader = (new carto.RendererJS({})).render(css);
|
||||
var layer = shader.getLayers()[0];
|
||||
var value = layer.shader['marker-width'].style({ name: 'wadus' }, { zoom: 1 });
|
||||
assert.equal(value, 14);
|
||||
}, ReferenceError);
|
||||
});
|
||||
|
||||
it("`=~` operator should support numbers", function(){
|
||||
var css = [
|
||||
'#layer[value=~"^10"] {',
|
||||
' marker-width: 14;',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
assert.doesNotThrow(function () {
|
||||
var shader = (new carto.RendererJS({})).render(css);
|
||||
var layer = shader.getLayers()[0];
|
||||
var value = layer.shader['marker-width'].style({ value: 10 }, { zoom: 1 });
|
||||
assert.equal(value, 14);
|
||||
}, Error);
|
||||
});
|
||||
});
|
||||
|
1655
test/underscore.js
1655
test/underscore.js
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user