1

I'm trying to make a web app that uses leaflet to display a map, users should be able to draw and edit polygons over the map and they should have the ability to name each polygon they create.

I want to open a popup when a polygon is created that asks for a name and then set it to a property in a geojson feature.

I tried to follow this example Leaflet popup form but I couldn't get it to work with the leaflet draw created event.

Here's what I got.

// Map center
var center = [-32.692825, -62.104689];

// Map creation
var map = L.map('map').setView(center, 14);

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

// Initialise the FeatureGroup to store editable layers
var editableLayers = new L.FeatureGroup();
map.addLayer(editableLayers);

// Draw plugin options
var drawPluginOptions = {
  position: 'topleft',
  draw: {
    polygon: {
      allowIntersection: false, // Restricts shapes to simple polygons
      drawError: {
        color: '#e1e100', // Color the shape will turn when intersects
        message: '<strong>Oh snap!<strong> you can\'t draw that!' // Message that will show when intersect
      },
      shapeOptions: {
        color: '#97009c'
      }
    },
    // disable toolbar item by setting it to false
    polyline: false,
    circle: false, // Turns off this drawing tool
    rectangle: false,
    marker: false,
  },
  edit: {
    featureGroup: editableLayers,
    polygon: {
      allowIntersection: false
    } //REQUIRED!!
  }
};

// Initialise the draw control and pass it the FeatureGroup of editable layers
var drawControl = new L.Control.Draw(drawPluginOptions);
map.addControl(drawControl);

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

// draw created event handler
function polygonCreateHandler(e) {

  var type = e.layerType;
  var layer = e.layer;

  if (type != 'polygon') {
    alert("ESTO NO ES UN POLIGONO");
    return;
  }

  editableLayers.addLayer(layer);
}

// draw created event
map.on('draw:created', function(e) {
  polygonCreateHandler(e);
});

//Ignore this

/*jshint multistr: true */
var template = '<form id="popup-form">\
  <label for="input-speed">New speed:</label>\
  <input id="input-speed" class="popup-input" type="number" />\
  <button id="button-submit" type="button">Save Changes</button>\
</form>';

/*
** fetch geojson example
let geojson_url = "https://raw.githubusercontent.com/delineas/leaflet-flyto-webpack-bulma/master/src/data/arboles_singulares_en_espacios_naturales.geojson"
fetch(
  geojson_url
).then(
  res => res.json()
).then(
  data => {
    let geojsonlayer = L.geoJson(data, {
      onEachFeature: function(feature, layer) {
        layer.bindPopup(feature.properties['arbol_nombre'])
        layer.setIcon(treeMarker)
      }
    }).addTo(map) 
    map.fitBounds(geojsonlayer.getBounds())
  }
)

** layer polygon example

var geojson_msjz_polygon = {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": { "name": "Test Distrito electoral"},
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -62.103266716003425,
              -32.687209099455636
            ],
            [
              -62.13047504425048,
              -32.68211618935444
            ],
            [
              -62.133564949035645,
              -32.693746380985395
            ],
            [
              -62.106142044067376,
              -32.698838627713116
            ],
            [
              -62.103266716003425,
              -32.687209099455636
            ]
          ]
        ]
      }
    }
  ]
};

let geojsonlayer = L.geoJson(geojson_msjz_polygon, {
      onEachFeature: function(feature, layer) {
        let text = L.tooltip({
          permanent: true,
          direction: 'center',
          className: 'text'
        })
        .setContent(feature.properties.name)
        .setLatLng(layer.getBounds().getCenter());
        text.addTo(map);
      }
    }).addTo(map);

map.fitBounds(geojsonlayer.getBounds())
*/
#map {
  height: 98vh;
  width: 100hw;
}

body {
  margin: 0;
}

html,
body,
#leaflet {
  height: 100%;
}

.popup-table {
  width: 100%;
}

.popup-table-row {
  background-color: grey;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0-beta.2.rc.2/leaflet.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0-beta.2.rc.2/leaflet.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.css" rel="stylesheet" />
<div id="map"></div>

2 Answers 2

0

Just bind a popup on the created layer and open it once it is created

function polygonCreateHandler(e) {

  var type = e.layerType;
  var layer = e.layer;

  if (type != 'polygon') {
    alert("ESTO NO ES UN POLIGONO");
    return;
  }

  editableLayers.addLayer(layer);
  
  layer.bindPopup(template).openPopup(); // here create and open the popup with your form
}

// Map center
var center = [-32.692825, -62.104689];

// Map creation
var map = L.map('map').setView(center, 14);

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

// Initialise the FeatureGroup to store editable layers
var editableLayers = new L.FeatureGroup();
map.addLayer(editableLayers);

// Draw plugin options
var drawPluginOptions = {
  position: 'topleft',
  draw: {
    polygon: {
      allowIntersection: false, // Restricts shapes to simple polygons
      drawError: {
        color: '#e1e100', // Color the shape will turn when intersects
        message: '<strong>Oh snap!<strong> you can\'t draw that!' // Message that will show when intersect
      },
      shapeOptions: {
        color: '#97009c'
      }
    },
    // disable toolbar item by setting it to false
    polyline: false,
    circle: false, // Turns off this drawing tool
    rectangle: false,
    marker: false,
  },
  edit: {
    featureGroup: editableLayers,
    polygon: {
      allowIntersection: false
    } //REQUIRED!!
  }
};

// Initialise the draw control and pass it the FeatureGroup of editable layers
var drawControl = new L.Control.Draw(drawPluginOptions);
map.addControl(drawControl);

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

var template = '<form id="popup-form">\
  <label for="input-speed">New speed:</label>\
  <input id="input-speed" class="popup-input" type="number" />\
  <button id="button-submit" type="button">Save Changes</button>\
</form>';

var createdPolygonTemplate = '<form id="popup-form">\
   <label for="input-speed">Name:</label>\
   <input id="name" type="text" />\
</form>';

// draw created event handler
function polygonCreateHandler(e) {

  var type = e.layerType;
  var layer = e.layer;

  if (type != 'polygon') {
    alert("ESTO NO ES UN POLIGONO");
    return;
  }

  editableLayers.addLayer(layer);

  layer.bindPopup(createdPolygonTemplate).openPopup()
}

// draw created event

map.on('draw:created', function(e) {
  polygonCreateHandler(e);
});

//Ignore this

/*jshint multistr: true */


/*
** fetch geojson example
let geojson_url = "https://raw.githubusercontent.com/delineas/leaflet-flyto-webpack-bulma/master/src/data/arboles_singulares_en_espacios_naturales.geojson"
fetch(
  geojson_url
).then(
  res => res.json()
).then(
  data => {
    let geojsonlayer = L.geoJson(data, {
      onEachFeature: function(feature, layer) {
        layer.bindPopup(feature.properties['arbol_nombre'])
        layer.setIcon(treeMarker)
      }
    }).addTo(map) 
    map.fitBounds(geojsonlayer.getBounds())
  }
)

** layer polygon example

var geojson_msjz_polygon = {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": { "name": "Test Distrito electoral"},
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -62.103266716003425,
              -32.687209099455636
            ],
            [
              -62.13047504425048,
              -32.68211618935444
            ],
            [
              -62.133564949035645,
              -32.693746380985395
            ],
            [
              -62.106142044067376,
              -32.698838627713116
            ],
            [
              -62.103266716003425,
              -32.687209099455636
            ]
          ]
        ]
      }
    }
  ]
};

let geojsonlayer = L.geoJson(geojson_msjz_polygon, {
      onEachFeature: function(feature, layer) {
        let text = L.tooltip({
          permanent: true,
          direction: 'center',
          className: 'text'
        })
        .setContent(feature.properties.name)
        .setLatLng(layer.getBounds().getCenter());
        text.addTo(map);
      }
    }).addTo(map);

map.fitBounds(geojsonlayer.getBounds())
*/
#map {
  height: 98vh;
  width: 100hw;
}

body {
  margin: 0;
}

html,
body,
#leaflet {
  height: 100%;
}

.popup-table {
  width: 100%;
}

.popup-table-row {
  background-color: grey;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0-beta.2.rc.2/leaflet.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0-beta.2.rc.2/leaflet.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.css" rel="stylesheet" />
<div id="map"></div>

1
  • 1
    Is it possible to make the popup content a dynamic html? I am using a React function component in place of createdPolygonTemplate and rendering it like this: layer.bindPopup(ReactDOMServer.renderToString(<CreatedShapeTemplate/>)).openPopup(); It is rendering fine but as a static html without onChange event working inside it. Commented Feb 17, 2023 at 9:38
0

Yes, the next is a code example:

<div id="map" style="width: 100%; height: 500px;"></div>

<script>
    var map = L.map('map', {
        center: [18.9, -71.2],
        zoom: 8,
    });
    const tileURL = 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png'
    L.tileLayer(tileURL).addTo(map);

    drawnItems = L.featureGroup().addTo(map);
    var drawControl = new L.Control.Draw({
        edit: {
            featureGroup: drawnItems,
        },
    });

    var getName = function(layer) {
        var name = prompt('please, enter the geometry name', 'geometry name');
        return name;
    };

    map.addControl(drawControl);
    map.on(L.Draw.Event.CREATED, function(e) {
        var layer = e.layer; 
        var name = getName(layer);
        if (name == 'geometry name') {
            layer.bindPopup('-- no name provided --');
        } else if (name == '') {
            layer.bindPopup('-- no name provided --');
        } else {
            layer.bindTooltip(name, {permanent:true, direction:'top'})
        };
        drawnItems.addLayer(layer);
    });

</script>

And this is the result: enter image description here

Do not forget the cdn's:

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw-src.css" integrity="sha512-vJfMKRRm4c4UupyPwGUZI8U651mSzbmmPgR3sdE3LcwBPsdGeARvUM5EcSTg34DK8YIRiIo+oJwNfZPMKEQyug==" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js" integrity="sha512-ozq8xQKq6urvuU6jNgkfqAmT7jKN2XumbrX1JiB3TnF7tI48DPI4Gy1GXKD/V3EExgAs1V+pRO7vwtS1LHg0Gw==" crossorigin="anonymous"></script>

Not the answer you're looking for? Browse other questions tagged or ask your own question.