How to highlight countries with Mapbox
Tags: javascript, mapbox, map, webgl
Published: 2020-12-21 08:11:18

I'm working on a trips section on my personal website. To visualize the countries I have visited, I wanted to show a map and highlight every country I visited. Since this was not a straightforward task and it took me longer than expected I thought I would share how this works.

Just here for the code? Checkout this [repository](https://github.com/ngnijland/highlight-countries-mapbox).

# Setup Mapbox

First, we want a running instance of Mapbox. I choose to use Mapbox GL JS as I wanted a smooth experience for future animations and transitions on the map of my personal website. Mapbox GL JS is a JavaScript library that uses WebGL to promise this smooth experience.

## Include sources

To render a Mapbox map you need to include the Mapbox GL JS library and styles in your code. You can either add it using Mapbox's CDN with a script and link tag or use a module bundler like npm or yarn. 

To be able to setup up a bare minimum as an example I chose to use Mapbox's CDN. It is done by adding the following lines of code to the `<head>` of your HTML file:

```html
<head>
  <!-- ... -->
  <script src='https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.js'></script>
  <link href='https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.css' rel='stylesheet' />
</head>
```

If you want to use a module bundler checkout their [documentation](https://docs.mapbox.com/mapbox-gl-js/api/).

## Access token

To use a Mapbox map you need an access token. To get one, you need to create a Mapbox account (https://account.mapbox.com/auth/signup/) and retrieve an access token from your account page (https://account.mapbox.com/). Once you have your access token it is time to render a map on your page!

## Render map

Mapbox needs an element to render its map in. Let's add one:

```html
<div id="map"></div>
```

To make it fill the entire page add the following CSS to the `<head>` of your HTML file:

```css
html,
body,
#map {
  height: 100%;
  margin: 0;
}
```

Now hand Mapbox your access token and initialize a new `Map` instance by adding the following script tag to the `<body>` of your HTML file:

```html
<script>
  mapboxgl.accessToken = '<YOUR ACCESS TOKEN HERE>';

  var map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/streets-v11',
    center: [5, 46],
    zoom: 3
  });
</script>
```

We now have a fully working Mapbox map running in our browser!

![A browser window showing a full-size Mapbox map.](https://dev-to-uploads.s3.amazonaws.com/i/qzxt6mwdhvy3ic0zjwch.png)

The complete code to achieve this:

```html
<!DOCTYPE html>
<html lang='en'>
<head>
  <meta charset='UTF-8'>
  <meta name='viewport' content='width=device-width, initial-scale=1'>
  <title>Highlight countries in mapbox</title>
  <script src='https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.js'></script>
  <link href='https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.css' rel='stylesheet' />
  <style>
    html,
    body,
    #map {
      height: 100%;
      margin: 0;
    }
  </style>
</head>
<body>
  <div id='map'></div>

  <script>
    mapboxgl.accessToken = '<YOUR ACCESS TOKEN HERE>';

    var map = new mapboxgl.Map({
      container: 'map',
      style: 'mapbox://styles/mapbox/streets-v11',
      center: [5, 46],
      zoom: 3
    });
  </script>
</body>
</html>
```

# Highlight countries

Now we have a map, the next step is to highlight individual countries. 

## Tilesets

Mapbox works with layers where you can display tilesets. These tilesets consist of vectors that render on a specific place on the map. You can create your own tileset or use existing ones. 

We will use this [countries tileset](https://studio.mapbox.com/tilesets/mapbox.country-boundaries-v1/) supplied by Mapbox.

## Add a layer

To render this tileset on top of our map we have to add a layer to our map. We can do this on the callback of the `Map`'s `load` event.

```javascript
map.on('load', function() {
  map.addLayer();
});
```

Now we add a config which will add the countries tileset to this layer:

```javascript
map.on('load', function() {
  map.addLayer(
    {
      id: 'country-boundaries',
      source: {
        type: 'vector',
        url: 'mapbox://mapbox.country-boundaries-v1',
      },
      'source-layer': 'country_boundaries',
      type: 'fill',
      paint: {
        'fill-color': '#d2361e',
        'fill-opacity': 0.4,
      },
    },
    'country-label'
  );
});
```

After the tileset config, we add `'country-label'` to make sure the country names render on top of the country tileset.

In the `paint` section of the config, you can choose the color and opacity in which countries should highlight. In this case `#d2361e` with an opacity of `0.4`.

This results in all countries being highlighted:

![A browser window showing a full-size Mapbox map highlighting all countries in red with a 60% opacity.](https://dev-to-uploads.s3.amazonaws.com/i/g61klpxo442f2ahre72l.png)

## Filter

Mapbox's country tileset identify countries with [ISO 3166-1 country codes](https://www.iso.org/iso-3166-country-codes.html). You can add a filter to the `country-boundaries` layer and use these country codes to highlight specific countries. This should also be done in the `Map`'s `load` event:

```javascript
map.setFilter('country-boundaries', [
  "in",
  "iso_3166_1_alpha_3",
  'NLD',
  'ITA'
]);
```

This will highlight The Netherlands and Italy.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/c0m2q4rx5iggzb42by1x.png)

Now we achieved what we wanted! Check out all the code needed here:

```html
<!DOCTYPE html>
<html lang='en'>
<head>
  <meta charset='UTF-8'>
  <meta name='viewport' content='width=device-width, initial-scale=1'>
  <title>Highlight countries in mapbox</title>
  <script src='https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.js'></script>
  <link href='https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.css' rel='stylesheet' />
  <style>
    html,
    body,
    #map {
      height: 100%;
      margin: 0;
    }
  </style>
</head>
<body>
  <div id='map'></div>

  <script>
    mapboxgl.accessToken = '<YOUR ACCESS TOKEN HERE>';

    var map = new mapboxgl.Map({
      container: 'map',
      style: 'mapbox://styles/mapbox/streets-v11',
      center: [5, 46],
      zoom: 3
    });

    map.on('load', function() {
      map.addLayer(
        {
          id: 'country-boundaries',
          source: {
            type: 'vector',
            url: 'mapbox://mapbox.country-boundaries-v1',
          },
          'source-layer': 'country_boundaries',
          type: 'fill',
          paint: {
            'fill-color': '#d2361e',
            'fill-opacity': 0.4,
          },
        },
        'country-label'
      );

      map.setFilter('country-boundaries', [
        "in",
        "iso_3166_1_alpha_3",
        'NLD',
        'ITA'
      ]);
    });
  </script>
</body>
</html>
```

# Conclusion
Thanks for reading this article! Check out all the code needed in this [repository](https://github.com/ngnijland/highlight-countries-mapbox). If you're interested in how I applied it on my website you can find it at [https://nieknijland.nl/trips](https://nieknijland.nl/trips).

Do you like this article? Maybe you'll like these as well:
* [Use multiple versions of an npm package at the same time](https://dev.to/ngnijland/use-multiple-versions-of-an-npm-package-at-the-same-time-582g)
* [Run asynchronous tasks in batches in NodeJS](https://dev.to/ngnijland/run-asynchronous-tasks-in-batches-in-nodejs-599a)

Let's get in contact! Comment below on this article or follow me on Twitter [@ngnijland](https://twitter.com/ngnijland).