Skip to content
This repository has been archived by the owner on Jan 12, 2024. It is now read-only.

Commit

Permalink
add ability to define variables within selectors and filters, ref #461
Browse files Browse the repository at this point in the history
  • Loading branch information
nebulon42 committed Jul 4, 2017
1 parent 9ea8663 commit 7b2722f
Show file tree
Hide file tree
Showing 33 changed files with 770 additions and 99 deletions.
19 changes: 1 addition & 18 deletions lib/carto/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,28 +237,11 @@ carto.Parser = function Parser(env) {

// call populates Invalid-caused errors
var definitions = this.flatten([], [], env);
definitions.sort(specificitySort);
definitions.sort(tree.specificitySort);
return definitions;
};
})();

// Sort rules by specificity: this function expects selectors to be
// split already.
//
// Written to be used as a .sort(Function);
// argument.
//
// [1, 0, 0, 467] > [0, 0, 1, 520]
var specificitySort = function(a, b) {
var as = a.specificity;
var bs = b.specificity;

if (as[0] != bs[0]) return bs[0] - as[0];
if (as[1] != bs[1]) return bs[1] - as[1];
if (as[2] != bs[2]) return bs[2] - as[2];
return bs[3] - as[3];
};

return root;
},

Expand Down
4 changes: 3 additions & 1 deletion lib/carto/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -555,11 +555,13 @@ function sortStyles(styles) {
function foldStyle(style) {
for (var i = 0; i < style.length; i++) {
for (var j = style.length - 1; j > i; j--) {
if (style[j].filters.cloneWith(style[i].filters) === null) {
if (style[j].zoom === style[i].zoom &&
style[j].filters.cloneWith(style[i].filters) === null) {
style.splice(j, 1);
}
}
}

return style;
}

Expand Down
28 changes: 28 additions & 0 deletions lib/carto/tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,31 @@ module.exports.find = function (obj, fun) {
}
return null;
};

// Sort rules by specificity: this function expects selectors to be
// split already.
//
// Specificity: [ID, Class, Filters, Zoom, Position in document]
//
// Written to be used as a .sort(Function);
// argument.
//
// [1, 0, 0, 467] > [0, 0, 1, 520]
module.exports.specificitySort = function (a, b) {
var as = a.specificity;
var bs = b.specificity;

if (as[0] != bs[0]) { // ID
return bs[0] - as[0];
}
if (as[1] != bs[1]) { // Class
return bs[1] - as[1];
}
if (as[2] != bs[2]) { // Filters
return bs[2] - as[2];
}
if (as[3] != -1 && bs[3] != -1 && as[3] != bs[3]) { // Zoom
return bs[4] - as[4];
}
return bs[4] - as[4]; // Position in document
};
9 changes: 9 additions & 0 deletions lib/carto/tree/call.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ tree.Call = function Call(name, args, filename, index) {
this.args = args;
this.filename = filename;
this.index = index;
this.rule = null;
};

tree.Call.prototype = {
Expand Down Expand Up @@ -105,6 +106,14 @@ tree.Call.prototype = {
} else {
return this.name;
}
},
setRule: function (rule) {
this.rule = rule;
_.forEach(this.args, function (a) {
if (typeof a.setRule === 'function') {
a.setRule(rule);
}
});
}
};

Expand Down
9 changes: 9 additions & 0 deletions lib/carto/tree/color.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ tree.Color = function Color(hsl, a, perceptual) {
} else {
this.perceptual = false;
}
this.rule = null;
};

tree.Color.prototype = {
Expand Down Expand Up @@ -149,6 +150,14 @@ tree.Color.prototype = {

round: function(value, decimals) {
return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
},

setRule: function (rule) {
this.rule = rule;
},

clone: function () {
return _.clone(this);
}
};

Expand Down
67 changes: 59 additions & 8 deletions lib/carto/tree/definition.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ var assert = require('assert'),
// }
//
// The selector can have filters
tree.Definition = function Definition(selector, rules) {
tree.Definition = function Definition(selector, rules, env) {
var that = this;

this.elements = selector.elements;
assert.ok(selector.filters instanceof tree.Filterset);
this.rules = rules;
Expand All @@ -19,10 +21,42 @@ tree.Definition = function Definition(selector, rules) {
this.rules[i].zoom = selector.zoom;
this.ruleIndex[this.rules[i].updateID()] = true;
}

this.filters = selector.filters;
if (this.filters) {
if (_.isArray(this.filters)) {
_.forEach(this.filters, function (f) {
if (typeof f.setRule === 'function') {
f.setRule(that);
}
});
}
else {
if (typeof this.filters.setRule === 'function') {
this.filters.setRule(that);
}
}
}

this.zoom = selector.zoom;

if (this.zoom) {
if (_.isArray(this.zoom)) {
_.forEach(this.zoom, function (f) {
if (typeof f.setRule === 'function') {
f.setRule(that);
}
});
}
else {
if (typeof this.zoom.setRule === 'function') {
this.zoom.setRule(that);
}
}
}

this.attachment = selector.attachment || '__default__';
this.specificity = selector.specificity();
this.specificity = selector.specificity(env);
this.matchCount = 0;

// special handling for Map selector
Expand All @@ -47,17 +81,34 @@ tree.Definition.prototype.clone = function(filters) {
clone.ruleIndex = _.clone(this.ruleIndex);
clone.filters = filters ? filters : this.filters.clone();
clone.attachment = this.attachment;
clone.matchCount = this.matchCount;
clone.specificity = this.specificity;
clone.zoom = this.zoom;
return clone;
};

tree.Definition.prototype.addRules = function(rules) {
var added = 0;
var added = 0,
parent = null;

if (this.rules.length && this.rules[0]) {
parent = this.rules[0].parent;
}

// Add only unique rules.
for (var i = 0; i < rules.length; i++) {
if (!this.ruleIndex[rules[i].id]) {
this.rules.push(rules[i]);
this.ruleIndex[rules[i].id] = true;
var rule = rules[i].clone();
rule.parent = parent;
// match rule to definition zoom level
// if rule zoom less specific than definition zoom
if (this.zoom && rule.zoom > this.zoom) {
rule.zoom = this.zoom;
rule.updateID();
}

if (!this.ruleIndex[rule.id]) {
this.rules.push(rule);
this.ruleIndex[rule.id] = true;
added++;
}
}
Expand Down Expand Up @@ -224,9 +275,9 @@ tree.Definition.prototype.collectSymbolizers = function(zooms, i) {
}
};

// The tree.Zoom.toString function ignores the holes in zoom ranges and outputs
// The tree.Zoom.toObject function ignores the holes in zoom ranges and outputs
// scaledenominators that cover the whole range from the first to last bit set.
// This algorithm can produces zoom ranges that may have holes. However,
// This algorithm can produce zoom ranges that may have holes. However,
// when using the filter-mode="first", more specific zoom filters will always
// end up before broader ranges. The filter-mode will pick those first before
// resorting to the zoom range with the hole and stop processing further rules.
Expand Down
7 changes: 7 additions & 0 deletions lib/carto/tree/dimension.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ tree.Dimension = function Dimension(value, unit, index, filename) {
this.unit = unit || null;
this.filename = filename;
this.index = index;
this.rule = null;
};

tree.Dimension.prototype = {
Expand Down Expand Up @@ -96,6 +97,12 @@ tree.Dimension.prototype = {
//here the operands are either the same (% or undefined or px), or one is undefined and the other is px
return new tree.Dimension(tree.operate(op, this.value, other.value),
this.unit || other.unit, this.index, this.filename);
},
setRule: function (rule) {
this.rule = rule;
},
clone: function () {
return _.clone(this);
}
};

Expand Down
42 changes: 42 additions & 0 deletions lib/carto/tree/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var _ = require('lodash');

tree.Expression = function Expression(value) {
this.value = value;
this.rule = null;
};

tree.Expression.prototype = {
Expand Down Expand Up @@ -33,6 +34,47 @@ tree.Expression.prototype = {
return mappedVal;
}
return mappedVal.join(' ');
},

setRule: function (rule) {
this.rule = rule;
if (_.isArray(this.value)) {
_.forEach(this.value, function (v) {
if (typeof v.setRule === 'function') {
v.setRule(rule);
}
});
}
else {
if (typeof this.value.setRule === 'function') {
this.value.setRule(rule);
}
}
},

clone: function () {
var clone = Object.create(tree.Expression.prototype);
clone.rule = this.rule;
if (_.isArray(this.value)) {
clone.value = [];
_.forEach(this.value, function (v) {
if (typeof v.clone === 'function') {
clone.value.push(v.clone());
}
else {
clone.value.push(v);
}
});
}
else {
if (typeof this.value.clone === 'function') {
clone.value = this.value.clone();
}
else {
clone.value = this.value;
}
}
return clone;
}
};

Expand Down
18 changes: 18 additions & 0 deletions lib/carto/tree/field.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

tree.Field = function Field(content) {
this.value = content || '';
this.rule = null;
};

tree.Field.prototype = {
Expand All @@ -11,6 +12,23 @@ tree.Field.prototype = {
},
'ev': function() {
return this;
},
setRule: function (rule) {
this.rule = rule;
if (typeof this.value.setRule === 'function') {
this.value.setRule(rule);
}
},
clone: function () {
var clone = Object.create(tree.Field.prototype);
clone.rule = this.rule;
if (typeof this.value.clone === 'function') {
clone.value = this.value.clone();
}
else {
clone.value = this.value;
}
return clone;
}
};

Expand Down
14 changes: 14 additions & 0 deletions lib/carto/tree/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ tree.Filter = function Filter(key, op, val, index, filename) {
this.val = val;
this.index = index;
this.filename = filename;
this.rule = null;

this.id = this.key + this.op + this.val;
};
Expand Down Expand Up @@ -67,4 +68,17 @@ tree.Filter.prototype.toString = function() {
return '[' + this.id + ']';
};

tree.Filter.prototype.setRule = function (rule) {
this.rule = rule;
if (typeof this.key.setRule === 'function') {
this.key.setRule(rule);
}
if (typeof this.op.setRule === 'function') {
this.op.setRule(rule);
}
if (typeof this.val.setRule === 'function') {
this.val.setRule(rule);
}
}

})(require('../tree'));
16 changes: 14 additions & 2 deletions lib/carto/tree/filterset.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
var tree = require('../tree'),
util = require('../util');
util = require('../util'),
_ = require('lodash');

tree.Filterset = function Filterset() {
this.filters = {};
this.rule = null;
};

tree.Filterset.prototype.toObject = function(env) {
Expand Down Expand Up @@ -50,8 +52,9 @@ tree.Filterset.prototype.ev = function(env) {
tree.Filterset.prototype.clone = function() {
var clone = new tree.Filterset();
for (var id in this.filters) {
clone.filters[id] = this.filters[id];
clone.filters[id] = _.clone(this.filters[id]);
}
clone.rule = this.rule;
return clone;
};

Expand Down Expand Up @@ -288,3 +291,12 @@ tree.Filterset.prototype.add = function(filter) {
}
}
};

tree.Filterset.prototype.setRule = function (rule) {
this.rule = rule;
_.forEach(this.filters, function (f) {
if (typeof f.setRule === 'function') {
f.setRule(rule);
}
});
}
Loading

0 comments on commit 7b2722f

Please sign in to comment.