'
Mapbox GL JS  |  Choropleth: Vector Tiles with Joined Data

This example is based on the Mapbox example with the addition of color scales and quintile breaks from chroma.js. It uses 2015 overdose death rate categories from the National Center for Health Statistics. Since these values are loaded into the map, they could also be used to create a legend or interactive buttons to change to scale and styling of the data.

« Choropleth Maps Compare Two Maps: Swipe Map Plugin »

Full Map Code

      
/*Blank Mapbox GL Map*/
var style = {
  "version": 8,
  "name": "blank",
  "sources": {
    "openmaptiles": {
      "type": "vector",
      "url": ""
    }
  },
  "layers": [{
    "id": "background",
    "type": "background",
    "paint": {
      "background-color": "#1d1f20"
    }
  }]
};

var map = new mapboxgl.Map({
  container: 'map',
  hash: true,
  style: style,
  center: [-95.39, 39.15],
  zoom: 3.4,
  debug: 1
});

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

/*End Blank Map*/

map.on('load', function() {
  var maxValue = 16;
  var jsonData;
  $.getJSON("/gis-tutorials/tutorial-data/nchs_overdose_2015.json")
    .done(function(data) {
      console.log('json data loaded');
      //console.log(data);
      jsonData = data;
      buildMap();
    });

  function buildMap() {

    // Get the vector geometries to join
    // US Census Data Source
    // https://www.census.gov/geo/maps-data/data/cbf/cbf_county.html
    var layerName = "uscounties";
    var vtMatchProp = "GEOID";
    var dataMatchProp = "geoid";
    var dataStyleProp = "category";

    // Add source for state polygons hosted by OVRDC Node JS Tileserver
    map.addSource("source", {
      type: "vector",
      url: "mapbox://ovrdc.18vllzwu"
    });

    // First value is the default, used where the is no data
    var stops = [];

    // Calculate color for each state based on the overdose death rate

    var numbers = jsonData.map(function(val) {
      return Number(val[dataStyleProp])
    });

    //console.log(numbers);

    var numbersIndex = jsonData.map(function(val) {
      var index = val[dataMatchProp] + "|" + val[dataStyleProp];
      return index
    });

    //console.log(numbersIndex);

    //chroma quantile scale
    var limits = chroma.limits(numbers, 'q', 4);

    //chroma color scale
    var colorScale = chroma.scale(['#fafa6e', '#2A4858']).mode('lch').colors(5);

    console.log(limits);

    console.log(colorScale);

    var newData = jsonData.map(function(county) {

      var color = "#fafa6e";

      for (var i = 0; i < limits.length; i++) {
        if (county[dataStyleProp] <= limits[i]) {
          color = colorScale[i];
          break;
        }
      }

      var id = county[dataMatchProp];
      return [id, color]
    });

    console.log(newData);

    // Add layer from the vector tile source with data-driven style
    map.addLayer({
      "id": "joined-data",
      "type": "fill",
      "source": "source",
      "source-layer": layerName,
      "paint": {
        "fill-color": {
          "property": vtMatchProp,
          "type": "categorical",
          "stops": newData
        },
        "fill-opacity": 0.7,
        "fill-outline-color": "hsla(11,0%,75%,1)"
      }
    });
    var div = document.createElement('DIV');
    div.className = 'legend';
    /* Add min & max*/
    var labels = []
    div.innerHTML = '<div><h3 style="font-weight:bolder;font-size:larger;">Drug Overdose Death Rates 2015</h3><br> \
      </div><div class="labels"><div class="min">Low</div> \
      <div class="max">High</div></div>'

    for (i = 0; i < colorScale.length; i++) {
      labels.push('<li style="background-color: ' + colorScale[i] + '"></li>')
    }

    div.innerHTML += '<ul style="list-style-type:none;display:flex">' + labels.join('') + '</ul>'
    document.getElementById('map').appendChild(div);
  }
});