From a3538d9007e8557ac45fccd83a8e698f2ee55128 Mon Sep 17 00:00:00 2001 From: IagoLast Date: Fri, 18 Aug 2017 12:57:45 +0200 Subject: [PATCH 1/5] Add filtered field tests --- test/filtered.test.js | 84 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 test/filtered.test.js diff --git a/test/filtered.test.js b/test/filtered.test.js new file mode 100644 index 0000000..97af562 --- /dev/null +++ b/test/filtered.test.js @@ -0,0 +1,84 @@ +/** + * 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 is inside a population filter. + * + * #layer { + * maker-width: 20; + * [population > 100] { + * marker-color: red; // + * } + * } + */ +var assert = require('assert'); +var Carto = require('../lib/carto/index.js'); +var renderer = new Carto.RendererJS({strict: true}); + + +describe('Field:filtered propery', function () { + it('should be false when the property is not filtered', function () { + var style = ` + #layer { + marker-fill: red; + }`; + var layers = renderer.render(style).layers[0].shader; + assert(!layers['marker-fill'].filtered); + }); + + it('should be true when the property is filtered', function () { + style = ` + #layer { + [foo > 30]{ + marker-fill: red; + } + }`; + + 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 () { + style = ` + #layer [foo > 30]{ + marker-fill: red; + }`; + + 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 () { + style = ` + #layer { + marker-fill: red; + [bar < 200]{ + marker-allow-overlap: false; + } + }`; + + 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 () { + style = ` + #layer { + marker-fill: red; + [bar < 200]{ + marker-fill: blue; + } + }`; + + var layers = renderer.render(style).layers[0].shader; + + assert(layers['marker-fill'].filtered); + }); +}); \ No newline at end of file From 72f93abf16e1ffa2f69f936a20a44c4ace47b1f1 Mon Sep 17 00:00:00 2001 From: IagoLast Date: Fri, 18 Aug 2017 12:58:01 +0200 Subject: [PATCH 2/5] Expose filtered field --- lib/carto/renderer_js.js | 2 ++ lib/carto/tree/definition.js | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/carto/renderer_js.js b/lib/carto/renderer_js.js index 906086b..9e024ed 100644 --- a/lib/carto/renderer_js.js +++ b/lib/carto/renderer_js.js @@ -229,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; } } diff --git a/lib/carto/tree/definition.js b/lib/carto/tree/definition.js index 2ba7fc7..10aa271 100644 --- a/lib/carto/tree/definition.js +++ b/lib/carto/tree/definition.js @@ -236,7 +236,11 @@ tree.Definition.prototype.toJS = function(env) { } r.constant = rule.value.ev(env).is !== 'field'; - r.filtered = !!_if; + var DEFAULT_FILTER = "(8388607 & (1 << ctx.zoom))"; + r.filtered = false; + if (_if && _if !== DEFAULT_FILTER){ + r.filtered = true; + } shaderAttrs[rule.name].push(r); } else { From 1016f6870cb9a930587bc45a5b78307467299bcd Mon Sep 17 00:00:00 2001 From: IagoLast Date: Fri, 18 Aug 2017 13:10:15 +0200 Subject: [PATCH 3/5] Refactor filtered field code --- lib/carto/tree/definition.js | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/lib/carto/tree/definition.js b/lib/carto/tree/definition.js index 10aa271..808ed65 100644 --- a/lib/carto/tree/definition.js +++ b/lib/carto/tree/definition.js @@ -216,10 +216,19 @@ tree.Definition.prototype.toJS = function(env) { var zoom = "(" + this.zoom + " & (1 << ctx.zoom))"; var frame_offset = this.frame_offset; var _if = this.filters.toJS(env); + var filtered = _if !== ''; var filters = [zoom]; - if(_if) filters.push(_if); - if(frame_offset) filters.push('ctx["frame-offset"] === ' + frame_offset); + + 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] || []; @@ -230,30 +239,16 @@ tree.Definition.prototype.toJS = function(env) { }; if (_if) { - r.js = "if(" + _if + "){" + rule.value.toJS(env) + "}" + r.js = "if(" + _if + "){" + rule.value.toJS(env) + "}"; } else { r.js = rule.value.toJS(env); } r.constant = rule.value.ev(env).is !== 'field'; - var DEFAULT_FILTER = "(8388607 & (1 << ctx.zoom))"; - r.filtered = false; - if (_if && _if !== DEFAULT_FILTER){ - r.filtered = true; - } - + r.filtered = filtered; 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]); - //} - //} - //} } }); return shaderAttrs; From 41133a65adffaf119be31c6d1c07d1dbba80e72c Mon Sep 17 00:00:00 2001 From: IagoLast Date: Fri, 18 Aug 2017 13:21:22 +0200 Subject: [PATCH 4/5] Make test compatible with an old node version --- test/filtered.test.js | 64 +++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/test/filtered.test.js b/test/filtered.test.js index 97af562..caa6166 100644 --- a/test/filtered.test.js +++ b/test/filtered.test.js @@ -18,49 +18,53 @@ */ var assert = require('assert'); var Carto = require('../lib/carto/index.js'); -var renderer = new Carto.RendererJS({strict: true}); +var renderer = new Carto.RendererJS({ strict: true }); describe('Field:filtered propery', function () { it('should be false when the property is not filtered', function () { - var style = ` - #layer { - marker-fill: red; - }`; + 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 () { - style = ` - #layer { - [foo > 30]{ - marker-fill: red; - } - }`; + 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 () { - style = ` - #layer [foo > 30]{ - marker-fill: red; - }`; + 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 () { - style = ` - #layer { - marker-fill: red; - [bar < 200]{ - marker-allow-overlap: false; - } - }`; + var style = [ + '#layer {', + ' marker-fill: red;', + ' [bar < 200]{', + ' marker-allow-overlap: false;', + ' }', + '}`' + ].join('\n'); var layers = renderer.render(style).layers[0].shader; @@ -69,14 +73,14 @@ describe('Field:filtered propery', function () { }); it('should be true when the property is filtered and have a default value', function () { - style = ` - #layer { - marker-fill: red; - [bar < 200]{ - marker-fill: blue; - } - }`; - + 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); From 34799db0cc6b5456497ef0587c288bf8d7932112 Mon Sep 17 00:00:00 2001 From: IagoLast Date: Fri, 18 Aug 2017 15:59:04 +0200 Subject: [PATCH 5/5] Boy scout rule --- lib/carto/tree/definition.js | 54 +++++++++++++++--------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/lib/carto/tree/definition.js b/lib/carto/tree/definition.js index 808ed65..8483e63 100644 --- a/lib/carto/tree/definition.js +++ b/lib/carto/tree/definition.js @@ -210,47 +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 filtered = _if !== ''; - var filters = [zoom]; + var zoomFilter = "(" + this.zoom + " & (1 << ctx.zoom))"; + var filters = [zoomFilter]; + var originalFilters = this.filters.toJS(env); - if(_if) { - filters.push(_if); + + if (originalFilters) { + filters.push(originalFilters); } - if(frame_offset){ - filters.push('ctx["frame-offset"] === ' + frame_offset); + 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 r = { - index: rule.index, - symbolizer: rule.symbolizer - }; - - 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 = filtered; - shaderAttrs[rule.name].push(r); - } else { - throw new Error("Ruleset not supported"); + 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 = originalFilters !== ''; + + shaderAttrs[rule.name] = shaderAttrs[rule.name] || []; + shaderAttrs[rule.name].push(exportedRule); }); + return shaderAttrs; };