From a5a8dfe5b90737dbb295eaca7f41c667ae4060a8 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 18 May 2018 08:44:14 -0700 Subject: [PATCH] Simplify categorical function conversion 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. --- src/style-spec/function/convert.js | 29 ++++-------- test/unit/style-spec/convert_function.test.js | 45 +++++++++++++++++++ 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/style-spec/function/convert.js b/src/style-spec/function/convert.js index 1fd944418f4..3fa43c170b5 100644 --- a/src/style-spec/function/convert.js +++ b/src/style-spec/function/convert.js @@ -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}`); } diff --git a/test/unit/style-spec/convert_function.test.js b/test/unit/style-spec/convert_function.test.js index 9100a135dab..5b489c676fe 100644 --- a/test/unit/style-spec/convert_function.test.js +++ b/test/unit/style-spec/convert_function.test.js @@ -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: [