如何在 onClick 事件处理程序中识别在同一张地图(使用 react-leaflet)上绘制的许多多边形中单击了哪个?

How to identify, inside an onClick event handler, which out of many polygons plotted on the same map (using react-leaflet) was clicked?

情况: 我正在使用 react-leaflet 在地图上绘制一个国家及其所有州边界。我将每个州边界绘制为多边形(定义在 JSON 文件中传递。)使用函数 .所有状态边界定义都作为不同的 JSON 对象在单个 JSON 文件中传递。每个对象都有一个唯一的 ID。

我的代码:

import React from 'react'
import { MapContainer, TileLayer, GeoJSON } from 'react-leaflet'
import * as L from "leaflet";


const Map = (props) => {
let cordinates = [14.716, -14.467]       // Dispaly coordinates
return (
    // Cordinates of map 
    <MapContainer center={cordinates} zoom={7} scrollWheelZoom={false}>
         {/* Display map  */}
         <TileLayer
            attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
     {/* <GeoJSON id={Math.random()} data={country} /> */}

     {/* Highlited area in map  */}
        <GeoJSON data={props.state} onEachFeature={props.handleEachFeature} />
   </MapContainer> 
)
}

export default Map

我正在传递 JSON 文件和 handleEachFeature 函数(在控制台中返回整个 JSON 文件)作为道具。

我想做的事情: 当用户点击地图时,我想清除整个地图并只绘制点击所在的状态。基本上,州将被放大,我也想绘制它的地区边界(我也有每个州的地区边界定义)。

我采用的方法: 我正在尝试捕获与在 onClick 事件中单击的多边形(对应于状态)关联的 id。然后我可以擦除现有地图并使用捕获的 id 我可以绘制所点击的州(及其地区)。但是,无论单击哪个状态,onClick 事件都会向我返回所有多边形的全部数据。以下是我的代码:

点击 handleEachFeature 函数:

 function handleEachFeature(feature, layer) {
         layer.on("click", L.bind(handleClick, null, layer));
}

 // This is returning whole json file in console. But, I want only Polygon id on which user clicked. 
 function handleClick(e) {
    console.log(e);
}

我已经尝试过的事情:

  1. 我使用了一个包含多个多边形的 JSON 文件。但是,onClick 事件我得到了整个 JSON 文件,而不是任何唯一值来识别多边形。
  2. 我也尝试为每个多边形(州)使用不同的 JSON 文件,并将它们一一添加到地图中,但得到了相同的结果。

请建议任何使用 react-leaflet 或其他库的方法。

您可以通过将唯一标识符(在提供的示例中为cartodb_id)存储在一个变量中,然后使用它来更改 geojson 的样式并以特定样式呈现单击的区域来执行此操作。

使用onEachFeature函数你可以得到唯一的id并缩放到点击的区域。一旦将其存储在 var 中,您就可以通过仅显示包含唯一 ID 的对象来过滤 geojson。由于 react-leaflet 的 geojson comp 数据 属性 是不可变的,因此您必须使用参考 (ref)。您可以使用 leaflet 的 eachLayer 将特定样式附加到除被单击对象之外的所有对象。一旦您通过 useeffect 过滤 geojson(请参见下面的代码),后者将通过设置单击的图层样式来实现。然后使用传单的 addData 你可以在地图上读取过滤后的 geojson。

export default function Map() {
  const [map, setMap] = useState(null);
  const geojsonRef = useRef();
  const [featureId, setFeatureId] = useState(null);

  const handleEachFeature = (feature, layer) => {
    layer.on({
      click: (e) => {
        setFeatureId(feature.properties.cartodb_id);
        map.fitBounds(e.target.getBounds());
      }
    });
  };

  useEffect(() => {
    if (!featureId || !geojsonRef.current) return;
    geojsonRef.current.eachLayer((layer) => {
      layer.setStyle({
        opacity: 0.5,
        weight: 0
      });
    }); // inherited from LayerGroup
    const newDistricts = districts.features.filter((district) => {
      return district.properties.cartodb_id === featureId;
    });
    geojsonRef.current.addData(newDistricts);
  }, [featureId]);

  return (
    <MapContainer
      center={position}
      zoom={9}
      style={{ height: "100vh" }}
      ref={setMap}
    >
      <TileLayer
        attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />
      {map && (
        <GeoJSON
          ref={geojsonRef}
          data={districts}
          onEachFeature={handleEachFeature}
        />
      )}
    </MapContainer>
  );
}

您可以使用 clearLayers 方法将其完全删除,但这对我来说毫无意义,因为一旦您单击它,您最终将只显示被单击的区域。我尝试了另一种方法,通过更改除单击区域之外的所有其他区域的样式。这样你就可以点击一个新的并恢复上一个的样式。

使用简单的免费 geojson 来呈现结果。

Demo