Skip to content

Query features from remote MVT tiles by location

License

Notifications You must be signed in to change notification settings

mmomtchev/query-mvt

Repository files navigation

query-mvt

Query map features nearest to a given point from a remote MVT vector tiles layer

License: ISC Node.js CIcodecov

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.

Usage

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):

with metadata.json

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);
  })

raw MVT tiles

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);
  })

CLI

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

API

Table of Contents

Result

Type: {distance: number, feature: turf.Feature}

Properties

  • distance number
  • feature turf.Feature

distance

Distance in km

Type: number

feature

Feature (turf.js and GeoJSON compatible)

Type: turf.Feature

acquire

Parameters

  • url string URL of a GDAL-style metadata.json
  • fetchOpts RequestInit? optional fetch options (AbortController, authorization headers...)

Returns MVTMetadata

search

Parameters

  • opts Record<string, any> options

    • opts.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 tilesets
    • opts.lon number longitude
    • opts.lat number latitude
    • opts.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 1
    • opts.maxRadius number? optional maximum radius in km to search in, @default 10
    • opts.fetchOpts RequestInit? optional fetch options (AbortController, authorization headers...)
    • opts.dedupe boolean? dedupe the returned features (as the text will usually stretch across several tiles)

Returns Promise<Array<Result>>