1

I'd like to know how I can improve the code below, making it better and easier to read. The idea is that when the user turns on / off the layer, their representation in the legend is also shown / hidden:

The complete example is here: https://codepen.io/marcellobenigno/pen/MZRZgg

in this part of the code is configured the functionality


L.Control.Layers.include({
        getOverlays: function () {
            var control, layers;
            layers = {};
            control = this;
            control._layers.forEach(function (obj) {
                var layerName;
                if (obj.overlay) {
                    layerName = obj.name;
                    return layers[layerName] = control._map.hasLayer(obj.layer);
                }
            });
            return layers;
        }
    });

var legend = L.control({position: 'bottomright'});

legend.onAdd = function (map) {
    var div = L.DomUtil.create('div', 'info legend');
    var title = '<h3>LEGEND:</h3>';
    div.innerHTML = title;
    div.innerHTML += '<span id="freeBus"><i></i> Free Bus</span>';
    div.innerHTML += '<span id="campus"><i></i> Campus</span>';
    div.innerHTML += '<span id="bicycleRental"><i></i> Bicycle Rental</span>';
    return div;
};
legend.addTo(map);

function showLegend(layer) {
    var item = ".legend > span:contains(" + layer + ")";
    $(item).show();
}

function hideLegend(layer) {
    var item = ".legend > span:contains(" + layer + ")";
    $(item).hide();
}

map.on('overlayadd', function (eventLayer) {
    showLegend(eventLayer.name);
});

map.on('overlayremove', function (eventLayer) {
    hideLegend(eventLayer.name);
});


$.each(control.getOverlays(), function (index, value) {
    if (!value) {
        hideLegend(index);
    }
});
1

I'd be using some Array.prototype functions, jQuery magic and ES6 features (arrow functions, template literals) to simplify your code (the latter doesn't work on IE11).

First of all, some redundant code in the legend.onAdd function can be removed (not necessarily making the function easier to understand):

legend.onAdd = map => {
  const title = '<h3>LEGEND:</h3>';
  const div = L.DomUtil.create('div', 'info legend')
  div.innerHTML = title + [ //array of id/text pairs
    ['freeBus','Free Bus'],
    ['campus', 'Campus'],
    ['bicycleRental','Bicycle Rental']
  ].map(a => `<span id="${a[0]}"><i></i> ${a[1]}</span>`).join('') //mapping HTML to id/text pairs
  return div;
};

Secondly, we can simplify the listener functions using jQuery's toggle().

map.on('overlayadd', e => $(`.legend > span:contains(${e.name})`).toggle() );

map.on('overlayremove', e => $(`.legend > span:contains(${e.name})`).toggle() );

Here is a jsfiddle: https://jsfiddle.net/newluck77/o8fphu6x/ To be honest, I didn't understand the L.Control.Layers.include({...}) and the $.each(...) parts. Commenting them out didn't change the functionality.

PS.: This saves 13 lines of code (or up to 36 if you count the commented lines).

  • L.Control.Layers.include({...}) returns the active layers, I think it's necessary if some layers are off when the application starts. And the $.each(...) find this layers and remove then for the legend panel. It's easier to understand if you remove one layer (or more) from the map initialization, for example: layers: [grayscale, campus] – Marcello Benigno Jan 18 at 9:31
  • improving my answer, L.Control.Layers.include({...}) returns true if the layer is active and false, for the opposite. – Marcello Benigno Jan 18 at 9:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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