Search code examples
javascriptmapboxmapbox-gl-jsopenmaptiles

How to use OpenMapTiles server for MapBox GL JS?


In OpenMapTiles' docs it is said, that it can serve vector tiles for MapBox GL JS.

But digging docs for both projects I didn't find an option: how to configure self-hosted MapBox GL JS library to use tiles from my self-hosted OpenMapTiles server?


Solution

  • I was also use able to successfully use Klokantech's tileserver-gl

    However, I really wanted something even more minimalist than that. Something smaller and more suited to my low intelligence.

    As it happens there is an MBTiles module in npm. That made setting up a node tileserver very easy. I explain it in a blog here and here. They are both the same blog.

    Here is the js code for the server (borrowed in part from this Git GIST by manuelroth). I recommend reading the above blog (here and here) which shows a minimalist example combining display and server sides. (There are a few gotchas which can be avoided by looking at the example).

    var express = require("express"),
        app = express(),
        MBTiles = require('mbtiles'),
        p = require("path");
    
    
    // Enable CORS and set correct mime type/content encoding
    var header = {
      "Access-Control-Allow-Origin":"*",
      "Access-Control-Allow-Headers":"Origin, X-Requested-With, Content-Type, Accept",
      "Content-Type":"application/x-protobuf",
      "Content-Encoding":"gzip"
    };
    
    // Serve the fonts as static files
    //app.use('/fonts', express.static('fonts'))
    app.use('/fonts', express.static('fonts', {
        setHeaders: function setHeaders(res, path, stat) {
            res.header('Access-Control-Allow-Origin', '*');
            res.header('Access-Control-Allow-Methods', 'GET');
            res.header('Access-Control-Allow-Headers', 'Content-Type');
        }
    }))
    
    app.use('/sprite', express.static('sprite', {
        setHeaders: function setHeaders(res, path, stat) {
            res.header('Access-Control-Allow-Origin', '*');
            res.header('Access-Control-Allow-Methods', 'GET');
            res.header('Access-Control-Allow-Headers', 'Content-Type');
        }
    }))
    
    
    // Route which handles requests like the following: /<mbtiles-name>/0/1/2.pbf
    app.get('/:source/:z/:x/:y.pbf', function(req, res) {
        console.log('req.params.source : ' + req.params.source)
        console.log('MBTiles file : ' +  p.join(__dirname, req.params.source + '.mbtiles'))
        console.log(req.params.z + '/' + req.params.x + '/' + req.params.y)
      new MBTiles(p.join(__dirname, req.params.source + '.mbtiles'), function(err, mbtiles) {
        mbtiles.getTile(req.params.z, req.params.x, req.params.y, function(err, tile, headers) {
          if (err) {
            res.set({"Content-Type": "text/plain"});
            res.status(404).send('Tile rendering error: ' + err + '\n');
          } else {
            res.set(header);
            res.send(tile);
          }
        });
        if (err) console.log("error opening database");
      });
    });
    
    // Starts up the server on port 3000
    console.log('__dirname : ' + __dirname)
    console.log('command line args:')
    process.argv.forEach(function (val, index, array) {
      console.log(index + ': ' + val);
    });
    console.log('Listening on port: ' + 3000);
    app.listen(3000);