- Published on
Adding dynamic geo data to existing MBTiles using Martin
Introduction
So, for the project I'm working on I wanted to host my own map tiles but also wanted to dynamically update only one or two layers of the tiles I will be serving. I didn't want to recreate map tiles every time I had to add a new route so I decided to go with Martin which allows me to have a base map data as a .mbtile but also attach dynamic data that sits in some database. The database can be easily updated with new routes/geo data for specific layers. This way I don't have to recreate and reupload a large .mbtile file every time I want to add a new route.
I didn't find a lot of information or a quick start guide how to achieve it so I'm sharing this info for others.
What will we do?
Let's create a map for Netherlands with additional map layer that will contain some bike routes added by us.
The map will be served via map tiles using Martin. We will be returning MVT(Mapbox Vector Tile) files to client based on requested coordinates and zoom level.
Base map tiles
First let's grab some already created tiles in a .mbtiles format. Here's a great website where you can download more or less up to date generated tiles: https://osm.dbtc.link/mbtiles/
Let's go with the Netherlands map as it's the smallest one up there, that is: {DATE}-netherlands.mbtiles
As of time of writing this the most up to date file is: 2024-07-07-netherlands.mbtiles
and I will be using it further in the article.
Then move the .mbtiles file to a desired folder: {YOUR_PATH}/martin
Dynamic database data
Next let's set up a simple PostGIS databse to hold our data about bike routes. We will create a table called "bike-routes" where we can add new bike routes or delete existing one and Martin will connect that data with our base map tiles.
Let's use a Docker Compose for a quick setup of PostGIS database. Create a new folder: {YOUR_PATH}/postgis
and create a docker-compose.yaml file there.
{YOUR_PATH}/postgis/docker-compose.yaml
:
services:
postgis:
image: postgis/postgis
restart: always
environment:
- POSTGRES_DB=gis
- POSTGRES_USER=gis
- POSTGRES_PASSWORD=password
ports:
- 5432:5432
volumes:
- ./data/postgis:/var/lib/postgresql/data
This standard docker compose config will host a database on a port 5432 and also store the data from database locally inside current directory, in data folder.
Inside the martin
directory in your terminal use this commend to run the docker container:
docker-compose up
Now we have a database where we can add our dynamic geo data.
Adding geojson to database
We will be adding "Limes Route" bike route geojson to our database. You can grab it here: [link]
Move the geojson file to {YOUR_PATH}/martin
folder and run the command:
ogr2ogr -f "PostgreSQL" PG:"dbname=gis user=gis password=password host=localhost port=5432" "path.geojson" -nln paths -append
Note that you will need to install GDAL to use the ogr2ogr command. You can install GDAL using these commands (on mac):
`sudo port install gdal`
Installing Martin and creating config file
Download Martin from the release page: https://github.com/maplibre/martin/releases
Inside the martin
folder create file config.yaml
with minimal config.
{YOUR_PATH}/martin/config.yaml
:
listen_addresses: '0.0.0.0:3000'
worker_processes: 4
cache_size_mb: 512
mbtiles:
sources:
basemap: './2024-07-07-netherlands.mbtiles'
postgres:
connection_string: 'postgresql://gis:password@localhost:5432/gis'
auto_publish:
from_schemas:
- public
tables:
source_id_format: '{table}'
clip_geom: true
buffer: 64
extent: 4096
Now we are all set up and can start our Martin server. Move to the {YOUR_PATH}/martin
directory in your terminal and run:
martin --config config.yaml
Martin catalog
We can also verify that the Martin is serving specified mbtiles file and data from PostGIS databse by navigating to: http://0.0.0.0:3000/catalog
You will see the following:
{
"tiles":{
"basemap":{
"content_type":"application/x-protobuf",
"content_encoding":"gzip",
"name":"OpenMapTiles",
"description":"A tileset showcasing all layers in OpenMapTiles. https://openmaptiles.org",
"attribution":"<a href=\"https://www.openmaptiles.org/\" target=\"_blank\">© OpenMapTiles</a> <a href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\">© OpenStreetMap contributors</a>"
},
"paths":{
"content_type":"application/x-protobuf",
"description":"public.paths.wkb_geometry"
}
},
"sprites":{},
"fonts":{}
}
Now you can access your vector files by specifying host url and the tiles source in this format: {HOST_URL}/{SOURCE_ID}/{Z}/{X}/{Y}
where:
- SOURCE_ID - is the id of the source of the tiles
- Z - zoom level
- X,Y - coordinates
For example: http://localhost:3000/basemap/8/131/85
will return a tile from basemap tiles source with zoom level equal 8 and coordinates x=131, y=85.