Adding External GeoJSON with Mapbox.js

A couple years ago, I wrote a blog post about adding external GeoJSON data to your Leaflet map using link relations. Then I wrote another one about using AJAX tools to do the same thing. Here, years later, is the third part of that series: Adding External GeoJSON with Mapbox.js.

Mapbox.js vs Leaflet

Mapbox.js is an extension of Leaflet.js. It includes everything in Leaflet, plus some additional objects and methods. These additions were added to make it super simple to work with Mapbox tools and services while still utilizing the awesome power of Leaflet.

For example, initializing a map with Mapbox tiles in Mapbox.js:

L.mapbox.accessToken = <your access token here>
var map = L.mapbox.map('map', 'mapbox.streets');

Initializing a map with Mapbox tiles in Leaflet:

var map = L.map('map');
L.tileLayer('https://api.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
    attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
    id: 'mapbox.streets',
    accessToken: '<your access token here>'
}).addTo(map);

In Mapbox.js, we have access to a L.mapbox.map() object that handles a lot of things for us, including attribution, creating the request for tiles, etc. Neither of these methods are better than the other one – with Mapbox.js, you can initialize your map either way.

Mapbox.js adds a few other objects, too. (Hint: anything that starts with L.mapbox is Mapbox.js-specific.) One that is particularly useful for putting data on a map is L.mapbox.featureLayer().

loadURL()

By far the most fascinating part of L.mapbox.featureLayer() for me is the built-in loadURL() method. It does exactly what you think it does: it takes data from a URL and passes it as data into the L.mapbox.featureLayer() object.

var myLayer = L.mapbox.featureLayer()
  .loadURL('mydata.geojson')
  .addTo(map);

I seriously have no idea why I didn’t write this blog post before now. This is magical stuff.

So, what’s going on here? Through loadURL(), L.mapbox.featureLayer() essentially has built-in AJAX functionality. It’s asynchronously loading the data from the URL into our myLayer object and adding it to the map.

Yes. It’s that easy.

Adding additional functionality

Because the data is being loaded asynchronously, the code will continue to execute before the data is finished loading. This means that if you want to do anything with the data at all (add custom tooltips, for example), you have to make sure the data is finished loading first.

We can do this with the on('ready', ...) event handler:

var myLayer = L.mapbox.featureLayer()
  .loadURL('mydata.geojson')
  .on('ready', function() {
    myLayer.eachLayer(function(layer) {
      layer.bindPopup(layer.features.properties.name);
    });
  })
  .addTo(map);

With this code, we’re saying, “When the data is finished loading, iterate over each feature in the layer and bind to it a popup with that feature’s ‘name’ property.”

Or, as another example, let’s say you want your map to zoom and pan to the bounds of your data:

var myLayer = L.mapbox.featureLayer()
  .loadURL('mydata.geojson')
  .on('ready', function() {
    map.fitBounds(myLayer.getBounds());
  })
  .addTo(map);

Ooh, what about the two together?!

var myLayer = L.mapbox.featureLayer()
  .loadURL('mydata.geojson')
  .on('ready', function() {
    myLayer.eachLayer(function(layer) {
      map.fitBounds(myLayer.getBounds());
      layer.bindPopup(layer.features.properties.name);
    });
  })
  .addTo(map);

If we need to manipulate myLayer at all, we can add functionality to do so in the on('ready', ...) event handler.

L.mapbox.featureLayer() does other stuff too

While loadURL() is clearly the coolest thing L.mapbox.featureLayer() can do (clearly I’m biased), there are plenty of other awesome things about it!

It has some magical properties!

If you add certain properties to your GeoJSON and then load the data as a L.mapbox.featureLayer(), you can see them in action:

You can load data from your Mapbox Editor projects!

Instead of passing data as the first argument when creating the object, you have the option to add a Mapbox project ID. Projects are what’s created when you make a map with Mapbox Editor – if you create a L.mapbox.featureLayer() with a project ID, the data loaded in will be whatever data is in that project.

L.mapbox.featureLayer('mapbox.dc-markers')
  .addTo(map);

You can dynamically set data filters!

When you define your L.mapbox.featureLayer(), you can add a filter option. filter is defined by a function that iterates over the GeoJSON features with some sort of condition – if the feature passes the condition, it’s added to the object, and if it doesn’t, it’s not included. L.mapbox.featureLayer() has a setFilter() method that can be called whenever you want – ou can pass in a function with a condition, and only the features that pass the condition will be displayed on the map.

Be careful with this one, though! setFilter() works by removing all of the data from the map and then re-adding it, so if you add any external functionality to your object, make sure that functionality is added every time the layer is loaded.

You can see an example of setFilter() in action here.

Seriously, though, this is super cool

Give this a try! Check out the Mapbox.js examples for more things you can play with. As always, let me know if you have any questions (I’m @lyzidiamond on Twitter).

Also, here is a puppy: