I've been searching for a way to use a local mbtiles file as a provider, has anyone had any luck with this?
thanks,
Ian
I've been searching for a way to use a local mbtiles file as a provider, has anyone had any luck with this?
thanks,
Ian
You’d need a server that knows how to read tiles out of the database in response to incoming requests. It’s not too hard - I wrote one in a couple hundred lines of Python that can search for available MBTiles packages, and handle incoming requests that match a /zoom/x/y format and either serve them out of the appropriate MBTiles file or off disk. Can’t share it, unfortunately, since it’s part of a project at work, but it’s pretty straightforward.
Hey Mark,
Thanks for the info and sorry for the late reply. If anyone else needs to implement a local mbtiles imagery provider, this is how I got started:
var viewer = new Cesium.Viewer('cesiumContainer', {
baseLayerPicker: false,
imageryProvider: new Cesium.UrlTemplateImageryProvider({
url: 'http://localhost:8081/{z}/{x}/{y}',
minimumLevel:1,
maximumLevel:5
}),
geocoder: false
});
And a small node.js express server with sqlite3:
var express = require('express');
var sqlite3 = require('sqlite3').verbose();
var dbName = 'C:/data/map.mbtiles';
var db = new sqlite3.cached.Database( dbName, sqlite3.OPEN_READONLY,
function ( err ) {
if( err == null ) {
console.log( dbName + ' ok');
}
else {
console.log('Failed to open database \''+ dbName + ' ' + err );
}
});
var app = express();
// This responds a GET request for anything starting with a number
app.get('/[0-9]*', function(req, res, next) {
console.log("Got a GET request for /[0-9] (z/x/y) " + req.originalUrl );
url = req.originalUrl.slice(1); // get rid of leading slash or it will result in an empty tokens[0] value
var tokens = url.split("/",3); // limit of 3
var zoom_lvl = tokens[0];
var X = tokens[1];
var Y = tokens[2];
var stmt = "SELECT tile_data FROM tiles WHERE zoom_level=" + zoom_lvl + " AND tile_column=" + Y + " AND tile_row=" + X;
db.all(stmt, function(err, rows) {
if(err !== null) {
console.log('ERROR:'+err);
// Express handles errors via its next function.
// It will call the next operation layer (middleware),
// which is by default one that handles errors.
next(err);
}
else {
rows.forEach( function( row ) {
console.log('Lvl:' + zoom_lvl +' Y:' + Y + ' X:'+ X );
res.writeHead(200, {'Content-Type': 'image/png' });
res.end( row.tile_data, 'binary');
});
}
});
})
var server = app.listen( 8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
Caveat: This is intended as a starting point. It is important to note that I do have an issue with the above code in that my displayed map is a little garbled. chunks of the world map get displayed in the wrong areas. I've tried swapping {y} for {reverseY} and other small attempts at fixing the problem, but no luck yet. If anyone has any clues please comment.
Cheers,
Ian