diff --git a/examples/filter-points-webgl.js b/examples/filter-points-webgl.js
index fa09676c8b..b2d39f0bd6 100644
--- a/examples/filter-points-webgl.js
+++ b/examples/filter-points-webgl.js
@@ -18,7 +18,7 @@ const period = 12; // animation period in seconds
const animRatio =
['^',
['/',
- ['mod',
+ ['%',
['+',
['time'],
[
diff --git a/examples/icon-sprite-webgl.html b/examples/icon-sprite-webgl.html
index 2af2b66f59..2a6bce2201 100644
--- a/examples/icon-sprite-webgl.html
+++ b/examples/icon-sprite-webgl.html
@@ -20,3 +20,7 @@ cloak:
---
Current sighting:
+
+ Filter by UFO shape:
+
+
diff --git a/examples/icon-sprite-webgl.js b/examples/icon-sprite-webgl.js
index 434473ca36..45d78a80fd 100644
--- a/examples/icon-sprite-webgl.js
+++ b/examples/icon-sprite-webgl.js
@@ -10,6 +10,22 @@ import WebGLPointsLayer from '../src/ol/layer/WebGLPoints.js';
const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg';
+const map = new Map({
+ layers: [
+ new TileLayer({
+ source: new TileJSON({
+ url: 'https://api.tiles.mapbox.com/v4/mapbox.world-dark.json?secure&access_token=' + key,
+ crossOrigin: 'anonymous'
+ })
+ })
+ ],
+ target: document.getElementById('map'),
+ view: new View({
+ center: [0, 4000000],
+ zoom: 2
+ })
+});
+
const vectorSource = new Vector({
features: [],
attributions: 'National UFO Reporting Center'
@@ -20,6 +36,15 @@ const newColor = [180, 255, 200];
const size = 16;
const style = {
+ variables: {
+ filterShape: 'all'
+ },
+ filter: [
+ 'case',
+ ['!=', ['var', 'filterShape'], 'all'],
+ ['==', ['get', 'shape'], ['var', 'filterShape']],
+ true
+ ],
symbol: {
symbolType: 'image',
src: 'data/ufo_shapes.png',
@@ -51,61 +76,71 @@ const style = {
}
};
-function loadData() {
- const client = new XMLHttpRequest();
- client.open('GET', 'data/csv/ufo_sighting_data.csv');
- client.onload = function() {
- const csv = client.responseText;
- const features = [];
-
- let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
-
- let curIndex;
- while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
- const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
- prevIndex = curIndex + 1;
-
- const coords = fromLonLat([parseFloat(line[5]), parseFloat(line[4])]);
-
- // only keep valid points
- if (isNaN(coords[0]) || isNaN(coords[1])) {
- continue;
- }
-
- features.push(new Feature({
- datetime: line[0],
- year: parseInt(/[0-9]{4}/.exec(line[0])[0]), // extract the year as int
- shape: line[2],
- duration: line[3],
- geometry: new Point(coords)
- }));
- }
- vectorSource.addFeatures(features);
- };
- client.send();
+// key is shape name, value is sightings count
+const shapeTypes = {
+ all: 0
+};
+const shapeSelect = document.getElementById('shape-filter');
+shapeSelect.addEventListener('input', function() {
+ style.variables.filterShape = shapeSelect.options[shapeSelect.selectedIndex].value;
+ map.render();
+});
+function fillShapeSelect() {
+ Object.keys(shapeTypes)
+ .sort(function(a, b) {
+ return shapeTypes[b] - shapeTypes[a];
+ })
+ .forEach(function(shape) {
+ const option = document.createElement('option');
+ option.text = `${shape} (${shapeTypes[shape]} sightings)`;
+ option.value = shape;
+ shapeSelect.appendChild(option);
+ });
}
-loadData();
+const client = new XMLHttpRequest();
+client.open('GET', 'data/csv/ufo_sighting_data.csv');
+client.onload = function() {
+ const csv = client.responseText;
+ const features = [];
-const map = new Map({
- layers: [
- new TileLayer({
- source: new TileJSON({
- url: 'https://api.tiles.mapbox.com/v4/mapbox.world-dark.json?secure&access_token=' + key,
- crossOrigin: 'anonymous'
- })
- }),
- new WebGLPointsLayer({
- source: vectorSource,
- style: style
- })
- ],
- target: document.getElementById('map'),
- view: new View({
- center: [0, 4000000],
- zoom: 2
+ let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
+
+ let curIndex;
+ while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
+ const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
+ prevIndex = curIndex + 1;
+
+ const coords = fromLonLat([parseFloat(line[5]), parseFloat(line[4])]);
+
+ // only keep valid points
+ if (isNaN(coords[0]) || isNaN(coords[1])) {
+ continue;
+ }
+
+ const shape = line[2];
+ shapeTypes[shape] = (shapeTypes[shape] ? shapeTypes[shape] : 0) + 1;
+ shapeTypes['all']++;
+
+ features.push(new Feature({
+ datetime: line[0],
+ year: parseInt(/[0-9]{4}/.exec(line[0])[0]), // extract the year as int
+ shape: shape,
+ duration: line[3],
+ geometry: new Point(coords)
+ }));
+ }
+ vectorSource.addFeatures(features);
+ fillShapeSelect();
+};
+client.send();
+
+map.addLayer(
+ new WebGLPointsLayer({
+ source: vectorSource,
+ style: style
})
-});
+);
const info = document.getElementById('info');
map.on('pointermove', function(evt) {
diff --git a/src/ol/style/expressions.js b/src/ol/style/expressions.js
index d2355648e7..25921154b8 100644
--- a/src/ol/style/expressions.js
+++ b/src/ol/style/expressions.js
@@ -23,10 +23,13 @@ import {asArray, isStringColor} from '../color.js';
* * `['+', value1, value1]` adds `value1` and `value2`
* * `['-', value1, value1]` subtracts `value2` from `value1`
* * `['clamp', value, low, high]` clamps `value` between `low` and `high`
- * * `['mod', value1, value1]` returns the result of `value1 % value2` (modulo)
+ * * `['%', value1, value1]` returns the result of `value1 % value2` (modulo)
* * `['^', value1, value1]` returns the value of `value1` raised to the `value2` power
*
* * Transform operators:
+ * * `['case', condition1, output1, ...conditionN, outputN, fallback]` selects the first output whose corresponding
+ * condition evaluates to `true`. If no match is found, returns the `fallback` value.
+ * All conditions should be `boolean`, output and fallback can be any kind.
* * `['match', input, match1, output1, ...matchN, outputN, fallback]` compares the `input` value against all
* provided `matchX` values, returning the output associated with the first valid match. If no match is found,
* returns the `fallback` value.
@@ -41,14 +44,15 @@ import {asArray, isStringColor} from '../color.js';
* between `output1` and `outputN`.
*
* * Logical operators:
- * * `['<', value1, value2]` returns `1` if `value1` is strictly lower than value 2, or `0` otherwise.
- * * `['<=', value1, value2]` returns `1` if `value1` is lower than or equals value 2, or `0` otherwise.
- * * `['>', value1, value2]` returns `1` if `value1` is strictly greater than value 2, or `0` otherwise.
- * * `['>=', value1, value2]` returns `1` if `value1` is greater than or equals value 2, or `0` otherwise.
- * * `['==', value1, value2]` returns `1` if `value1` equals value 2, or `0` otherwise.
- * * `['!', value1]` returns `0` if `value1` strictly greater than `0`, or `1` otherwise.
- * * `['between', value1, value2, value3]` returns `1` if `value1` is contained between `value2` and `value3`
- * (inclusively), or `0` otherwise.
+ * * `['<', value1, value2]` returns `true` if `value1` is strictly lower than value 2, or `false` otherwise.
+ * * `['<=', value1, value2]` returns `true` if `value1` is lower than or equals value 2, or `false` otherwise.
+ * * `['>', value1, value2]` returns `true` if `value1` is strictly greater than value 2, or `false` otherwise.
+ * * `['>=', value1, value2]` returns `true` if `value1` is greater than or equals value 2, or `false` otherwise.
+ * * `['==', value1, value2]` returns `true` if `value1` equals value 2, or `false` otherwise.
+ * * `['!=', value1, value2]` returns `true` if `value1` equals value 2, or `false` otherwise.
+ * * `['!', value1]` returns `false` if `value1` is `true` or greater than `0`, or `true` otherwise.
+ * * `['between', value1, value2, value3]` returns `true` if `value1` is contained between `value2` and `value3`
+ * (inclusively), or `false` otherwise.
*
* * Conversion operators:
* * `['array', value1, ...valueN]` creates a numerical array from `number` values; please note that the amount of
@@ -59,6 +63,7 @@ import {asArray, isStringColor} from '../color.js';
*
* Values can either be literals or another operator, as they will be evaluated recursively.
* Literal values can be of the following types:
+ * * `boolean`
* * `number`
* * `string`
* * {@link module:ol/color~Color}
@@ -252,9 +257,9 @@ function assertNumber(value) {
throw new Error(`A numeric value was expected, got ${JSON.stringify(value)} instead`);
}
}
-function assertNumbers(arr) {
- for (let i = 0; i < arr.length; i++) {
- assertNumber(arr[i]);
+function assertNumbers(values) {
+ for (let i = 0; i < values.length; i++) {
+ assertNumber(values[i]);
}
}
function assertString(value) {
@@ -287,6 +292,11 @@ function assertArgsEven(args) {
throw new Error(`An even amount of arguments was expected, got ${args} instead`);
}
}
+function assertArgsOdd(args) {
+ if (args.length % 2 === 0) {
+ throw new Error(`An even amount of arguments was expected, got ${args} instead`);
+ }
+}
function assertUniqueInferredType(args, types) {
if (!isTypeUnique(types)) {
throw new Error(`Could not infer only one type from the following expression: ${JSON.stringify(args)}`);
@@ -349,6 +359,7 @@ Operators['resolution'] = {
return 'u_resolution';
}
};
+
Operators['*'] = {
getReturnType: function(args) {
return ValueTypes.NUMBER;
@@ -401,7 +412,7 @@ Operators['clamp'] = {
return `clamp(${expressionToGlsl(context, args[0])}, ${min}, ${max})`;
}
};
-Operators['mod'] = {
+Operators['%'] = {
getReturnType: function(args) {
return ValueTypes.NUMBER;
},
@@ -421,6 +432,7 @@ Operators['^'] = {
return `pow(${expressionToGlsl(context, args[0])}, ${expressionToGlsl(context, args[1])})`;
}
};
+
Operators['>'] = {
getReturnType: function(args) {
return ValueTypes.BOOLEAN;
@@ -461,16 +473,31 @@ Operators['<='] = {
return `(${expressionToGlsl(context, args[0])} <= ${expressionToGlsl(context, args[1])})`;
}
};
-Operators['=='] = {
- getReturnType: function(args) {
- return ValueTypes.BOOLEAN;
- },
- toGlsl: function(context, args) {
- assertArgsCount(args, 2);
- assertNumbers(args);
- return `(${expressionToGlsl(context, args[0])} == ${expressionToGlsl(context, args[1])})`;
- }
-};
+
+function getEqualOperator(operator) {
+ return {
+ getReturnType: function(args) {
+ return ValueTypes.BOOLEAN;
+ },
+ toGlsl: function(context, args) {
+ assertArgsCount(args, 2);
+
+ // find common type
+ let type = ValueTypes.ANY;
+ for (let i = 0; i < args.length; i++) {
+ type = type & getValueType(args[i]);
+ }
+ if (type === 0) {
+ throw new Error(`All arguments should be of compatible type, got ${JSON.stringify(args)} instead`);
+ }
+
+ return `(${expressionToGlsl(context, args[0], type)} ${operator} ${expressionToGlsl(context, args[1], type)})`;
+ }
+ };
+}
+Operators['=='] = getEqualOperator('==');
+Operators['!='] = getEqualOperator('!=');
+
Operators['!'] = {
getReturnType: function(args) {
return ValueTypes.BOOLEAN;
@@ -494,6 +521,7 @@ Operators['between'] = {
return `(${value} >= ${min} && ${value} <= ${max})`;
}
};
+
Operators['array'] = {
getReturnType: function(args) {
return ValueTypes.NUMBER_ARRAY;
@@ -526,6 +554,7 @@ Operators['color'] = {
return `vec${args.length}(${parsedArgs.join(', ')})`;
}
};
+
Operators['interpolate'] = {
getReturnType: function(args) {
let type = ValueTypes.COLOR | ValueTypes.NUMBER;
@@ -580,7 +609,6 @@ Operators['match'] = {
assertArgsEven(args);
assertArgsMinCount(args, 4);
- // compute input/output types
const typeHint = opt_typeHint !== undefined ? opt_typeHint : ValueTypes.ANY;
const outputType = Operators['match'].getReturnType(args) & typeHint;
assertUniqueInferredType(args, outputType);
@@ -596,3 +624,33 @@ Operators['match'] = {
return result;
}
};
+Operators['case'] = {
+ getReturnType: function(args) {
+ let type = ValueTypes.ANY;
+ for (let i = 1; i < args.length; i += 2) {
+ type = type & getValueType(args[i]);
+ }
+ type = type & getValueType(args[args.length - 1]);
+ return type;
+ },
+ toGlsl: function(context, args, opt_typeHint) {
+ assertArgsOdd(args);
+ assertArgsMinCount(args, 3);
+
+ const typeHint = opt_typeHint !== undefined ? opt_typeHint : ValueTypes.ANY;
+ const outputType = Operators['case'].getReturnType(args) & typeHint;
+ assertUniqueInferredType(args, outputType);
+ for (let i = 0; i < args.length - 1; i += 2) {
+ assertBoolean(args[i]);
+ }
+
+ const fallback = expressionToGlsl(context, args[args.length - 1], outputType);
+ let result = null;
+ for (let i = args.length - 3; i >= 0; i -= 2) {
+ const condition = expressionToGlsl(context, args[i]);
+ const output = expressionToGlsl(context, args[i + 1], outputType);
+ result = `(${condition} ? ${output} : ${result || fallback})`;
+ }
+ return result;
+ }
+};
diff --git a/src/ol/webgl/ShaderBuilder.js b/src/ol/webgl/ShaderBuilder.js
index e3a141e187..bea9a05926 100644
--- a/src/ol/webgl/ShaderBuilder.js
+++ b/src/ol/webgl/ShaderBuilder.js
@@ -3,7 +3,7 @@
* @module ol/webgl/ShaderBuilder
*/
-import {expressionToGlsl, ValueTypes} from '../style/expressions.js';
+import {expressionToGlsl, stringToGlsl, ValueTypes} from '../style/expressions.js';
/**
* @typedef {Object} VaryingDescription
@@ -445,8 +445,14 @@ export function parseLiteralStyle(style) {
fragContext.variables.forEach(function(varName) {
builder.addUniform(`float u_${varName}`);
uniforms[`u_${varName}`] = function() {
- return style.variables && style.variables[varName] !== undefined ?
- style.variables[varName] : 0;
+ if (!style.variables || style.variables[varName] === undefined) {
+ throw new Error(`The following variable is missing from the style: ${varName}`);
+ }
+ let value = style.variables[varName];
+ if (typeof value === 'string') {
+ value = parseFloat(stringToGlsl(vertContext, value));
+ }
+ return value !== undefined ? value : -9999999; // to avoid matching with the first string literal
};
});
@@ -481,7 +487,7 @@ export function parseLiteralStyle(style) {
callback: function(feature) {
let value = feature.get(attributeName);
if (typeof value === 'string') {
- value = vertContext.stringLiteralsMap[value];
+ value = parseFloat(stringToGlsl(vertContext, value));
}
return value !== undefined ? value : -9999999; // to avoid matching with the first string literal
}
diff --git a/test/spec/ol/style/expressions.test.js b/test/spec/ol/style/expressions.test.js
index d2aa7bf273..d3d15fdf48 100644
--- a/test/spec/ol/style/expressions.test.js
+++ b/test/spec/ol/style/expressions.test.js
@@ -130,12 +130,13 @@ describe('ol.style.expressions', function() {
expect(getValueType(['*', ['get', 'size'], 12])).to.eql(ValueTypes.NUMBER);
expect(getValueType(['clamp', ['get', 'attr2'], ['get', 'attr3'], 20])).to.eql(ValueTypes.NUMBER);
expect(getValueType(['^', 10, 2])).to.eql(ValueTypes.NUMBER);
- expect(getValueType(['mod', ['time'], 10])).to.eql(ValueTypes.NUMBER);
+ expect(getValueType(['%', ['time'], 10])).to.eql(ValueTypes.NUMBER);
expect(getValueType(['>', 10, ['get', 'attr4']])).to.eql(ValueTypes.BOOLEAN);
expect(getValueType(['>=', 10, ['get', 'attr4']])).to.eql(ValueTypes.BOOLEAN);
expect(getValueType(['<', 10, ['get', 'attr4']])).to.eql(ValueTypes.BOOLEAN);
expect(getValueType(['<=', 10, ['get', 'attr4']])).to.eql(ValueTypes.BOOLEAN);
expect(getValueType(['==', 10, ['get', 'attr4']])).to.eql(ValueTypes.BOOLEAN);
+ expect(getValueType(['!=', 10, ['get', 'attr4']])).to.eql(ValueTypes.BOOLEAN);
expect(getValueType(['between', ['get', 'attr4'], -4.0, 5.0])).to.eql(ValueTypes.BOOLEAN);
expect(getValueType(['!', ['get', 'attr4']])).to.eql(ValueTypes.BOOLEAN);
expect(getValueType(['array', ['get', 'attr4'], 1, 2, 3])).to.eql(ValueTypes.NUMBER_ARRAY);
@@ -164,12 +165,13 @@ describe('ol.style.expressions', function() {
expect(expressionToGlsl(context, ['+', ['*', ['get', 'size'], 0.001], 12])).to.eql('((a_size * 0.001) + 12.0)');
expect(expressionToGlsl(context, ['/', ['-', ['get', 'size'], 20], 100])).to.eql('((a_size - 20.0) / 100.0)');
expect(expressionToGlsl(context, ['clamp', ['get', 'attr2'], ['get', 'attr3'], 20])).to.eql('clamp(a_attr2, a_attr3, 20.0)');
- expect(expressionToGlsl(context, ['^', ['mod', ['time'], 10], 2])).to.eql('pow(mod(u_time, 10.0), 2.0)');
+ expect(expressionToGlsl(context, ['^', ['%', ['time'], 10], 2])).to.eql('pow(mod(u_time, 10.0), 2.0)');
expect(expressionToGlsl(context, ['>', 10, ['get', 'attr4']])).to.eql('(10.0 > a_attr4)');
expect(expressionToGlsl(context, ['>=', 10, ['get', 'attr4']])).to.eql('(10.0 >= a_attr4)');
expect(expressionToGlsl(context, ['<', 10, ['get', 'attr4']])).to.eql('(10.0 < a_attr4)');
expect(expressionToGlsl(context, ['<=', 10, ['get', 'attr4']])).to.eql('(10.0 <= a_attr4)');
expect(expressionToGlsl(context, ['==', 10, ['get', 'attr4']])).to.eql('(10.0 == a_attr4)');
+ expect(expressionToGlsl(context, ['!=', 10, ['get', 'attr4']])).to.eql('(10.0 != a_attr4)');
expect(expressionToGlsl(context, ['between', ['get', 'attr4'], -4.0, 5.0])).to.eql('(a_attr4 >= -4.0 && a_attr4 <= 5.0)');
expect(expressionToGlsl(context, ['!', ['get', 'attr4']])).to.eql('(!a_attr4)');
expect(expressionToGlsl(context, ['array', ['get', 'attr4'], 1, 2, 3])).to.eql('vec4(a_attr4, 1.0, 2.0, 3.0)');
@@ -292,6 +294,94 @@ describe('ol.style.expressions', function() {
});
});
+ describe('case operator', function() {
+ let context;
+
+ beforeEach(function() {
+ context = {
+ variables: [],
+ attributes: [],
+ stringLiteralsMap: {}
+ };
+ });
+
+ it('correctly guesses the output type', function() {
+ expect(getValueType(['case', true, 0, false, [3, 4, 5], 'green']))
+ .to.eql(ValueTypes.NONE);
+ expect(getValueType(['case', true, 0, false, 1, 2]))
+ .to.eql(ValueTypes.NUMBER);
+ expect(getValueType(['case', true, [0, 0, 0], true, [1, 2, 3], ['get', 'attr'], [4, 5, 6, 7], [8, 9, 0]]))
+ .to.eql(ValueTypes.COLOR | ValueTypes.NUMBER_ARRAY);
+ expect(getValueType(['case', true, 'red', true, 'yellow', ['get', 'attr'], 'green', 'white']))
+ .to.eql(ValueTypes.COLOR | ValueTypes.STRING);
+ expect(getValueType(['case', true, [0, 0], false, [1, 1], [2, 2]]))
+ .to.eql(ValueTypes.NUMBER_ARRAY);
+ });
+
+ it('throws if no single output type could be inferred', function() {
+ let thrown = false;
+ try {
+ expressionToGlsl(context, ['case', false, 'red', true, 'yellow', 'green'], ValueTypes.COLOR);
+ } catch (e) {
+ thrown = true;
+ }
+ expect(thrown).to.be(false);
+
+ try {
+ expressionToGlsl(context, ['case', true, 'red', true, 'yellow', 'green']);
+ } catch (e) {
+ thrown = true;
+ }
+ expect(thrown).to.be(true);
+
+ thrown = false;
+ try {
+ expressionToGlsl(context, ['case', true, 'red', false, 'yellow', 'green'], ValueTypes.NUMBER);
+ } catch (e) {
+ thrown = true;
+ }
+ expect(thrown).to.be(true);
+
+ thrown = false;
+ try {
+ expressionToGlsl(context, ['case', true, 'red', false, 'yellow', 'not_a_color'], ValueTypes.COLOR);
+ } catch (e) {
+ thrown = true;
+ }
+ expect(thrown).to.be(true);
+ });
+
+ it('throws if invalid argument count', function() {
+ let thrown = false;
+ try {
+ expressionToGlsl(context, ['case', true, 0, false, 1]);
+ } catch (e) {
+ thrown = true;
+ }
+ expect(thrown).to.be(true);
+
+ thrown = false;
+ try {
+ expressionToGlsl(context, ['case', true, 0]);
+ } catch (e) {
+ thrown = true;
+ }
+ expect(thrown).to.be(true);
+
+ try {
+ expressionToGlsl(context, ['case', false]);
+ } catch (e) {
+ thrown = true;
+ }
+ expect(thrown).to.be(true);
+ });
+
+ it('correctly parses the expression (colors)', function() {
+ expect(expressionToGlsl(context, ['case', ['>', ['get', 'attr'], 3], 'red', ['>', ['get', 'attr'], 1], 'yellow', 'white'], ValueTypes.COLOR))
+ .to.eql('((a_attr > 3.0) ? vec4(1.0, 0.0, 0.0, 1.0) : ((a_attr > 1.0) ? vec4(1.0, 1.0, 0.0, 1.0) : vec4(1.0, 1.0, 1.0, 1.0)))');
+ });
+ });
+
describe('match operator', function() {
let context;
@@ -529,7 +619,7 @@ describe('ol.style.expressions', function() {
['linear'],
['^',
['/',
- ['mod',
+ ['%',
['+',
['time'],
[
diff --git a/test/spec/ol/webgl/shaderbuilder.test.js b/test/spec/ol/webgl/shaderbuilder.test.js
index f2b9145c96..4b08699ebb 100644
--- a/test/spec/ol/webgl/shaderbuilder.test.js
+++ b/test/spec/ol/webgl/shaderbuilder.test.js
@@ -402,6 +402,56 @@ void main(void) {
expect(result.attributes).to.eql([]);
expect(result.uniforms).to.have.property('u_ratio');
});
+
+ it('correctly adds string variables to the string literals mapping', function() {
+ const result = parseLiteralStyle({
+ variables: {
+ mySize: 'abcdef'
+ },
+ symbol: {
+ symbolType: 'square',
+ size: ['match', ['var', 'mySize'], 'abc', 10, 'def', 20, 30],
+ color: 'red'
+ }
+ });
+
+ expect(result.uniforms['u_mySize']()).to.be.greaterThan(0);
+ });
+
+ it('throws when a variable is requested but not present in the style', function(done) {
+ const result = parseLiteralStyle({
+ variables: {},
+ symbol: {
+ symbolType: 'square',
+ size: ['var', 'mySize'],
+ color: 'red'
+ }
+ });
+
+ try {
+ result.uniforms['u_mySize']();
+ } catch (e) {
+ done();
+ }
+ done(true);
+ });
+
+ it('throws when a variable is requested but the style does not have a variables dict', function(done) {
+ const result = parseLiteralStyle({
+ symbol: {
+ symbolType: 'square',
+ size: ['var', 'mySize'],
+ color: 'red'
+ }
+ });
+
+ try {
+ result.uniforms['u_mySize']();
+ } catch (e) {
+ done();
+ }
+ done(true);
+ });
});
});