Drawing Features in Leaflet using the Leaflet.draw plugin

Andrew Dennison and I recently implemented a tool into an existing web map to allow stakeholders to send in their story about an area and capture spatial data to illustrate their story. Our client wanted a low-cost solution that was fairly straight-forward to accomplish using existing technology, as well as work with tools we already had in place, namely WordPress and Leaflet (a Javascript mapping library). To enable this, we made use of a Leaflet plugin called Leaflet Draw, a Javascript library to allow drawing of basic geometry (lines, areas and markers) into a Leaflet-based map. The features the user draws are submitted via a contact form in the GeoJSON format.

The Leaflet map code along with the Leaflet.draw code are bundled into a WordPress plugin, which is essentially a PHP wrapper for the Javascript code. The submission of the data was handled via a popular WordPress plugin called Contact Form 7, which handles all the form field layout and email-submission functions.

Working with Leaflet Draw, assuming a Leaflet map object has already been created and the required layers added, the drawing controls need to be declared and added to the map as a layer. Here we created a control that allows drawing of polylines, polygons and markers, but omits rectangles and circles. We also added some customization to the polylines and polygons.

var drawControl = new L.Control.Draw({
    position: ‘topright’,
    draw: {
        polyline: {
            metric: true
        },
        polygon: {
            allowIntersection: false,
            showArea: true,
            drawError: {
                color: ‘#b00b00’,
                timeout: 1000
            },
            shapeOptions: {
                 color: ‘#bada55’

           }

        },

        rectangle: false,
        circle: false,
        marker: true
    },
    edit: {
        featureGroup: drawnItems,
        remove: true
    }
});
map.addControl(drawControl);

Next, a Leaflet FeatureGroup which will store all the drawn features needs to be declared and added to the map as a layer:

var drawnFeatures = new L.FeatureGroup();
map.addLayer(drawnFeatures);

The third part of the tool was to create functions to respond to the creation, editing and deletion of features events, whereby the features are stored or removed from the drawnFeatures collection, and also that the shapes are converted to GeoJSON and stored in a field of the contact form. This is because Contact Form 7 can only process data that has been entered into its own declared form elements (designed in the WordPress plugin configuration) so the GeoJSON data has to be stored in a hidden field of the form. Contact Form 7 doesn’t actually offer hidden fields so this required installing a module for Contact Form 7 called Contact Form 7 Modules: Hidden Fields – a plugin for a plugin (plugin-ception?).

One thing to note is that the Leaflet code needs a way to know about the hidden field, so at some point the field needs to be hooked up to a known variable. Do do this we inserted some Javascript directly into the page post after both plugins had been inserted, with the hidden field having the ID layer-data.

<script>
    // create namespace if it doesn’t exist already
    window.MapPlugin = window.MapPlugin || {};
    // hook up layer-data hidden field to store layer data
    window.MapPlugin.dataElement = document.getElementById(“layer-data”);
</script>

Leaflet has a handy in-built function called JSON.stringify, which converts features directly into GeoJSON format. With this in mind, the code for responding to events is as follows:

map.on(‘draw:created’, function (e) {
    layer = e.layer;

    drawnFeatures.addLayer(layer);

    if(‘dataElement’ in window.MapPlugin)
        window.MapPlugin.dataElement.value = JSON.stringify(drawnFeatures.toGeoJSON());
});

map.on(‘draw:edited’, function (e) {
    if(‘dataElement’ in window.CCMapPlugin)
        window.MapPlugin.dataElement.value = JSON.stringify(drawnFeatures.toGeoJSON());
});

map.on(‘draw:deleted’, function (e) {
    var layer = e.layer;

    drawnFeatures.removeLayer(layer);

    if(‘dataElement’ in window.CCMapPlugin)
        window.MapPlugin.dataElement.value = JSON.stringify(drawnFeatures.toGeoJSON());
});

The resulting plugin will look like this:

leaflet-draw-example

Email Andrew directly here or Tony here.

Comments are closed.