传单绘制“无法读取未定义的属性‘启用’"向 geoJSON 层添加控制

2022-01-12 00:00:00 leaflet javascript leaflet.draw

我正在尝试对从数据库加载的多边形使用传单的编辑功能.当我单击传单的编辑按钮时,我收到错误
无法读取未定义的属性启用"

I am trying to use leaflet's edit function on polygons that I loaded from my database. When I click on leaflet's edit button I get the error
Cannot read property 'enable' of undefined

这个帖子描述了一个类似的问题,用户ddproxy说

This thread describes a similar problem, and user ddproxy said

由于FeatureGroup扩展了LayerGroup,你可以遍历图层呈现并将它们单独添加到用于Leaflet.draw"

"Since FeatureGroup extends LayerGroup You can walk through the layers presented and add them individually to the FeatureGroup used for Leaflet.draw"

我很困惑他所说的穿过"是什么意思,我以为我正在添加一个图层组,所以我不确定我会穿过什么.这是否与我将多边形添加为 geoJSON 对象这一事实有关?
将多边形添加到地图,绑定它们的弹出窗口,并为它们分配自定义颜色,仅供参考.

I am confused what he means by "walk through", I thought I was adding a layer group, so i'm not sure what I would be walking through. Does this have to do with the fact that i'm adding the polygons as a geoJSON object?
Adding the polygons to the map, binding their popups, and assigning them custom colors works perfectly FYI.

以下是相关代码:

<script>
window.addEventListener("load", function(event){
    //other stuff
    loadHazards(); 

});

//next 6 lines siply add map to page
var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
var osmAttrib = '&copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors'
var osm = L.tileLayer(osmUrl, { maxZoom: 18, attribution: osmAttrib})
var map = new L.Map('map', { center: new L.LatLng(39.255467, -76.711964), zoom: 16 })

osm.addTo(map);

var drawnItems = L.featureGroup().addTo(map);
var Hazards = L.featureGroup().addTo(map);

L.control.layers({
        'osm': osm.addTo(map)
        },
        {
           'drawlayer': drawnItems,
           "Hazards" : Hazards,
           "Tickets": Tickets
         },

         {
           position: 'topleft', collapsed: false
         }
         ).addTo(map);

map.addControl(new L.Control.Draw({
    edit: {
        featureGroup: Hazards,
        poly: {
            allowIntersection: false
        }
    },
    draw: {
        polygon: {
            allowIntersection: false,
            showArea: true
        },
        rectangle:false,
        circle:false,
        circlemarker:false
    }
}));

map.on(L.Draw.Event.CREATED, function (event) {
    var layer = event.layer;
    drawnItems.addLayer(layer);
});

</script>

还有 loadHazards() 函数:

And the loadHazards() function:

function loadHazards(){
$.ajax({
    type: 'GET',
    url:'/loadPolygonFromDatabase',
    success : function(polygons){           
        polygons = JSON.parse(polygons);

        var toAdd = [];
        for (i in polygons){

            var item = {
                    "type" : "Feature",
                    "properties":{
                        "category":"",
                        "description":"",
                        "ID":""
                     },
                     "geometry" : {
                        "type":"Polygon",
                        "coordinates":[],

                    }

            };

            item["geometry"]["coordinates"][0] = polygons[i]["coordinates"];
            item["properties"]["category"]     = polygons[i]["category"];
            item["properties"]["description"]  = polygons[i]["description"];
            item["properties"]["ID"]  = polygons[i]["ID"];
            toAdd.push(item);

        }

        //Add information to popup
        var layerGroup = L.geoJSON(toAdd, {
            onEachFeature: function (feature, layer) {
                layer.bindPopup(  '<h1>' + feature.properties.category + '</h1>'
                                + '<p>'  + feature.properties.description + '</p>');
                layer.id = feature.properties.ID;

          },
          style: function(feature){
             switch (feature.properties.category) {
                case 'Rabid_Beavers': return {color: "#663326"};
                case 'Fire':   return {color: "#ff0000"};
                case 'Flood':   return {color: "#0000ff"};
            }
          }
        }).addTo(Hazards);

    }
});
}

提前致谢!

推荐答案

不幸的是,Leaflet.draw 插件不处理嵌套层组(功能组/GeoJSON 层组相同).

Unfortunately Leaflet.draw plugin does not handle nested Layer Groups (same for Feature Groups / GeoJSON Layer Groups).

这就是你参考的Leaflet.draw #398问题的意思:他们建议遍历您的 Layer/Feature/GeoJSON 层组的 child 层(例如,使用他们的 eachLayer 方法).如果子图层是非组图层,则将其添加到您的可编辑要素组.如果是另一个嵌套组,则再次循环遍历其自己的子层.

That is the meaning of the Leaflet.draw #398 issue you reference: they advise looping through the child layers of your Layer/Feature/GeoJSON Layer Group (e.g. with their eachLayer method). If the child layer is a non-group layer, then add it to your editable Feature Group. If it is another nested group, then loop through its own child layers again.

查看该帖子中提出的代码:

See the code proposed in that post:

https://gis.stackexchange.com/questions/203540/how-to-edit-an-existing-layer-using-leaflet

var geoJsonGroup = L.geoJson(myGeoJSON);
addNonGroupLayers(geoJsonGroup, drawnItems);

// Would benefit from https://github.com/Leaflet/Leaflet/issues/4461
function addNonGroupLayers(sourceLayer, targetGroup) {
  if (sourceLayer instanceof L.LayerGroup) {
    sourceLayer.eachLayer(function(layer) {
      addNonGroupLayers(layer, targetGroup);
    });
  } else {
    targetGroup.addLayer(sourceLayer);
  }
}

在您的情况下,您还可以使用 2 个其他解决方案重构您的代码:

In your very case, you can also refactor your code with 2 other solutions:

  • 而不是构建您的 layerGroup(实际上是一个 LeafletGeoJSON 图层组),然后将其添加到您的 Hazards 功能组中,从头开始将后者设为 GeoJSON 图层组,然后 addData 用于您的每个功能(item):
  • Instead of building your layerGroup (which is actually a Leaflet GeoJSON Layer Group) first and then add it into your Hazards Feature Group, make the latter a GeoJSON Layer Group from the beginning, and addData for each of your single Features (item):
var Hazards = L.geoJSON(null, yourOptions).addTo(map);

for (i in polygons) {
  var item = {
    "type" : "Feature",
    // etc.
  };
  // toAdd.push(item);
  Hazards.addData(item); // Directly add the GeoJSON Feature object
}

  • 您可以直接构建一个 Leaflet Polygon 并将其添加到您的 Hazards 图层/功能组中:
    • Instead of building a GeoJSON Feature Object (item) and parse it into a Leaflet GeoJSON Layer, you can directly build a Leaflet Polygon and add it into your Hazards Layer/Feature Group:
    • for (i in polygons) {
        var coords = polygons[i]["coordinates"];
        var style = getStyle(polygons[i]["category"]);
        var popup = ""; // fill it as you wish
      
        // Directly build a Leaflet layer instead of an intermediary GeoJSON Feature
        var itemLayer = L.polygon(coords, style).bindPopup(popup);
        itemLayer.id = polygons[i]["ID"];
        itemLayer.addTo(Hazards);
      }
      
      function getStyle(category) {
        switch (category) {
          case 'Rabid_Beavers': return {color: "#663326"};
          case 'Fire':   return {color: "#ff0000"};
          case 'Flood':   return {color: "#0000ff"};
        }
      }
      

相关文章