diff --git a/js/data/feature_tree.js b/js/data/feature_tree.js index 55fd69e1025..f158d7ed676 100644 --- a/js/data/feature_tree.js +++ b/js/data/feature_tree.js @@ -49,8 +49,6 @@ FeatureTree.prototype.query = function(args, styleLayersByID) { if (this.toBeInserted.length) this._load(); var params = args.params || {}, - x = args.x, - y = args.y, pixelsToTileUnits = EXTENT / args.tileSize / args.scale, result = []; @@ -73,25 +71,25 @@ FeatureTree.prototype.query = function(args, styleLayersByID) { additionalRadius = Math.max(additionalRadius, styleLayerDistance * pixelsToTileUnits); } - var bounds, symbolQueryBox, queryPolygon; - if (x !== undefined && y !== undefined) { - // a point query - bounds = [x - additionalRadius, y - additionalRadius, x + additionalRadius, y + additionalRadius]; - symbolQueryBox = new CollisionBox(new Point(x, y), 0, 0, 0, 0, args.scale, null); - queryPolygon = [new Point(x, y)]; - } else { - // a rectangle query - bounds = [ args.minX, args.minY, args.maxX, args.maxY ]; - symbolQueryBox = new CollisionBox(new Point(args.minX, args.minY), 0, 0, args.maxX - args.minX, args.maxY - args.minY, args.scale, null); - queryPolygon = [ - new Point(args.minX, args.minY), - new Point(args.maxX, args.minY), - new Point(args.maxX, args.maxY), - new Point(args.minX, args.maxY), - new Point(args.minX, args.minY) - ]; + var queryGeometry = args.queryGeometry.map(function(p) { + return new Point(p.x, p.y); + }); + + var minX = Infinity; + var minY = Infinity; + var maxX = -Infinity; + var maxY = -Infinity; + for (var i = 0; i < queryGeometry.length; i++) { + var p = queryGeometry[i]; + minX = Math.min(minX, p.x); + minY = Math.min(minY, p.y); + maxX = Math.max(maxX, p.x); + maxY = Math.max(maxY, p.y); } + var bounds = [minX - additionalRadius, minY - additionalRadius, maxX + additionalRadius, maxY + additionalRadius]; + var symbolQueryBox = new CollisionBox(new Point(minX, minY), 0, 0, maxX - minX, maxY - minY, args.scale, null); + var matching = this.rtree.search(bounds).concat(this.collisionTile.getFeaturesAt(symbolQueryBox, args.scale)); for (var k = 0; k < matching.length; k++) { @@ -146,7 +144,7 @@ FeatureTree.prototype.query = function(args, styleLayersByID) { function translate(translate, translateAnchor) { if (!translate[0] && !translate[1]) { - return queryPolygon; + return queryGeometry; } translate = Point.convert(translate); @@ -156,8 +154,8 @@ FeatureTree.prototype.query = function(args, styleLayersByID) { } var translated = []; - for (var i = 0; i < queryPolygon.length; i++) { - translated.push(queryPolygon[i].sub(translate._mult(pixelsToTileUnits))); + for (var i = 0; i < queryGeometry.length; i++) { + translated.push(queryGeometry[i].sub(translate._mult(pixelsToTileUnits))); } return translated; } @@ -199,6 +197,7 @@ function polygonIntersectsBufferedMultiPoint(polygon, rings, radius) { if (pointIntersectsBufferedLine(point, polygon, radius)) return true; } } + return false; } function polygonIntersectsMultiPolygon(polygon, multiPolygon) { diff --git a/js/source/geojson_source.js b/js/source/geojson_source.js index f46bdbce643..8fcf05db825 100644 --- a/js/source/geojson_source.js +++ b/js/source/geojson_source.js @@ -138,8 +138,7 @@ GeoJSONSource.prototype = util.inherit(Evented, /** @lends GeoJSONSource.prototy getVisibleCoordinates: Source._getVisibleCoordinates, getTile: Source._getTile, - featuresAt: Source._vectorFeaturesAt, - featuresIn: Source._vectorFeaturesIn, + queryFeatures: Source._queryVectorFeatures, getTileData: Source._getVectorTileData, _updateData: function() { diff --git a/js/source/image_source.js b/js/source/image_source.js index 02d8c970123..024e61377fa 100644 --- a/js/source/image_source.js +++ b/js/source/image_source.js @@ -145,11 +145,7 @@ ImageSource.prototype = util.inherit(Evented, { * be selectable, so always return an empty array. * @private */ - featuresAt: function(point, params, callback) { - return callback(null, []); - }, - - featuresIn: function(bbox, params, callback) { + queryFeatures: function(point, params, callback) { return callback(null, []); }, diff --git a/js/source/raster_tile_source.js b/js/source/raster_tile_source.js index 801bfb19dad..ee18b9a6a6b 100644 --- a/js/source/raster_tile_source.js +++ b/js/source/raster_tile_source.js @@ -116,11 +116,7 @@ RasterTileSource.prototype = util.inherit(Evented, { if (tile.texture) this.map.painter.saveTexture(tile.texture); }, - featuresAt: function(point, params, callback) { - callback(null, []); - }, - - featuresIn: function(bbox, params, callback) { + queryFeatures: function(point, params, callback) { callback(null, []); }, diff --git a/js/source/source.js b/js/source/source.js index b98071200a4..103ff431b45 100644 --- a/js/source/source.js +++ b/js/source/source.js @@ -68,34 +68,11 @@ exports._getVisibleCoordinates = function() { else return this._pyramid.renderedIDs().map(TileCoord.fromID); }; -exports._vectorFeaturesAt = function(coord, params, classes, zoom, bearing, callback) { +exports._queryVectorFeatures = function(queryGeometry, params, classes, zoom, bearing, callback) { if (!this._pyramid) return callback(null, []); - var result = this._pyramid.tileAt(coord); - if (!result) - return callback(null, []); - - this.dispatcher.send('query features', { - uid: result.tile.uid, - x: result.x, - y: result.y, - scale: result.scale, - tileSize: result.tileSize, - classes: classes, - zoom: zoom, - bearing: bearing, - source: this.id, - params: params - }, callback, result.tile.workerID); -}; - - -exports._vectorFeaturesIn = function(bounds, params, classes, zoom, bearing, callback) { - if (!this._pyramid) - return callback(null, []); - - var results = this._pyramid.tilesIn(bounds); + var results = this._pyramid.tilesIn(queryGeometry); if (!results) return callback(null, []); @@ -103,12 +80,9 @@ exports._vectorFeaturesIn = function(bounds, params, classes, zoom, bearing, cal this.dispatcher.send('query features', { uid: result.tile.uid, source: this.id, - minX: result.minX, - maxX: result.maxX, - minY: result.minY, - maxY: result.maxY, + queryGeometry: result.queryGeometry, scale: result.scale, - tileSize: result.tileSize, + tileSize: result.tile.tileSize, classes: classes, zoom: zoom, bearing: bearing, diff --git a/js/source/tile_pyramid.js b/js/source/tile_pyramid.js index 371d15b3aea..9a0c42215f6 100644 --- a/js/source/tile_pyramid.js +++ b/js/source/tile_pyramid.js @@ -3,6 +3,7 @@ var Tile = require('./tile'); var TileCoord = require('./tile_coord'); var Point = require('point-geometry'); +var Coordinate = require('../geo/coordinate'); var Cache = require('../util/mru_cache'); var util = require('../util/util'); var EXTENT = require('../data/buffer').EXTENT; @@ -349,57 +350,51 @@ TilePyramid.prototype = { this._cache.reset(); }, - /** - * For a given coordinate, search through our current tiles and attempt - * to find a tile at that point - * @param {Coordinate} coord - * @returns {Object} tile - * @private - */ - tileAt: function(coord) { - var ids = this.orderedIDs(); - for (var i = 0; i < ids.length; i++) { - var tile = this._tiles[ids[i]]; - var pos = tile.positionAt(coord); - if (pos && pos.x >= 0 && pos.x < EXTENT && pos.y >= 0 && pos.y < EXTENT) { - // The click is within the viewport. There is only ever one tile in - // a layer that has this property. - return { - tile: tile, - x: pos.x, - y: pos.y, - scale: Math.pow(2, this.transform.zoom - tile.coord.z), - tileSize: tile.tileSize - }; - } - } - }, - /** * Search through our current tiles and attempt to find the tiles that * cover the given bounds. - * @param {Array} bounds [minxminy, maxxmaxy] coordinates of the corners of bounding rectangle + * @param {Array} queryGeometry coordinates of the corners of bounding rectangle * @returns {Array} result items have {tile, minX, maxX, minY, maxY}, where min/max bounding values are the given bounds transformed in into the coordinate space of this tile. * @private */ - tilesIn: function(bounds) { + tilesIn: function(queryGeometry) { var result = []; var ids = this.orderedIDs(); + var minX = Infinity; + var minY = Infinity; + var maxX = -Infinity; + var maxY = -Infinity; + var z = queryGeometry[0].zoom; + + for (var k = 0; k < queryGeometry.length; k++) { + var p = queryGeometry[k]; + minX = Math.min(minX, p.column); + minY = Math.min(minY, p.row); + maxX = Math.max(maxX, p.column); + maxY = Math.max(maxY, p.row); + } + for (var i = 0; i < ids.length; i++) { var tile = this._tiles[ids[i]]; + var tileSpaceBounds = [ - tile.positionAt(bounds[0]), - tile.positionAt(bounds[1]) + tile.positionAt(new Coordinate(minX, minY, z)), + tile.positionAt(new Coordinate(maxX, maxY, z)) ]; + if (tileSpaceBounds[0].x < EXTENT && tileSpaceBounds[0].y < EXTENT && tileSpaceBounds[1].x >= 0 && tileSpaceBounds[1].y >= 0) { + + var tileSpaceQueryGeometry = []; + for (var j = 0; j < queryGeometry.length; j++) { + tileSpaceQueryGeometry.push(tile.positionAt(queryGeometry[j])); + } + result.push({ tile: tile, - minX: tileSpaceBounds[0].x, - maxX: tileSpaceBounds[1].x, - minY: tileSpaceBounds[0].y, - maxY: tileSpaceBounds[1].y + queryGeometry: tileSpaceQueryGeometry, + scale: Math.pow(2, this.transform.zoom - tile.coord.z) }); } } diff --git a/js/source/vector_tile_source.js b/js/source/vector_tile_source.js index b61f3778491..2703711f7ad 100644 --- a/js/source/vector_tile_source.js +++ b/js/source/vector_tile_source.js @@ -53,8 +53,7 @@ VectorTileSource.prototype = util.inherit(Evented, { getVisibleCoordinates: Source._getVisibleCoordinates, getTile: Source._getTile, - featuresAt: Source._vectorFeaturesAt, - featuresIn: Source._vectorFeaturesIn, + queryFeatures: Source._queryVectorFeatures, getTileData: Source._getVectorTileData, _loadTile: function(tile) { diff --git a/js/source/video_source.js b/js/source/video_source.js index 271c1e54a2c..f68961676bf 100644 --- a/js/source/video_source.js +++ b/js/source/video_source.js @@ -165,11 +165,7 @@ VideoSource.prototype = util.inherit(Evented, /** @lends VideoSource.prototype * return this.tile; }, - featuresAt: function(point, params, callback) { - return callback(null, []); - }, - - featuresIn: function(bbox, params, callback) { + queryFeatures: function(point, params, callback) { return callback(null, []); }, diff --git a/js/style/style.js b/js/style/style.js index f5aef3c3f12..0d98dc0419f 100644 --- a/js/style/style.js +++ b/js/style/style.js @@ -402,15 +402,7 @@ Style.prototype = util.inherit(Evented, { }, function(value) { return value !== undefined; }); }, - featuresAt: function(coord, params, classes, zoom, bearing, callback) { - this._queryFeatures('featuresAt', coord, params, classes, zoom, bearing, callback); - }, - - featuresIn: function(bbox, params, classes, zoom, bearing, callback) { - this._queryFeatures('featuresIn', bbox, params, classes, zoom, bearing, callback); - }, - - _queryFeatures: function(queryType, bboxOrCoords, params, classes, zoom, bearing, callback) { + queryFeatures: function(queryGeometry, params, classes, zoom, bearing, callback) { var features = []; var error = null; @@ -420,7 +412,7 @@ Style.prototype = util.inherit(Evented, { util.asyncAll(Object.keys(this.sources), function(id, callback) { var source = this.sources[id]; - source[queryType](bboxOrCoords, params, classes, zoom, bearing, function(err, result) { + source.queryFeatures(queryGeometry, params, classes, zoom, bearing, function(err, result) { if (result) features = features.concat(result); if (err) error = err; callback(); diff --git a/js/ui/map.js b/js/ui/map.js index 07060a0a292..06a4cf4cedb 100644 --- a/js/ui/map.js +++ b/js/ui/map.js @@ -325,7 +325,7 @@ util.extend(Map.prototype, /** @lends Map.prototype */{ featuresAt: function(point, params, callback) { var location = this.unproject(point).wrap(); var coord = this.transform.locationCoordinate(location); - this.style.featuresAt(coord, params, this._classes, this.transform.zoom, this.transform.angle, callback); + this.style.queryFeatures([coord], params, this._classes, this.transform.zoom, this.transform.angle, callback); return this; }, @@ -357,17 +357,14 @@ util.extend(Map.prototype, /** @lends Map.prototype */{ ]; } bounds = bounds.map(Point.convert.bind(Point)); - bounds = [ - new Point( - Math.min(bounds[0].x, bounds[1].x), - Math.min(bounds[0].y, bounds[1].y) - ), - new Point( - Math.max(bounds[0].x, bounds[1].x), - Math.max(bounds[0].y, bounds[1].y) - ) - ].map(this.transform.pointCoordinate.bind(this.transform)); - this.style.featuresIn(bounds, params, this._classes, this.transform.zoom, this.transform.angle, callback); + + var queryGeometry = [ + bounds[0], + new Point(bounds[1].x, bounds[0].y), + bounds[1], + new Point(bounds[0].x, bounds[1].y), + bounds[0]].map(this.transform.pointCoordinate.bind(this.transform)); + this.style.queryFeatures(queryGeometry, params, this._classes, this.transform.zoom, this.transform.angle, callback); return this; }, diff --git a/test/js/data/feature_tree.test.js b/test/js/data/feature_tree.test.js index 63c2e4358f1..4f0c2cf3a7c 100644 --- a/test/js/data/feature_tree.test.js +++ b/test/js/data/feature_tree.test.js @@ -3,6 +3,7 @@ var test = require('prova'); var vt = require('vector-tile'); var fs = require('fs'); +var Point = require('point-geometry'); var Protobuf = require('pbf'); var FeatureTree = require('../../../js/data/feature_tree'); var path = require('path'); @@ -42,8 +43,7 @@ test('featuretree', function(t) { scale: 1, tileSize: 512, params: { }, - x: 0, - y: 0 + queryGeometry: [new Point(0, 0)] }, styleLayers), []); t.end(); }); @@ -65,8 +65,7 @@ test('featuretree with args', function(t) { params: {}, scale: 1, tileSize: 512, - x: 0, - y: 0 + queryGeometry: [new Point(0, 0)] }, styleLayers), []); t.end(); }); @@ -86,8 +85,7 @@ test('featuretree point query', function(t) { params: { includeGeometry: true }, - x: -180, - y: 1780 + queryGeometry: [new Point(-180, 1780)] }, styleLayers); t.notEqual(features.length, 0, 'non-empty results for queryFeatures'); features.forEach(function(f) { @@ -116,10 +114,13 @@ test('featuretree rect query', function(t) { params: { includeGeometry: true }, - minX: 0, - minY: 3072, - maxX: 2048, - maxY: 4096 + queryGeometry: [ + new Point(0, 3072), + new Point(2048, 3072), + new Point(2048, 4096), + new Point(0, 4096), + new Point(0, 3072) + ] }, styleLayers); t.notEqual(features.length, 0, 'non-empty results for queryFeatures'); features.forEach(function(f) { @@ -164,8 +165,7 @@ test('featuretree query with layerIds', function(t) { params: { layerIds: ['water'] }, - x: -180, - y: 1780 + queryGeometry: [new Point(-180, 1780)] }, styleLayers); t.equal(features.length, 1); @@ -177,8 +177,7 @@ test('featuretree query with layerIds', function(t) { params: { layerIds: ['none'] }, - x: 1842, - y: 2014 + queryGeometry: [new Point(1842, 2014)] }, styleLayers); t.equal(features2.length, 0); diff --git a/test/js/source/tile_pyramid.test.js b/test/js/source/tile_pyramid.test.js index e5dab7757c0..5304aed8e2c 100644 --- a/test/js/source/tile_pyramid.test.js +++ b/test/js/source/tile_pyramid.test.js @@ -232,81 +232,6 @@ test('TilePyramid#removeTile', function(t) { }); }); -test('TilePyramid#tileAt', function(t) { - t.test('regular tile', function(t) { - var pyramid = createPyramid({ - load: function(tile) { tile.loaded = true; }, - minzoom: 1, - maxzoom: 1, - tileSize: 512 - }); - - var transform = new Transform(); - transform.resize(512, 512); - transform.zoom = 1.5; - pyramid.update(true, transform); - - var result = pyramid.tileAt(new Coordinate(0, 3, 2)); - - t.deepEqual(result.tile.coord.id, 65); - t.deepEqual(result.scale, 1.4142135623730951); - t.deepEqual(result.tileSize, 512); - t.deepEqual(result.x, 0); - t.deepEqual(result.y, 4096); - - t.end(); - }); - - t.test('reparsed overscaled tile', function(t) { - var pyramid = createPyramid({ - load: function(tile) { tile.loaded = true; }, - reparseOverscaled: true, - minzoom: 1, - maxzoom: 1, - tileSize: 512 - }); - - var transform = new Transform(); - transform.resize(512, 512); - transform.zoom = 2.5; - pyramid.update(true, transform); - - var result = pyramid.tileAt(new Coordinate(0, 3, 2)); - - t.deepEqual(result.tile.coord.id, 130); - t.deepEqual(result.scale, 1.4142135623730951); - t.deepEqual(result.tileSize, 1024); - t.deepEqual(result.x, 0); - t.deepEqual(result.y, 4096); - t.end(); - }); - - t.test('overscaled tile', function(t) { - var pyramid = createPyramid({ - load: function(tile) { tile.loaded = true; }, - minzoom: 1, - maxzoom: 1, - tileSize: 512 - }); - - var transform = new Transform(); - transform.resize(512, 512); - transform.zoom = 2.5; - pyramid.update(true, transform); - - var result = pyramid.tileAt(new Coordinate(0, 3, 2)); - - t.deepEqual(result.tile.coord.id, 65); - t.deepEqual(result.scale, 2 * 1.4142135623730951); - t.deepEqual(result.tileSize, 512); - t.deepEqual(result.x, 0); - t.deepEqual(result.y, 4096); - - t.end(); - }); - t.end(); -}); - test('TilePyramid#update', function(t) { t.test('loads no tiles if used is false', function(t) { var transform = new Transform(); @@ -531,61 +456,176 @@ test('TilePyramid#clearTiles', function(t) { }); test('TilePyramid#tilesIn', function (t) { - var transform = new Transform(); - transform.resize(511, 511); - transform.zoom = 1; + t.test('regular tiles', function(t) { + var transform = new Transform(); + transform.resize(511, 511); + transform.zoom = 1; - var pyramid = createPyramid({ - load: function(tile) { - tile.loaded = true; - } + var pyramid = createPyramid({ + load: function(tile) { + tile.loaded = true; + } + }); + + pyramid.update(true, transform); + + t.deepEqual(pyramid.orderedIDs(), [ + new TileCoord(1, 0, 0).id, + new TileCoord(1, 1, 0).id, + new TileCoord(1, 0, 1).id, + new TileCoord(1, 1, 1).id + ]); + + var tiles = pyramid.tilesIn([ + new Coordinate(0.5, 0.25, 1), + new Coordinate(1.5, 0.75, 1) + ]); + + tiles.sort(function (a, b) { return a.tile.coord.x - b.tile.coord.x; }); + tiles.forEach(function (result) { delete result.tile.uid; }); + + t.deepEqual(tiles, [ + { + tile: { + coord: { z: 1, x: 0, y: 0, w: 0, id: 1 }, + loaded: true, + uses: 1, + tileSize: 512, + sourceMaxZoom: 14 + }, + scale: 1, + queryGeometry: [{x: 4096, y: 2048}, {x:12288, y: 6144}] + }, + { + tile: { + coord: { z: 1, x: 1, y: 0, w: 0, id: 33 }, + loaded: true, + uses: 1, + tileSize: 512, + sourceMaxZoom: 14 + }, + scale: 1, + queryGeometry: [{x: -4096, y: 2048}, {x: 4096, y: 6144}] + } + ]); + t.end(); }); - pyramid.update(true, transform); - - t.deepEqual(pyramid.orderedIDs(), [ - new TileCoord(1, 0, 0).id, - new TileCoord(1, 1, 0).id, - new TileCoord(1, 0, 1).id, - new TileCoord(1, 1, 1).id - ]); - - var tiles = pyramid.tilesIn([ - new Coordinate(0.5, 0.25, 1), - new Coordinate(1.5, 0.75, 1) - ]); - - tiles.sort(function (a, b) { return a.tile.coord.x - b.tile.coord.x; }); - tiles.forEach(function (result) { delete result.tile.uid; }); - - t.deepEqual(tiles, [ - { - tile: { - coord: { z: 1, x: 0, y: 0, w: 0, id: 1 }, - loaded: true, - uses: 1, - tileSize: 512, - sourceMaxZoom: 14 + t.test('reparsed overscaled tiles', function(t) { + var pyramid = createPyramid({ + load: function(tile) { tile.loaded = true; }, + reparseOverscaled: true, + minzoom: 1, + maxzoom: 1, + tileSize: 512 + }); + + var transform = new Transform(); + transform.resize(512, 512); + transform.zoom = 2.0; + pyramid.update(true, transform); + + + t.deepEqual(pyramid.orderedIDs(), [ + new TileCoord(2, 0, 0).id, + new TileCoord(2, 1, 0).id, + new TileCoord(2, 0, 1).id, + new TileCoord(2, 1, 1).id + ]); + + var tiles = pyramid.tilesIn([ + new Coordinate(0.5, 0.25, 1), + new Coordinate(1.5, 0.75, 1) + ]); + + tiles.sort(function (a, b) { return a.tile.coord.x - b.tile.coord.x; }); + tiles.forEach(function (result) { delete result.tile.uid; }); + + t.deepEqual(tiles, [ + { + tile: { + coord: { z: 2, x: 0, y: 0, w: 0, id: 2 }, + loaded: true, + uses: 1, + tileSize: 1024, + sourceMaxZoom: 1 + }, + scale: 1, + queryGeometry: [{x: 4096, y: 2048}, {x:12288, y: 6144}] }, - minX: 4096, - maxX: 12288, - minY: 2048, - maxY: 6144 - }, - { - tile: { - coord: { z: 1, x: 1, y: 0, w: 0, id: 33 }, - loaded: true, - uses: 1, - tileSize: 512, - sourceMaxZoom: 14 + { + tile: { + coord: { z: 2, x: 1, y: 0, w: 0, id: 34 }, + loaded: true, + uses: 1, + tileSize: 1024, + sourceMaxZoom: 1 + }, + scale: 1, + queryGeometry: [{x: -4096, y: 2048}, {x: 4096, y: 6144}] + } + ]); + + t.end(); + }); + + t.test('overscaled tiles', function(t) { + var pyramid = createPyramid({ + load: function(tile) { tile.loaded = true; }, + reparseOverscaled: false, + minzoom: 1, + maxzoom: 1, + tileSize: 512 + }); + + var transform = new Transform(); + transform.resize(512, 512); + transform.zoom = 2.0; + pyramid.update(true, transform); + + + t.deepEqual(pyramid.orderedIDs(), [ + new TileCoord(1, 0, 0).id, + new TileCoord(1, 1, 0).id, + new TileCoord(1, 0, 1).id, + new TileCoord(1, 1, 1).id + ]); + + var tiles = pyramid.tilesIn([ + new Coordinate(0.5, 0.25, 1), + new Coordinate(1.5, 0.75, 1) + ]); + + tiles.sort(function (a, b) { return a.tile.coord.x - b.tile.coord.x; }); + tiles.forEach(function (result) { delete result.tile.uid; }); + + t.deepEqual(tiles, [ + { + tile: { + coord: { z: 1, x: 0, y: 0, w: 0, id: 1 }, + loaded: true, + uses: 1, + tileSize: 512, + sourceMaxZoom: 1 + }, + scale: 2, + queryGeometry: [{x: 4096, y: 2048}, {x:12288, y: 6144}] }, - minX: -4096, - maxX: 4096, - minY: 2048, - maxY: 6144 - } - ]); + { + tile: { + coord: { z: 1, x: 1, y: 0, w: 0, id: 33 }, + loaded: true, + uses: 1, + tileSize: 512, + sourceMaxZoom: 1 + }, + scale: 2, + queryGeometry: [{x: -4096, y: 2048}, {x: 4096, y: 6144}] + } + ]); + + t.end(); + }); t.end(); }); diff --git a/test/js/style/style.test.js b/test/js/style/style.test.js index b176139364a..97f671e1953 100644 --- a/test/js/style/style.test.js +++ b/test/js/style/style.test.js @@ -819,7 +819,7 @@ test('Style#setLayerZoomRange', function(t) { }); }); -test('Style#featuresAt - race condition', function(t) { +test('Style#queryFeatures - race condition', function(t) { var style = new Style({ "version": 8, "sources": { @@ -847,7 +847,7 @@ test('Style#featuresAt - race condition', function(t) { style._cascade([]); style._recalculate(0); - style.sources.mapbox.featuresAt = function(position, params, classes, zoom, bearing, callback) { + style.sources.mapbox.queryFeatures = function(position, params, classes, zoom, bearing, callback) { var features = [{ type: 'Feature', layer: 'land', @@ -859,8 +859,8 @@ test('Style#featuresAt - race condition', function(t) { }, 10); }; - t.test('featuresAt race condition', function(t) { - style.featuresAt([256, 256], {}, {}, 0, 0, function(err, results) { + t.test('queryFeatures race condition', function(t) { + style.queryFeatures([256, 256], {}, {}, 0, 0, function(err, results) { t.error(err); t.equal(results.length, 0); t.end(); @@ -870,7 +870,7 @@ test('Style#featuresAt - race condition', function(t) { }); }); -test('Style#featuresAt', function(t) { +test('Style#queryFeatures', function(t) { var style = new Style({ "version": 8, "sources": { @@ -906,7 +906,7 @@ test('Style#featuresAt', function(t) { style._cascade([]); style._recalculate(0); - style.sources.mapbox.featuresAt = style.sources.mapbox.featuresIn = function(position, params, classes, zoom, bearing, callback) { + style.sources.mapbox.queryFeatures = function(position, params, classes, zoom, bearing, callback) { var features = [{ type: 'Feature', layer: 'land', @@ -938,77 +938,71 @@ test('Style#featuresAt', function(t) { }, 10); }; - [ - style.featuresAt.bind(style, [256, 256]), - style.featuresIn.bind(style, [256, 256, 512, 512]) - ].forEach(function (featuresInOrAt) { - t.test('returns feature type', function(t) { - featuresInOrAt({}, {}, 0, 0, function(err, results) { - t.error(err); - t.equal(results[0].geometry.type, 'Polygon'); - t.end(); - }); + t.test('returns feature type', function(t) { + style.queryFeatures([{column: 1, row: 1, zoom: 1}], {}, {}, 0, 0, function(err, results) { + t.error(err); + t.equal(results[0].geometry.type, 'Polygon'); + t.end(); }); + }); - t.test('filters by `layer` option', function(t) { - featuresInOrAt({layer: 'land'}, {}, 0, 0, function(err, results) { - t.error(err); - t.equal(results.length, 2); - t.end(); - }); + t.test('filters by `layer` option', function(t) { + style.queryFeatures([{column: 1, row: 1, zoom: 1}], {layer: 'land'}, {}, 0, 0, function(err, results) { + t.error(err); + t.equal(results.length, 2); + t.end(); }); + }); - t.test('includes layout properties', function(t) { - featuresInOrAt({}, {}, 0, 0, function(err, results) { - t.error(err); - var layout = results[0].layer.layout; - t.deepEqual(layout['line-cap'], 'round'); - t.end(); - }); + t.test('includes layout properties', function(t) { + style.queryFeatures([{column: 1, row: 1, zoom: 1}], {}, {}, 0, 0, function(err, results) { + t.error(err); + var layout = results[0].layer.layout; + t.deepEqual(layout['line-cap'], 'round'); + t.end(); }); + }); - t.test('includes paint properties', function(t) { - featuresInOrAt({}, {}, 0, 0, function(err, results) { - t.error(err); - t.deepEqual(results[0].layer.paint['line-color'], 'red'); - t.end(); - }); + t.test('includes paint properties', function(t) { + style.queryFeatures([{column: 1, row: 1, zoom: 1}], {}, {}, 0, 0, function(err, results) { + t.error(err); + t.deepEqual(results[0].layer.paint['line-color'], 'red'); + t.end(); }); + }); - t.test('ref layer inherits properties', function(t) { - featuresInOrAt({}, {}, 0, 0, function(err, results) { - t.error(err); + t.test('ref layer inherits properties', function(t) { + style.queryFeatures([{column: 1, row: 1, zoom: 1}], {}, {}, 0, 0, function(err, results) { + t.error(err); - var layer = results[1].layer; - var refLayer = results[2].layer; - t.deepEqual(layer.layout, refLayer.layout); - t.deepEqual(layer.type, refLayer.type); - t.deepEqual(layer.id, refLayer.ref); - t.notEqual(layer.paint, refLayer.paint); + var layer = results[1].layer; + var refLayer = results[2].layer; + t.deepEqual(layer.layout, refLayer.layout); + t.deepEqual(layer.type, refLayer.type); + t.deepEqual(layer.id, refLayer.ref); + t.notEqual(layer.paint, refLayer.paint); - t.end(); - }); + t.end(); }); + }); - t.test('includes metadata', function(t) { - featuresInOrAt({}, {}, 0, 0, function(err, results) { - t.error(err); + t.test('includes metadata', function(t) { + style.queryFeatures([{column: 1, row: 1, zoom: 1}], {}, {}, 0, 0, function(err, results) { + t.error(err); - var layer = results[0].layer; - t.equal(layer.metadata.something, 'else'); + var layer = results[0].layer; + t.equal(layer.metadata.something, 'else'); - t.end(); - }); + t.end(); }); + }); - t.test('include multiple layers', function(t) { - featuresInOrAt({layer: ['land', 'landref']}, {}, 0, 0, function(err, results) { - t.error(err); - t.equals(results.length, 3); - t.end(); - }); + t.test('include multiple layers', function(t) { + style.queryFeatures([{column: 1, row: 1, zoom: 1}], {layer: ['land', 'landref']}, {}, 0, 0, function(err, results) { + t.error(err); + t.equals(results.length, 3); + t.end(); }); - }); diff --git a/test/js/ui/map.test.js b/test/js/ui/map.test.js index 434ea8439d6..469c0eb217e 100644 --- a/test/js/ui/map.test.js +++ b/test/js/ui/map.test.js @@ -403,8 +403,8 @@ test('Map', function(t) { var opts = {}; t.test('normal coords', function(t) { - map.style.featuresAt = function (coords, o, classes, zoom, bearing, cb) { - t.deepEqual(coords, { column: 0.5, row: 0.5, zoom: 0 }); + map.style.queryFeatures = function (coords, o, classes, zoom, bearing, cb) { + t.deepEqual(coords, [{ column: 0.5, row: 0.5, zoom: 0 }]); t.equal(o, opts); t.equal(cb, callback); t.deepEqual(classes, map._classes); @@ -417,11 +417,11 @@ test('Map', function(t) { }); t.test('wraps coords', function(t) { - map.style.featuresAt = function (coords, o, classes, zoom, bearing, cb) { + map.style.queryFeatures = function (coords, o, classes, zoom, bearing, cb) { // avoid floating point issues - t.equal(parseFloat(coords.column.toFixed(4)), 0.5); - t.equal(coords.row, 0.5); - t.equal(coords.zoom, 0); + t.equal(parseFloat(coords[0].column.toFixed(4)), 0.5); + t.equal(coords[0].row, 0.5); + t.equal(coords[0].zoom, 0); t.equal(o, opts); t.deepEqual(classes, map._classes);