From 12954a57a30f80eaf2bd51a98831ca81f832ba2e Mon Sep 17 00:00:00 2001 From: Brett Camper Date: Tue, 30 Apr 2019 23:17:42 -0400 Subject: [PATCH] add filter syntax to match if a feature property that's an array contains some or all of a list of values --- src/styles/filter.js | 45 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/styles/filter.js b/src/styles/filter.js index e13595116..d8c7d421f 100644 --- a/src/styles/filter.js +++ b/src/styles/filter.js @@ -22,9 +22,9 @@ function lookUp(key) { // escaped dot notation will be interpreted as a single-level feature property with dots in the name // this splits on unescaped dots, which requires a temporary swap of escaped and unescaped dots let keys = key - .replace(/\\\./g, '__TANGRAM_SEPARATOR__') + .replace(/\\\./g, '__TANGRAM_DELIMITER__') .split('.') - .map(s => s.replace(/__TANGRAM_SEPARATOR__/g, '.')); + .map(s => s.replace(/__TANGRAM_DELIMITER__/g, '.')); return `context.feature.properties${keys.map(k => '[\'' + k + '\']').join('')}`; } } @@ -71,23 +71,51 @@ function propertyMatchesBoolean(key, value) { return wrap(lookUp(key) + (value ? ' != ' : ' == ') + 'null'); } -function rangeMatch(key, values, options) { +function rangeMatch(key, value, options) { var expressions = []; var transform = options && (typeof options.rangeTransform === 'function') && options.rangeTransform; - if (values.max) { - var max = transform ? transform(values.max) : values.max; + if (value.max) { + var max = transform ? transform(value.max) : value.max; expressions.push('' + lookUp(key) + ' < ' + max); } - if (values.min) { - var min = transform ? min = transform(values.min) : values.min; + if (value.min) { + var min = transform ? min = transform(value.min) : value.min; expressions.push('' + lookUp(key) + ' >= ' + min); } return wrap(expressions.join(' && ')); } +function includesMatch(key, value) { + let expressions = []; + + // the array includes ONE OE MORE of the provided values + if (value.includes) { + if (Array.isArray(value.includes)) { + let arr = '['+ value.includes.map(maybeQuote).join(',') + ']'; + expressions.push(`${arr}.some(function(v) { return ${lookUp(key)}.indexOf(v) > -1 })`); + } + else { + expressions.push(`${lookUp(key)}.indexOf(${maybeQuote(value.includes)}) > -1`); + } + } + + // the array includes ALL of the provided values + if (value.includes_all) { + if (Array.isArray(value.includes_all)) { + let arr = '[' + value.includes_all.map(maybeQuote).join(',') + ']'; + expressions.push(`${arr}.every(function(v) { return ${lookUp(key)}.indexOf(v) > -1 })`); + } + else { + expressions.push(`${lookUp(key)}.indexOf(${maybeQuote(value.includes_all)}) > -1`); + } + } + + return wrap(expressions.join(' && ')); +} + function parseFilter(filter, options) { var filterAST = []; @@ -129,6 +157,9 @@ function parseFilter(filter, options) { if (value.max || value.min) { filterAST.push(rangeMatch(key, value, options)); } + else if (value.includes || value.includes_all) { + filterAST.push(includesMatch(key, value, options)); + } } else if (value == null) { filterAST.push(nullValue(key, value)); } else {