Basic Leaflet Map with Overlaying Polygons

with No Comments

In this example, you will see how to create a basic Leaflet map with additional layers. These layers are added with the Queue.js framework and are in GeoJSON format. Because I have commented the source code pretty thoroughly, I will not go into detail. I am however happy to answer any questions you might have, just contact me.

The Result

Additional Resources

      <!-- Leaflet resources -->
      <script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
      <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />

      <!-- JQuery -->
      <script src="http://code.jquery.com/jquery-1.11.2.min.js"></script>

      <!-- D3 Resources -->
      <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
      <script src="http://d3js.org/queue.v1.min.js"></script>

Additional Style

      <style>
        .legend {
            text-align: left;
            line-height: 18px;
            color: #000000;
        }

        .info {
            padding: 8px 8px;
            background: white;
            background: rgba(255,255,255,1);
            box-shadow: 0 0 15px rgba(0,0,0,0.2);
            border-radius: 5px;
        }

        .info h4 {
            margin: 0 0 5px;
            color: #777;
        }

        .legend i {
            width: 18px;
            height: 18px;
            float: left;
            margin-right: 8px;
            opacity: 1;
        }
      </style>

The HTML

	<div id="densityMap" style="height:600px;"></div>

The JavaScript

		<script type="text/javascript">


        // Load the JSON file(s)
    queue()
            .defer(d3.json, "../../content/blog/20151224-basic-leaflet-map-with-overlaying-polygons/geom/density1990.json") // Load density1990.json
            .defer(d3.json, "../../content/blog/20151224-basic-leaflet-map-with-overlaying-polygons/geom/density2000.json") // Load density2000.json
            .defer(d3.json, "../../content/blog/20151224-basic-leaflet-map-with-overlaying-polygons/geom/density2010.json") // Load density2010.json
            .await(loadGeom); // When the CSV is fully loaded, call the function loadGeom

        // Function loadGeom. This function is executed as soon as all the files in queue() are loaded
        function loadGeom(error, density1990, density2000, density2010){

            // For easier use with leaflet, the GeoJSON's are implemented into the leaflet GeoJSON handler
            // L.geoJson() and stored into a variable. If you inspect a GeoJSON before this is done, you will
            // find that the Geo-Features are all in a subobjekt called "features", hence the density1990.features
            // Additionally the style is dynamically created over functions listed below


            var density1990 = L.geoJson(density1990.features,{
                style: densityStyle,
                onEachFeature: function (feature, layer) {
                    layer.bindPopup(feature.properties.name + ": " + feature.properties.density+" Inh./Km²");
                }
            });

            var density2000 = L.geoJson(density2000.features, {
                style: densityStyle,
                onEachFeature: function (feature, layer) {
                    layer.bindPopup(feature.properties.name +": "+ feature.properties.density+" Inh./Km²");
                }
            });

            var density2010 = L.geoJson(density2010.features, {
                style: densityStyle,
                onEachFeature: function (feature, layer) {
                    layer.bindPopup(feature.properties.name +": "+ feature.properties.density+" Inh./Km²");
                }
            });


            // This function creates the style definitions for all the layers. Each layer calls this function
            // and is assigned the same style, except for the colour which again is defined dymanically over
            // a function.
            function densityStyle(feature){
                return {
                    "fillColor": getColour(feature.properties.density), // Call function to get fill colour
                    "weight": 2, //
                    "opacity": 1, //
                    "color": '#000', //
                    "fillOpacity": 0.7 //
                };
            }


            // Function to get the colour of the polygon.
            // This function basically takes the attribute value, stores the attribute value in the variable d,
            // compares the variable d (attribute value) to various numbers (300, 250, 200 ...)  and then takes
            // the color, where the condition is true.
            // For example: If we have an attribute value of '220', the function starts at the top and
            // checks if 220 is bigger than 300. Thats false so the function goes to the next value. It now checks
            // is 220 bigger than 250? Thats also false so it goes to the next value again. Is 220 bigger than
            // 200? This is true so the function takes the color defined where d > 200.

            function getColour(d){
                return  d > 300 ? '#e31a1c':
                        d > 250 ? '#fc4e2a':
                        d > 200 ? '#fd8d3c':
                        d > 150 ? '#feb24c':
                        d > 100 ? '#fed976':
                        d > 50  ? '#ffeda0':
                                  '#ffffcc';
            }


            // Define a basemap and min/max Zoom
            var basemap = L.tileLayer('http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.png', {
                attribution: "Map tiles by <a href='http://stamen.com'>Stamen Design</a>, under <a href='http://creativecommons.org/licenses/by/3.0'>CC BY 3.0</a>. Data by <a href='http://openstreetmap.org'>OpenStreetMap</a>, under <a href='http://www.openstreetmap.org/copyright'>ODbL</a>. Statistical data by <a href='http://www.swisstopo.ch'>Swisstopo</a>",
                maxZoom: 8,
                minZoom: 8
            });

            // Define map container. This puts the map in the <div> with the ID= 'densityMap'
            // Hide Zoom Controles and fit initial map to the boundaries of the geometry
            // stored in density1990.json.
            var map = L.map("densityMap", {zoomControl: false}).fitBounds(density1990.getBounds());

            // Add the base map to the map
            basemap.addTo(map);
            // Add density overlay to map. Only add the overlay to map, which we want to initially
            // display. The others are added to the map through the layer controls
            density1990.addTo(map);
          //  density2000.addTo(map);
          //  density2010.addTo(map);

            // Define the layer controls:
            // This means, that the  layers density2010, density2000 and density1990 can be chosen to
            // be displayed.
            var control = L.control.layers(
                    {
                         "Density in 2010" : density2010
                        ,"Density in 2000" : density2000
                        ,"Density in 1990" : density1990
                    }, null , {collapsed:true});

            // Add the map controls to the map
            control.addTo(map);


            // Add a legend
            // Create the legend variable and set its position
            var densityLegend = L.control({position: "topleft"});
            // Define what happens when the legend gets loaded

                // Create a div to store our legend in
            densityLegend.onAdd = function (map) {var div = L.DomUtil.create("div", "info legend"); return div;}
                // Create an array with the different intervals to be
                // displayed in the legend

            // Add empty legend to map
            densityLegend.addTo(map);

                var grades = [0,50,100,150,200,250, 300];
                // Create an array called 'labels' and set the first 2 lines
            var labels = ["<strong>Population density<br>[Inhabitants/Km²]</strong>"];
                // For each element in the array 'grades' create a new line in the
                // legend.
                for (var i = 0; i < grades.length; i++){
                    // set the from value. This gets the number stored in the
                    // array 'grades' at position i
                    var from = grades [i];
                    // set the to value. This gets the number in the array
                    // 'grades' at position i+1. Additionally 1 is subtracted
                    // so that the legend says: "from 0 to 49" and not from "0 to 50"
                    var to = grades [i+1]-1;
                    // Create the text for each line
                    labels.push("<i style='background:" + getColour(from + 1) + "'></i> " + from + (to ? "&ndash;" + to : "+"));
                }

            // Join all the labels in the labels-array and add a <br> after each element
            var legendText = labels.join("<br>");
            
            // Use D3.js to fill up the legend DIV with our legend items
            d3.select(".legend.leaflet-control") // select the div with class '.legend.leaflet-control'
                .html(legendText); // Add the html stored in the legendText variable.
        }
		
	</script>