I want to use Mapbox GL to render vector tiles that I am generating from PostGIS requests. I have built a tile server using Mapnik, sphericalmecator, and pg plugins for npm. I added the tile endpoint to the stylesheet for Mapbox GL, and have confirmed that the correct tiles are requested, but the tiles are not rendered on the map. I used the same backend for a leaflet plugin and it works correctly, so I'm not sure I have to change the backend. Any advice is appreciated. Code is below.
This is the index.html file that I am loading.
var map = new mapboxgl.Map({
container: 'map',
style: 'outdoors-v7.json',
center: [47.4333, 19.2500],
zoom: 9
});
map.on('style.load', function() {
map.addSource("parcelLayer", {
"type": "vector",
"tiles": ["http://localhost:5001/data/city/lots/budapest/{z}/{x}/{y}.pbf"],
});
map.addLayer({
"id": "parcelLayer",
"type": "fill",
"source": "parcelLayer",
"layout": {
"visibility": "visible"
},
"paint": {
"fill-color": '#ff0000',
"fill-opacity": 1
}
});
});
This is the routes that the map is calling.
var express = require('express');
var router = express.Router();
var conString = require('../../database').conString;
var pg = require('pg');
var SphericalMercator = require('sphericalmercator');
var mapnik = require('mapnik');
var zlib = require('zlib');
mapnik.register_default_fonts();
mapnik.register_default_input_plugins();
var mercator = new SphericalMercator({
size: 256
});
router.get('/:city_name/:z/:x/:y.pbf', function(req, res) {
var city_name = req.params.city_name;
var bbox = mercator.bbox(
+req.params.x,
+req.params.y,
+req.params.z,
false,
'4326'
);
pg.connect(conString, function(err, client, done){
var config_object = {
'medellin' : {
'attributes': ['cobama', 'subtipo_lote', 'tipo_lote', 'estrato', 'zona', 'usopredial', 'npisos', 'calificacion']
},
'lima' : {
'attributes': ['objectid', 'id_lote', 'tip_uso', 'id_dist', 'estado']
},
'budapest': {
'attributes': ['id', 'tags']
}
};
var handleError = function(err) {
// no error occurred, continue with the request
if(!err) return false;
// An error occurred, remove the client from the connection pool.
// A truthy value passed to done will remove the connection from the pool
// instead of simply returning it to be reused.
// In this case, if we have successfully received a client (truthy)
// then it will be removed from the pool.
if(client){
done(client);
}
console.log(err);
// res.writeHead(500, {'content-type': 'text/plain'});
// res.end('An error occurred');
return true;
};
// handle an error from the connection
if(handleError(err)) return;
if(city_name === 'medellin' || city_name === 'lima' || city_name === 'budapest'){
client.query('SELECT row_to_json(fc) FROM ( SELECT "FeatureCollection" As type, array_to_json(array_agg(f)) As features FROM (SELECT 'Feature' As type, ST_AsGeoJSON(lg.wkb_geometry)::json As geometry, row_to_json((SELECT l FROM (SELECT ' + config_object[city_name]['attributes'].join(', ') + ' ) As l )) As properties FROM ' + city_name + '_parcels As lg WHERE st_intersects(lg.wkb_geometry, st_makeenvelope(' + bbox.toString() + ', 4326) ) ) As f ) As fc', function(err, result){
if (err) {
console.log('error in the query');
return console.error('error running query', err);
}
// handle an error from the connection
if(handleError(err)) return;
var vtile = new mapnik.VectorTile(+req.params.z, +req.params.x, +req.params.y);
if( (typeof result.rows[0] !== 'undefined') && (result.rows[0].row_to_json.features !== null )){
try {
vtile.addGeoJSON(JSON.stringify(result.rows[0].row_to_json), 'lots');
console.log(result.rows[0].row_to_json.features[0]);
} catch (e) {
console.log('came back with an error');
console.log(e);
}
}
res.setHeader('Content-Encoding', 'deflate');
res.setHeader('Content-Type', 'application/x-protobuf');
zlib.deflate(vtile.getData(), function(err, pbf) {
done();
// res.writeHead(200);
res.send(pbf);
});
});
}
});
});
Please ask any other questions you might have.