'How to change map zoom dynamically when clicking on a marker in react leaflet v.3.x?
i tried to find many things regards this but i can't make it work. what i want is when click on marker map got center on that location and got full zoom. for example i have total 23 markers on all around Unites states and initial map zoom is 4. what i want is if user click on marker in map then map center change to that marker lat, lng and got zoom in for suppose to 14 from 4. markeres are render already i don't want markers renders in function MyMapComponent. it come from API data. there is no clue how to do. i tried useMapEvents but it works on map click not marker click and if i use markers eventHandlers click i can't call map useMapEvents to set lat, lng and change zoom.
Here is my code:
function MyMapComponent() {
const map = useMapEvents({
click: () => {
let data = {lat: 46.8835319, lng: -114.0348327}
map.flyTo(data, 18)
}
})
return null}
above code is i need to change map center and zoom
<div className="project-view-section">
<MapContainer bounds={outerBounds} center={[37.2755, -104.6571]} zoom={mapOptions.zoom} scrollWheelZoom={false}>
<MyMapComponent />
<LayersControl position="topright">
<LayersControl.BaseLayer checked name="Mapbox Satellite">
<TileLayer
url={'https://api.mapbox.com/styles/v1/mapbox/satellite-v9/tiles/256/{z}/{x}/{y}@2x?access_token='+MAPBOX_TOKEN}
attribution="Map data © <a href="https://www.mapbox.com/">Mapbox</a>"
/>
</LayersControl.BaseLayer>
<LayersControl.BaseLayer name="Mapbox Streets">
<TileLayer
url={'https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/{z}/{x}/{y}@2x?access_token='+MAPBOX_TOKEN}
attribution="Map data © <a href="https://www.mapbox.com/">Mapbox</a>"
/>
</LayersControl.BaseLayer>
</LayersControl>
<MarkerClusterGroup>
{
state.markersData.map((element, index) =>
<Marker
key={index}
marker_index={index}
position={element}
icon={icon}
eventHandlers={{click: () => {test()},}}>
</Marker>
)
}
</MarkerClusterGroup>
</MapContainer>
</div>
is there any way to accomplish this?
Solution 1:[1]
You should use eventHandlers prop on Marker and listen to click event. Then use native leaflet's code: map.setView(coords, zoom)
function Markers({ data }) {
const map = useMap();
return (
data.length > 0 &&
data.map((marker, index) => {
return (
<Marker
eventHandlers={{
click: () => {
map.setView(
[
marker.geometry.coordinates[1],
marker.geometry.coordinates[0]
],
14
);
}
}}
key={index}
position={{
lat: marker.geometry.coordinates[1], // your api structure
lng: marker.geometry.coordinates[0] // your api structure
}}
icon={icon}
>
<Popup>
<span>{marker.properties.label}</span>
</Popup>
</Marker>
);
})
);
}
Use Markers comp as a MapContainer child then.
Solution 2:[2]
import React, { useState, useRef, useEffect } from 'react';
import {
MapContainer,
Marker,
Popup,
TileLayer,
useMap
} from 'react-leaflet';
import L from 'leaflet';
import { v4 as uuidv4 } from 'uuid';
import 'leaflet/dist/leaflet.css';
import { useTranslation } from 'react-i18next';
const iconMarker = new L.Icon({
iconUrl: require('../assets/images/loc.png'),
iconAnchor: [25, 50],
popupAnchor: [0, -30],
iconSize: new L.Point(50, 50),
});
function Markers({ data, isActive }) {
const map = useMap();
const [refReady, setRefReady] = useState(false);
let popupRef = useRef();
useEffect(() => {
if (refReady && isActive) {
popupRef.addTo(map);
}
}, [isActive, refReady, map]);
return (
data.length > 0 &&
data.map((marker, index) => {
return (
<Marker
key={index}
eventHandlers={{
click: () => {
map.setView([marker.latitude, marker.longitude], 16);
},
}}
position={{
lat: marker.latitude,
lng: marker.longitude,
}}
icon={iconMarker}
>
<Popup
ref={(r) => {
popupRef = r;
setRefReady(true);
}}
>
<span>{marker.name}</span>
</Popup>
</Marker>
);
})
);
}
const Map = ({ devices }) => {
const { t } = useTranslation();
const locationLati = [devices?.map((location) => location.latitude)];
const latitudeList = [...locationLati[0]];
const locationLongi = [devices?.map((location) => location.longitude)];
const longitudeList = [...locationLongi[0]];
let positionCurrent = [latitudeList[0], longitudeList[0]];
const newDevice = [...devices].reverse();
return (
<MapContainer
center={[0,0]}
zoom={12}
markerZoomAnimation={true}
>
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Markers data={newDevice} isActive />
</MapContainer>
);
};
export default Map;
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Thanh H? Ng?c |
