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

Commit e919b6b

Browse files
committed
add ability to define variables within selectors and filters, ref #461
1 parent d240d6b commit e919b6b

33 files changed

+770
-99
lines changed

lib/carto/parser.js

+1-18
Original file line numberDiff line numberDiff line change
@@ -237,28 +237,11 @@ carto.Parser = function Parser(env) {
237237

238238
// call populates Invalid-caused errors
239239
var definitions = this.flatten([], [], env);
240-
definitions.sort(specificitySort);
240+
definitions.sort(tree.specificitySort);
241241
return definitions;
242242
};
243243
})();
244244

245-
// Sort rules by specificity: this function expects selectors to be
246-
// split already.
247-
//
248-
// Written to be used as a .sort(Function);
249-
// argument.
250-
//
251-
// [1, 0, 0, 467] > [0, 0, 1, 520]
252-
var specificitySort = function(a, b) {
253-
var as = a.specificity;
254-
var bs = b.specificity;
255-
256-
if (as[0] != bs[0]) return bs[0] - as[0];
257-
if (as[1] != bs[1]) return bs[1] - as[1];
258-
if (as[2] != bs[2]) return bs[2] - as[2];
259-
return bs[3] - as[3];
260-
};
261-
262245
return root;
263246
},
264247

lib/carto/renderer.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -555,11 +555,13 @@ function sortStyles(styles) {
555555
function foldStyle(style) {
556556
for (var i = 0; i < style.length; i++) {
557557
for (var j = style.length - 1; j > i; j--) {
558-
if (style[j].filters.cloneWith(style[i].filters) === null) {
558+
if (style[j].zoom === style[i].zoom &&
559+
style[j].filters.cloneWith(style[i].filters) === null) {
559560
style.splice(j, 1);
560561
}
561562
}
562563
}
564+
563565
return style;
564566
}
565567

lib/carto/tree.js

+28
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,31 @@ module.exports.find = function (obj, fun) {
88
}
99
return null;
1010
};
11+
12+
// Sort rules by specificity: this function expects selectors to be
13+
// split already.
14+
//
15+
// Specificity: [ID, Class, Filters, Zoom, Position in document]
16+
//
17+
// Written to be used as a .sort(Function);
18+
// argument.
19+
//
20+
// [1, 0, 0, 467] > [0, 0, 1, 520]
21+
module.exports.specificitySort = function (a, b) {
22+
var as = a.specificity;
23+
var bs = b.specificity;
24+
25+
if (as[0] != bs[0]) { // ID
26+
return bs[0] - as[0];
27+
}
28+
if (as[1] != bs[1]) { // Class
29+
return bs[1] - as[1];
30+
}
31+
if (as[2] != bs[2]) { // Filters
32+
return bs[2] - as[2];
33+
}
34+
if (as[3] != -1 && bs[3] != -1 && as[3] != bs[3]) { // Zoom
35+
return bs[4] - as[4];
36+
}
37+
return bs[4] - as[4]; // Position in document
38+
};

lib/carto/tree/call.js

+9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ tree.Call = function Call(name, args, filename, index) {
77
this.args = args;
88
this.filename = filename;
99
this.index = index;
10+
this.rule = null;
1011
};
1112

1213
tree.Call.prototype = {
@@ -105,6 +106,14 @@ tree.Call.prototype = {
105106
} else {
106107
return this.name;
107108
}
109+
},
110+
setRule: function (rule) {
111+
this.rule = rule;
112+
_.forEach(this.args, function (a) {
113+
if (typeof a.setRule === 'function') {
114+
a.setRule(rule);
115+
}
116+
});
108117
}
109118
};
110119

lib/carto/tree/color.js

+9
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ tree.Color = function Color(hsl, a, perceptual) {
2929
} else {
3030
this.perceptual = false;
3131
}
32+
this.rule = null;
3233
};
3334

3435
tree.Color.prototype = {
@@ -149,6 +150,14 @@ tree.Color.prototype = {
149150

150151
round: function(value, decimals) {
151152
return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
153+
},
154+
155+
setRule: function (rule) {
156+
this.rule = rule;
157+
},
158+
159+
clone: function () {
160+
return _.clone(this);
152161
}
153162
};
154163

lib/carto/tree/definition.js

+59-8
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ var assert = require('assert'),
99
// }
1010
//
1111
// The selector can have filters
12-
tree.Definition = function Definition(selector, rules) {
12+
tree.Definition = function Definition(selector, rules, env) {
13+
var that = this;
14+
1315
this.elements = selector.elements;
1416
assert.ok(selector.filters instanceof tree.Filterset);
1517
this.rules = rules;
@@ -19,10 +21,42 @@ tree.Definition = function Definition(selector, rules) {
1921
this.rules[i].zoom = selector.zoom;
2022
this.ruleIndex[this.rules[i].updateID()] = true;
2123
}
24+
2225
this.filters = selector.filters;
26+
if (this.filters) {
27+
if (_.isArray(this.filters)) {
28+
_.forEach(this.filters, function (f) {
29+
if (typeof f.setRule === 'function') {
30+
f.setRule(that);
31+
}
32+
});
33+
}
34+
else {
35+
if (typeof this.filters.setRule === 'function') {
36+
this.filters.setRule(that);
37+
}
38+
}
39+
}
40+
2341
this.zoom = selector.zoom;
42+
43+
if (this.zoom) {
44+
if (_.isArray(this.zoom)) {
45+
_.forEach(this.zoom, function (f) {
46+
if (typeof f.setRule === 'function') {
47+
f.setRule(that);
48+
}
49+
});
50+
}
51+
else {
52+
if (typeof this.zoom.setRule === 'function') {
53+
this.zoom.setRule(that);
54+
}
55+
}
56+
}
57+
2458
this.attachment = selector.attachment || '__default__';
25-
this.specificity = selector.specificity();
59+
this.specificity = selector.specificity(env);
2660
this.matchCount = 0;
2761

2862
// special handling for Map selector
@@ -47,17 +81,34 @@ tree.Definition.prototype.clone = function(filters) {
4781
clone.ruleIndex = _.clone(this.ruleIndex);
4882
clone.filters = filters ? filters : this.filters.clone();
4983
clone.attachment = this.attachment;
84+
clone.matchCount = this.matchCount;
85+
clone.specificity = this.specificity;
86+
clone.zoom = this.zoom;
5087
return clone;
5188
};
5289

5390
tree.Definition.prototype.addRules = function(rules) {
54-
var added = 0;
91+
var added = 0,
92+
parent = null;
93+
94+
if (this.rules.length && this.rules[0]) {
95+
parent = this.rules[0].parent;
96+
}
5597

5698
// Add only unique rules.
5799
for (var i = 0; i < rules.length; i++) {
58-
if (!this.ruleIndex[rules[i].id]) {
59-
this.rules.push(rules[i]);
60-
this.ruleIndex[rules[i].id] = true;
100+
var rule = rules[i].clone();
101+
rule.parent = parent;
102+
// match rule to definition zoom level
103+
// if rule zoom less specific than definition zoom
104+
if (this.zoom && rule.zoom > this.zoom) {
105+
rule.zoom = this.zoom;
106+
rule.updateID();
107+
}
108+
109+
if (!this.ruleIndex[rule.id]) {
110+
this.rules.push(rule);
111+
this.ruleIndex[rule.id] = true;
61112
added++;
62113
}
63114
}
@@ -224,9 +275,9 @@ tree.Definition.prototype.collectSymbolizers = function(zooms, i) {
224275
}
225276
};
226277

227-
// The tree.Zoom.toString function ignores the holes in zoom ranges and outputs
278+
// The tree.Zoom.toObject function ignores the holes in zoom ranges and outputs
228279
// scaledenominators that cover the whole range from the first to last bit set.
229-
// This algorithm can produces zoom ranges that may have holes. However,
280+
// This algorithm can produce zoom ranges that may have holes. However,
230281
// when using the filter-mode="first", more specific zoom filters will always
231282
// end up before broader ranges. The filter-mode will pick those first before
232283
// resorting to the zoom range with the hole and stop processing further rules.

lib/carto/tree/dimension.js

+7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ tree.Dimension = function Dimension(value, unit, index, filename) {
1010
this.unit = unit || null;
1111
this.filename = filename;
1212
this.index = index;
13+
this.rule = null;
1314
};
1415

1516
tree.Dimension.prototype = {
@@ -96,6 +97,12 @@ tree.Dimension.prototype = {
9697
//here the operands are either the same (% or undefined or px), or one is undefined and the other is px
9798
return new tree.Dimension(tree.operate(op, this.value, other.value),
9899
this.unit || other.unit, this.index, this.filename);
100+
},
101+
setRule: function (rule) {
102+
this.rule = rule;
103+
},
104+
clone: function () {
105+
return _.clone(this);
99106
}
100107
};
101108

lib/carto/tree/expression.js

+42
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var _ = require('lodash');
44

55
tree.Expression = function Expression(value) {
66
this.value = value;
7+
this.rule = null;
78
};
89

910
tree.Expression.prototype = {
@@ -33,6 +34,47 @@ tree.Expression.prototype = {
3334
return mappedVal;
3435
}
3536
return mappedVal.join(' ');
37+
},
38+
39+
setRule: function (rule) {
40+
this.rule = rule;
41+
if (_.isArray(this.value)) {
42+
_.forEach(this.value, function (v) {
43+
if (typeof v.setRule === 'function') {
44+
v.setRule(rule);
45+
}
46+
});
47+
}
48+
else {
49+
if (typeof this.value.setRule === 'function') {
50+
this.value.setRule(rule);
51+
}
52+
}
53+
},
54+
55+
clone: function () {
56+
var clone = Object.create(tree.Expression.prototype);
57+
clone.rule = this.rule;
58+
if (_.isArray(this.value)) {
59+
clone.value = [];
60+
_.forEach(this.value, function (v) {
61+
if (typeof v.clone === 'function') {
62+
clone.value.push(v.clone());
63+
}
64+
else {
65+
clone.value.push(v);
66+
}
67+
});
68+
}
69+
else {
70+
if (typeof this.value.clone === 'function') {
71+
clone.value = this.value.clone();
72+
}
73+
else {
74+
clone.value = this.value;
75+
}
76+
}
77+
return clone;
3678
}
3779
};
3880

lib/carto/tree/field.js

+18
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
tree.Field = function Field(content) {
44
this.value = content || '';
5+
this.rule = null;
56
};
67

78
tree.Field.prototype = {
@@ -11,6 +12,23 @@ tree.Field.prototype = {
1112
},
1213
'ev': function() {
1314
return this;
15+
},
16+
setRule: function (rule) {
17+
this.rule = rule;
18+
if (typeof this.value.setRule === 'function') {
19+
this.value.setRule(rule);
20+
}
21+
},
22+
clone: function () {
23+
var clone = Object.create(tree.Field.prototype);
24+
clone.rule = this.rule;
25+
if (typeof this.value.clone === 'function') {
26+
clone.value = this.value.clone();
27+
}
28+
else {
29+
clone.value = this.value;
30+
}
31+
return clone;
1432
}
1533
};
1634

lib/carto/tree/filter.js

+14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ tree.Filter = function Filter(key, op, val, index, filename) {
88
this.val = val;
99
this.index = index;
1010
this.filename = filename;
11+
this.rule = null;
1112

1213
this.id = this.key + this.op + this.val;
1314
};
@@ -67,4 +68,17 @@ tree.Filter.prototype.toString = function() {
6768
return '[' + this.id + ']';
6869
};
6970

71+
tree.Filter.prototype.setRule = function (rule) {
72+
this.rule = rule;
73+
if (typeof this.key.setRule === 'function') {
74+
this.key.setRule(rule);
75+
}
76+
if (typeof this.op.setRule === 'function') {
77+
this.op.setRule(rule);
78+
}
79+
if (typeof this.val.setRule === 'function') {
80+
this.val.setRule(rule);
81+
}
82+
}
83+
7084
})(require('../tree'));

lib/carto/tree/filterset.js

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
var tree = require('../tree'),
2-
util = require('../util');
2+
util = require('../util'),
3+
_ = require('lodash');
34

45
tree.Filterset = function Filterset() {
56
this.filters = {};
7+
this.rule = null;
68
};
79

810
tree.Filterset.prototype.toObject = function(env) {
@@ -50,8 +52,9 @@ tree.Filterset.prototype.ev = function(env) {
5052
tree.Filterset.prototype.clone = function() {
5153
var clone = new tree.Filterset();
5254
for (var id in this.filters) {
53-
clone.filters[id] = this.filters[id];
55+
clone.filters[id] = _.clone(this.filters[id]);
5456
}
57+
clone.rule = this.rule;
5558
return clone;
5659
};
5760

@@ -288,3 +291,12 @@ tree.Filterset.prototype.add = function(filter) {
288291
}
289292
}
290293
};
294+
295+
tree.Filterset.prototype.setRule = function (rule) {
296+
this.rule = rule;
297+
_.forEach(this.filters, function (f) {
298+
if (typeof f.setRule === 'function') {
299+
f.setRule(rule);
300+
}
301+
});
302+
}

0 commit comments

Comments
 (0)