如何使用 useMapEvents 将视图集中到新标记?
How to center view to new Markers with useMapEvents?
让我总结一下我正在开发的应用程序:
我正在创建一个 React 应用程序,用于根据您的年龄、性别和您居住的城市寻找足球俱乐部。
目前它工作正常,但我希望地图在新标记出现在结果中时将视图居中。
我读到我们必须在 MapContainer 上使用 {WhenCreated} 初始化中心,并使用 useMapEvents 来处理视图的更新,但我无法嵌套它或者我失去了我的范围标记数组..
这是我的代码:
import React, { useState, useEffect } from "react";
import Header from "../header/Header";
import "./Moible3.css";
import { MapContainer, TileLayer, Marker, Popup, useMapEvents } from "react-leaflet";
import TextField from "@mui/material/TextField";
import Autocomplete from "@mui/material/Autocomplete";
import FormControlLabel from "@mui/material/FormControlLabel";
import FormControl from "@mui/material/FormControl";
import Radio from "@mui/material/Radio";
import RadioGroup from "@mui/material/RadioGroup";
import btnPicture from "../../assets/Boutons/buttontransparent.png";
import axios from "axios";
import Geolocalisation from "../Hook/Geolocalisation";
import MarkerClusterGroup from "react-leaflet-markercluster";
import Footer from '../../components/Footer/Footer.jsx';
import L from "leaflet";
function Mobile3() {
const [allcities, setallcities] = useState([]);
const [categories, setCategories] = useState([]);
const [allteams, setallTeams] = useState([]);
const [clubSearch, setclubSearch] = useState([]);
const [formData, setformData] = useState({
age: null,
city: "",
type: 'Libre',
gender2: '',
category: "",
})
const filterSearch = (e) => {
e.preventDefault();
let categorieWanted = categories.filter(
(categorySelected) =>
(formData.gender2 === categorySelected.gender
&& formData.age >= categorySelected.minAge && formData.age <= categorySelected.maxAge && formData.type === categorySelected.type))
const resultofSearch = allteams.filter((clubWanted) =>
clubWanted.Category === categorieWanted[0].name && clubWanted.Localite === formData.city);
setclubSearch(resultofSearch);
console.log(resultofSearch)}
const handleChange = (e) => {
setformData({ ...formData, [e.target.name]: e.target.value })
}
useEffect(() => {
axios.get("https://api-clubs-cvl.herokuapp.com/cities")
.then((res) => {
let result = [];
res.data.forEach(element => {
result.push({ label: element.name })
});
setallcities(result)
})
}, []);
useEffect(() => {
axios.get("https://api-clubs-cvl.herokuapp.com/categories")
.then((res) => setCategories(res.data))
}, [])
useEffect(() => {
axios.get("https://api-clubs-cvl.herokuapp.com/allteams").then((res) => setallTeams(res.data))
}, [])
return (
<div className="fullPage">
<Header />
<div className="subContainer">
<h1 className="titlePart1">Trouvez un club près </h1>
<h1 className="titlePart2">de chez vous ! </h1>
<main className="mapContainer">
<MapContainer
className="mapLeaflet"
center={[48.856614, 2.3522219]}
zoom={13}
scrollWheelZoom={true}
doubleClickZoom={true}
zoomControl={true}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Geolocalisation />
<MarkerClusterGroup
animate={true}
onClusterClick={(cluster) =>
console.warn(
"cluster-click",
cluster,
cluster.layer.getAllChildMarkers()
)
}
>
{clubSearch.length !== 0 ?
clubSearch.slice(0, 100).map((res, index2) => {
return (
<Marker key={index2} position={[res.Latitude, res.Longitude]} >
<Popup key={index2}>
<p> {res.Club}</p>
</Popup>
</Marker>)
})
: null
}
</MarkerClusterGroup>
</MapContainer>
</main>
<div className="legendAndForm">
<section className="legendMap">
<p className="legend">
Entrez votre <em className="birthday">date de naissance </em>et la{" "}
<em className="ranked"> compétition </em> souhaitée pour découvrir
les clubs à proximité !{" "}
</p>
</section>
<div className="filtrations">
<form className="filtrationsWrapper" onSubmit={(e) => filterSearch(e)}>
<div className="filtre1">
<span className="filterTitle1">VOTRE ÂGE </span>
<TextField
label="Âge"
type="number"
margin="normal"
name="age"
onChange={(e) => { handleChange(e) }}
helperText="Renseingez votre aĝe ici"
focused
inputProps={{
inputMode: "numeric",
pattern: "[0-9]*",
placeholder: "10, 15, 30...",
}}
/>
</div>
<div className="filtre2">
<FormControl component="fieldset">
<span className="filterTitle2">COMPETITION :</span>
<RadioGroup
row
aria-label="gender"
defaultValue="female"
name="gender2"
error="Vous devez renseigner une compétition"
onChange={(e) => handleChange(e)}
required={true}
>
<FormControlLabel
value="Male"
className="radio1"
control={<Radio />}
label="Masculine"
/>
<FormControlLabel
className="radio1"
value="Female"
control={<Radio />}
label="Feminine"
/>
</RadioGroup>
</FormControl>
</div>
<div className="filtre3">
<span className="filterTitle3"> VOTRE VILLE </span>
<Autocomplete
disablePortal
id="combo-box-demo"
inputValue={formData.city}
options={allcities}
noOptionsText="Pas d'élement correspondant"
onInputChange={(event, newInputValue) => {
setformData({ ...formData, city: newInputValue });
}}
sx={{ width: 250 }}
renderInput={(params) => (
<TextField {...params} label="Rechercher" />
)}
/>
<div className="hiddenSearchResult" id='hidden'>
<p className="resultError"> Nique ta mère</p>
</div>
</div>
<div className="btnContainer" id='test'>
<button className="btnBackground" type="submit">
<img
className="findclubBtn"
alt="trouvez votre club"
src={btnPicture}
/>
</button>
</div>
</form>
</div>
<div className="resul">
{clubSearch.length !==0 ?
clubSearch.map((clubSelected, Uniqueindex) => {
return (
<div className="cardResult" key={Uniqueindex}>
<div className="titleContainer">
<span className="titleCard">
{clubSelected.name}
</span>
</div>
<div className="columnContainer">
<div className="column1">
<div className="logo1"></div>
<div className="logo2"></div>
<div className="logo3"></div>
</div>
<div className="column2">
<div className="info1"> {clubSelected.Mail}</div>
<div className="info2">{clubSelected.Adresse}</div>
<div className="info3">Voir plus d'infos</div>
</div>
</div>
</div>)
})
: null }
</div>
</div>
<Footer/>
</div>
</div>
);
}
export default Mobile3;
您可以在这里找到要点:https://gist.github.com/ManuelWCS/4e67a75fc9a1053ed6f1ff095225ea0c
如果您想观看演示,请单击 here
感谢您的阅读,如果您有任何问题或解决方案,请联系我!
:)
你不需要useMapEvents
。您也可以仅使用地图实例来完成此操作。
首先使用whenCreated
prop获取地图实例
在 filterSearch
函数中检查两种情况。如果 resultofSearch 数组为空且没有可用位置,那么您需要 return 并发出警报。
否则,使用可用标记中的所有坐标并围绕所有这些坐标缩放地图。您可以使用 fitBounds Leaflet 方法实现。
const [map, setMap] = useState(null);
...
<MapContainer whenCreated={setMap} />
...
const filterSearch = (e) => {
...
if (resultofSearch.length === 0)
return alert("There are no available locations");
const arrayOfLatLngs = resultofSearch.map(({ Latitude, Longitude }) => [
Latitude,
Longitude
]);
const bounds = L.latLngBounds(arrayOfLatLngs);
if (map) map.fitBounds(bounds);
}
Demo 包含您的部分应用程序
让我总结一下我正在开发的应用程序:
我正在创建一个 React 应用程序,用于根据您的年龄、性别和您居住的城市寻找足球俱乐部。
目前它工作正常,但我希望地图在新标记出现在结果中时将视图居中。
我读到我们必须在 MapContainer 上使用 {WhenCreated} 初始化中心,并使用 useMapEvents 来处理视图的更新,但我无法嵌套它或者我失去了我的范围标记数组..
这是我的代码:
import React, { useState, useEffect } from "react";
import Header from "../header/Header";
import "./Moible3.css";
import { MapContainer, TileLayer, Marker, Popup, useMapEvents } from "react-leaflet";
import TextField from "@mui/material/TextField";
import Autocomplete from "@mui/material/Autocomplete";
import FormControlLabel from "@mui/material/FormControlLabel";
import FormControl from "@mui/material/FormControl";
import Radio from "@mui/material/Radio";
import RadioGroup from "@mui/material/RadioGroup";
import btnPicture from "../../assets/Boutons/buttontransparent.png";
import axios from "axios";
import Geolocalisation from "../Hook/Geolocalisation";
import MarkerClusterGroup from "react-leaflet-markercluster";
import Footer from '../../components/Footer/Footer.jsx';
import L from "leaflet";
function Mobile3() {
const [allcities, setallcities] = useState([]);
const [categories, setCategories] = useState([]);
const [allteams, setallTeams] = useState([]);
const [clubSearch, setclubSearch] = useState([]);
const [formData, setformData] = useState({
age: null,
city: "",
type: 'Libre',
gender2: '',
category: "",
})
const filterSearch = (e) => {
e.preventDefault();
let categorieWanted = categories.filter(
(categorySelected) =>
(formData.gender2 === categorySelected.gender
&& formData.age >= categorySelected.minAge && formData.age <= categorySelected.maxAge && formData.type === categorySelected.type))
const resultofSearch = allteams.filter((clubWanted) =>
clubWanted.Category === categorieWanted[0].name && clubWanted.Localite === formData.city);
setclubSearch(resultofSearch);
console.log(resultofSearch)}
const handleChange = (e) => {
setformData({ ...formData, [e.target.name]: e.target.value })
}
useEffect(() => {
axios.get("https://api-clubs-cvl.herokuapp.com/cities")
.then((res) => {
let result = [];
res.data.forEach(element => {
result.push({ label: element.name })
});
setallcities(result)
})
}, []);
useEffect(() => {
axios.get("https://api-clubs-cvl.herokuapp.com/categories")
.then((res) => setCategories(res.data))
}, [])
useEffect(() => {
axios.get("https://api-clubs-cvl.herokuapp.com/allteams").then((res) => setallTeams(res.data))
}, [])
return (
<div className="fullPage">
<Header />
<div className="subContainer">
<h1 className="titlePart1">Trouvez un club près </h1>
<h1 className="titlePart2">de chez vous ! </h1>
<main className="mapContainer">
<MapContainer
className="mapLeaflet"
center={[48.856614, 2.3522219]}
zoom={13}
scrollWheelZoom={true}
doubleClickZoom={true}
zoomControl={true}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Geolocalisation />
<MarkerClusterGroup
animate={true}
onClusterClick={(cluster) =>
console.warn(
"cluster-click",
cluster,
cluster.layer.getAllChildMarkers()
)
}
>
{clubSearch.length !== 0 ?
clubSearch.slice(0, 100).map((res, index2) => {
return (
<Marker key={index2} position={[res.Latitude, res.Longitude]} >
<Popup key={index2}>
<p> {res.Club}</p>
</Popup>
</Marker>)
})
: null
}
</MarkerClusterGroup>
</MapContainer>
</main>
<div className="legendAndForm">
<section className="legendMap">
<p className="legend">
Entrez votre <em className="birthday">date de naissance </em>et la{" "}
<em className="ranked"> compétition </em> souhaitée pour découvrir
les clubs à proximité !{" "}
</p>
</section>
<div className="filtrations">
<form className="filtrationsWrapper" onSubmit={(e) => filterSearch(e)}>
<div className="filtre1">
<span className="filterTitle1">VOTRE ÂGE </span>
<TextField
label="Âge"
type="number"
margin="normal"
name="age"
onChange={(e) => { handleChange(e) }}
helperText="Renseingez votre aĝe ici"
focused
inputProps={{
inputMode: "numeric",
pattern: "[0-9]*",
placeholder: "10, 15, 30...",
}}
/>
</div>
<div className="filtre2">
<FormControl component="fieldset">
<span className="filterTitle2">COMPETITION :</span>
<RadioGroup
row
aria-label="gender"
defaultValue="female"
name="gender2"
error="Vous devez renseigner une compétition"
onChange={(e) => handleChange(e)}
required={true}
>
<FormControlLabel
value="Male"
className="radio1"
control={<Radio />}
label="Masculine"
/>
<FormControlLabel
className="radio1"
value="Female"
control={<Radio />}
label="Feminine"
/>
</RadioGroup>
</FormControl>
</div>
<div className="filtre3">
<span className="filterTitle3"> VOTRE VILLE </span>
<Autocomplete
disablePortal
id="combo-box-demo"
inputValue={formData.city}
options={allcities}
noOptionsText="Pas d'élement correspondant"
onInputChange={(event, newInputValue) => {
setformData({ ...formData, city: newInputValue });
}}
sx={{ width: 250 }}
renderInput={(params) => (
<TextField {...params} label="Rechercher" />
)}
/>
<div className="hiddenSearchResult" id='hidden'>
<p className="resultError"> Nique ta mère</p>
</div>
</div>
<div className="btnContainer" id='test'>
<button className="btnBackground" type="submit">
<img
className="findclubBtn"
alt="trouvez votre club"
src={btnPicture}
/>
</button>
</div>
</form>
</div>
<div className="resul">
{clubSearch.length !==0 ?
clubSearch.map((clubSelected, Uniqueindex) => {
return (
<div className="cardResult" key={Uniqueindex}>
<div className="titleContainer">
<span className="titleCard">
{clubSelected.name}
</span>
</div>
<div className="columnContainer">
<div className="column1">
<div className="logo1"></div>
<div className="logo2"></div>
<div className="logo3"></div>
</div>
<div className="column2">
<div className="info1"> {clubSelected.Mail}</div>
<div className="info2">{clubSelected.Adresse}</div>
<div className="info3">Voir plus d'infos</div>
</div>
</div>
</div>)
})
: null }
</div>
</div>
<Footer/>
</div>
</div>
);
}
export default Mobile3;
您可以在这里找到要点:https://gist.github.com/ManuelWCS/4e67a75fc9a1053ed6f1ff095225ea0c
如果您想观看演示,请单击 here
感谢您的阅读,如果您有任何问题或解决方案,请联系我!
:)
你不需要useMapEvents
。您也可以仅使用地图实例来完成此操作。
首先使用whenCreated
prop获取地图实例
在 filterSearch
函数中检查两种情况。如果 resultofSearch 数组为空且没有可用位置,那么您需要 return 并发出警报。
否则,使用可用标记中的所有坐标并围绕所有这些坐标缩放地图。您可以使用 fitBounds Leaflet 方法实现。
const [map, setMap] = useState(null);
...
<MapContainer whenCreated={setMap} />
...
const filterSearch = (e) => {
...
if (resultofSearch.length === 0)
return alert("There are no available locations");
const arrayOfLatLngs = resultofSearch.map(({ Latitude, Longitude }) => [
Latitude,
Longitude
]);
const bounds = L.latLngBounds(arrayOfLatLngs);
if (map) map.fitBounds(bounds);
}
Demo 包含您的部分应用程序