react-leaflet:在呈现新标记之前清除标记簇
react-leaflet: Clear marker cluster before rendering new markers
TLDR;有没有办法使用 react-leaflet 和 react-leaflet-markercluster 清除标记簇中的所有标记?
编辑:是的,有!我刚刚向 MarkerClusterGroup 添加了一个关键道具,正如@SethLutske 所推荐的。现在,每次重新渲染地图时,以前的标记都会被删除,只剩下新的标记。
<MarkerClusterGroup
key={uuidv4()}
spiderfyDistanceMultiplier={1}
showCoverageOnHover={true}
>
我在我所在州的 Public 安全机构工作。有一个 API 从我所在州的所需城市获取监控摄像机的集合。我正在使用 React PWA 检索这些摄像头的图像,因此警方可以使用我的应用程序进行实时监控。警察对系统进行身份验证,使用表格按所在城市筛选摄像机,结果显示在地图中,地图上带有指示每个摄像机位置的标记。触摸标记时,会显示一个弹出窗口,其中包含该摄像机的信息和一个按钮,触摸时会在新页面中显示摄像机图像。
Map markers and popup
我选择 Leaflet 和 react-leaflet 进行地图渲染,并使用 react-leaflet-markercluster 对相邻的标记进行分组。我有一个小问题:如果用户按城市过滤相机,然后他 returns 填写表格并决定按不同城市过滤,我希望发生的行为是:
- 清除之前过滤掉的城市的所有标记;
- 显示当前城市的所有标记;
但实际情况是这样的:之前城市的标记保留在地图中,弹出窗口为空。
Marker groups from different cities
我的目标:我想在添加新城市的标记之前清除过去的城市标记!
这是我的 MapContainer。尽管存在我提到的错误,它运行良好。
<MapContainer
center={[-26.627817, -51.196288]}
zoom={6}
scrollWheelZoom={false}
style={{ height: '100vh', width: '100wh' }}
>
{//<ClearLayers /> this clears the entire map, even the tile layer, leaving it blank
}
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<MarkerClusterGroup
spiderfyDistanceMultiplier={1}
showCoverageOnHover={false}
>
{cameras.map((camera: Camera) => (
<Marker icon={iconBTV} key={camera.name} position={[camera.latitude, camera.longitude]}>
<Popup>
{camera.name} <br /> {camera.description} <br />
<Link
to={{
pathname: "/cameraScreen",
}}
style={{ textDecoration: 'none' }}
>
<button
style={{marginTop: "1rem"}}
onClick={(e) => insertLog(e, camera)}
>Ver câmera</button>
</Link>
</Popup>
</Marker>
))}
</MarkerClusterGroup>
</MapContainer>
我试过使用这个功能,但它没有达到我想要的效果。它会破坏地图,使其完全空白。
function ClearLayers() {
const map = useMap();
map.eachLayer(function (layer) {
map.removeLayer(layer);
});
return null
}
我在这里搜索并接近解决方案:我能够通过使用 Leaflet 的核心 API 并留下 react-leaflet-markercluster 包装器 来清除过去的城市标记.在将新标记添加到 MCG 之前,我确实执行了 clearLayers(),这就达到了目的。这是我尝试做的事情:
import * as L from 'leaflet';
import 'leaflet.markercluster';
import { useMap } from 'react-leaflet';
import { useContext, useEffect } from 'react';
import { Link } from 'react-router-dom';
import CameraContext from '../../contexts/CameraContext';
const mcg = L.markerClusterGroup({
chunkedLoading: true,
showCoverageOnHover: false,
});
const MarkerCluster = ({ markers, icon }) => {
const { setCamera } = useContext(CameraContext);
const inserirLog = (e, camera) => {
setCamera(camera);
var ajax_log = new XMLHttpRequest();
ajax_log.open('GET', `https://fakeurl.sc.gov.br/api/ajax-log-bemtevi.php?camera=${camera.nome}&servidor=${camera.servidor}`);
ajax_log.send();
}
console.log(markers);
const map = useMap();
useEffect(() => {
mcg.clearLayers();
const markerList = markers.map((camera) => {
return L.marker(new L.LatLng(camera.latitude, camera.longitude), {
icon: icon,
}).bindPopup(
`
${camera.name} <br /> ${camera.description} <br />
<Link
to={{
pathname: "/cameraScreen",
}}
style={{ textDecoration: 'none' }}
>
<button
style={{marginTop: "1rem"}}
onClick={(e) => insertLog(e, camera)}
>Watch camera</button>
</Link>
`
);
});
mcg.addLayers(markerList);
map.fitBounds(mcg.getBounds());
map.addLayer(mcg);
}, [markers, icon, map]);
return null;
};
export default MarkerCluster;
通过这样做,我无法在 Popup 中注入 JSX,也无法使用 react-router-dom 中的 Link 组件。我也无法将相机对象保存在上下文中以在下一页中进一步使用它。所以我结束了坚持我当前的代码,尽管有这个“无法清除过去的城市标记”错误,但它仍然有效。
所以我想有一种方法可以在使用 React 组件进行 Leaflet 地图和 Marker Cluster 时清除过去的城市标记。如果有一个用于 MarkerClusterGroup 的钩子,就像有一个用于 Leaflet 地图的钩子,我想这会更容易做到:我需要做的只是一些简单的事情:
const markercluster = useMarkerClusterGroup();
markercluster.clearLayers();
但是,据我所知,react-leaflet-markercluster 中没有钩子。
您可以将 key
属性添加到 MarkerClusterGroup
,并在您希望集群完全重新渲染时更改它。
<MarkerClusterGroup
key={somekey}
spiderfyDistanceMultiplier={1}
showCoverageOnHover={false}
>
我不确定是什么逻辑触发标记发生变化,但在相同的逻辑中,当标记发生变化时,会生成一个新的唯一值(无论是递增的简单计数器,还是新的 uuid),将 key
设置为该新值,整个组件应卸载并重新安装。虽然如果有大量标记,这对性能来说不是很好,但这听起来像你想要做的。
TLDR;有没有办法使用 react-leaflet 和 react-leaflet-markercluster 清除标记簇中的所有标记?
编辑:是的,有!我刚刚向 MarkerClusterGroup 添加了一个关键道具,正如@SethLutske 所推荐的。现在,每次重新渲染地图时,以前的标记都会被删除,只剩下新的标记。
<MarkerClusterGroup
key={uuidv4()}
spiderfyDistanceMultiplier={1}
showCoverageOnHover={true}
>
我在我所在州的 Public 安全机构工作。有一个 API 从我所在州的所需城市获取监控摄像机的集合。我正在使用 React PWA 检索这些摄像头的图像,因此警方可以使用我的应用程序进行实时监控。警察对系统进行身份验证,使用表格按所在城市筛选摄像机,结果显示在地图中,地图上带有指示每个摄像机位置的标记。触摸标记时,会显示一个弹出窗口,其中包含该摄像机的信息和一个按钮,触摸时会在新页面中显示摄像机图像。
Map markers and popup
我选择 Leaflet 和 react-leaflet 进行地图渲染,并使用 react-leaflet-markercluster 对相邻的标记进行分组。我有一个小问题:如果用户按城市过滤相机,然后他 returns 填写表格并决定按不同城市过滤,我希望发生的行为是:
- 清除之前过滤掉的城市的所有标记;
- 显示当前城市的所有标记;
但实际情况是这样的:之前城市的标记保留在地图中,弹出窗口为空。
Marker groups from different cities
我的目标:我想在添加新城市的标记之前清除过去的城市标记!
这是我的 MapContainer。尽管存在我提到的错误,它运行良好。
<MapContainer
center={[-26.627817, -51.196288]}
zoom={6}
scrollWheelZoom={false}
style={{ height: '100vh', width: '100wh' }}
>
{//<ClearLayers /> this clears the entire map, even the tile layer, leaving it blank
}
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<MarkerClusterGroup
spiderfyDistanceMultiplier={1}
showCoverageOnHover={false}
>
{cameras.map((camera: Camera) => (
<Marker icon={iconBTV} key={camera.name} position={[camera.latitude, camera.longitude]}>
<Popup>
{camera.name} <br /> {camera.description} <br />
<Link
to={{
pathname: "/cameraScreen",
}}
style={{ textDecoration: 'none' }}
>
<button
style={{marginTop: "1rem"}}
onClick={(e) => insertLog(e, camera)}
>Ver câmera</button>
</Link>
</Popup>
</Marker>
))}
</MarkerClusterGroup>
</MapContainer>
我试过使用这个功能,但它没有达到我想要的效果。它会破坏地图,使其完全空白。
function ClearLayers() {
const map = useMap();
map.eachLayer(function (layer) {
map.removeLayer(layer);
});
return null
}
我在这里搜索并接近解决方案:我能够通过使用 Leaflet 的核心 API 并留下 react-leaflet-markercluster 包装器
import * as L from 'leaflet';
import 'leaflet.markercluster';
import { useMap } from 'react-leaflet';
import { useContext, useEffect } from 'react';
import { Link } from 'react-router-dom';
import CameraContext from '../../contexts/CameraContext';
const mcg = L.markerClusterGroup({
chunkedLoading: true,
showCoverageOnHover: false,
});
const MarkerCluster = ({ markers, icon }) => {
const { setCamera } = useContext(CameraContext);
const inserirLog = (e, camera) => {
setCamera(camera);
var ajax_log = new XMLHttpRequest();
ajax_log.open('GET', `https://fakeurl.sc.gov.br/api/ajax-log-bemtevi.php?camera=${camera.nome}&servidor=${camera.servidor}`);
ajax_log.send();
}
console.log(markers);
const map = useMap();
useEffect(() => {
mcg.clearLayers();
const markerList = markers.map((camera) => {
return L.marker(new L.LatLng(camera.latitude, camera.longitude), {
icon: icon,
}).bindPopup(
`
${camera.name} <br /> ${camera.description} <br />
<Link
to={{
pathname: "/cameraScreen",
}}
style={{ textDecoration: 'none' }}
>
<button
style={{marginTop: "1rem"}}
onClick={(e) => insertLog(e, camera)}
>Watch camera</button>
</Link>
`
);
});
mcg.addLayers(markerList);
map.fitBounds(mcg.getBounds());
map.addLayer(mcg);
}, [markers, icon, map]);
return null;
};
export default MarkerCluster;
通过这样做,我无法在 Popup 中注入 JSX,也无法使用 react-router-dom 中的 Link 组件。我也无法将相机对象保存在上下文中以在下一页中进一步使用它。所以我结束了坚持我当前的代码,尽管有这个“无法清除过去的城市标记”错误,但它仍然有效。
所以我想有一种方法可以在使用 React 组件进行 Leaflet 地图和 Marker Cluster 时清除过去的城市标记。如果有一个用于 MarkerClusterGroup 的钩子,就像有一个用于 Leaflet 地图的钩子,我想这会更容易做到:我需要做的只是一些简单的事情:
const markercluster = useMarkerClusterGroup();
markercluster.clearLayers();
但是,据我所知,react-leaflet-markercluster 中没有钩子。
您可以将 key
属性添加到 MarkerClusterGroup
,并在您希望集群完全重新渲染时更改它。
<MarkerClusterGroup
key={somekey}
spiderfyDistanceMultiplier={1}
showCoverageOnHover={false}
>
我不确定是什么逻辑触发标记发生变化,但在相同的逻辑中,当标记发生变化时,会生成一个新的唯一值(无论是递增的简单计数器,还是新的 uuid),将 key
设置为该新值,整个组件应卸载并重新安装。虽然如果有大量标记,这对性能来说不是很好,但这听起来像你想要做的。