Tilelive isn't a server itself but a backend framework that deals with tiles in different formats from different sources. But it's based on Node.js so you can turn it into a server in a pretty straight-forward way. To read tiles from a .mbtiles
source as exported by Mapbox Studio, you need the node-mbtiles tilelive module.
Here is my minimalistic approach which is loosely based on these implementations:
Install Node.js
Grab the node packages with npm install @mapbox/tilelive @mapbox/mbtiles express
Implement the server in the file server.js
:
var express = require('express');
var http = require('http');
var app = express();
var tilelive = require('tilelive');
require('mbtiles').registerProtocols(tilelive);
//Depending on the OS the path might need to be 'mbtiles:///' on OS X and linux
tilelive.load('mbtiles://path/to/osm_roads.mbtiles', function(err, source) {
if (err) {
throw err;
}
app.set('port', 7777);
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.get(/^\/v2\/tiles\/(\d+)\/(\d+)\/(\d+).pbf$/, function(req, res){
var z = req.params[0];
var x = req.params[1];
var y = req.params[2];
console.log('get tile %d, %d, %d', z, x, y);
source.getTile(z, x, y, function(err, tile, headers) {
if (err) {
res.status(404)
res.send(err.message);
console.log(err.message);
} else {
res.set(headers);
res.send(tile);
}
});
});
http.createServer(app).listen(app.get('port'), function() {
console.log('Express server listening on port ' + app.get('port'));
});
});
Note: The Access-Control-Allow-...
headers enable cross-origin resource sharing (CORS) so webpages served from a different server may access the tiles.
Run it with node server.js
Set up the webpage using Mapbox GL JS in minimal.html
:
<!DOCTYPE html >
<html>
<head>
<meta charset='UTF-8'/>
<title>Mapbox GL JS rendering my own tiles</title>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.css' rel='stylesheet' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.js'></script>
<style>
body { margin:0; padding:0 }
#map { position:absolute; top:0; bottom:50px; width:100%; }
</style>
</head>
<body>
<div id='map'>
</div>
<script>
var map = new mapboxgl.Map({
container: 'map',
center: [46.8, 8.5],
zoom: 7,
style: 'minimal.json'
});
</script>
</body>
</html>
Indicate the location of the tile source and style the layers with the following minimal.json
:
{
"version": 6,
"constants": {
"@background": "#808080",
"@road": "#000000"
},
"sources": {
"osm_roads": {
"type": "vector",
"tiles": [
"http://localhost:7777/v2/tiles/{z}/{x}/{y}.pbf"
],
"minzoom": 0,
"maxzoom": 12
}
},
"layers": [{
"id": "background",
"type": "background",
"paint": {
"background-color": "@background"
}
}, {
"id": "roads",
"type": "line",
"source": "osm_roads",
"source-layer": "roads",
"paint": {
"line-color": "@road"
}
}]
}
Serve the webpage and rejoice.
Best Answer
UPDATE(after Dec 8 2020): No longer free with Mapbox-GL JS 2.0+.
2.0 release of mapbox-gl-js is now billing us for the tile request for our tile sources as a result of TOS and license change. The alternative is either to stick to v1.13.1 or switch to a maplibre-gl-js (maintained-community-fork-of-v1.13.0).
OLD ANSWER (2016):
Describe
I could successfully feed Mapbox SDK with non-mapbox (wikimedia) datasource without API key, which likely means there is no restriction for it. Also in code comments (logoView on iOS) they mention that you only need to display the Mapbox watermark if you use mapbox-hosted maps, you can safely hide it otherwise.
Attaching the Mapbox GL style json file for reference. (you need to feed the URL to this file, as styleURL when initialising the mapBox's mapView)