Leaftlet:如何将GeoJSON数据集动态过滤到一系列“图层”复选框中?

时间:2019-08-04 19:30:07

标签: leaflet geojson

我有一个网页,该网页可以从本地数据库中获取一些标记针的位置,还可以从远程GeoJSON源(API)中获取功能的集合。

当前,用户可以使用两个复选框,以允许他们选择要查看的两层中的哪一层。一切正常:

<script>

    // Center the map
    var map = L.map('map').setView([54.233669, -4.406027], 6);


    // Attribution
    L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=REMOVED', {
        attribution: 'Map &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a>',
        id: 'mapbox.streets'
    }).addTo(map);



    // Create an empty layergroup for the Locations data
    var LayerLocations = L.layerGroup();

    // Format the popup markers for the Locations
    function forEachFeature(feature, layer) {

        // Image
        var ImageContent
        if (feature.properties.ImageURL) {
            ImageContent = "<img src='" + feature.properties.ImageURL + "' width='300' height='200' /><br /><br />"
        } else if (feature.properties.YouTubeID) {
                ImageContent = "<img src='https://img.youtube.com/vi/" + feature.properties.YouTubeID + "/hqdefault.jpg' width='300' height='200' /><br /><br />"

        } else {
            ImageContent = ""
        }

        // Build the popup content
        var popupContent = "<h4>" +
            feature.properties.Title +
            Author +
            "</h4>" +
            ImageContent +
            CommentsContent +
            "View and discuss this location.";
        layer.bindPopup(popupContent);
    }

    // Build layer: Locations
    fetch("JSONMapPoints.json")
      .then(function (response) { return response.json() })
      .then(function (data) {
          // Create a L.GeoJSON out of the data
          var locations = L.geoJson(data, {
              onEachFeature: forEachFeature,
              pointToLayer: function (feature, latlng) {
                  return L.marker(latlng, {
                      icon: L.icon({
                      iconUrl: "images/pins/" + feature.properties.CategoryID + ".png",
                      iconSize: [32, 37],
                      iconAnchor: [10, 32],
                      popupAnchor: [5, -30]
                      }),
                  })
              }
          });
          // Add the L.GeoJSON instance to the empty layergroup
          map.fitBounds(locations.getBounds());
          LayerLocations.addLayer(locations).addTo(map);
    });


    // Create an empty layergroup for the Guardian UTM data
    var LayerGuardianUTM = L.layerGroup();

    // Style the Guardian UTM features
    function setStyle(feature) {
        return {
            fillColor: feature.properties.fillColor,
            color: feature.properties.strokeColor,
            fillOpacity: feature.properties.fillOpacity,
            opacity: feature.properties.strokeOpacity
        };
    }

    // Build Layer: Guardian UTM
    function getGuardianUTMdata() {
        LayerGuardianUTM.clearLayers();
        fetch("https://example.com/v2/mapdata/geojson?n=" + map.getBounds().getNorth() + "&e=" + map.getBounds().getEast() + "&s=" + map.getBounds().getSouth() + "&w=" + map.getBounds().getWest(), { headers: { 'Authorization': 'REMOVED', 'X-AA-DeviceId': 'mySite' } })
          .then(function (responseGuardianUTM) { return responseGuardianUTM.json() })
          .then(function (dataGuardianUTM) {
              // Create a L.GeoJSON out of the data
              var featuresAA = L.geoJson(dataGuardianUTM, {
                  style: setStyle,
                  pointToLayer: function (feature, latlng) {
                      return L.marker(latlng, { icon: L.icon({ iconUrl: feature.properties.iconUrl }), })
                  },
                  onEachFeature: function (feature, layer) {
                      layer.bindPopup(feature.properties.name);
                  },
              });
              // Add the L.GeoJSON instance to the empty layergroup
              LayerGuardianUTM.addLayer(featuresAA).addTo(map);
          });
    }


    // Update the Guardian UTM layer if the map moves
    map.on('dragend', function () { getGuardianUTMdata(); });
    map.on('zoomend', function () { getGuardianUTMdata(); });


    // Layer controls
    var layerControl = new L.Control.Layers(null, {
        'Locations': LayerLocations,
        'Restrictions & Hazards': LayerGuardianUTM
    }).addTo(map);


</script>

我希望增加最终用户可用的功能。

我希望通过一个API而不是一个复选框来打开/关闭Restrictions & Hazards层,而要遍历从API返回的GeoJSON,并根据{{ 1}}。

因此,当用户单击“图层”按钮图标时,他们应该看到一系列复选框,使他们可以选择想要查看的GeoJSON中的哪些功能。

从API返回的GeoJSON是动态的,其内容根据用户位置和缩放级别而变化。

GeoJSON的示例是:

feature.properties.filters.name

基于示例GeoJSON,“图层”按钮应包含以下复选框:

  • { "isCompleteData": true, "excludedData": [], "countriesInViewport": [], "nationalFlightRestrictions": [], "features": [ { "geometry": { "coordinates": [ [ -2.6300508975982666, 53.536331176757812 ], [ -2.6293964385986328, 53.533683776855469 ], [ -2.6288816928863525, 53.531524658203125 ], [ -2.6228303909301758, 53.529739379882813 ], [ -2.6218380928039551, 53.528053283691406 ], [ -2.6206841468811035, 53.526073455810547 ] ], "type": "LineString" }, "id": "A05B59534A594F20583A3B8EB479F211E507F265", "properties": { "hazardFactor": "40", "hazardFactorName": "Warning", "fillColor": "#ffbb00", "strokeColor": "#b88702", "fillOpacity": "0.35", "strokeWidth": "1", "strokeOpacity": "0.8", "detailedCategory": "power:line", "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=power_line.png", "name": "Power Line", "category": "groundHazard", "filters": [ { "name": "Ground Hazards", "property": "show", "active": true } ], "display": { "category": "Ground Hazard", "detailedCategory": "Power Line", "title": "Ground Hazard", "sections": [ { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=power_line.png", "title": "Power Hazard", "text": "The highlighted area is believed to contain power infrastructure. Power infrastructure presents heightened risk of damage to your equipment and critical National infrastructure." }, { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Summary", "text": "Yellow zones indicate regions where operation of your drone may raise security, privacy or safety concerns." } ], "actions": [] } }, "type": "Feature" }, { "geometry": { "coordinates": [ -2.6228303909301758, 53.529739379882813 ], "type": "Point" }, "id": "6EB24E66D75083A4A135296C12BE004D79629818", "properties": { "hazardFactor": "40", "hazardFactorName": "Warning", "fillColor": "#ffbb00", "strokeColor": "#b88702", "fillOpacity": "0.35", "strokeWidth": "1", "strokeOpacity": "0.8", "detailedCategory": "power:tower", "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=power_tower.png", "name": "Power Pylon", "category": "groundHazard", "filters": [ { "name": "Ground Hazards", "property": "show", "active": true } ], "display": { "category": "Ground Hazard", "detailedCategory": "Power Pylon", "title": "Ground Hazard", "sections": [ { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=power_tower.png", "title": "Power Hazard", "text": "The highlighted area is believed to contain power infrastructure. Power infrastructure presents heightened risk of damage to your equipment and critical National infrastructure." }, { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Summary", "text": "Yellow zones indicate regions where operation may raise security, privacy or safety concerns." } ], "actions": [] } }, "type": "Feature" }, { "geometry": { "coordinates": [ [ [ -2.6234986782073975, 53.533077239990234 ], [ -2.6215133666992187, 53.528900146484375 ], [ -2.6183879375457764, 53.529270172119141 ], [ -2.6178712844848633, 53.529655456542969 ] ] ], "type": "Polygon" }, "id": "557952B3668AC5DF5C583BE8E8C1840D97B5ABD4", "properties": { "hazardFactor": "40", "hazardFactorName": "Warning", "fillColor": "#ffbb00", "strokeColor": "#b88702", "fillOpacity": "0.35", "strokeWidth": "1", "strokeOpacity": "0.8", "detailedCategory": "landuse:cemetery", "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=landuse_cemetery.png", "name": "Wigan Borough Cemetery", "category": "groundHazard", "filters": [ { "name": "Ground Hazards", "property": "show", "active": true } ], "display": { "category": "Ground Hazard", "detailedCategory": "Cemetery", "title": "Wigan Borough Cemetery", "sections": [ { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Summary", "text": "Yellow zones indicate regions where operation of your drone may raise security, privacy or safety concerns." } ], "actions": [] } }, "type": "Feature" }, { "geometry": { "coordinates": [ [ [ -3.235, 53.53694 ], [ -3.05278, 53.45944 ], [ -3.20139, 53.38583 ], [ -3.02778, 53.24083 ], [ -2.73028, 53.10722 ] ] ], "type": "Polygon" }, "id": "616CB45B9DA924146E9A5483843B588B36F0AD31", "properties": { "hazardFactor": "60", "hazardFactorName": "Danger", "fillColor": "#ffffff", "strokeColor": "#ffffff", "fillOpacity": "0.2", "strokeWidth": "1", "strokeOpacity": "0.8", "detailedCategory": "type:tma", "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=class_type_tma.png", "airac": { "to": "2019-08-15", "from": "2019-07-18" }, "altitudeFloor": { "datum": "Msl", "meters": 1066.7999983784639, "feet": 3499.9999946799994 }, "altitudeCeiling": { "datum": "Sps", "meters": 7467.5999886492482, "feet": 24499.99996276 }, "name": "MANCHESTER TMA 1", "listOrderHint": "1000", "category": "airspace", "designator": "EGCC1", "airspaceType": "TMA", "filters": [ { "name": "Upper Airspace", "property": "show", "active": false }, { "name": "Type TMA", "property": "show", "active": true } ], "display": { "category": "airspace", "detailedCategory": "Type TMA", "title": "MANCHESTER TMA 1", "sections": [ { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Altitude", "text": "This piece of airspace is in effect above 1067m / 3500ft MSL" }, { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Terminal control area", "text": "Control area normally established at the confluence of ATS routes in the vicinity of one or more major aerodromes." }, { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Regulated Airspace", "text": "This airspace has a specific classification." }, { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Summary", "text": "Red zones are regulated high-risk areas." } ], "actions": [] } }, "type": "Feature" }, { "geometry": { "coordinates": [ [ [ -3.05278, 53.45944 ], [ -2.06667, 53.575 ], [ -2.83333, 53.53333 ], [ -3.05278, 53.45944 ] ] ], "type": "Polygon" }, "id": "BC69E04789D9A790DB5B29B0EE2804D42E4FA12A", "properties": { "hazardFactor": "60", "hazardFactorName": "Danger", "fillColor": "#ffffff", "strokeColor": "#ffffff", "fillOpacity": "0.2", "strokeWidth": "1", "strokeOpacity": "0.8", "detailedCategory": "class:d", "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=class_d.png", "airac": { "to": "2019-08-15", "from": "2019-07-18" }, "altitudeFloor": { "datum": "Msl", "meters": 761.99999884176, "feet": 2499.9999961999997 }, "altitudeCeiling": { "datum": "Msl", "meters": 1066.7999983784639, "feet": 3499.9999946799994 }, "name": "MANCHESTER CTA 1", "listOrderHint": "600", "category": "airspace", "designator": "EGCC1", "airspaceClass": "D", "airspaceType": "CTA", "filters": [ { "name": "Upper Airspace", "property": "show", "active": false }, { "name": "Class D", "property": "show", "active": true } ], "display": { "category": "airspace", "detailedCategory": "Class D", "title": "MANCHESTER CTA 1", "sections": [ { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Altitude", "text": "This piece of airspace is in effect above 762m / 2500ft MSL" }, { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Regulated Airspace", "text": "This airspace has a specific classification." }, { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Summary", "text": "Red zones are regulated high-risk areas." } ], "actions": [] } }, "type": "Feature" }, { "geometry": { "coordinates": [ [ [ -10, 54.56667 ], [ -9, 54.75 ], [ -8.25, 55.33333 ] ] ], "type": "Polygon" }, "id": "11DD2D3CBA8992F29E49A277FC322D19FCD67066", "properties": { "hazardFactor": "60", "hazardFactorName": "Danger", "fillColor": "#ffffff", "strokeColor": "#ffffff", "fillOpacity": "0.2", "strokeWidth": "1", "strokeOpacity": "0.8", "detailedCategory": "type:cta", "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=class_type_cta.png", "airac": { "to": "2019-08-15", "from": "2019-07-18" }, "altitudeFloor": { "datum": "Sps", "meters": 7467.5999886492482, "feet": 24499.99996276 }, "altitudeCeiling": { "datum": "Sps", "meters": 20116.799969422464, "feet": 65999.99989968 }, "name": "UPPER AIRSPACE CTA", "listOrderHint": "1000", "category": "airspace", "designator": "EGUP", "airspaceType": "CTA", "filters": [ { "name": "Upper Airspace", "property": "show", "active": false }, { "name": "Type CTA", "property": "show", "active": true } ], "display": { "category": "airspace", "detailedCategory": "Type CTA", "title": "UPPER AIRSPACE CTA", "sections": [ { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Altitude", "text": "This piece of airspace is in effect above FL244.9999996276" }, { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Control area", "text": "A controlled airspace extending upwards from a specified limit above the earth." }, { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Regulated Airspace", "text": "This airspace has a specific classification." }, { "iconUrl": "https://aa-ne-prod-public-api.example.com//v1/map/icon?icon=warning.png", "title": "Summary", "text": "Red zones are regulated high-risk areas." } ], "actions": [] } }, "type": "Feature" } ], "bbox": [ -2.6261, 53.5288, -2.6201, 53.5308 ], "type": "FeatureCollection" }
  • Locations
  • Ground Hazards

这有可能吗?!

1 个答案:

答案 0 :(得分:3)

创建多个L.GeoJSON实例,并利用其filter option

  

一个Function,将用于决定是否包括功能。默认值为包括所有功能:

function (geoJsonFeature) {
    return true;
}
     

注意:动态更改filter选项仅对新添加的数据有效。它不会重新评估已经包含的功能。

例如:

fetch("JSONMapPoints.json")
  .then(function (response) { return response.json() })
  .then(function (data) {

      var locations = L.geoJson(data, {
          filter: function(feat) { return feat.properties.filters.name === 'Location'},
          /* etc */
      });
      var hazards = L.geoJson(data, {
          filter: function(feat) { return feat.properties.filters.name === 'Hazard'},
          /* etc */
      });
      var airspace = L.geoJson(data, {
          filter: function(feat) { return feat.properties.filters.name === 'Air Space'},
          /* etc */
      });
});

对于那些不同的L.GeoJSON实例,将它们添加到图层控件中仅是调用addOverlay()的问题,例如

layersControl.addOverlay(locations, "Locations");      
layersControl.addOverlay(hazards, "Hazards);    
layersControl.addOverlay(airspace, "Air Space");

请注意scope。 JS的一个新手错误是假设,该变量将在需要的范围内神奇地存在。在这种情况下,我将确保在创建GeoJSON图层时已实例化图层控件,并将其添加到所述图层控件中。


一种更复杂的方法是自动检测类别或过滤器,遍历GeoJSON结构以获取它们,例如:

fetch("JSONMapPoints.json")
  .then(function (response) { return response.json() })
  .then(function (data) {

    // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
    var categories = new Set();

    for (var i in data) {
      var feature = data[i];
      categories.add(feature.properties.filters.name);
    }

然后遍历类别以编程方式创建L.GeoJSON实例,并注意适当的闭包:

    categories.forEach(function(category) {
      var layer = L.geoJSON(data, {
        filter: function(f){ f.properties.filters.name === category }
        /* etc */ });
      layersControl.addOverlay(layer, category);
    });

// And we're done here.
});

这对于需要三个过滤器的数据集来说有点过分设计,但是当数量更大时,效果很好。