1

How would I go about grouping the two layers in the sample code below so they could be toggled on and off together with one button?

<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.22.1/mapbox-gl.js'></script>
    <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.22.1/mapbox-gl.css' rel='stylesheet' />
    <style>
        body { margin:0; padding:0; }
        #map { position:absolute; top:0; bottom:0; width:100%; }
    </style>
</head>
<body>

<style>
    #menu {
        background: #fff;
        position: absolute;
        z-index: 1;
        top: 10px;
        right: 10px;
        border-radius: 3px;
        width: 120px;
        border: 1px solid rgba(0,0,0,0.4);
        font-family: 'Open Sans', sans-serif;
    }

    #menu a {
        font-size: 13px;
        color: #404040;
        display: block;
        margin: 0;
        padding: 0;
        padding: 10px;
        text-decoration: none;
        border-bottom: 1px solid rgba(0,0,0,0.25);
        text-align: center;
    }

    #menu a:last-child {
        border: none;
    }

    #menu a:hover {
        background-color: #f8f8f8;
        color: #404040;
    }

    #menu a.active {
        background-color: #3887be;
        color: #ffffff;
    }

    #menu a.active:hover {
        background: #3074a4;
    }
</style>

<nav id="menu"></nav>
<div id="map"></div>

<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiZnJlZWFjY291bnQxIiwiYSI6ImNpZmFqZm53NDJmNXhzbWx4dXM5bm1leDMifQ.MMgR4bJlNNVYrzCLA_NBeA';
var map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/streets-v9',
    zoom: 15,
    center: [-71.97722138410576, -13.517379300798098]
});

map.on('load', function () {
    map.addSource('museums', {
        type: 'vector',
        url: 'mapbox://mapbox.2opop9hr'
    });
    map.addLayer({
        'id': 'museums',
        'type': 'circle',
        'source': 'museums',
        'layout': {
            'visibility': 'visible'
        },
        'paint': {
            'circle-radius': 8,
            'circle-color': 'rgba(55,148,179,1)'
        },
        'source-layer': 'museum-cusco'
    });

    map.addSource('contours', {
        type: 'vector',
        url: 'mapbox://mapbox.mapbox-terrain-v2'
    });
    map.addLayer({
        'id': 'contours',
        'type': 'line',
        'source': 'contours',
        'source-layer': 'contour',
        'layout': {
            'visibility': 'visible',
            'line-join': 'round',
            'line-cap': 'round'
        },
        'paint': {
            'line-color': '#877b59',
            'line-width': 1
        }
    });
});

var toggleableLayerIds = [ 'contours', 'museums' ];

for (var i = 0; i < toggleableLayerIds.length; i++) {
    var id = toggleableLayerIds[i];

    var link = document.createElement('a');
    link.href = '#';
    link.className = 'active';
    link.textContent = id;

    link.onclick = function (e) {
        var clickedLayer = this.textContent;
        e.preventDefault();
        e.stopPropagation();

        var visibility = map.getLayoutProperty(clickedLayer, 'visibility');

        if (visibility === 'visible') {
            map.setLayoutProperty(clickedLayer, 'visibility', 'none');
            this.className = '';
        } else {
            this.className = 'active';
            map.setLayoutProperty(clickedLayer, 'visibility', 'visible');
        }
    };

    var layers = document.getElementById('menu');
    layers.appendChild(link);
}

</script>

</body>
</html>

1 Answer 1

2

It's as simple as iterating the toggleableLayerIds array and toggle on and off the layers. Move the link stuff outside the for loop to get just a single button.

var toggleableLayerIds = [ 'contours', 'museums' ];

var link = document.createElement('a');
link.href = '#';
link.className = 'active';
link.textContent = "toggle layers";
link.onclick = function (e) {
    for(var index in toggleableLayerIds) {
      var clickedLayer = toggleableLayerIds[index];
      e.preventDefault();
      e.stopPropagation();

      var visibility = map.getLayoutProperty(clickedLayer, 'visibility');

      if (visibility === 'visible') {
          map.setLayoutProperty(clickedLayer, 'visibility', 'none');
          this.className = '';
      } else {
          this.className = 'active';
          map.setLayoutProperty(clickedLayer, 'visibility', 'visible');
      }
    }

};
var layers = document.getElementById('menu');
layers.appendChild(link);

Demo: https://plnkr.co/edit/HxV766XO1F8FXZbUqRNh?p=preview

5
  • Thanks for your reply, however I may have slightly miscommunicated what exactly I was after, I actually wanted to end up with only one button that controlled both layers, not two buttons that control both. Aug 22, 2016 at 3:22
  • @Nickelberry I edited it
    – chrki
    Aug 22, 2016 at 17:43
  • Could i edit that so it only allows one layer to be on at a time? Ie if you turn on contours you turn off msueums Oct 31, 2018 at 11:05
  • @mappingdom the original question was how to switch two layers at the same time, I don't believe an edit like you said would make much sense in my answer here :/ I suppose it's a fairly easy change, just flipping the layer's visibility properties in a different order and moving the if/else blocks around a bit
    – chrki
    Nov 1, 2018 at 3:27
  • @chrki thanks found what i was looking for here; gis.stackexchange.com/questions/253469/mapbox-gl-checkbox-menu Nov 1, 2018 at 10:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.