[GIS] Load external tileJSON file in Mapbox

jsonmapboxmaperitiveopenstreetmaptiles

I have tiles generated by Maperitive from an OSM file, and there's a nice tiles.json generated with them which specifies neatly the tiles-path, bounding box, minzoom, maxzoom, center, etc. The format is identical to the tileJSON specification given here: https://www.mapbox.com/guides/an-open-platform/#tilejson

But it just blows that the example stopped a step short and inline'd the JSON code into the example's source code, hence rendering it (pun intended) useless. No clue on https://github.com/mapbox/tilejson-spec either. All web searches for this lead to these sites; the rest digress into GeoJSON which is something else entirely. Why in the world would anyone go through the trouble of using JSON if one wasn't importing it from an external file? (no, please don't try to answer that.. it's not the main question. Focus!)

So, a humble request: Please re-write this example code given on mapbox.com, to show an external JSON file being loaded. (And please put in a word with someone there if you know them to post a proper example on the website)

<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title></title>
  <script src='https://api.tiles.mapbox.com/mapbox.js/v2.1.4/mapbox.js'></script>
  <link href='https://api.tiles.mapbox.com/mapbox.js/v2.1.4/mapbox.css' rel='stylesheet' />
  <style>
    body { margin:0; padding:0; }
    .map { position:absolute; top:0; bottom:0; width:100%; }
  </style>
</head>
<body>
<div id='map' class='map'> </div>
<script>
L.mapbox.accessToken = '<your access token here>';
var tilejson = {
  "tiles": [ "https://api.tiles.mapbox.com/v4/examples.map-i86l3621/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoidHJpc3RlbiIsImEiOiJuZ2E5MG5BIn0.39lpfFC5Nxyqck1qbTNquQ" ],
  "minzoom": 0,
  "maxzoom": 18
}
L.mapbox.map('map', tilejson, {
    scrollWheelZoom: false
}).setView([43.6519,-79.3852], 15);
</script>
</body>
</html>

Edit: Included jquery.min.js and changed code as advised; am getting a "not well-formed" error in console. I reckon jquery doesn't like tileJSON. This is why full examples ought to be given 😛. Please see and advise what needs to change here. Is there a more generic JSON-loader we can use instead of jquery? I believe we're very close to getting this.

var tilejson;
$.getJSON('pune/tiles.json', function(data) {
  tilejson = data;
});
console.log(tilejson.name);

L.mapbox.map('map', tilejson, {
    scrollWheelZoom: false
});

Here is the content of tiles.json (loading local tiles, generated by Maperitive; tested to be valid JSON as per http://codebeautify.org/jsonviewer):

{
    "tilejson": "1.0.0",
    "name": "Pune 1 to 16",
    "description": "Made with Maperitive",
    "attribution": "Map data © OpenStreetMap contributors",
    "tiles": [
        "pune/{z}/{x}/{y}.png"
    ],
    "minzoom": 1,
    "maxzoom": 16,
    "bounds": [
        73.59366818720622,
        18.33281593564951,
        74.07630689997964,
        18.77938751279949
    ],
    "center": [
        73.83498754359293,
        18.5561017242245,
        1
    ]
}

Best Answer

The reason you are getting a "not well formed" error in console is because your tilejson file loads asynchronously, meaning the script continues to execute while the tilejson object is only partly loaded as an incomplete promise object. So when you pass your tilejson object to L.mapbox.map, you are actually passing a promise object (which it can't parse).

So initialize your map in the success callback function that $.getJSON() provides. Like so:

$.getJSON('<url to tilejson>', function(tilejson) {
  L.mapbox.accessToken = 'pk.eyJ1IjoiamFtZXMtbGFuZS1jb25rbGluZyIsImEiOiJ3RHBOc1BZIn0.edCFqVis7qgHPRgdq0WYsA';
  var map = L.mapbox.map('map', tilejson, {
    scrollWheelZoom: false
  });  
});

However, you might still run into problems (e.g. w/ retina screens as outlined in my other answer) because L.mapbox.map makes some expectations that the tilejson is coming from MapBox's own server. For a more reliable solution, try something like this:

$.getJSON('<url to tilejson>', function(tilejson) {
  L.mapbox.accessToken = 'pk.eyJ1IjoiamFtZXMtbGFuZS1jb25rbGluZyIsImEiOiJ3RHBOc1BZIn0.edCFqVis7qgHPRgdq0WYsA';
  var map = L.mapbox.map('map', undefined, {
    layers: L.tileLayer(tilejson.tiles[0]),
    center: tilejson.center.slice(0,2).reverse(),
    zoom: tilejson.center[2],
    minzoom: tilejson.minzoom,
    maxzoom: tilejson.maxzoom,
    scrollWheelZoom: false
  })
});