December 2, 2017 Viswesh Subramanian 0Comment

Mapbox provides an exceptional platform to build experiences for exploration. Their offerings for Maps, Navigation, Search and customization along with SDKs; Android, IOS, GL JS, Unity makes it a well-rounded solution.

Mapbox products
Mapbox products

MapBox offers 2 JavaScript libraries – Mapbox.js and Mapbox GL JS. Mapbox.js is a leaflet plugin which essentially extends from L.Map to offer Mapbox magic. Mapbox GL JS, on the other hand, is a brand new library based on WebGL.

According to MDN –

WebGL enables web content to use an API based on OpenGL ES 2.0 to perform 3D rendering in an HTML <canvas> in browsers that support it without the use of plug-ins. WebGL programs consist of control code written in JavaScript and special effects code(shader code) that is executed on a computer’s Graphics Processing Unit (GPU). WebGL elements can be mixed with other HTML elements and composited with other parts of the page or page background.

If you have no prior experience with WebGL, WebGL tutorial is a good place to start. If you take a stroll around the WebGL APIs, you can easily get lost in a world of Giants, Goblins, and Golens. The bright minds at Mapbox have paved this mysterious land with APIs and built Mapbox GL JS for the humble mortals.

Since Mapbox GL JS  uses WebGL; unlike other JavaScript-based map libraries which offers configurable zoom levels and center point, it provides camera options such as bearing and pitch. With bearing, you can control the maps rotation (0 to 360 degrees) and with Pitch, you can control its tilt (0-60 degrees). These parameters are new as we have only been exposed to a high-level flat viewpoint.

Creating a map with Mapbox GL JS is as simple as providing a container id and style spec.

var map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/dark-v9'
});

Out of the box, there are 6 styles: basic, streets, bright, light, dark and satellite. If you are not satisfied with these styles, Mapbox offers a studio with which you can customize anything and everything under the sun (literally).

Mapbox Studio demo
Mapbox Studio

Once the base map is loaded and rendered, events (on, off, once, fire, listens) are triggered on the map instance for post-processing. Mostly post-processing consists of adding multiple layers to represent data, sending network requests or attaching interaction events.

Interaction events (MapMouseEvent, MapTouchEvent, MapBoxZoomEvent, MapDataEvent) are also available on the map instance. Mapbox APIs and events meet parity with all the map libraries out there, as well as offers unique ways to create immersive experiences.

Furthermore, there are readily available user interface controls –

NavigationControl

var nav = new mapboxgl.NavigationControl();
map.addControl(nav, 'top-left');

GeoLocateControl

map.addControl(new mapboxgl.GeolocateControl({
    positionOptions: {
        enableHighAccuracy: true
    },
    trackUserLocation: true
}));

FullScreenControl

map.addControl(new mapboxgl.FullscreenControl());

Popup

var popup = new mapboxgl.Popup({offset:popupOffsets})
  .setLngLat(e.lngLat)
  .setHTML("<h1>Point of interest</h1>")
  .addTo(map);

On 29th Jan 1998, 15 governments came together to sign the International Space Station Intergovernmental Agreement to set rules and guidelines for cooperatively using a space station for peaceful purposes. Later that year, on November 20th, the space station was launched into orbit. Since then, we have learned quite a bit about space. Take the tour.

Now that we are aware of Mapbox GL js foundations, how about we build a fullscreen map and track the location of ISS. That sounds fascinating!

There is already an available public API to get coordinates of the ISS – https://api.wheretheiss.at/v1/satellites/25544

curl https://api.wheretheiss.at/v1/satellites/25544

{
 name: "iss",
 id: 25544,
 latitude: 51.800269351886,
 longitude: 63.544658101307,
 altitude: 411.18132267885,
 velocity: 27613.660073487,
 visibility: "eclipsed",
 footprint: 4462.3230747636,
 timestamp: 1512228876,
 daynum: 2458090.1490278,
 solar_lat: -22.039773780531,
 solar_lon: 303.73942197035,
 units: "kilometers"
}

Unfortunately, the response is not in a GeoJSON format which Mapbox expects. What do we do? Well, we build it ourselves. Thanks to OSS – there is a geojson npm module which converts coordinates to GeoJSON.  

You may grab the source code to follow along.

First, create a map.

var map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/dark-v9',
    center: [0, 0],
    maxBounds: [[-180, -85], [180, 85]],
    zoom: 1
});

Write an express application to server index.html

var request = require('request'),
    geojson = require('geojson'),
    express = require('express'),
    path = require('path');

var app = express();

app.set('port', (process.env.PORT || 5000));

app.use(express.static(__dirname + '/public'));

app.get('/', function(req, res) {
    res.sendFile(path.join(__dirname + '/index.html'));
});

app.listen(app.get('port'), function () {
    console.log("App listening on port " + app.get('port'));
});
ISS Finder app
ISS Finder app

Introduce a route ‘/findiss’ to server ISS coordinates in GeoJSON format.

app.get('/findiss', function (req, res) {
    request("https://api.wheretheiss.at/v1/satellites/25544", function (err, resp, body) {
        if (err) {
            console.log(err);
            res.status(400).json({error: 'Unable to contact ISS API'});
            return;
        }

        var apiResponse = JSON.parse(body);
        var issGeoJSON = geojson.parse([apiResponse], {Point: ['latitude', 'longitude']});

        res.json(issGeoJSON);
    });
});

On map ‘load’ event, add a data source and its related layer.

map.addSource('iss', {type: 'geojson', data: '/findiss'});
map.addLayer({
   "id": "iss",
   "type": "symbol",
   "source": "iss",
   "layout": {
        "icon-image": "rocket-15"
    }
});

The above code places a rocket icon at the current ISS location. And as you refresh your page, the position of the ISS (rocket icon) will change. Aha! All that is remaining now is to fetch ISS coordinates at regular interval and update source data. 

window.setInterval(function () {
      fetch(url).then(function (response) {
          return response.json();
      })
      .then(function (json) {
           map.getSource('iss').setData(json);
      })
      .catch(function (error) {
         console.log(error);
      });
}, 2000);

Fullscreen controls? Easy.

map.addControl(new mapboxgl.FullscreenControl());

Mapbox offers a flyTo API with which you can fly to the specified coordinates. And what do you know, it fits our use case. What if we get lost with zoom levels and lose sight of ISS? By caching the last seen ISS coordinates, we can fly to it anytime we are lost.

map.flyTo({
    center: lastSeenLocaton
});

That concludes our implementation to track the International Space Station.

Check out the deployed application.

This post is part of a multi-part series:

  1. Data Visualization with Maps
  2. Raster Maps
  3. Vector Maps