How to create your own vector tile web maps
Hi. Welcome to exciting maze.yuiseki.icon
Nowadays, there has been an industry standard process for creating your own vector tile web maps.
This document show that process as step by step.
TL;DR
Read the Dockerfile and Makefile of this repository
GitHub - yuiseki/vector-tile-builder
Abstruct
1. Get *.pbf of OpenStreetMap
2. Generate *.pbf -> *.mbtiles as MBTiles with OpenMapTiles schema
3. Generate *.mbtiles -> /{z}/{x}/{y}/*.pbf
4. Deploy /{z}/{x}/{y}/*.pbf to server
5. Write TileJSON file of your vector tile server and deploy to server
6. Write Mapbox style specification file (style.json) to styling and displaying your vector tiles
7. Write HTML/CSS/JS that load and draw the maps based on style.json
Befor to begin
What is vector tile? What is so convenient about it? How should I make it?
There is a good document on GitHub repository of tilemaker
tilemaker/VECTOR_TILES.md at master · systemed/tilemaker · GitHub
Point is below
Vector tile is a binary data format for digital maps
Vector tile has just only data of geometry and attributes
Maps based on vector tile will rendering by browser (or application), based on those geometry and attributes data with style definition
That means vector tile has capability to flexibly customize appearance at rendering time
Digital maps based on image can not change appearance after once generated images
When we want to provide multiple appearance maps, It will require a huge amount of image data
This is advantage of vector tile
Basically, Vector tile has no detailed rule about the data attributes, But there is industry standard data scheme
That is OpenMapTiles scheme
We need standard data scheme, Because vector tile file format is too flexible to styling maps by ourself
There is a lot of open source style difinition based on OpenMapTiles scheme
We should be riding on the shoulders of giants
Reference
GitHub - mapbox/vector-tile-spec: Mapbox Vector Tile specification
Open vector tile schema for OpenStreetMap layers
Get *.pbf of OpenStreetMap
Visit https://download.geofabrik.de/
Select region you want to create maps
Download *.pbf file
NOTE:
What is this site?
Geofabrik is a company for-profit based on using OpenStreetMap data, but also they offers many free services to the OpenStreetMap community
download.geofabrik.de is, Amazingly, provide the free download server of snapshot data of OpenStreetMap of whole Earth scale
What is the pbf file?
pbf is abbreviation word and file extension of Protocol Buffers data
Refecence
Protocol Buffers | Google Developers
Generate *.pbf -> *.mbtiles as MBTiles with OpenMapTiles schema
I recommend to use tilemaker
GitHub - systemed/tilemaker: Make OpenStreetMap vector tiles without the stack
This software has capabilities to generate MBTiles with OpenMapTiles schema from OpenStreetMap pbf file without database
Get source code of tilemaker
code:bash
git clone git@github.com:systemed/tilemaker.git
cd tilemaker
If you can successfully make tilemaker, the command you should run is below:
code:bash
tilemaker --input tmp/region.pbf --output tmp/region.mbtiles
I know that make tilemaker is quite difficult...
You can use Docker to make tilemaker. I recommend this way
code:bash
make clean # dont forget clean if you have tried to make tilemaker on host machine!
docker build . -t tilemaker
docker run --rm --mount type=bind,source=$(CURDIR)/tmp,target=/tmp tilemaker --input /tmp/region.pbf --output /tmp/region.mbtiles
If you want to more customize your maps, read the docs of tilemaker
tilemaker/CONFIGURATION.md at master · systemed/tilemaker · GitHub
NOTE:
What is the MBTiles file?
MBTiles is the file format of storing tilesets
In fact, MBTiles file is one of SQLite database file that has some rules for storing tilesets
Reference
GitHub - mapbox/mbtiles-spec: specification documents for the MBTiles tileset format
MBTiles | Help | Mapbox
Generate *.mbtiles -> /{z}/{x}/{y}/*.pbf
I'm using tippecanoe
GitHub - mapbox/tippecanoe: Build vector tilesets from large collections of GeoJSON features.
Get source code of tippecanoe
code:bash
git clone git@github.com:mapbox/tippecanoe.git
cd tippecanote
Make tippecanoe
If you can successfully make tippecanoe, the command you should run is below:
code:bash
tile-join --force --no-tile-compression --no-tile-size-limit --no-tile-stats --output-to-directory=docs/zxy path/to/region.mbtiles
I know that make tippecanoe is quite difficult...
You can use Docker to make tippecanoe. I recommend this way
code:bash
make clean
docker build -t tippecanoe .
docker run -it --rm --mount type=bind,source=$(CURDIR)/tmp,target=/tmp tippecanoe tile-join --force --no-tile-compression --no-tile-sizelimit --no-tile-stats --output-to-directory /tmp/zxy /tmp/region.mbtiles
cp -r tmp/zxy docs/
NOTE:
What is this step?
In fact, you can serve directory MBTiles file as vector tile server
But that will require keep running some application server that dynamically convert MBTiles to /{z}/{x}/{y}/*.pbf
Deploy /{z}/{x}/{y}/*.pbf to server
I'm using GitHub Pages
For simplify, you might be generate zxy files under the directory that named like docs/zxy/{z}/{x}/{y}/*.pbf
docs directory has special meanings on GitHub
You can directly deploy contents of this directory as a GitHub Pages
Dont forget: You must change settings of Pages section of your GitHub repository to publish docs directory
Write TileJSON file of your vector tile server and deploy to server
You can use mbtiles2tilejson
code:bash
npm i -g mbtiles2tilejson
mbtiles2tilejson tmp/region.mbtiles --url https://your-github-username.github.io/your-repo-name/zxy/ > docs/tiles.json
Write Mapbox style specification file (style.json) to styling and displaying your vector tiles
I'm using osm-bright-gl-style based style.json that has fixed glyphs issue
vector-tile-builder/style.json at main · yuiseki/vector-tile-builder · GitHub
I recommend copy this style.json
Write HTML/CSS/JS that load and draw the maps based on style.json
code:docs/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vector tile builder Demo</title>
<script src="https://unpkg.com/maplibre-gl@1.15.2/dist/maplibre-gl.js"></script>
<link
href="https://unpkg.com/maplibre-gl@1.15.2/dist/maplibre-gl.css"
rel="stylesheet"
/>
<style>
html,
body,
#map {
width: 100vw;
height: 100vh;
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
(async () => {
let map;
const res = await fetch("./tiles.json");
const tilejson = await res.json();
const bounds = tilejson.bounds;
const center = tilejson.center
? tilejson.center
: [(bounds0 + bounds2) / 2, (bounds1 + bounds3) / 2];
const zoom = (tilejson.minzoom + tilejson.maxzoom) / 2;
console.log(center, zoom);
map = new maplibregl.Map({
container: "map",
style: "./style.json",
center: center,
zoom: 5,
});
map.addControl(new maplibregl.NavigationControl());
map.addControl(
new maplibregl.AttributionControl({
compact: false,
customAttribution:
"Style © <a href='http://openmaptiles.org/'>OpenMapTiles</a> | " +
"Data © <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap contributors</a>",
})
);
})();
</script>
</body>
</html>