OSM buildings vector tiles in D3.js – City Tiles 🏙️

2 min read

#30DayMapChallenge Day 3. Polygons

City Tiles 🏙️

OSM buildings tiles map - page view

This is a OSM buildings vector tiles map made using D3.js and Nextzen, that I have prepared for #30DayMapChallenge on Twitter in 2021. You can find out more about the challenge and my other maps in this post.

You can watch a short movie that shows the functionality on YouTube.

Goal: A map with polygons.

Live: https://maptheclouds.com/playground/30-day-map-challenge/polygons/

Tweet: https://twitter.com/maptheclouds/status/1455980347066302471

Code: https://github.com/alexaac/map-challenges/tree/master/polygons


The visualization shows the Timișoara historical center, România.

Data: OSM Buildings, Nextzen

Tags: #D3js #Nextzen #OSMBuildings #VectorTiles



OSM buildings vector tiles with D3.js and Nextzen – making of

OSM buildings tiles map - zoom out page view
OSM buildings tiles map - zoomed in view
OSM buildings tiles map - gif animation

Challenges: For this map, I want to test vector tiles loading from different sources. Therefore, I use several layers to draw background from Nextzen, and add a buildings layer above from OSM Buildings. In order to obtain the data, I connect to specific data API’s and receive it tile by tile, using d3.tile.

First, I load the data for the layers in the background: background, water, earth and roads layers. Then I load the layer for the background, the buildings. After that, I use D3.js to style and display them, too.

const buildings = g
        .style('fill', '#3288bd')
        .style('fill-opacity', 1)
        .attr('d', path)
        .style('stroke-width', 0.1)
        .style('stroke', '#000');

However, loading tiles from different sources proves to be a tricky process. The biggest challenge with this map was to load all tiles from the Nextzen API before loading the buildings. Otherwise, some building tiles would have been covered by earth tiles.

In order to solve this issue, first I have used Promise.all and async to get base data with d3.tile.Then I have loaded the buildings only after all background layers were already on the page. Moreover, all the tiles from the Nextzen API had to be loaded before styling them, to prevent the same overlapping issue.

  return Promise.all(promises)
    .then((data) => {
      // Wait for the Nextzen tiles to complete, then render the OSM tiles

      return data;
    .catch((error) => console.log(error));

TODO: add seamless zoom, create print layout

To conclude, I must say I have enjoyed making this map and I have learned more about using vector tiles data from API’s to make maps in D3.js.

Leave a Reply

Your email address will not be published. Required fields are marked *