Search code examples
javascriptleafletgeojsonleaflet.drawmin.js

Leaflet edit GeoJson Data


I made a code below for creating shapes with some informations. I can edit thoose informations until my map is open. But after update geojson by "Export features to local file" and page reload, shapes remain unclickable and to correct the informations I have to delete some shapes and recreate them with proper parameters.

Question:

Is it possible to edit the shape's data each time I just open my page? Like I can edit the shapes itself by "Edit layers" button?

<html>
    <head>
        
        
       <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"
   integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="crossorigin=""/>
   
    <!-- Make sure you put this AFTER Leaflet's CSS -->
   

<script src="https://code.jquery.com/jquery-1.10.2.js" integrity="sha256-it5nQKHTz+34HijZJQkpNBIHsjpV8b6QzMJs9tmOBSo=" crossorigin="anonymous"></script>       
       
<script src="https://unpkg.com/[email protected]/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
  <style type="text/css">
        html { height: 100% }
        body { height: 100%; margin: 0; padding: 0 }
        #mapid { height: 100% }
    </style> 
    
  <!--Add draw plugin -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
    </script>
    
 <!--Load plugin -->    

<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-ajax/2.1.0/leaflet.ajax.min.js"></script>   


    <style>
   
      #export{
            position: absolute;
            top:600px;
            //right:1800px;
            z-index:1000;
            background:white;
            color:black;
            padding:6px;
            border-radius:4px;
            font-family: 'Helvetica Neue';
            cursor: pointer;
            font-size:12px;
            text-decoration:none;
        }
    
        #export {
            top:370px;
        }
        

    </style>
    </head>  
    <body>
    
        <a href='#' id='export'>Export Features to local file</a>
    
        <div id="mapid"></div>
    
    <script> 

var features = "https://api.npoint.io/4fefc36933cc5c22cee4";    
    
      var cities = L.layerGroup();




    var mbAttr = 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, ' +
            '<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
            'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
        mbUrl = 'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw';

    var streets   = L.tileLayer(mbUrl, {id: 'mapbox/streets-v11', tileSize: 512, zoomOffset: -1, attribution: mbAttr}),
        sat  = L.tileLayer('http://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}',{
    maxZoom: 20,
    subdomains:['mt0','mt1','mt2','mt3']
}),
OSM = L.tileLayer('https://maps.jakdojade.pl/osm/{z}/{x}/{y}.png');

Topo = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png');






    var map = L.map('mapid', {
        center: [49.9225,18.99195],
        //drawControl: true,
        zoom: 8,
        layers: [streets, cities]
        
    });
    

    var baseLayers = {
    

            "Podstawowa": streets,
        "Satelitarna": sat,
        "OSM": OSM,
        "Topo": Topo,
        
    };
//SVG2


//SVG2

    L.control.layers(baseLayers, {collapsed:false, position:'topleft'}).addTo(map);
    

    
</script> 




  <script>
  


  
var featureGroup = new L.GeoJSON.AJAX(features, {
             
       
}).addTo(map);


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

map.on('draw:created', function (event) {


    var layer = event.layer,
        feature = layer.feature = layer.feature || {};
    
    feature.type = feature.type || "Feature";
    var props = feature.properties = feature.properties || {};
   
    featureGroup.addLayer(layer);
    addPopup(layer);
    
});

var openLayer;

function addPopup(layer){
 
  let popupContent = 
  '<form>' + 
  'Link:<br><input type="text" id="input_link"><br>' +
  'Cena:<br><input type="text" id="input_cena"><br>' +
  'Area:<br><input type="text" id="input_area"><br>' +
  'Image:<br><input type="text" id="input_image"><br>' +
  '</form>';  
  

 
  layer.on("popupopen", function (e) {
    var _layer = e.popup._source;
    if(!_layer.feature){
        _layer.feature = {
        properties: {}
      };
      
      
    }
    
    document.getElementById("input_link").value = _layer.feature.properties.link || "";
    document.getElementById("input_cena").value = _layer.feature.properties.cena || "";
    document.getElementById("input_area").value = _layer.feature.properties.area || "";
    document.getElementById("input_image").value = _layer.feature.properties.image || "";
    document.getElementById("input_link").focus();
    openLayer = _layer;
    
  });
  
  layer.on("popupclose", function (e) {
    openLayer = undefined;
 });
 
 layer.bindPopup(popupContent).openPopup(); 

        
};

L.DomEvent.on(document,"keyup",function(){
  if(openLayer){
    link = document.getElementById("input_link").value;
    cena = document.getElementById("input_cena").value;
    area = document.getElementById("input_area").value;
    image = document.getElementById("input_image").value;

    openLayer.feature.properties.link = link;
    openLayer.feature.properties.cena = cena; 
    openLayer.feature.properties.area = area;
    openLayer.feature.properties.image = image;
    openLayer.feature.properties.N = 1;
    
    
  }
 
   
})
  



        document.getElementById('export').onclick = function(e) {
            // Extract GeoJson from featureGroup
            var data = featureGroup.toGeoJSON();

            // Stringify the GeoJson
            var convertedData = 'text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(data));

            // Create export
            document.getElementById('export').setAttribute('href', 'data:' + convertedData);
            document.getElementById('export').setAttribute('download','sl.geojson');
        };
        

    </script>

      
    </body>
</html>


Solution

  • Of course, I did it quickly, so you have to adapt to your own code. I removed L.GeoJSON.AJAX but nothing prevents you from continuing to use it, I advise you not to ;)

    var features = "https://api.npoint.io/4fefc36933cc5c22cee4";
    
    var cities = L.layerGroup();
    
    var mbAttr =
      'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, ' +
      '<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
      'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
      mbUrl =
      "https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw";
    
    var streets = L.tileLayer(mbUrl, {
      id: "mapbox/streets-v11",
      tileSize: 512,
      zoomOffset: -1,
      attribution: mbAttr,
    });
    
    var map = L.map("mapid", {
      center: [49.9225, 18.99195],
      zoom: 8,
    });
    
    streets.addTo(map);
    
    // add layers to map
    
    async function fetchData(url) {
      try {
        const response = await fetch(url);
        const data = await response.json();
        return data;
      } catch (err) {
        console.error(err);
      }
    }
    
    fetchData(features).then((geoJsonData) => {
      const feature = L.geoJSON(geoJsonData, {
        onEachFeature: function(feature, layer) {
          layer.on("mouseover", function(e) {
            e.target.setStyle({
              color: "red",
              weight: 2,
            });
          });
          layer.on("mouseout", function(e) {
            e.target.setStyle({
              color: "#3388ff",
              weight: 2,
            });
          });
          addPopup(layer);
        },
      }).addTo(map);
    });
    
    // --------------------------------------------------
    // draw section
    
    let drawnItems = L.featureGroup().addTo(map);
    
    map.addControl(
      new L.Control.Draw({
        edit: {
          featureGroup: drawnItems,
          poly: {
            allowIntersection: false,
          },
        },
        draw: {
          polygon: {
            allowIntersection: false,
            showArea: true,
          },
        },
      })
    );
    
    map.on(L.Draw.Event.CREATED, function(event) {
      let layer = event.layer;
      let feature = (layer.feature = layer.feature || {});
      let type = event.layerType;
    
      feature.type = feature.type || "Feature";
      let props = (feature.properties = feature.properties || {});
    
      props.type = type;
    
      if (type === "circle") {
        props.radius = layer.getRadius();
      }
    
      drawnItems.addLayer(layer);
      addPopup(layer);
    });
    
    var openLayer;
    
    function addPopup(layer) {
      let popupContent = `
        <form>Link:<br>
        <input type="text" id="input_link" value="${
          layer.feature.properties.link || ""
        }"><br>
        Cena:<br><input type="text" id="input_cena" value=${
          layer.feature.properties.cena || ""
        }><br>
        Area:<br><input type="text" id="input_area" value=${
          layer.feature.properties.area || ""
        }><br>
        Image:<br><input type="text" id="input_image" value=${
          layer.feature.properties.image || ""
        }><br>
        </form>`;
    
      layer.on("popupopen", function(e) {
        var _layer = e.popup._source;
        if (!_layer.feature) {
          _layer.feature = {
            properties: {},
          };
        }
    
        //   document.getElementById("input_link").value =
        //     _layer.feature.properties.link || "";
        //   document.getElementById("input_cena").value =
        //     _layer.feature.properties.cena || "";
        //   document.getElementById("input_area").value =
        //     _layer.feature.properties.area || "";
        //   document.getElementById("input_image").value =
        //     _layer.feature.properties.image || "";
        //   document.getElementById("input_link").focus();
        //   openLayer = _layer;
      });
    
      layer.on("popupclose", function(e) {
        openLayer = undefined;
      });
    
      layer.bindPopup(popupContent).openPopup();
    }
    
    L.DomEvent.on(document, "keyup", function() {
      if (openLayer) {
        link = document.getElementById("input_link").value;
        cena = document.getElementById("input_cena").value;
        area = document.getElementById("input_area").value;
        image = document.getElementById("input_image").value;
    
        openLayer.feature.properties.link = link;
        openLayer.feature.properties.cena = cena;
        openLayer.feature.properties.area = area;
        openLayer.feature.properties.image = image;
        openLayer.feature.properties.N = 1;
      }
    });
    
    document.getElementById("export").onclick = function(e) {
      // Extract GeoJson from featureGroup
      var data = featureGroup.toGeoJSON();
    
      // Stringify the GeoJson
      var convertedData =
        "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(data));
    
      // Create export
      document
        .getElementById("export")
        .setAttribute("href", "data:" + convertedData);
      document.getElementById("export").setAttribute("download", "sl.geojson");
    };
    html {
      height: 100%
    }
    
    body {
      height: 100%;
      margin: 0;
      padding: 0
    }
    
    #mapid {
      height: 100%
    }
    
    #export {
      position: absolute;
      top: 600px;
      z-index: 1000;
      background: white;
      color: black;
      padding: 6px;
      border-radius: 4px;
      font-family: 'Helvetica Neue';
      cursor: pointer;
      font-size: 12px;
      text-decoration: none;
    }
    
    #export {
      top: 370px;
    }
    <link href="https://unpkg.com/[email protected]/dist/leaflet.css" rel="stylesheet" />
    <link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" rel="stylesheet" />
    <script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
    <a href='#' id='export'>Export Features to local file</a>
    <div id="mapid"></div>

    You can add the option to modify fields (form) only when you click the edit button.

    map.on(L.Draw.Event.EDITED, function (event) {
      let layers = event.layers;
    
      layers.eachLayer(function (layer) {
        addPopup(layer);
      });
    });