Query map features nearest to a given point from a remote MVT vector tiles layer
query-mvt
allows you query remote vector tile sets for features. Its main advantage is that it does not require any special access or server-side software as it mimics the behavior of a web browser displaying the map.
It works both in Node.js and in the browser. It supports all vector mapping services that use MVT/PBF files and can adapt to different projections and tileset extents.
npm i query-mvt
Vector tile sets created by GDAL and a few other tools come with a de-facto standard metadata.json
that allows query-mvt
to automatically acquire all the needed parameters (such as map projects, tile grid and size, world bounds):
import * as queryMVT from 'query-mvt';
// Automatically imports the layer metadata
// (EPSG:4326 with world coverage in this case)
queryMVT.acquire('https://velivole.b-cdn.net/tiles/place/2/metadata.json')
.then((metadata) => queryMVT.search({
url: 'https://velivole.b-cdn.net/tiles/place/2/{z}/{x}/{y}.pbf',
lon: 6.220432,
lat: 45.779170,
metadata
}))
.then((result) => {
assert.strictEqual(result.feature.properties['n'], 'Doussard');
assert.closeTo(result.distance, 0.34, 0.1);
})
Most commercial public mapping services such as Qwant do not have a metadata.json
but tend to use the same EPSG:3857
projection (aka Web Mercator) and world bounds:
import * as queryMVT from 'query-mvt';
// Configure manually the layer metadata
// (EPSG:3857 with world coverage in this case)
queryMVT.search({
url: 'https://tiles.qwant.com/default/{z}/{x}/{y}',
lon: 2.348942,
lat: 48.853289,
// You can filter the results
filter: (f) => f.properties['class'] === 'city',
maxFeatures: 20,
maxRadius: 10,
metadata: queryMVT.constants.EPSG3857
})
.then((results) => {
assert.strictEqual(results[0].feature.properties['class'], 'city');
assert.strictEqual(results[0].feature.properties['name'], 'Paris');
assert.closeTo(results[0].distance, 0.04, 0.1);
})
A stand-alone CLI version exists as well:
# Query the nearest village near 45.779° N : 6.22° E
query-mvt 45.779 6.22 -f class=village
Type: {distance: number, feature: turf.Feature}
distance
numberfeature
turf.Feature
Distance in km
Type: number
Feature (turf.js and GeoJSON compatible)
Type: turf.Feature
url
string URL of a GDAL-style metadata.jsonfetchOpts
RequestInit? optional fetch options (AbortController, authorization headers...)
Returns MVTMetadata
-
opts
Record<string, any> optionsopts.url
string Openlayers-style URL template for requesting tiles, must contain {x}, {y} and {z}opts.metadata
MVTMetadata? optional GDAL-style metadata.json, may be empty for world-wide EPSG:3857 tilesetsopts.lon
number longitudeopts.lat
number latitudeopts.queue
Queue? optional shared Queue to be used for limiting concurrency, @default Queue(8,0)opts.maxFeatures
number? optional number of features to return, @default 1opts.maxRadius
number? optional maximum radius in km to search in, @default 10opts.fetchOpts
RequestInit? optional fetch options (AbortController, authorization headers...)opts.dedupe
boolean? dedupe the returned features (as the text will usually stretch across several tiles)