Skip to content

Commit

Permalink
Simplify categorical function conversion
Browse files Browse the repository at this point in the history
We can now take advantage of the relaxed typing for == and match, which allows full-fidelity conversion of categorical functions. Previously, we were relying on the default value being substituted at evaluation time if the input was not of the expected type. Now, case/match can handle that.
  • Loading branch information
jfirebaugh committed May 18, 2018
1 parent 72bec0b commit a5a8dfe
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 21 deletions.
29 changes: 8 additions & 21 deletions src/style-spec/function/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,37 +141,24 @@ function convertZoomAndPropertyFunction(parameters, propertySpec, stops, default
function convertPropertyFunction(parameters, propertySpec, stops, defaultExpression) {
const type = getFunctionType(parameters, propertySpec);

const inputType = typeof stops[0][0];
assert(
inputType === 'string' ||
inputType === 'number' ||
inputType === 'boolean'
);

let input = [inputType, ['get', parameters.property]];

let expression;
let isStep = false;
if (type === 'categorical' && inputType === 'boolean') {
if (type === 'categorical' && typeof stops[0][0] === 'boolean') {
assert(parameters.stops.length > 0 && parameters.stops.length <= 2);
if (parameters.stops[0][0] === false) {
input = ['!', input];
}
expression = [ 'case', input, parameters.stops[0][1] ];
if (parameters.stops.length > 1) {
expression.push(parameters.stops[1][1]);
} else {
expression.push(defaultExpression);
expression = ['case'];
for (const stop of stops) {
expression.push(['==', ['get', parameters.property], stop[0]], stop[1]);
}
expression.push(defaultExpression);
return expression;
} else if (type === 'categorical') {
expression = ['match', input];
expression = ['match', ['get', parameters.property]];
} else if (type === 'interval') {
expression = ['step', input];
expression = ['step', ['number', ['get', parameters.property]]];
isStep = true;
} else if (type === 'exponential') {
const base = parameters.base !== undefined ? parameters.base : 1;
expression = ['interpolate', ['exponential', base], input];
expression = ['interpolate', ['exponential', base], ['number', ['get', parameters.property]]];
} else {
throw new Error(`Unknown property function type ${type}`);
}
Expand Down
45 changes: 45 additions & 0 deletions test/unit/style-spec/convert_function.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,51 @@ import { test } from 'mapbox-gl-js-test';
import convertFunction from '../../../src/style-spec/function/convert';

test('convertFunction', (t) => {
t.test('boolean categorical', (t) => {
const fn = {
type: 'categorical',
property: 'p',
stops: [
[true, 'true'],
[false, 'false']
],
default: 'default'
};

t.deepEqual(convertFunction(fn, {}), [
'case',
['==', ['get', 'p'], true],
'true',
['==', ['get', 'p'], false],
'false',
'default'
]);

t.end();
});

t.test('numeric categorical', (t) => {
const fn = {
type: 'categorical',
property: 'p',
stops: [
[0, '0'],
[1, '1']
],
default: 'default'
};

t.deepEqual(convertFunction(fn, {}), [
'match',
['get', 'p'],
0, '0',
1, '1',
'default'
]);

t.end();
});

t.test('feature-constant text-field with token replacement', (t) => {
const functionValue = {
stops: [
Expand Down

0 comments on commit a5a8dfe

Please sign in to comment.