Leaflet – How to Improve Code for Show/Hide Legend Icon in JavaScript

javascriptleaflet

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);
    }
});

Best Answer

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).