Merge pull request #10168 from jahow/webgl-style-add-filter
Webgl / Add support for filtering and color interpolation in style expressions
This commit is contained in:
@@ -2,6 +2,7 @@ import {
|
||||
asArray,
|
||||
asString,
|
||||
fromString,
|
||||
isStringColor,
|
||||
normalize,
|
||||
toString
|
||||
} from '../../../src/ol/color.js';
|
||||
@@ -159,4 +160,18 @@ describe('ol.color', function() {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('isValid()', function() {
|
||||
|
||||
it('correctly detects valid colors', function() {
|
||||
expect(isStringColor('rgba(1,3,4,0.4)')).to.be(true);
|
||||
expect(isStringColor('rgb(1,3,4)')).to.be(true);
|
||||
expect(isStringColor('lightgreen')).to.be(true);
|
||||
expect(isStringColor('yellow')).to.be(true);
|
||||
expect(isStringColor('GREEN')).to.be(true);
|
||||
expect(isStringColor('notacolor')).to.be(false);
|
||||
expect(isStringColor('red_')).to.be(false);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import WebGLHelper from '../../../../src/ol/webgl/Helper.js';
|
||||
import WebGLHelper, {DefaultUniform} from '../../../../src/ol/webgl/Helper.js';
|
||||
import {
|
||||
create as createTransform,
|
||||
rotate as rotateTransform,
|
||||
@@ -11,9 +11,9 @@ import {FLOAT} from '../../../../src/ol/webgl.js';
|
||||
const VERTEX_SHADER = `
|
||||
precision mediump float;
|
||||
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
uniform float u_time;
|
||||
|
||||
attribute float a_test;
|
||||
uniform float u_test;
|
||||
@@ -25,9 +25,9 @@ const VERTEX_SHADER = `
|
||||
const INVALID_VERTEX_SHADER = `
|
||||
precision mediump float;
|
||||
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
uniform float u_time;
|
||||
|
||||
bla
|
||||
uniform float u_test;
|
||||
@@ -123,6 +123,12 @@ describe('ol.webgl.WebGLHelper', function() {
|
||||
expect(h.getCanvas().height).to.eql(160);
|
||||
});
|
||||
|
||||
it('has processed default uniforms', function() {
|
||||
expect(h.uniformLocations_[DefaultUniform.OFFSET_ROTATION_MATRIX]).not.to.eql(undefined);
|
||||
expect(h.uniformLocations_[DefaultUniform.OFFSET_SCALE_MATRIX]).not.to.eql(undefined);
|
||||
expect(h.uniformLocations_[DefaultUniform.TIME]).not.to.eql(undefined);
|
||||
});
|
||||
|
||||
it('has processed uniforms', function() {
|
||||
expect(h.uniforms_.length).to.eql(4);
|
||||
expect(h.uniforms_[0].name).to.eql('u_test1');
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import {
|
||||
getSymbolVertexShader,
|
||||
check,
|
||||
formatArray,
|
||||
formatColor,
|
||||
formatNumber,
|
||||
getSymbolFragmentShader,
|
||||
formatColor, formatArray, parse, parseSymbolStyle
|
||||
isValueTypeColor,
|
||||
isValueTypeNumber,
|
||||
isValueTypeString,
|
||||
parse,
|
||||
parseLiteralStyle,
|
||||
ShaderBuilder,
|
||||
ValueTypes
|
||||
} from '../../../../src/ol/webgl/ShaderBuilder.js';
|
||||
|
||||
describe('ol.webgl.ShaderBuilder', function() {
|
||||
@@ -19,39 +26,93 @@ describe('ol.webgl.ShaderBuilder', function() {
|
||||
|
||||
describe('formatArray', function() {
|
||||
it('outputs numbers with dot separators', function() {
|
||||
expect(formatArray([1, 0, 3.45, 0.8888])).to.eql('1.0, 0.0, 3.45, 0.8888');
|
||||
expect(formatArray([1, 0, 3.45, 0.8888])).to.eql('vec4(1.0, 0.0, 3.45, 0.8888)');
|
||||
expect(formatArray([3, 4])).to.eql('vec2(3.0, 4.0)');
|
||||
});
|
||||
it('throws on invalid lengths', function() {
|
||||
let thrown = false;
|
||||
try {
|
||||
formatArray([3]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
formatArray([3, 2, 1, 0, -1]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
expect(thrown).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatColor', function() {
|
||||
it('normalizes color and outputs numbers with dot separators', function() {
|
||||
expect(formatColor([100, 0, 255, 1])).to.eql('0.39215686274509803, 0.0, 1.0, 1.0');
|
||||
expect(formatColor([100, 0, 255])).to.eql('vec4(0.39215686274509803, 0.0, 1.0, 1.0)');
|
||||
expect(formatColor([100, 0, 255, 1])).to.eql('vec4(0.39215686274509803, 0.0, 1.0, 1.0)');
|
||||
});
|
||||
it('handles colors in string format', function() {
|
||||
expect(formatColor('red')).to.eql('vec4(1.0, 0.0, 0.0, 1.0)');
|
||||
expect(formatColor('#00ff99')).to.eql('vec4(0.0, 1.0, 0.6, 1.0)');
|
||||
expect(formatColor('rgb(100, 0, 255)')).to.eql('vec4(0.39215686274509803, 0.0, 1.0, 1.0)');
|
||||
expect(formatColor('rgba(100, 0, 255, 0.3)')).to.eql('vec4(0.39215686274509803, 0.0, 1.0, 0.3)');
|
||||
});
|
||||
});
|
||||
|
||||
describe('value type checking', function() {
|
||||
it('correctly recognizes a number value', function() {
|
||||
expect(isValueTypeNumber(1234)).to.eql(true);
|
||||
expect(isValueTypeNumber(['time'])).to.eql(true);
|
||||
expect(isValueTypeNumber(['clamp', ['get', 'attr'], -1, 1])).to.eql(true);
|
||||
expect(isValueTypeNumber(['interpolate', ['get', 'attr'], 'red', 'green'])).to.eql(false);
|
||||
expect(isValueTypeNumber('yellow')).to.eql(false);
|
||||
expect(isValueTypeNumber('#113366')).to.eql(false);
|
||||
expect(isValueTypeNumber('rgba(252,171,48,0.62)')).to.eql(false);
|
||||
});
|
||||
it('correctly recognizes a color value', function() {
|
||||
expect(isValueTypeColor(1234)).to.eql(false);
|
||||
expect(isValueTypeColor(['time'])).to.eql(false);
|
||||
expect(isValueTypeColor(['clamp', ['get', 'attr'], -1, 1])).to.eql(false);
|
||||
expect(isValueTypeColor(['interpolate', ['get', 'attr'], 'red', 'green'])).to.eql(true);
|
||||
expect(isValueTypeColor('yellow')).to.eql(true);
|
||||
expect(isValueTypeColor('#113366')).to.eql(true);
|
||||
expect(isValueTypeColor('rgba(252,171,48,0.62)')).to.eql(true);
|
||||
expect(isValueTypeColor('abcd')).to.eql(false);
|
||||
});
|
||||
it('correctly recognizes a string value', function() {
|
||||
expect(isValueTypeString(1234)).to.eql(false);
|
||||
expect(isValueTypeString(['time'])).to.eql(false);
|
||||
expect(isValueTypeString(['clamp', ['get', 'attr'], -1, 1])).to.eql(false);
|
||||
expect(isValueTypeString(['interpolate', ['get', 'attr'], 'red', 'green'])).to.eql(false);
|
||||
expect(isValueTypeString('yellow')).to.eql(true);
|
||||
expect(isValueTypeString('#113366')).to.eql(true);
|
||||
expect(isValueTypeString('rgba(252,171,48,0.62)')).to.eql(true);
|
||||
expect(isValueTypeString('abcd')).to.eql(true);
|
||||
});
|
||||
it('throws on an unsupported type', function(done) {
|
||||
try {
|
||||
isValueTypeColor(true);
|
||||
} catch (e) {
|
||||
done();
|
||||
}
|
||||
done(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSymbolVertexShader', function() {
|
||||
it('generates a symbol vertex shader (with varying)', function() {
|
||||
const parameters = {
|
||||
varyings: [{
|
||||
name: 'v_opacity',
|
||||
type: 'float',
|
||||
expression: formatNumber(0.4)
|
||||
}, {
|
||||
name: 'v_test',
|
||||
type: 'vec3',
|
||||
expression: 'vec3(' + formatArray([1, 2, 3]) + ')'
|
||||
}],
|
||||
sizeExpression: 'vec2(' + formatNumber(6) + ')',
|
||||
offsetExpression: 'vec2(' + formatArray([5, -7]) + ')',
|
||||
colorExpression: 'vec4(' + formatColor([80, 0, 255, 1]) + ')',
|
||||
texCoordExpression: 'vec4(' + formatArray([0, 0.5, 0.5, 1]) + ')',
|
||||
rotateWithView: false
|
||||
};
|
||||
const builder = new ShaderBuilder();
|
||||
builder.addVarying('v_opacity', 'float', formatNumber(0.4));
|
||||
builder.addVarying('v_test', 'vec3', formatArray([1, 2, 3]));
|
||||
builder.setSizeExpression(`vec2(${formatNumber(6)})`);
|
||||
builder.setSymbolOffsetExpression(formatArray([5, -7]));
|
||||
builder.setColorExpression(formatColor([80, 0, 255, 1]));
|
||||
builder.setTextureCoordinateExpression(formatArray([0, 0.5, 0.5, 1]));
|
||||
|
||||
expect(getSymbolVertexShader(parameters)).to.eql(`precision mediump float;
|
||||
expect(builder.getSymbolVertexShader()).to.eql(`precision mediump float;
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
uniform float u_time;
|
||||
|
||||
attribute vec2 a_position;
|
||||
attribute float a_index;
|
||||
@@ -80,19 +141,19 @@ void main(void) {
|
||||
}`);
|
||||
});
|
||||
it('generates a symbol vertex shader (with uniforms and attributes)', function() {
|
||||
const parameters = {
|
||||
uniforms: ['float u_myUniform'],
|
||||
attributes: ['vec2 a_myAttr'],
|
||||
sizeExpression: 'vec2(' + formatNumber(6) + ')',
|
||||
offsetExpression: 'vec2(' + formatArray([5, -7]) + ')',
|
||||
colorExpression: 'vec4(' + formatColor([80, 0, 255, 1]) + ')',
|
||||
texCoordExpression: 'vec4(' + formatArray([0, 0.5, 0.5, 1]) + ')'
|
||||
};
|
||||
const builder = new ShaderBuilder();
|
||||
builder.addUniform('float u_myUniform');
|
||||
builder.addAttribute('vec2 a_myAttr');
|
||||
builder.setSizeExpression(`vec2(${formatNumber(6)})`);
|
||||
builder.setSymbolOffsetExpression(formatArray([5, -7]));
|
||||
builder.setColorExpression(formatColor([80, 0, 255, 1]));
|
||||
builder.setTextureCoordinateExpression(formatArray([0, 0.5, 0.5, 1]));
|
||||
|
||||
expect(getSymbolVertexShader(parameters)).to.eql(`precision mediump float;
|
||||
expect(builder.getSymbolVertexShader()).to.eql(`precision mediump float;
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
uniform float u_time;
|
||||
uniform float u_myUniform;
|
||||
attribute vec2 a_position;
|
||||
attribute float a_index;
|
||||
@@ -119,18 +180,18 @@ void main(void) {
|
||||
}`);
|
||||
});
|
||||
it('generates a symbol vertex shader (with rotateWithView)', function() {
|
||||
const parameters = {
|
||||
sizeExpression: 'vec2(' + formatNumber(6) + ')',
|
||||
offsetExpression: 'vec2(' + formatArray([5, -7]) + ')',
|
||||
colorExpression: 'vec4(' + formatColor([80, 0, 255, 1]) + ')',
|
||||
texCoordExpression: 'vec4(' + formatArray([0, 0.5, 0.5, 1]) + ')',
|
||||
rotateWithView: true
|
||||
};
|
||||
const builder = new ShaderBuilder();
|
||||
builder.setSizeExpression(`vec2(${formatNumber(6)})`);
|
||||
builder.setSymbolOffsetExpression(formatArray([5, -7]));
|
||||
builder.setColorExpression(formatColor([80, 0, 255, 1]));
|
||||
builder.setTextureCoordinateExpression(formatArray([0, 0.5, 0.5, 1]));
|
||||
builder.setSymbolRotateWithView(true);
|
||||
|
||||
expect(getSymbolVertexShader(parameters)).to.eql(`precision mediump float;
|
||||
expect(builder.getSymbolVertexShader()).to.eql(`precision mediump float;
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
uniform float u_time;
|
||||
|
||||
attribute vec2 a_position;
|
||||
attribute float a_index;
|
||||
@@ -160,161 +221,365 @@ void main(void) {
|
||||
|
||||
describe('getSymbolFragmentShader', function() {
|
||||
it('generates a symbol fragment shader (with varying)', function() {
|
||||
const parameters = {
|
||||
varyings: [{
|
||||
name: 'v_opacity',
|
||||
type: 'float',
|
||||
expression: formatNumber(0.4)
|
||||
}, {
|
||||
name: 'v_test',
|
||||
type: 'vec3',
|
||||
expression: 'vec3(' + formatArray([1, 2, 3]) + ')'
|
||||
}],
|
||||
sizeExpression: 'vec2(' + formatNumber(6) + ')',
|
||||
offsetExpression: 'vec2(' + formatArray([5, -7]) + ')',
|
||||
colorExpression: 'vec4(' + formatColor([80, 0, 255]) + ', v_opacity)',
|
||||
texCoordExpression: 'vec4(' + formatArray([0, 0.5, 0.5, 1]) + ')',
|
||||
rotateWithView: false
|
||||
};
|
||||
const builder = new ShaderBuilder();
|
||||
builder.addVarying('v_opacity', 'float', formatNumber(0.4));
|
||||
builder.addVarying('v_test', 'vec3', formatArray([1, 2, 3]));
|
||||
builder.setSizeExpression(`vec2(${formatNumber(6)})`);
|
||||
builder.setSymbolOffsetExpression(formatArray([5, -7]));
|
||||
builder.setColorExpression(formatColor([80, 0, 255]));
|
||||
builder.setTextureCoordinateExpression(formatArray([0, 0.5, 0.5, 1]));
|
||||
|
||||
expect(getSymbolFragmentShader(parameters)).to.eql(`precision mediump float;
|
||||
expect(builder.getSymbolFragmentShader()).to.eql(`precision mediump float;
|
||||
uniform float u_time;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_quadCoord;
|
||||
varying float v_opacity;
|
||||
varying vec3 v_test;
|
||||
void main(void) {
|
||||
gl_FragColor = vec4(0.3137254901960784, 0.0, 1.0, v_opacity);
|
||||
if (false) { discard; }
|
||||
gl_FragColor = vec4(0.3137254901960784, 0.0, 1.0, 1.0);
|
||||
gl_FragColor.rgb *= gl_FragColor.a;
|
||||
}`);
|
||||
});
|
||||
it('generates a symbol fragment shader (with uniforms)', function() {
|
||||
const parameters = {
|
||||
uniforms: ['float u_myUniform', 'vec2 u_myUniform2'],
|
||||
sizeExpression: 'vec2(' + formatNumber(6) + ')',
|
||||
offsetExpression: 'vec2(' + formatArray([5, -7]) + ')',
|
||||
colorExpression: 'vec4(' + formatColor([255, 255, 255, 1]) + ')',
|
||||
texCoordExpression: 'vec4(' + formatArray([0, 0.5, 0.5, 1]) + ')'
|
||||
};
|
||||
const builder = new ShaderBuilder();
|
||||
builder.addUniform('float u_myUniform');
|
||||
builder.addUniform('vec2 u_myUniform2');
|
||||
builder.setSizeExpression(`vec2(${formatNumber(6)})`);
|
||||
builder.setSymbolOffsetExpression(formatArray([5, -7]));
|
||||
builder.setColorExpression(formatColor([255, 255, 255, 1]));
|
||||
builder.setTextureCoordinateExpression(formatArray([0, 0.5, 0.5, 1]));
|
||||
builder.setFragmentDiscardExpression('u_myUniform > 0.5');
|
||||
|
||||
expect(getSymbolFragmentShader(parameters)).to.eql(`precision mediump float;
|
||||
expect(builder.getSymbolFragmentShader()).to.eql(`precision mediump float;
|
||||
uniform float u_time;
|
||||
uniform float u_myUniform;
|
||||
uniform vec2 u_myUniform2;
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_quadCoord;
|
||||
|
||||
void main(void) {
|
||||
if (u_myUniform > 0.5) { discard; }
|
||||
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
gl_FragColor.rgb *= gl_FragColor.a;
|
||||
}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('check', function() {
|
||||
|
||||
it('does not throw on valid expressions', function(done) {
|
||||
check(1);
|
||||
check('attr');
|
||||
check('rgba(12, 34, 56, 0.5)');
|
||||
check([255, 255, 255, 1]);
|
||||
check([255, 255, 255]);
|
||||
check(['get', 'myAttr']);
|
||||
check(['var', 'myValue']);
|
||||
check(['time']);
|
||||
check(['+', ['*', ['get', 'size'], 0.001], 12]);
|
||||
check(['/', ['-', ['get', 'size'], 0.001], 12]);
|
||||
check(['clamp', ['get', 'attr2'], ['get', 'attr3'], 20]);
|
||||
check(['stretch', ['get', 'size'], 10, 100, 4, 8]);
|
||||
check(['mod', ['pow', ['get', 'size'], 0.5], 12]);
|
||||
check(['>', 10, ['get', 'attr4']]);
|
||||
check(['>=', 10, ['get', 'attr4']]);
|
||||
check(['<', 10, ['get', 'attr4']]);
|
||||
check(['<=', 10, ['get', 'attr4']]);
|
||||
check(['==', 10, ['get', 'attr4']]);
|
||||
check(['between', ['get', 'attr4'], -4.0, 5.0]);
|
||||
check(['!', ['get', 'attr4']]);
|
||||
check(['interpolate', ['get', 'attr4'], 'green', '#3344FF']);
|
||||
check(['interpolate', 0.2, [10, 20, 30], [255, 255, 255, 1]]);
|
||||
done();
|
||||
});
|
||||
|
||||
it('throws on unsupported types for operators', function() {
|
||||
let thrown = false;
|
||||
try {
|
||||
check(['var', 1234]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check(['<', 0, 'aa']);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check(['+', true, ['get', 'attr']]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check(['interpolate', ['get', 'attr4'], 1, '#3344FF']);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
expect(thrown).to.be(true);
|
||||
});
|
||||
|
||||
it('throws with the wrong number of arguments', function() {
|
||||
let thrown = false;
|
||||
try {
|
||||
check(['var', 1234, 456]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check(['<', 4]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check(['+']);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
expect(thrown).to.be(true);
|
||||
});
|
||||
|
||||
it('throws on invalid expressions', function() {
|
||||
let thrown = false;
|
||||
try {
|
||||
check(true);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check([123, 456]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check(null);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
expect(thrown).to.be(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('parse', function() {
|
||||
let attributes, prefix, parseFn;
|
||||
let attributes, prefix, variables, parseFn;
|
||||
|
||||
beforeEach(function() {
|
||||
attributes = [];
|
||||
variables = [];
|
||||
prefix = 'a_';
|
||||
parseFn = function(value) {
|
||||
return parse(value, attributes, prefix);
|
||||
parseFn = function(value, type) {
|
||||
return parse(value, attributes, prefix, variables, type);
|
||||
};
|
||||
});
|
||||
|
||||
it('parses expressions & literal values', function() {
|
||||
expect(parseFn(1)).to.eql('1.0');
|
||||
expect(parseFn('a_random_string')).to.eql('"a_random_string"');
|
||||
expect(parseFn([255, 127.5, 63.75, 0.1])).to.eql('vec4(1.0, 0.5, 0.25, 0.1)');
|
||||
expect(parseFn([255, 127.5, 63.75])).to.eql('vec4(1.0, 0.5, 0.25, 1.0)');
|
||||
expect(parseFn(['get', 'myAttr'])).to.eql('a_myAttr');
|
||||
expect(parseFn(['var', 'myValue'])).to.eql('u_myValue');
|
||||
expect(parseFn(['time'])).to.eql('u_time');
|
||||
expect(parseFn(['+', ['*', ['get', 'size'], 0.001], 12])).to.eql('((a_size * 0.001) + 12.0)');
|
||||
expect(parseFn(['/', ['-', ['get', 'size'], 20], 100])).to.eql('((a_size - 20.0) / 100.0)');
|
||||
expect(parseFn(['clamp', ['get', 'attr2'], ['get', 'attr3'], 20])).to.eql('clamp(a_attr2, a_attr3, 20.0)');
|
||||
expect(parseFn(['stretch', ['get', 'size'], 10, 100, 4, 8])).to.eql('(clamp(a_size, 10.0, 100.0) * ((8.0 - 4.0) / (100.0 - 10.0)) + 4.0)');
|
||||
expect(attributes).to.eql(['myAttr', 'size', 'attr2', 'attr3']);
|
||||
expect(parseFn(['stretch', ['get', 'size'], 10, 100, 4, 8])).to.eql('((clamp(a_size, 10.0, 100.0) - 10.0) * ((8.0 - 4.0) / (100.0 - 10.0)) + 4.0)');
|
||||
expect(parseFn(['pow', ['mod', ['time'], 10], 2])).to.eql('pow(mod(u_time, 10.0), 2.0)');
|
||||
expect(parseFn(['>', 10, ['get', 'attr4']])).to.eql('(10.0 > a_attr4 ? 1.0 : 0.0)');
|
||||
expect(parseFn(['>=', 10, ['get', 'attr4']])).to.eql('(10.0 >= a_attr4 ? 1.0 : 0.0)');
|
||||
expect(parseFn(['<', 10, ['get', 'attr4']])).to.eql('(10.0 < a_attr4 ? 1.0 : 0.0)');
|
||||
expect(parseFn(['<=', 10, ['get', 'attr4']])).to.eql('(10.0 <= a_attr4 ? 1.0 : 0.0)');
|
||||
expect(parseFn(['==', 10, ['get', 'attr4']])).to.eql('(10.0 == a_attr4 ? 1.0 : 0.0)');
|
||||
expect(parseFn(['between', ['get', 'attr4'], -4.0, 5.0])).to.eql('(a_attr4 >= -4.0 && a_attr4 <= 5.0 ? 1.0 : 0.0)');
|
||||
expect(parseFn(['!', ['get', 'attr4']])).to.eql('(a_attr4 > 0.0 ? 0.0 : 1.0)');
|
||||
expect(parseFn(['interpolate', ['get', 'attr4'], [255, 255, 255, 1], 'transparent'])).to.eql(
|
||||
'mix(vec4(1.0, 1.0, 1.0, 1.0), vec4(0.0, 0.0, 0.0, 0.0), a_attr4)');
|
||||
expect(attributes).to.eql(['myAttr', 'size', 'attr2', 'attr3', 'attr4']);
|
||||
expect(variables).to.eql(['myValue']);
|
||||
});
|
||||
|
||||
it('gives precedence to the string type unless asked otherwise', function() {
|
||||
expect(parseFn('lightgreen')).to.eql('"lightgreen"');
|
||||
expect(parseFn('lightgreen', ValueTypes.COLOR)).to.eql('vec4(0.5647058823529412, 0.9333333333333333, 0.5647058823529412, 1.0)');
|
||||
});
|
||||
|
||||
it('does not register an attribute several times', function() {
|
||||
parseFn(['get', 'myAttr']);
|
||||
parseFn(['var', 'myVar']);
|
||||
parseFn(['clamp', ['get', 'attr2'], ['get', 'attr2'], ['get', 'myAttr']]);
|
||||
parseFn(['*', ['get', 'attr2'], ['var', 'myVar']]);
|
||||
expect(attributes).to.eql(['myAttr', 'attr2']);
|
||||
expect(variables).to.eql(['myVar']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseSymbolStyle', function() {
|
||||
it('parses a style without expressions', function() {
|
||||
const result = parseSymbolStyle({
|
||||
symbolType: 'square',
|
||||
size: [4, 8],
|
||||
color: '#336699',
|
||||
rotateWithView: true
|
||||
});
|
||||
expect(result.params).to.eql({
|
||||
uniforms: [],
|
||||
attributes: [],
|
||||
varyings: [],
|
||||
colorExpression: 'vec4(0.2, 0.4, 0.6, 1.0) * vec4(1.0, 1.0, 1.0, 1.0 * 1.0)',
|
||||
sizeExpression: 'vec2(4.0, 8.0)',
|
||||
offsetExpression: 'vec2(0.0, 0.0)',
|
||||
texCoordExpression: 'vec4(0.0, 0.0, 1.0, 1.0)',
|
||||
rotateWithView: true
|
||||
const result = parseLiteralStyle({
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: [4, 8],
|
||||
color: '#ff0000',
|
||||
rotateWithView: true
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.builder.uniforms).to.eql([]);
|
||||
expect(result.builder.attributes).to.eql([]);
|
||||
expect(result.builder.varyings).to.eql([]);
|
||||
expect(result.builder.colorExpression).to.eql(
|
||||
'vec4(vec4(1.0, 0.0, 0.0, 1.0).rgb, vec4(1.0, 0.0, 0.0, 1.0).a * 1.0 * 1.0)');
|
||||
expect(result.builder.sizeExpression).to.eql('vec2(4.0, 8.0)');
|
||||
expect(result.builder.offsetExpression).to.eql('vec2(0.0, 0.0)');
|
||||
expect(result.builder.texCoordExpression).to.eql('vec4(0.0, 0.0, 1.0, 1.0)');
|
||||
expect(result.builder.rotateWithView).to.eql(true);
|
||||
expect(result.attributes).to.eql([]);
|
||||
expect(result.uniforms).to.eql({});
|
||||
});
|
||||
|
||||
it('parses a style with expressions', function() {
|
||||
const result = parseSymbolStyle({
|
||||
symbolType: 'square',
|
||||
size: ['get', 'attr1'],
|
||||
color: [
|
||||
1.0, 0.0, 0.5, ['get', 'attr2']
|
||||
],
|
||||
textureCoord: [0.5, 0.5, 0.5, 1],
|
||||
offset: [3, ['get', 'attr3']]
|
||||
const result = parseLiteralStyle({
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: ['get', 'attr1'],
|
||||
color: [255, 127.5, 63.75, 0.25],
|
||||
textureCoord: [0.5, 0.5, 0.5, 1],
|
||||
offset: [3, ['get', 'attr3']]
|
||||
}
|
||||
});
|
||||
expect(result.params).to.eql({
|
||||
uniforms: [],
|
||||
attributes: ['float a_attr1', 'float a_attr3', 'float a_attr2'],
|
||||
varyings: [{
|
||||
name: 'v_attr1',
|
||||
type: 'float',
|
||||
expression: 'a_attr1'
|
||||
}, {
|
||||
name: 'v_attr2',
|
||||
type: 'float',
|
||||
expression: 'a_attr2'
|
||||
}],
|
||||
colorExpression: 'vec4(1.0, 0.0, 0.5, v_attr2) * vec4(1.0, 1.0, 1.0, 1.0 * 1.0)',
|
||||
sizeExpression: 'vec2(a_attr1, a_attr1)',
|
||||
offsetExpression: 'vec2(3.0, a_attr3)',
|
||||
texCoordExpression: 'vec4(0.5, 0.5, 0.5, 1.0)',
|
||||
rotateWithView: false
|
||||
});
|
||||
expect(result.attributes.length).to.eql(3);
|
||||
|
||||
expect(result.builder.uniforms).to.eql([]);
|
||||
expect(result.builder.attributes).to.eql(['float a_attr1', 'float a_attr3']);
|
||||
expect(result.builder.varyings).to.eql([{
|
||||
name: 'v_attr1',
|
||||
type: 'float',
|
||||
expression: 'a_attr1'
|
||||
}]);
|
||||
expect(result.builder.colorExpression).to.eql(
|
||||
'vec4(vec4(1.0, 0.5, 0.25, 0.25).rgb, vec4(1.0, 0.5, 0.25, 0.25).a * 1.0 * 1.0)'
|
||||
);
|
||||
expect(result.builder.sizeExpression).to.eql('vec2(a_attr1, a_attr1)');
|
||||
expect(result.builder.offsetExpression).to.eql('vec2(3.0, a_attr3)');
|
||||
expect(result.builder.texCoordExpression).to.eql('vec4(0.5, 0.5, 0.5, 1.0)');
|
||||
expect(result.builder.rotateWithView).to.eql(false);
|
||||
expect(result.attributes.length).to.eql(2);
|
||||
expect(result.attributes[0].name).to.eql('attr1');
|
||||
expect(result.attributes[1].name).to.eql('attr3');
|
||||
expect(result.attributes[2].name).to.eql('attr2');
|
||||
expect(result.uniforms).to.eql({});
|
||||
});
|
||||
|
||||
it('parses a style with a uniform (texture)', function() {
|
||||
const result = parseSymbolStyle({
|
||||
symbolType: 'image',
|
||||
src: '../data/image.png',
|
||||
size: 6,
|
||||
color: '#336699',
|
||||
opacity: 0.5
|
||||
});
|
||||
expect(result.params).to.eql({
|
||||
uniforms: ['sampler2D u_texture'],
|
||||
attributes: [],
|
||||
varyings: [],
|
||||
colorExpression: 'vec4(0.2, 0.4, 0.6, 1.0) * vec4(1.0, 1.0, 1.0, 0.5 * 1.0) * texture2D(u_texture, v_texCoord)',
|
||||
sizeExpression: 'vec2(6.0, 6.0)',
|
||||
offsetExpression: 'vec2(0.0, 0.0)',
|
||||
texCoordExpression: 'vec4(0.0, 0.0, 1.0, 1.0)',
|
||||
rotateWithView: false
|
||||
const result = parseLiteralStyle({
|
||||
symbol: {
|
||||
symbolType: 'image',
|
||||
src: '../data/image.png',
|
||||
size: 6,
|
||||
color: '#336699',
|
||||
opacity: 0.5
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.builder.uniforms).to.eql(['sampler2D u_texture']);
|
||||
expect(result.builder.attributes).to.eql([]);
|
||||
expect(result.builder.varyings).to.eql([]);
|
||||
expect(result.builder.colorExpression).to.eql(
|
||||
'vec4(vec4(0.2, 0.4, 0.6, 1.0).rgb, vec4(0.2, 0.4, 0.6, 1.0).a * 0.5 * 1.0) * texture2D(u_texture, v_texCoord)'
|
||||
);
|
||||
expect(result.builder.sizeExpression).to.eql('vec2(6.0, 6.0)');
|
||||
expect(result.builder.offsetExpression).to.eql('vec2(0.0, 0.0)');
|
||||
expect(result.builder.texCoordExpression).to.eql('vec4(0.0, 0.0, 1.0, 1.0)');
|
||||
expect(result.builder.rotateWithView).to.eql(false);
|
||||
expect(result.attributes).to.eql([]);
|
||||
expect(result.uniforms).to.have.property('u_texture');
|
||||
});
|
||||
|
||||
it('parses a style with variables', function() {
|
||||
const result = parseLiteralStyle({
|
||||
variables: {
|
||||
lower: 100,
|
||||
higher: 400
|
||||
},
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: ['stretch', ['get', 'population'], ['var', 'lower'], ['var', 'higher'], 4, 8],
|
||||
color: '#336699',
|
||||
opacity: 0.5
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.builder.uniforms).to.eql(['float u_lower', 'float u_higher']);
|
||||
expect(result.builder.attributes).to.eql(['float a_population']);
|
||||
expect(result.builder.varyings).to.eql([{
|
||||
name: 'v_population',
|
||||
type: 'float',
|
||||
expression: 'a_population'
|
||||
}]);
|
||||
expect(result.builder.colorExpression).to.eql(
|
||||
'vec4(vec4(0.2, 0.4, 0.6, 1.0).rgb, vec4(0.2, 0.4, 0.6, 1.0).a * 0.5 * 1.0)'
|
||||
);
|
||||
expect(result.builder.sizeExpression).to.eql(
|
||||
'vec2(((clamp(a_population, u_lower, u_higher) - u_lower) * ((8.0 - 4.0) / (u_higher - u_lower)) + 4.0), ((clamp(a_population, u_lower, u_higher) - u_lower) * ((8.0 - 4.0) / (u_higher - u_lower)) + 4.0))'
|
||||
);
|
||||
expect(result.builder.offsetExpression).to.eql('vec2(0.0, 0.0)');
|
||||
expect(result.builder.texCoordExpression).to.eql('vec4(0.0, 0.0, 1.0, 1.0)');
|
||||
expect(result.builder.rotateWithView).to.eql(false);
|
||||
expect(result.attributes.length).to.eql(1);
|
||||
expect(result.attributes[0].name).to.eql('population');
|
||||
expect(result.uniforms).to.have.property('u_lower');
|
||||
expect(result.uniforms).to.have.property('u_higher');
|
||||
});
|
||||
|
||||
it('parses a style with a filter', function() {
|
||||
const result = parseLiteralStyle({
|
||||
filter: ['between', ['get', 'attr0'], 0, 10],
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: 6,
|
||||
color: '#336699'
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.builder.attributes).to.eql(['float a_attr0']);
|
||||
expect(result.builder.varyings).to.eql([{
|
||||
name: 'v_attr0',
|
||||
type: 'float',
|
||||
expression: 'a_attr0'
|
||||
}]);
|
||||
expect(result.builder.colorExpression).to.eql(
|
||||
'vec4(vec4(0.2, 0.4, 0.6, 1.0).rgb, vec4(0.2, 0.4, 0.6, 1.0).a * 1.0 * 1.0)'
|
||||
);
|
||||
expect(result.builder.sizeExpression).to.eql('vec2(6.0, 6.0)');
|
||||
expect(result.builder.offsetExpression).to.eql('vec2(0.0, 0.0)');
|
||||
expect(result.builder.texCoordExpression).to.eql('vec4(0.0, 0.0, 1.0, 1.0)');
|
||||
expect(result.builder.discardExpression).to.eql('(v_attr0 >= 0.0 && v_attr0 <= 10.0 ? 1.0 : 0.0) <= 0.0');
|
||||
expect(result.builder.rotateWithView).to.eql(false);
|
||||
expect(result.attributes.length).to.eql(1);
|
||||
expect(result.attributes[0].name).to.eql('attr0');
|
||||
});
|
||||
|
||||
it('parses a style with a color interpolation', function() {
|
||||
const result = parseLiteralStyle({
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: 6,
|
||||
color: ['interpolate', ['var', 'ratio'], [255, 255, 0], 'red']
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.builder.attributes).to.eql([]);
|
||||
expect(result.builder.varyings).to.eql([]);
|
||||
expect(result.builder.colorExpression).to.eql(
|
||||
'vec4(mix(vec4(1.0, 1.0, 0.0, 1.0), vec4(1.0, 0.0, 0.0, 1.0), u_ratio).rgb, mix(vec4(1.0, 1.0, 0.0, 1.0), vec4(1.0, 0.0, 0.0, 1.0), u_ratio).a * 1.0 * 1.0)'
|
||||
);
|
||||
expect(result.builder.sizeExpression).to.eql('vec2(6.0, 6.0)');
|
||||
expect(result.builder.offsetExpression).to.eql('vec2(0.0, 0.0)');
|
||||
expect(result.builder.texCoordExpression).to.eql('vec4(0.0, 0.0, 1.0, 1.0)');
|
||||
expect(result.builder.rotateWithView).to.eql(false);
|
||||
expect(result.attributes).to.eql([]);
|
||||
expect(result.uniforms).to.have.property('u_ratio');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user