Leaflet and GeoDjango Exploration

This section explores direct use of the leaflet.js API. The examples on this page are taken from a combination of the tutorials on the leaflet.js website and from a presentation at DjangoCon (see the powerpoint in the github).

Leaflet.js can be found at: https://leafletjs.com/
Example htmx and leaflet demo: https://github.com/andywar65/map_swap_example


Basic Usage

In this example we set up a map with an OpenStreetMap base and present a country (Multi-polygon) in a layer group. The map is centered according to the bounds of the geometry.

In this example we use htmx to cal the back end and replace the button html with a partial. The "HX-Trigger-After-Settle" header is attached to the response which triggers the javascript fucntion (initMap1()) to initialise the map. The details of the partial are included in the code block below. We use the geojson plugin to serialise the geometry into a form that is suitable for leaflet.js.

This is relatively straightforward and does not require too much js.


    
    #template partial
    {% load geojson_tags %}

    <div id="map1" class="lmap container"></div>
    <script id="geodata_map1" type="application/json"
        >{{ country|geojsonfeature|safe }}</script>
       
    


    # javascript
    document.body.addEventListener("initMap1", function(evt){

        // get the passed in spatial data
        collection = JSON.parse(document.getElementById("geodata_map1").textContent);

        // create basic map
        const map = L.map('map1',{center: [52.00, 0.00], zoom: 10});

        // set base_map and add to map
        const base_map = L.tileLayer(
            "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
            attribution: 'Map data © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> 
            contributors',
            maxZoom: 19,
            }).addTo(map);
        
        // create a layer and add features to layer
        const layerGroup = L.layerGroup().addTo(map);
        
        for (feature of collection.features) {
            L.geoJson(feature).addTo(layerGroup);
        }

        // set map view to bounds of the features
        if (collection.features.length !== 0) {
            map.fitBounds(L.geoJson(collection).getBounds(), {padding: [30,30]});
        } else {
            map.setView([52,0], 2)
        }
    })
       

Pop-ups and markers

In this example markers are placed on the map. We loop through these features extracting the fields a building html for display in the popup.


    
    #template partial
    {% load geojson_tags %}

    <div id="map2" class="lmap container"></div>
    <script id="geodata_map2" type="application/json"
        >{{ venues|geojsonfeature:"name,capacity:geom"|safe }}</script>

       
    

    // event listener Javascript
    document.body.addEventListener("initMap2", function(evt){

        // loop to bind popup content
        function onEachFeature(feature, layer) {
        if (feature.properties && feature.properties.name) {
            layer.bindPopup(
                `<strong>Name:</strong> ${feature.properties.name}<br> <strong>Capacity:</strong> ${feature.properties.capacity}`
                , {minWidth: 150});
            }
        }

        // get the passed in spatial data
        collection = JSON.parse(document.getElementById("geodata_map2").textContent);

        console.log(collection);

        // create basic map
        const map = L.map('map2',{center: [52.00, 0.00], zoom: 10});

        // set base_map and add to map
        const base_map = L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
            attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
            maxZoom: 19,
            }).addTo(map);
        
        const layerGroup = L.layerGroup().addTo(map);

        for (marker of collection.features) {
            L.geoJson(marker, {onEachFeature: onEachFeature}).addTo(layerGroup);
        }
        
        // fit to bounds
        if (collection.features.length !== 0) {
            map.fitBounds(L.geoJson(collection).getBounds(), {padding: [30,30]});
        } else {
            map.setView([0,0], 2)
        }

    })