From b4bc18df79d54c5ec3b6a69092c85aa6cb1ed778 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 29 Jan 2016 15:51:10 +0200 Subject: [PATCH 1/5] faster and simpler filter implementation Closes #6, closes #10, ref #8. --- index.js | 103 ++++++++++++++++++--------------------------------- package.json | 9 +++++ test.js | 2 +- 3 files changed, 47 insertions(+), 67 deletions(-) diff --git a/index.js b/index.js index b54dc4b..a0352ce 100644 --- a/index.js +++ b/index.js @@ -1,66 +1,8 @@ 'use strict'; -var VectorTileFeatureTypes = ['Unknown', 'Point', 'LineString', 'Polygon']; +module.exports = createFilter; -function infix(operator) { - return function(_, key, value) { - if (key === '$type') { - return 't' + operator + VectorTileFeatureTypes.indexOf(value); - } else { - return 'p[' + JSON.stringify(key) + ']' + operator + JSON.stringify(value); - } - }; -} - -function strictInfix(operator) { - var nonstrictInfix = infix(operator); - return function(_, key, value) { - if (key === '$type') { - return nonstrictInfix(_, key, value); - } else { - return 'typeof(p[' + JSON.stringify(key) + ']) === typeof(' + JSON.stringify(value) + ') && ' + - nonstrictInfix(_, key, value); - } - }; -} - -var operators = { - '==': infix('==='), - '!=': infix('!=='), - '>': strictInfix('>'), - '<': strictInfix('<'), - '<=': strictInfix('<='), - '>=': strictInfix('>='), - 'in': function(_, key) { - return '(function(){' + Array.prototype.slice.call(arguments, 2).map(function(value) { - return 'if (' + operators['=='](_, key, value) + ') return true;'; - }).join('') + 'return false;})()'; - }, - '!in': function() { - return '!(' + operators.in.apply(this, arguments) + ')'; - }, - 'any': function() { - return Array.prototype.slice.call(arguments, 1).map(function(filter) { - return '(' + compile(filter) + ')'; - }).join('||') || 'false'; - }, - 'all': function() { - return Array.prototype.slice.call(arguments, 1).map(function(filter) { - return '(' + compile(filter) + ')'; - }).join('&&') || 'true'; - }, - 'none': function() { - return '!(' + operators.any.apply(this, arguments) + ')'; - } -}; - -function compile(filter) { - return operators[filter[0]].apply(filter, filter); -} - -function truth() { - return true; -} +var types = ['Unknown', 'Point', 'LineString', 'Polygon']; /** * Given a filter expressed as nested arrays, return a new function @@ -70,9 +12,38 @@ function truth() { * @param {Array} filter mapbox gl filter * @returns {Function} filter-evaluating function */ -module.exports = function (filter) { - if (!filter) return truth; - var filterStr = 'var p = f.properties || f.tags || {}, t = f.type; return ' + compile(filter) + ';'; - // jshint evil: true - return new Function('f', filterStr); -}; +function createFilter(filter) { + return new Function('f', 'return ' + compile(filter)); +} + +function compile(filter) { + if (!filter || filter.length <= 1) return 'true'; + var op = filter[0]; + var str = + op === '==' ? compare(filter[1], filter[2], '===', false) : + op === '!=' ? compare(filter[1], filter[2], '!==', false) : + op === '<' || + op === '>' || + op === '<=' || + op === '>=' ? compare(filter[1], filter[2], op, true) : + op === 'any' ? filter.slice(1).map(compile).join('||') : + op === 'all' ? filter.slice(1).map(compile).join('&&') : + op === 'none' ? '!(' + filter.slice(1).map(compile).join('||') + ')' : + op === 'in' ? compileIn(filter[1], filter.slice(2)) : + op === '!in' ? '!(' + compileIn(filter[1], filter.slice(2)) + ')' : + 'true'; + return '(' + str + ')'; +} + +function valueExpr(key) { + return key === '$type' ? 'f.type' : '(f.properties || {})[' + JSON.stringify(key) + ']'; +} +function compare(key, val, op, checkType) { + var left = valueExpr(key); + var right = key === '$type' ? types.indexOf(val) : JSON.stringify(val); + return (checkType ? 'typeof ' + left + '=== typeof ' + right + '&&' : '') + left + op + right; +} +function compileIn(key, values) { + if (key === '$type') values = values.map(types.indexOf.bind(types)); + return JSON.stringify(values) + '.indexOf(' + valueExpr(key) + ') !== -1'; +} diff --git a/package.json b/package.json index 9549e70..ae39c5e 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,20 @@ "description": "Creates filtering function for vector tile features", "dependencies": {}, "devDependencies": { + "eslint": "^1.10.3", + "eslint-config-mourner": "^1.0.1", "tape": "^3.2.1" }, "scripts": { + "pretest": "eslint index.js test.js", "test": "tape test.js" }, + "eslintConfig": { + "extends": "mourner", + "rules": { + "space-before-function-paren": [2, "never"] + } + }, "repository": { "type": "git", "url": "git@github.com:mapbox/feature-filter.git" diff --git a/test.js b/test.js index 1335145..d747f8c 100644 --- a/test.js +++ b/test.js @@ -294,7 +294,7 @@ test('!in, $type', function(t) { test('any', function(t) { var f1 = filter(['any']); - t.equal(f1({properties: {foo: 1}}), false); + t.equal(f1({properties: {foo: 1}}), true); var f2 = filter(['any', ['==', 'foo', 1]]); t.equal(f2({properties: {foo: 1}}), true); From 2a0e9510f746a12e25051eb6d4252b739a7ec20b Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 29 Jan 2016 19:59:26 +0200 Subject: [PATCH 2/5] implement binary search for huge in filters, close #8 --- index.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index a0352ce..ccc9475 100644 --- a/index.js +++ b/index.js @@ -45,5 +45,18 @@ function compare(key, val, op, checkType) { } function compileIn(key, values) { if (key === '$type') values = values.map(types.indexOf.bind(types)); - return JSON.stringify(values) + '.indexOf(' + valueExpr(key) + ') !== -1'; + var left = JSON.stringify(values.sort(compareFn)); + var right = valueExpr(key); + + if (values.length <= 200) return left + '.indexOf(' + right + ') !== -1'; + + return 'function(v, a, i, j) {' + + 'while (i <= j) { var m = (i + j) >> 1;' + + ' if (a[m] === v) return true; if (a[m] > v) j = m - 1; else i = m + 1;' + + '}' + + 'return false; }(' + right + ', ' + left + ',0,' + (values.length - 1) + ')'; +} + +function compareFn(a, b) { + return a < b ? -1 : a > b ? 1 : 0; } From 41b7910a4b652836e292c022be16fb8a35501964 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 29 Jan 2016 20:07:02 +0200 Subject: [PATCH 3/5] add benchmarks --- bench/785.vector.pbf | Bin 0 -> 48392 bytes bench/bench.js | 59 ++ bench/big.js | 21 + bench/filters.json | 1462 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1542 insertions(+) create mode 100644 bench/785.vector.pbf create mode 100644 bench/bench.js create mode 100644 bench/big.js create mode 100644 bench/filters.json diff --git a/bench/785.vector.pbf b/bench/785.vector.pbf new file mode 100644 index 0000000000000000000000000000000000000000..dd9a664e0bbd5540c390a504cf4ae967b9a5565c GIT binary patch literal 48392 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

3XJ~t>@}x*lzMYX=Yn>%MW{w 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 Y<=Zbw30R;uCm?D_+yDRo literal 0 HcmV?d00001 diff --git a/bench/bench.js b/bench/bench.js new file mode 100644 index 0000000..715f9a5 --- /dev/null +++ b/bench/bench.js @@ -0,0 +1,59 @@ +'use strict'; + +var VectorTile = require('vector-tile').VectorTile; +var Pbf = require('pbf'); +var fs = require('fs'); +var createFilter = require('../'); +var filters = require('./filters.json'); +var path = require('path'); + +var tile = new VectorTile(new Pbf(fs.readFileSync(path.join(__dirname, './785.vector.pbf')))); + +var layers = []; +for (var name in tile.layers) { + var layer = tile.layers[name]; + if (!layer.length) continue; + + var features = []; + for (var j = 0; j < layer.length; j++) { + features.push(layer.feature(j)); + } + + var layerFilters = []; + for (j = 0; j < filters.length; j++) { + if (filters[j].layer === name) layerFilters.push(filters[j].filter); + } + + layers.push({ + name: name, + features: features, + rawFilters: layerFilters + }); +} + +console.time('create filters'); +for (var m = 0; m < 100; m++) { + for (var i = 0; i < layers.length; i++) { + var layer = layers[i]; + layer.filters = []; + for (j = 0; j < layer.rawFilters.length; j++) { + layer.filters.push(createFilter(layer.rawFilters[j])); + } + } +} +console.timeEnd('create filters'); + +console.time('apply filters'); +for (var m = 0; m < 100; m++) { + for (var i = 0; i < layers.length; i++) { + var layer = layers[i]; + for (j = 0; j < layer.features.length; j++) { + var feature = layer.features[j]; + for (var k = 0; k < layer.filters.length; k++) { + var filter = layer.filters[k]; + filter(feature); + } + } + } +} +console.timeEnd('apply filters'); diff --git a/bench/big.js b/bench/big.js new file mode 100644 index 0000000..dda7e54 --- /dev/null +++ b/bench/big.js @@ -0,0 +1,21 @@ +'use strict'; + +var filter = require('../'); + +var N = 64000; + +var arr = ['in', 'foo']; +for (var i = 0; i < N; i++) arr.push(i); + +console.time('create ' + N + '-item filter'); +var f = filter(arr); +console.timeEnd('create ' + N + '-item filter'); + +var feature = {properties: {foo: 0}}; + +console.time('filter 1 million times'); +for (var i = 0; i < 1000000; i++) { + feature.properties.foo = Math.floor(Math.random() * N * 2); + f(feature); +} +console.timeEnd('filter 1 million times'); diff --git a/bench/filters.json b/bench/filters.json new file mode 100644 index 0000000..9a90c41 --- /dev/null +++ b/bench/filters.json @@ -0,0 +1,1462 @@ +[ + { + "filter": [ + "==", + "class", + "crop" + ], + "layer": "landcover" + }, + { + "filter": [ + "==", + "class", + "grass" + ], + "layer": "landcover" + }, + { + "filter": [ + "==", + "class", + "scrub" + ], + "layer": "landcover" + }, + { + "filter": [ + "==", + "class", + "wood" + ], + "layer": "landcover" + }, + { + "filter": [ + "==", + "class", + "snow" + ], + "layer": "landcover" + }, + { + "filter": [ + "==", + "class", + "hospital" + ], + "layer": "landuse" + }, + { + "filter": [ + "==", + "class", + "school" + ], + "layer": "landuse" + }, + { + "filter": [ + "==", + "class", + "park" + ], + "layer": "landuse" + }, + { + "filter": [ + "==", + "class", + "pitch" + ], + "layer": "landuse" + }, + { + "filter": [ + "==", + "class", + "pitch" + ], + "layer": "landuse" + }, + { + "filter": [ + "==", + "class", + "cemetery" + ], + "layer": "landuse" + }, + { + "filter": [ + "==", + "class", + "industrial" + ], + "layer": "landuse" + }, + { + "filter": [ + "==", + "class", + "sand" + ], + "layer": "landuse" + }, + { + "filter": [ + "==", + "level", + 94 + ], + "layer": "hillshade" + }, + { + "filter": [ + "==", + "level", + 90 + ], + "layer": "hillshade" + }, + { + "filter": [ + "==", + "level", + 89 + ], + "layer": "hillshade" + }, + { + "filter": [ + "==", + "level", + 78 + ], + "layer": "hillshade" + }, + { + "filter": [ + "==", + "level", + 67 + ], + "layer": "hillshade" + }, + { + "filter": [ + "==", + "level", + 56 + ], + "layer": "hillshade" + }, + { + "filter": [ + "all", + [ + "!=", + "class", + "river" + ], + [ + "!=", + "class", + "canal" + ] + ], + "layer": "waterway" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "==", + "class", + "land" + ] + ], + "layer": "barrier_line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "land" + ] + ], + "layer": "barrier_line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "!=", + "type", + "apron" + ] + ], + "layer": "aeroway" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "==", + "class", + "street_limited" + ] + ], + "layer": "tunnel" + }, + { + "filter": [ + "==", + "class", + "path" + ], + "layer": "tunnel" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "street" + ] + ], + "layer": "tunnel" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "street_limited" + ] + ], + "layer": "tunnel" + }, + { + "filter": [ + "==", + "class", + "motorway_link" + ], + "layer": "tunnel" + }, + { + "filter": [ + "in", + "class", + "service", + "driveway" + ], + "layer": "tunnel" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "!=", + "type", + "construction" + ] + ] + ], + "layer": "tunnel" + }, + { + "filter": [ + "==", + "class", + "street" + ], + "layer": "tunnel" + }, + { + "filter": [ + "all", + [ + "==", + "class", + "main" + ], + [ + "!=", + "type", + "trunk" + ] + ], + "layer": "tunnel" + }, + { + "filter": [ + "all", + [ + "==", + "class", + "main" + ], + [ + "==", + "type", + "trunk" + ] + ], + "layer": "tunnel" + }, + { + "filter": [ + "==", + "class", + "motorway" + ], + "layer": "tunnel" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "type", + "construction" + ] + ] + ], + "layer": "tunnel" + }, + { + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "in", + "class", + "main", + "street", + "street_limited" + ], + [ + "!=", + "type", + "trunk" + ] + ], + "layer": "tunnel" + }, + { + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "==", + "type", + "trunk" + ] + ], + "layer": "tunnel" + }, + { + "filter": [ + "in", + "class", + "major_rail", + "minor_rail" + ], + "layer": "tunnel" + }, + { + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "in", + "class", + "motorway", + "motorway_link" + ] + ], + "layer": "tunnel" + }, + { + "filter": [ + "==", + "class", + "path" + ], + "layer": "road" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "street" + ] + ], + "layer": "road" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "street_limited" + ] + ], + "layer": "road" + }, + { + "filter": [ + "in", + "class", + "service", + "driveway" + ], + "layer": "road" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "!=", + "type", + "construction" + ] + ] + ], + "layer": "road" + }, + { + "filter": [ + "==", + "class", + "street" + ], + "layer": "road" + }, + { + "filter": [ + "all", + [ + "==", + "class", + "main" + ], + [ + "!=", + "type", + "trunk" + ] + ], + "layer": "road" + }, + { + "filter": [ + "==", + "class", + "motorway" + ], + "layer": "road" + }, + { + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "in", + "class", + "main", + "street", + "street_limited" + ], + [ + "!=", + "type", + "trunk" + ] + ], + "layer": "road" + }, + { + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "==", + "type", + "trunk" + ] + ], + "layer": "road" + }, + { + "filter": [ + "in", + "class", + "major_rail", + "minor_rail" + ], + "layer": "road" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "type", + "construction" + ] + ] + ], + "layer": "road" + }, + { + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "in", + "class", + "motorway", + "motorway_link" + ] + ], + "layer": "road" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "==", + "class", + "street_limited" + ] + ], + "layer": "bridge" + }, + { + "filter": [ + "==", + "class", + "path" + ], + "layer": "bridge" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "street" + ] + ], + "layer": "bridge" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "street_limited" + ] + ], + "layer": "bridge" + }, + { + "filter": [ + "==", + "class", + "motorway_link" + ], + "layer": "bridge" + }, + { + "filter": [ + "in", + "class", + "service", + "driveway" + ], + "layer": "bridge" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "!=", + "type", + "construction" + ] + ] + ], + "layer": "bridge" + }, + { + "filter": [ + "==", + "class", + "street" + ], + "layer": "bridge" + }, + { + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "in", + "class", + "main", + "street", + "street_limited" + ], + [ + "!=", + "type", + "trunk" + ] + ], + "layer": "bridge" + }, + { + "filter": [ + "any", + [ + "==", + "class", + "motorway" + ], + [ + "==", + "type", + "trunk" + ] + ], + "layer": "bridge" + }, + { + "filter": [ + "in", + "class", + "service", + "driveway" + ], + "layer": "bridge" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "type", + "construction" + ] + ] + ], + "layer": "bridge" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "!=", + "type", + "construction" + ] + ] + ], + "layer": "bridge" + }, + { + "filter": [ + "==", + "class", + "street" + ], + "layer": "bridge" + }, + { + "filter": [ + "all", + [ + "==", + "class", + "main" + ], + [ + "!=", + "type", + "trunk" + ] + ], + "layer": "bridge" + }, + { + "filter": [ + "all", + [ + "==", + "class", + "main" + ], + [ + "==", + "type", + "trunk" + ] + ], + "layer": "bridge" + }, + { + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "==", + "type", + "trunk" + ] + ], + "layer": "bridge" + }, + { + "filter": [ + "==", + "class", + "motorway" + ], + "layer": "bridge" + }, + { + "filter": [ + "in", + "class", + "major_rail", + "minor_rail" + ], + "layer": "bridge" + }, + { + "filter": [ + "==", + "class", + "aerialway" + ], + "layer": "bridge" + }, + { + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "in", + "class", + "motorway", + "motorway_link" + ] + ], + "layer": "bridge" + }, + { + "filter": [ + "==", + "class", + "hedge" + ], + "layer": "barrier_line" + }, + { + "filter": [ + "==", + "class", + "fence" + ], + "layer": "barrier_line" + }, + { + "filter": [ + "==", + "class", + "gate" + ], + "layer": "barrier_line" + }, + { + "filter": [ + "all", + [ + ">=", + "admin_level", + 3 + ], + [ + "==", + "maritime", + 0 + ] + ], + "layer": "admin" + }, + { + "filter": [ + "all", + [ + ">=", + "admin_level", + 3 + ], + [ + "==", + "maritime", + 0 + ] + ], + "layer": "admin" + }, + { + "filter": [ + "!=", + "index", + 5 + ], + "layer": "contour" + }, + { + "filter": [ + "==", + "index", + 5 + ], + "layer": "contour" + }, + { + "filter": [ + "==", + "index", + 5 + ], + "layer": "contour" + }, + { + "filter": [ + "==", + "class", + "river" + ], + "layer": "waterway_label" + }, + { + "filter": [ + "all", + [ + "!in", + "maki", + "rail-light", + "rail-metro", + "rail", + "airport", + "airfield", + "heliport", + "rocket", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "==", + "scalerank", + 4 + ], + [ + ">=", + "localrank", + 15 + ] + ], + "layer": "poi_label" + }, + { + "filter": [ + "all", + [ + "!in", + "maki", + "rail-light", + "rail-metro", + "rail", + "airport", + "airfield", + "heliport", + "rocket", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "==", + "scalerank", + 4 + ], + [ + "<=", + "localrank", + 14 + ] + ], + "layer": "poi_label" + }, + { + "filter": [ + "all", + [ + "in", + "maki", + "park", + "cemetery", + "golf", + "zoo", + "playground" + ], + [ + "==", + "scalerank", + 4 + ] + ], + "layer": "poi_label" + }, + { + "filter": [ + "all", + [ + "!in", + "maki", + "rail-light", + "rail-metro", + "rail", + "airport", + "airfield", + "heliport", + "rocket", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "==", + "scalerank", + 3 + ] + ], + "layer": "poi_label" + }, + { + "filter": [ + "all", + [ + "in", + "maki", + "park", + "cemetery", + "golf", + "zoo" + ], + [ + "==", + "scalerank", + 3 + ] + ], + "layer": "poi_label" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "!in", + "class", + "motorway", + "main", + "street_limited", + "street" + ] + ], + "layer": "road_label" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "street", + "street_limited" + ] + ], + "layer": "road_label" + }, + { + "filter": [ + "in", + "class", + "main", + "motorway" + ], + "layer": "road_label" + }, + { + "filter": [ + "all", + [ + "!in", + "shield", + "us-interstate", + "us-interstate-business", + "us-interstate-duplex" + ], + [ + "<=", + "reflen", + 6 + ] + ], + "layer": "road_label" + }, + { + "filter": [ + "all", + [ + "in", + "shield", + "us-interstate", + "us-interstate-business", + "us-interstate-duplex" + ], + [ + "<=", + "reflen", + 6 + ] + ], + "layer": "road_label" + }, + { + "filter": [ + "all", + [ + "!in", + "maki", + "rail-light", + "rail-metro", + "rail", + "airport", + "airfield", + "heliport", + "rocket", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "==", + "scalerank", + 2 + ] + ], + "layer": "poi_label" + }, + { + "filter": [ + "all", + [ + "in", + "maki", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "==", + "scalerank", + 2 + ] + ], + "layer": "poi_label" + }, + { + "filter": [ + "==", + "type", + "Rail Station" + ], + "layer": "poi_label" + }, + { + "filter": [ + "<=", + "area", + 10000 + ], + "layer": "water_label" + }, + { + "filter": [ + "all", + [ + "in", + "maki", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "<=", + "scalerank", + 1 + ] + ], + "layer": "poi_label" + }, + { + "filter": [ + "all", + [ + "!in", + "maki", + "rail-light", + "rail-metro", + "rail", + "airport", + "airfield", + "heliport", + "rocket", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "<=", + "scalerank", + 1 + ], + [ + "!=", + "type", + "Island" + ] + ], + "layer": "poi_label" + }, + { + "filter": [ + "==", + "type", + "Islet" + ], + "layer": "poi_label" + }, + { + "filter": [ + "==", + "type", + "Island" + ], + "layer": "poi_label" + }, + { + "filter": [ + "all", + [ + "!in", + "scalerank", + 0, + 1, + 2, + 3, + 4, + 5 + ], + [ + "==", + "type", + "city" + ] + ], + "layer": "place_label" + }, + { + "filter": [ + "all", + [ + "in", + "scalerank", + 3, + 4, + 5 + ], + [ + "==", + "type", + "city" + ], + [ + "in", + "ldir", + "S", + "SE", + "SW", + "E" + ] + ], + "layer": "place_label" + }, + { + "filter": [ + "all", + [ + "in", + "scalerank", + 3, + 4, + 5 + ], + [ + "==", + "type", + "city" + ], + [ + "in", + "ldir", + "N", + "NE", + "NW", + "W" + ] + ], + "layer": "place_label" + } +] From 5739338b4c53b74df7ce2e58cd5b2557aa7f4d38 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 29 Jan 2016 22:13:19 +0200 Subject: [PATCH 4/5] bring back empty any = false behavior --- index.js | 3 ++- test.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index ccc9475..4524be2 100644 --- a/index.js +++ b/index.js @@ -17,8 +17,9 @@ function createFilter(filter) { } function compile(filter) { - if (!filter || filter.length <= 1) return 'true'; + if (!filter) return 'true'; var op = filter[0]; + if (filter.length <= 1) return op === 'any' ? 'false' : 'true'; var str = op === '==' ? compare(filter[1], filter[2], '===', false) : op === '!=' ? compare(filter[1], filter[2], '!==', false) : diff --git a/test.js b/test.js index d747f8c..1335145 100644 --- a/test.js +++ b/test.js @@ -294,7 +294,7 @@ test('!in, $type', function(t) { test('any', function(t) { var f1 = filter(['any']); - t.equal(f1({properties: {foo: 1}}), true); + t.equal(f1({properties: {foo: 1}}), false); var f2 = filter(['any', ['==', 'foo', 1]]); t.equal(f2({properties: {foo: 1}}), true); From 69bb5751b3e5035f0ca60364879569c5ecd6bbb0 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 29 Jan 2016 22:40:44 +0200 Subject: [PATCH 5/5] add gitignore, update package.json --- .gitignore | 4 ++++ package.json | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..31aae6f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules +*.log +coverage +.nyc_output diff --git a/package.json b/package.json index ae39c5e..38f72e3 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "devDependencies": { "eslint": "^1.10.3", "eslint-config-mourner": "^1.0.1", - "tape": "^3.2.1" + "pbf": "^1.3.5", + "tape": "^3.2.1", + "vector-tile": "^1.2.0" }, "scripts": { "pretest": "eslint index.js test.js", @@ -16,7 +18,10 @@ "eslintConfig": { "extends": "mourner", "rules": { - "space-before-function-paren": [2, "never"] + "space-before-function-paren": [ + 2, + "never" + ] } }, "repository": {