24

I have two overlays http://02d0c8c.netsolhost.com/dev/lcb_census_layers3.html that can be turned on and off with a Layer Control. I’d like the legend for each layer to turn on/off along with the layers.

I am new to JavaScript and new to Leaflet.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Lake Champlain Basin Census Data</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.4.5/leaflet.css" />
<!--[if lte IE 8]>
    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.4.5/leaflet.ie.css" />
<![endif]-->

<style>
        #map {
            width: 750px;
            height: 580px;
        }
        .info {
            padding: 6px 8px;
            font: 14px/16px Verdana, Geneva, sans-serif;
            background: white;
            background: rgba(255,255,255,0.8);
            box-shadow: 0 0 15px rgba(0,0,0,0.2);
            border-radius: 5px;
        }
        .info h4 {
            font-family: Verdana, Geneva, sans-serif;
            margin: 0 0 5px;
            color: #065581;
        }
        .legend {
            line-height: 18px;
            color: #555;
        }
        .legend i {
            width: 18px;
            height: 18px;
            float: left;
            margin-right: 8px;
            opacity: 0.7;
        }
</style>
<script src="http://cdn.leafletjs.com/leaflet-0.4.5/leaflet.js"></script>
</head>

<body>
<div id="map">
<script type="text/javascript" src="js/LCB_Census_Towns.js"></script>

<script type="text/javascript">

        var map = L.map('map').setView([44.3, -73.1], 8);
        var cloudmade = L.tileLayer('http://{s}.tile.cloudmade.com/d2a498d874144e7dae5e7ab4807f3032/{styleId}/256/{z}/{x}/{y}.png', {
            attribution: 'Map data &copy; 2011 OpenStreetMap contributors, Imagery &copy; 2011 CloudMade',
            key: 'BC9A493B41014CAABB98F0471D759707',
            styleId: 22677
        }).addTo(map);

        // control that shows state info on hover
        var info = L.control({position: 'bottomleft'});

        info.onAdd = function (map) {
            this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
            this.update();
            return this._div;
        };

        // method that we will use to update the control based on feature           properties passed
        info.update = function (props) {
            this._div.innerHTML = '<h4>Population Change</h4>' +  (props ?
        '<b>Town: ' + props.NAME10 + '</b><br />Percent change, 1970-2010<br />(2001-2011 in Qu&eacute;bec): <em><strong> ' + props.CHNG_70_10 + '</strong></em>%<br /><br />1970 Population: ' + props.POP1970 + '<br />1980 Population: ' + props.POP1980 + '<br />1990 Population: ' + props.POP1990 + '<br />2000 Population: ' + props.POP2000 + '<br />2010 Population: ' + props.POP2010 
        : '<b>Hover over a town</b>');
        };

        info.addTo(map);

        //STYLES FOR POPULATION CHANGE MAP

        // get color depending on population density value
        function getColor(d) {
            return d > 100  ? '#BD0026' :
                   d > 50  ? '#F03B20' :
                   d > 20  ? '#FD8D3C' :
                   d > 10   ? '#FEB24C' :
                   d > 0   ? '#FED976' :
                   d > -30   ? '#1C9099' :
                              '#1C9099';
        }

        function style(feature) {
            return {
                weight: 2,
                opacity: 1,
                color: 'white',
                dashArray: '3',
                fillOpacity: 0.7,
                fillColor: getColor(feature.properties.CHNG_70_10)
            };
        }

        //STYLES FOR POPULATION MAP

        // get color for Population Map depending on population value
        function getColor2(d) {
            return d > 20000  ? '#006D2C' :
                   d > 10000  ? '#31A354' :
                   d > 5000  ? '#74C476' :
                   d > 2500   ? '#A1D99B' :
                   d > 0   ? '#C7E9C0' :
                              '#1C9099';
        }

        function style2(feature) {
            return {
                weight: 2,
                opacity: 1,
                color: '#666',
                dashArray: '3',
                fillOpacity: 0.7,
                fillColor: getColor2(feature.properties.POP2010)
            };
        }

        //LAYER FUNCTIONALITY

        var popChange = new L.geoJson(lcbCensusData, {
            style: style,
            onEachFeature: function (feature, layer) {
            var defaultStyle = layer.style,
                that = this;//NEW

            layer.on('mouseover', function (e) {
                this.setStyle({
                weight: 5,
                color: '#666',
                dashArray: '',
                fillOpacity: 0.7
                });

            if (!L.Browser.ie && !L.Browser.opera) {
                layer.bringToFront();
            }

                info.update(layer.feature.properties);
            });
            layer.on('mouseout', function (e) {
                popChange.resetStyle(e.target); //NEW
                info.update();
            });
            }
            });

        var population = L.geoJson(lcbCensusData, {
            style: style2,
            onEachFeature: function (feature, layer) {
            var defaultStyle = layer.style,
                that = this;//NEW

            layer.on('mouseover', function (e) {
                this.setStyle({
                weight: 5,
                color: '#666',
                dashArray: '',
                fillOpacity: 0.7
                });

            if (!L.Browser.ie && !L.Browser.opera) {
                layer.bringToFront();
            }

                info.update(layer.feature.properties);
            });
            layer.on('mouseout', function (e) {
                population.resetStyle(e.target); //NEW
                info.update();
            });
            }
            }).addTo(map);

        //LAYER CONTROL 
        var overlays = {
            "Population Change,'70-'10": popChange,
            "Population": population
        };

        L.control.layers(null, overlays, {collapsed: false}).addTo(map);

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

        legend.onAdd = function (map) {
        var div = L.DomUtil.create('div', 'info legend');

            div.innerHTML +=
            '<img src="legend.png" alt="legend" width="134" height="147">';

        return div;
        };

        legend.addTo(map);

    </script>
</div>
</body>
</html>
2

2 Answers 2

24

You could listen for the "overlayadd" and/or the "overlayremove" events on the map object and have two separate legends (two controls) defined, e.g.:

map.on('overlayadd', function (eventLayer) {
    // Switch to the Population legend...
    if (eventLayer.name === 'Population') {
        this.removeControl(populationChangeLegend);
        populationLegend.addTo(this);
    } else { // Or switch to the Population Change legend...
        this.removeControl(populationLegend);
        populationChangeLegend.addTo(this);
    }
});

EDIT: A more complete example:

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

populationLegend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend');
    div.innerHTML +=
    '<img src="legend.png" alt="legend" width="134" height="147">';
return div;
};

populationChangeLegend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend');
    div.innerHTML +=
    '<img src="change_legend.png" alt="legend" width="134" height="147">';
return div;
};

// Add this one (only) for now, as the Population layer is on by default
populationLegend.addTo(map);

map.on('overlayadd', function (eventLayer) {
    // Switch to the Population legend...
    if (eventLayer.name === 'Population') {
        this.removeControl(populationChangeLegend);
        populationLegend.addTo(this);
    } else { // Or switch to the Population Change legend...
        this.removeControl(populationLegend);
        populationChangeLegend.addTo(this);
    }
});

Note that the this keyword in the event listener is the map object i.e. this is the same as map.

3
  • Thanks, I'm afraid I'll need some hand-holding. Appreciate your help, if you're so inclined... I've defined a second legend (and changed the name of the image in the first) here <02d0c8c.netsolhost.com/dev/lcb_census_layers4.html>. Do I need to change the way I add overlays to the control before using the overlayadd event?
    – ryan
    Commented Aug 19, 2013 at 17:28
  • You can add the second legend the same way you added the first. I'll edit my answer to provide a more complete example.
    – Arthur
    Commented Aug 19, 2013 at 19:11
  • Yep, that's what I tried with no luck. How would the if/else statement in the overlayadd event work if both layers were turned on? Seems like population change legend could not be added as long as the population layer was checked. I also tried using the overlays as base layers with radio button toggling, but still didn't work.
    – ryan
    Commented Aug 20, 2013 at 12:44
0

This code actually works for me!

    var divLegend = `
        <h4>Legend</h4>
        <div id="marker-geo"><i class="icon" style="background-image: url(./assets/marker.svg);background-repeat: no-repeat;"></i><span>Marker GeoJson (Intersect)</span></div>
        <div id="marker-geo-not-intersect"><i class="icon" style="background-image: url(./assets/marker_green.png);background-repeat: no-repeat;"></i><span>Marker GeoJson (Not Intersect)</span></div>
        <div id="ruas-geo"><i style="background: #3388FF"></i><span>Jalan Nasional dari GeoJson</span></div>
        <div id="ruas-zip"><i style="background: #858585"></i><span>Jalan Nasional dari Zip</span></div>
        <div id="marker-zip"><i class="icon" style="background-image: url(https://unpkg.com/[email protected]/dist/images/marker-icon.png);background-repeat: no-repeat;"></i><span>Marker Zip</span></div>
    `

    function stripSpaces(str){
        return str.replace(/\s+/g, '');
    }
var div = L.DomUtil.create("div", "legend");
    div.innerHTML = divLegend;

        L.LegendControl = L.Control.extend({
            onAdd: function (map) {


                return div;
            }
        });


        var strDivMarkerUser = "#"+stripSpaces("marker-user");
        var strDivMarkerGeo = "#"+stripSpaces("marker-geo");
        var strDivRuasGeo = "#"+stripSpaces("ruas-geo");
        var strDivRuasZip = "#"+stripSpaces("ruas-zip");
        var strDivMarkerZip = "#"+stripSpaces("marker-zip");
        var strDivLegend = "#"+stripSpaces("legend");
        var strDivNotIntersectMarker = "#"+stripSpaces("marker-geo-not-intersect");
        
        $(document).ready(function(){
            $(strDivMarkerUser).hide();
            $(strDivMarkerGeo).hide();
            $(strDivRuasGeo).hide();
            $(strDivRuasZip).hide();
            $(strDivMarkerZip).hide();
            $(strDivLegend).hide();
            $(strDivNotIntersectMarker).hide();
        });

Then you can add this code for overlayadd logic

map.on('overlayadd', function (e) {
    $(strDivLegend).show();
    if (e.name == "Marker dari url geojson") {
        $(strDivMarkerGeo).show();
        $(strDivNotIntersectMarker).show();
    }
    if (e.name == "Ruas Jalan dari url geojson") {
        $(strDivRuasGeo).show();
    }
    if (e.name == "Ruas Jalan dari file zip") {
        $(strDivRuasZip).show();
    }
    if (e.name == "Marker dari file zip") {
        $(strDivMarkerZip).show();
    }
})

map.on('overlayremove', function (e) {
    if (e.name == "Marker dari url geojson") {
        $(strDivMarkerGeo).hide();
    }
    if (e.name == "Ruas Jalan dari url geojson") {
        $(strDivRuasGeo).hide();
    }
    if (e.name == "Ruas Jalan dari file zip") {
        $(strDivRuasZip).hide();
    }
    if (e.name == "Marker dari file zip") {
        $(strDivMarkerZip).hide();
    }
})

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.