[GIS] Adding WMS to Mapbox GL JS

mapboxmapbox-gl-jswms

I am in the process of adding a WMS map server to a map I wrote in JavaScript using the Mapbox GL JS library.

The map server is using the WMS from the FEMA National Flood Hazard Layer, and I would like to subset that data to a few specific Fields and overlay that onto my map..

I am using this Mapbox GL JS tutorial to add the WMS layer, I am running into two problems:

  1. I can't get the layer to display
  2. I can't subset the right fields I need to display

The code I am using…

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset='utf-8' />
        <title></title>
        <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
        <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.js'></script>
        <script src='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v2.2.0/mapbox-gl-geocoder.min.js'></script>
        <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
        <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.css' rel='stylesheet' />
        <link href="https://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet">
        <link rel='stylesheet' href='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v2.2.0/mapbox-gl-geocoder.css' type='text/css' />
            <style>
                body {
                  margin: 0;
                  padding: 0;
                }
                #map {
                  position: absolute;
                  top: 0;
                  bottom: 0;
                  width: 100%;
                  height: 100%;
                }
            </style>
            </head>
            <body>
            <style>
                #menu {
                  position: absolute;
                  background: rgba(64, 64, 64, 0.15);
                  padding: 5px;
                  font-family: 'Inconsolata';
                  font-size: 12px;
                }
                .marker {
                  background-image: url('/maki_icons/icons/square-stroked-11.svg');
                  background-size: cover;
                  width: 12px;
                  height: 12px;
                  cursor: pointer;
                  padding: 0px;
                }
                .mapboxgl-popup {
                  max-width: 200px;
                }
                .mapboxgl-popup-content {
                  text-align: center;
                  font-family: 'Open Sans', sans-serif;
                }
              </style>
    <div id='map'></div>
    <div id='menu'>
        <input id='streets' type='radio' name='rtoggle' value='streets'>
        <label for='streets'>streets</label>
        <input id='light' type='radio' name='rtoggle' value='light'>
        <label for='light'>light</label>
        <input id='satellite' type='radio' name='rtoggle' value='satellite'>
        <label for='satellite'>satellite</label>
    </div>
    <script>
    mapboxgl.accessToken =
    'pk.eyJ1IjoiZHlhdnJvbSIsImEiOiJjamVoNDc0MGowYjBlMndvNjRkMjEwenExIn0.uTE8zI8ELLNs1rIT2_Od2A';

        //load map
          var map = new mapboxgl.Map({
            container: 'map',
            style: 'mapbox://styles/mapbox/streets-v10',
            center: [-96, 37.8],
            zoom: 3.5,
            attributionControl:false
          });

        //add second layer of data
            map.on('load', function() {

          //add the FEMA WMS layer
              map.addLayer({
                'id': 'wms-test-layer',
                'type': 'raster',
                'source': {
                'type': 'raster',
                'tiles': [
                  'https://hazards.fema.gov/gis/nfhl/rest/services/public/NFHL/MapServer/28'
                ],}}
              );
              });

          // Tile switcher
          var layerList = document.getElementById('menu');
          var inputs = layerList.getElementsByTagName('input');

          function switchLayer(layer) {
              var layerId = layer.target.id;
              map.setStyle('mapbox://styles/mapbox/' + layerId + '-v9');
          }

          for (var i = 0; i < inputs.length; i++) {
              inputs[i].onclick = switchLayer;
          }
    </script>
</body>
</html>

Best Answer

In your addLayer function, the tiles option must be the URL to the raster tiles. https://hazards.fema.gov/gis/nfhl/rest/services/public/NFHL/MapServer/28 is the URL to the HTML page describing the ERSI MapServer service.

Although that service doesn't appear to support WMS it supports an /export which we can force to return raster tiles in the right format for Mapbox GL JS. So you should replace your tiles URL with this:

https://hazards.fema.gov/gis/nfhl/rest/services/public/NFHL/MapServer/export?bbox={bbox-epsg-3857}&bboxSR=EPSG%3A3857&layers=28&layerDefs=&size=256%2c256&imageSR=&format=png&transparent=true&dpi=&time=&layerTimeOptions=&dynamicLayers=&gdbVersion=&mapScale=&f=image

You can change that layers=28 to another layer number or I think use a comma separated value for multiple layers.

You might want to consider inserting this layer below the roads and label layers as well.