0

Leaflet uses the principle of loading map tiles according to the zoom level, that is, the resolution of the map image depends on the zoom level. Can we apply the same principle to a polygon?

My website main page loads a broad map with several high-resolution polygons, but they take a lot of time to load (around 7 MB, ~2s, which is a lot for a main page). Is there a way to load only a low resolution version of the polygons, and load higher resolution versions according to zoom level, exactly as it's done with the raster tiles?

enter image description here

13
  • 1
    It's not just question of resolution but also of extent of what is being loaded. Raster tiles are loaded only for what is visible in the map view, but vector layer is loaded in it's entirety regardless of the map view.You could have several version of vector data for different zooms, but if you would zoom in, you would have to load entire detailed vector layer. The only solution is to convert you vector layer data to vector tiles (see en.wikipedia.org/wiki/Vector_tiles).
    – TomazicM
    Commented Apr 29 at 12:44
  • 1
    You might want to have a look at Leaflet.VectorGrid.Slicer. Commented Apr 29 at 13:31
  • 1
    found it richorama.github.io/2019/02/05/… Commented Apr 30 at 11:01
  • 1
    As you have found out, it has to be done server side.
    – TomazicM
    Commented Apr 30 at 11:38
  • 1
    See github.com/Leaflet/Leaflet.VectorGrid. You have to use L.VectorGrid.Protobuf
    – TomazicM
    Commented Apr 30 at 11:49

1 Answer 1

1

Backend

I need a Vector tiles server (from here)

const http = require('http')
const geojsonvt = require('geojson-vt')
const vtpbf = require('vt-pbf')
const data = require('./geojson-source-data.json')

// build the tile index from GeoJSON source data
const tileIndex = geojsonvt(data)

const port = process.env.PORT || 8080
http.createServer(handleRequest).listen(port)
console.log(`listening on port ${port}`)

// expects urls in the format: /{Z}/{X}/{Y}.pbf
function handleRequest(req, res) {
  const [z, x, y] = req.url
    .replace('.pbf', '')
    .split('/')
    .filter(n => n)
    .map(n => parseInt(n))

  // get the vectors for this tile
  const tile = tileIndex.getTile(z, x, y)

  // if there is no tile data, return an empty response
  if (!tile) {
    res.writeHead(204, { 'Access-Control-Allow-Origin': '*' })
    return res.end()
  }

  // encode as protobuf
  const buffer = Buffer.from(vtpbf.fromGeojsonVt({ geojsonLayer: tile }))

  // write the buffer to the response stream
  res.writeHead(200, {
    'Content-Type': 'application/protobuf',
    'Access-Control-Allow-Origin': '*'
  })
  res.write(buffer, 'binary')
  res.end(null, 'binary')
}

Frontend

Then on the client side I need to use the plugin Leaflet.VectorGrid and particularly the method L.VectorGrid.Protobuf

Example:

import 'leaflet.vectorgrid/dist/Leaflet.VectorGrid.bundled.js'

L.vectorGrid.protobuf('/{z}/{x}/{y}.pbf', {
  rendererFactory: L.canvas.tile
}).addTo(map)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.