根据在选择/下拉框中而不是复选框中选择的值动态获取和显示地图图层

Posted

技术标签:

【中文标题】根据在选择/下拉框中而不是复选框中选择的值动态获取和显示地图图层【英文标题】:Dynamically fetch and display map layers based on the value selected in a select/dropdown box instead of checkbox 【发布时间】:2021-09-22 06:04:12 【问题描述】:

我有大约 5 个地图层作为单独的 json 文件。使用复选框单击动态获取和显示每个地图图层文件。它运行良好。我的代码如下所示。我有另一个要求将这 5 个复选框更改为单个下拉列表。当我从下拉输入字段中选择特定值时,它必须显示其相应的图层。如果我从下拉列表中选择另一个值,它必须删除先前选择的地图图层并显示新选择的值的相应图层。是否可以在下拉菜单中做同样的事情?

<div id="inputParentId" />
<input type="checkbox" id="1" onClick="togglejsonLayer(this,'lay1');" />
Layer 1
<input type="checkbox" id="2" onClick="togglejsonLayer(this,'lay2');" />
Layer 2
<input type="checkbox" id="3" onClick="togglejsonLayer(this,'lay3');" />
Layer 3
<input type="checkbox" id="4" onClick="togglejsonLayer(this,'lay4');" />
Layer 4
<input type="checkbox" id="5" onClick="togglejsonLayer(this,'lay5');" />
Layer 5

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

<script>
  const mbAttr = "";
  const mbUrl =
    "https://api.mapbox.com/styles/v1/id/tiles/z/x/y?access_token=xxxxxxxx";

  const streets = L.tileLayer(mbUrl, 
    id: "mapbox/streets-v11",
    tileSize: 512,
    zoomOffset: -1,
    attribution: mbAttr
  );

  const sattelite = L.tileLayer(mbUrl, 
    id: "mapbox/satellite-v9",
    tileSize: 512,
    zoomOffset: -1,
    attribution: mbAttr
  );

  const map = L.map("map", 
    center: [39.74739, -105],
    zoom: 12,
    layers: [streets]
  );

  var baseLayers = 
    Streets: streets,
    Sattelite: sattelite
  ;
  L.control.layers(baseLayers).addTo(map);

  function onEachFeature(feature, layer) 
    var popupContent;
    if (feature.properties && feature.properties.popupContent) 
      popupContent = feature.properties.popupContent;
    
    layer.bindPopup(popupContent);
  

  async function getGeojson(checkbox, layerName) 
    if (layers[layerName]) 
      if (checkbox.checked) layers[layerName].addTo(map);
      else map.removeLayer(layers[layerName]);
      return;
    

    const response = await fetch(`./$layerName.json`);
    const geojson = await response.json();
    return geojson;
  

  const layers = ;

  const togglejsonLayer = async (checkbox, layerName) => 
    const geojsonData = await getGeojson(checkbox, layerName);
    const geojson = L.geoJSON([geojsonData], 
      onEachFeature
    );

    const checkId = checkbox.id;
    if (checkbox.checked) 
      layers[layerName] = geojson;
      layers[layerName].addTo(map);
     else map.removeLayer(layers[layerName]);
  ;
</script>

【问题讨论】:

所以在这种情况下,您只想在每次选择一个下拉项目时显示一个 json,而不是多个。对吗? 您是否尝试过查看 Leaflet 文档中的图层控件?或者您的应用程序是否需要图层选择器以不同方式工作或放置在其他位置? @kboul,是的。基于从 Dropbox 中选择的值的单个 json 文件。我有一个参考。但其中所有层都在一个 json 文件中。 ahalota.github.io/Leaflet.CountrySelect/demo.html 【参考方案1】:

您可以使用Layer.Control,因为它与 JRI 提到的工作相同,但由于您想要在地图之外实现,您可以执行以下操作:

你保持原来的样子,只是稍微改变一下缓存已经获取的层

async function getGeojson(layerName) 
    const response = await fetch(`./$layerName.json`);
    const geojson = await response.json();
    return geojson;

您可以使用一个变量来保留所有获取的图层,并使用一个变量来立即在地图上添加/删除当前选定的图层。一旦您处于缓存而不是缓存模式,还可以重用 clearMap 函数来清空地图。

const layerCaching = ;
const currentDisplayedLayer = ;

document.getElementById("layers").onchange = (e) => 
  togglejsonLayer(e.target.value);
;

const clearMap = () => 
    Object.keys(currentDisplayedLayer).forEach((layer) => 
      map.removeLayer(currentDisplayedLayer[layer]);
      delete currentDisplayedLayer[layer];
    );
;

const togglejsonLayer = async (id) => 
  if (id === "0") return clearMap();

  const layerName = `lay$id`;

  let geojson;
  if (!layerCaching[layerName]) 
     const geojsonData = await getGeojson(layerName);
     geojson = L.geoJSON([geojsonData],  onEachFeature );
   else geojson = layerCaching[layerName];

  if (Object.keys(currentDisplayedLayer).length > 0) clearMap();

  currentDisplayedLayer[layerName] = geojson;
  if (!layerCaching[layerName]) layerCaching[layerName] = geojson;
  currentDisplayedLayer[layerName].addTo(map);

最后但并非最不重要的一点是,您可以运行 for 循环来动态构建选择项,因此如果您决定将来使用约定的层数添加更多层,这样做真的很容易。

<select name="layers" id="layers"></select>

const layersSelect = document.getElementById("layers");
layersSelect.add(new Option("Select Layer", "0"));
const arrayLength = Array.from(Array(5).keys());

arrayLength.forEach((_, id) => 
  layersSelect.add(new Option(`Layer $id + 1`, id + 1));
);

Demo

【讨论】:

谢谢@kboul,我的下拉字段选项值是从数据库中获取的。因此,我对您的代码进行了必要的修改,并且效果很好。非常感谢。 :) 在您给出的上述演示中,假设 layer4 (lay4.json) 有许多内部边界,每个边界也有自己的特征。是否可以根据通过地图外搜索按钮触发的文本输入字段输入的特征值突出显示并缩放到该 layer4 中的特定边界?

以上是关于根据在选择/下拉框中而不是复选框中选择的值动态获取和显示地图图层的主要内容,如果未能解决你的问题,请参考以下文章

怎么在动态添加select下拉框中 选择一个默认的option

jsp下拉列框不可编辑,<select></select> ;只能选择下拉框的值,而不能手动去输入值

如何从 Shiny 中的下拉框中根据变量选择动态创建直方图

根据下拉选择动态填充字段(Javascript / HTML)

如何从下拉框中获取用户选择的值并将其添加到模型中? [重复]

怎么用jquery实现 在一个下拉框中添加一个“其他”的选项来代表除去已选项的其余所有未选项