問題描述
TLDR;有沒有辦法使用 react-leaflet 和 react-leaflet-markercluster 從標(biāo)記簇中清除所有標(biāo)記?
是的,有!我剛剛向 MarkerClusterGroup 添加了一個(gè)關(guān)鍵道具,正如@SethLutske 推薦的那樣.現(xiàn)在,每次重新渲染地圖時(shí),之前的標(biāo)記都會(huì)被移除,只保留新的標(biāo)記.
Yes, there is! I just added a key prop to the MarkerClusterGroup, as @SethLutske recommended. Now, every time there is a re-render of the map, the previous markers are removed and only the new ones remain.
<MarkerClusterGroup
key={uuidv4()}
spiderfyDistanceMultiplier={1}
showCoverageOnHover={true}
>
我在我所在州的公安機(jī)關(guān)工作.有一個(gè) API 可以從我所在州的所需城市獲取監(jiān)控?cái)z像頭的集合.我正在使用 React PWA 來檢索這些攝像頭的圖像,因此警察可以使用我的應(yīng)用程序進(jìn)行實(shí)時(shí)監(jiān)控.警察在系統(tǒng)中進(jìn)行身份驗(yàn)證,使用表格按城市過濾攝像機(jī),結(jié)果顯示在地圖中,地圖上帶有指示每個(gè)攝像機(jī)位置的標(biāo)記.觸摸標(biāo)記時(shí),會(huì)顯示一個(gè)彈出窗口,其中包含該攝像機(jī)的信息,以及一個(gè)按鈕,觸摸時(shí)會(huì)在新頁面中顯示攝像機(jī)圖像.
I work in the Public Security agency of my state. There is an API that gets a collection of monitoring cameras from a desired city of my State. I'm working in a React PWA that retrieves the image of these cameras, so the police can use my app for live monitoring. The policemen authenticate into the system, filter the cameras by their city using a form, and the result is shown in a map with markers that indicate the position of each camera. When touching a marker, a popup is shown with information of that camera and a button that shows the camera image in a new page when touched.
地圖標(biāo)記和彈出窗口
我選擇 Leaflet 和 react-leaflet 進(jìn)行地圖渲染,并選擇 react-leaflet-markercluster 來對(duì)彼此相鄰的標(biāo)記進(jìn)行分組.我有一個(gè)小問題:如果用戶按城市過濾相機(jī),然后他返回表單并決定按不同城市過濾,我想要發(fā)生的行為是:
I chose Leaflet and react-leaflet for the map rendering, and react-leaflet-markercluster to group the markers that are next each other. I'm having a little problem: if an user filters cameras by a city, then he returns to the form and decides to filter by a different city, the behavior that I wanted to happen is:
- 清除上一個(gè)被過濾城市的所有標(biāo)記;
- 顯示當(dāng)前城市的所有標(biāo)記;
但發(fā)生的情況是:前一個(gè)城市的標(biāo)記仍保留在地圖中,彈出窗口為空.
But what happens is this: the markers from the previous city remain in the map, with an empty popup.
不同城市的標(biāo)記組
我的目標(biāo):我想在添加新城市的標(biāo)記之前清除過去的城市標(biāo)記!
這是我的 MapContainer.盡管存在我提到的錯(cuò)誤,但它運(yùn)行良好.
Here is how it is my MapContainer. It is working quite well, despite of the bug I mentioned.
<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 camera</button>
</Link>
</Popup>
</Marker>
))}
</MarkerClusterGroup>
</MapContainer>
我嘗試使用此功能,但它沒有按我的意愿工作.它會(huì)破壞地圖,使其完全空白.
I tried using this function, but it doesn't work as I wanted. It bugs the map, leaving it completely blank.
function ClearLayers() {
const map = useMap();
map.eachLayer(function (layer) {
map.removeLayer(layer);
});
return null
}
我在這里搜索并接近解決方案:我能夠通過使用 Leaflet 的核心 API 并留下 react-leaflet-markercluster 包裝器來清除過去的城市標(biāo)記 如本答案所示.在向 MCG 添加新標(biāo)記之前,我確實(shí)執(zhí)行了 clearLayers(),這樣就可以了.這是我嘗試做的:
I've searched in here and came close to a resolution: I was able to clear the past city markers by using Leaflet's core API and leaving behind react-leaflet-markercluster wrapper as shown in this answer. I do execute clearLayers() before adding new markers to the MCG, and that does the trick. Here's what I tried to do:
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 組件.我也無法將相機(jī)對(duì)象保存在上下文中以在下一頁中進(jìn)一步使用它.所以我結(jié)束了堅(jiān)持我當(dāng)前的代碼,這是有效的,盡管有這個(gè)無法清除過去的城市標(biāo)記".錯(cuò)誤.
By doing that, I can't inject JSX inside the Popup, and can't use the Link component from react-router-dom. I also couldn't save the camera object in a context to use it further in the next page. So I ended sticking to my current code, that is working, despite of having this "can't clear past city markers" bug.
所以我想在使用 React 組件用于 Leaflet 地圖和 Marker Cluster 時(shí)有一種方法可以清除過去的城市標(biāo)記.如果 MarkerClusterGroup 有一個(gè)鉤子,就像 Leaflet 地圖有一個(gè)鉤子一樣,我想這會(huì)更容易做到:我需要做的就是這樣簡單的事情:
So I'd like to have a way to clear the past city markers when using the React components for Leaflet map and Marker Cluster. If there was a hook for the MarkerClusterGroup like there is one for the Leaflet map, I guess this would be easier to do: all I would need to do is something simple as this:
const markercluster = useMarkerClusterGroup();
markercluster.clearLayers();
但是,據(jù)我所知,react-leaflet-markercluster 中沒有鉤子.
But, as long as I know, there aren't hooks in react-leaflet-markercluster.
推薦答案
你可以在 MarkerClusterGroup
中添加一個(gè) key
屬性,當(dāng)你希望集群成為完全重新渲染.
You can add a key
prop to MarkerClusterGroup
, and change it when you want the cluster to be completely rerendered.
<MarkerClusterGroup
key={somekey}
spiderfyDistanceMultiplier={1}
showCoverageOnHover={false}
>
我不確定是什么邏輯觸發(fā)了標(biāo)記的更改,但在相同的邏輯中,當(dāng)標(biāo)記更改時(shí),會(huì)生成一個(gè)新的唯一值(無論是遞增的簡單計(jì)數(shù)器,還是新的 uuid),將 key
設(shè)置為該新值,整個(gè)組件應(yīng)卸載并重新安裝.雖然如果有大量標(biāo)記,這對(duì)性能來說并不是很好,但這聽起來像是您正在嘗試做的事情.
I'm not sure what logic is triggering the markers to change, but within that same logic, when the markers change, generate a new unique value (whether its a simple counter that increments, or a new uuid), set the key
to that new value, and the entire component should unmount and remount. While this isn't great for performance if there are a huge number of markers, it sounds like what you're trying to do.
這篇關(guān)于react-leaflet:在渲染新標(biāo)記之前清除標(biāo)記簇的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!