I currently have this map
import React, { useEffect } from "react";
import "./App.css";
import { MapContainer, TileLayer, Marker } from "react-leaflet";
function App() {
useEffect(() => {
console.log("first run");
}, []);
return (
<div className="App">
<div id="mapid">
<MapContainer
style={{ height: "100vh", width: "100vw" }}
center={[51.505, -0.09]}
zoom={13}
scrollWheelZoom={true}
>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[51.505, -0.09]}></Marker>
<Marker position={[51.490114, -0.09066]}></Marker>
</MapContainer>
</div>
</div>
);
}
export default App;
And i somehow need to find the latitude min, latitude max, longitude min, longitude max
But i cannot find how to do it with hooks / useeffect
After taking the map reference, when the component mounts, you can get the map bounds using map.getBounds(). It contains the current or the updated coordinates of southWest, southEast, northWest, northEast etc.
useEffect(() => {
if (!map) return;
console.log(map.getBounds());
}, [map]);
and if you want to take the new ones after you zoom in or out you can add a zoomend event
useEffect(() => {
if (!map) return;
console.log(map.getBounds());
map.on("zoomend", function () {
console.log(map.getBounds());
});
}, [map]);
Demo
Related
I have a project using React, react-leaflet and Framework 7. In one component I have a Fab-Button from Framework 7 and a Map from react-leaflet. My Map.jsx component looks like this:
import React, { useState } from "react";
import { MapContainer, TileLayer, useMapEvents, Marker, Popup } from "react-leaflet";
import "../css/leaflet.css";
import "../css/app.css";
import {Fab, Icon, PageContent} from "framework7-react";
export default function Map(){
function LocationMarker() {
const [position, setPosition] = useState(null)
const map = useMapEvents({
click() {
map.locate()
},
locationfound(e) {
setPosition(e.latlng)
map.flyTo(e.latlng, map.getZoom())
},
locationerror(e) {
alert("Unfortunately, we could not find your location")
}
})
return position === null ? null : (
<Marker position={position}>
<Popup>You are here</Popup>
</Marker>
)
}
function fabGoToCurrentPosition() {
//probably something like this:
map.locate()
}
return (
<>
<Fab position="right-bottom" slot="fixed" id="fab-button" onClick={() => {
fabGoToCurrentPosition()
}}>
<Icon f7="placemark_fill" ios="f7:placemark_fill" aurora="f7:placemark_fill"></Icon>
</Fab>
<PageContent className='page-content-map'>
<MapContainer center={[51.505, -0.09]} zoom={13} scrollWheelZoom={true} id="map">
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<LocationMarker/>
</MapContainer>
</PageContent>
</>
);
}
The function "LocationMarker" is from a react-leaflet tutorial and sets the position of the Map to the current location of the user if the Map is clicked. My aim is that the position is set if the user clicks the Fab-Button instead of the Map.
I'd like to ask if I'm using the map from React Leaflet (https://react-leaflet.js.org/) but how do I add the Base Map Gallery button to the map? like this example Basemap Gallery button on the image that I marked with red arrow and do I need to change or delete any of my code?
Example view of BasemapGallery but map from React-Leaflet - ReactJS:
import { React, useState, useEffect } from 'react'
import {
LayersControl,
MapContainer,
TileLayer,
Marker,
Popup,
useMapEvents,
} from 'react-leaflet'
import List from '../Component/List'
import L from 'leaflet'
import SearchControl from './SearchControl'
const { BaseLayer } = LayersControl
function LocationMarker() {
const [position, setPosition] = useState(null)
const map = useMapEvents({
locationfound(e) {
setPosition(e.latlng)
map.flyTo(e.latlng, map.getZoom())
},
})
return position === null ? null : (
<Marker position={position}>
<Popup>Location Me</Popup>
</Marker>
)
}
function MyLocationMe() {
const [map, setMap] = useState(null)
const [position, setPosition] = useState(null)
useEffect(() => {
if (!map) return
L.easyButton('fa-map-marker', () => {
map.locate().on('locationfound', function (e) {
setPosition(e.latlng)
map.flyTo(e.latlng, map.getZoom())
})
}).addTo(map)
}, [map])
return (
<div className="flex ml-auto">
<List />
<div className="w-4/5">
<MapContainer
center={{ lat: 51.505, lng: -0.09 }}
zoom={20}
style={{ height: '100vh' }}
whenCreated={setMap}
>
<SearchControl className="MarkerIcon" position="topright" />
<LayersControl position="topleft">
<BaseLayer checked name="OpenStreetMap">
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png "
/>
</BaseLayer>
</LayersControl>
<LocationMarker />
</MapContainer>
</div>
</div>
)
}
export default MyLocationMe
Example view of BasemapGallery but map from React-Leaflet - ReactJS:
Images
I'd like to ask if I'm using the map from React Leaflet (https://react-leaflet.js.org/) but how do I add the Base Map Gallery button to the map? like this example Basemap Gallery button on the image that I marked with red arrow.
And pictures in the link:
Example of an arrow Basemap Gallery
An example on my map where I want to add Basemap Gallery
And how to show the Basemap Gallery button, where do you save it from my coding?
import { React, useState, useEffect } from 'react'
import {
LayersControl,
MapContainer,
TileLayer,
Marker,
Popup,
useMapEvents,
} from 'react-leaflet'
import L from 'leaflet'
import 'leaflet-easybutton/src/easy-button'
import 'leaflet-easybutton/src/easy-button.css'
import 'font-awesome/css/font-awesome.min.css'
const { BaseLayer } = LayersControl;
export default function MyMaps() {
const [map, setMap] = useState(null);
const [position, setPosition] = useState(null);
useEffect(() => {
if (!map) return;
L.easyButton("fa-map-marker", () => {
map.locate().on("locationfound", function (e) {
setPosition(e.latlng);
map.flyTo(e.latlng, map.getZoom());
});
}).addTo(map);
}, [map]);
return (
<div className="flex ml-auto">
<div className="w-4/5">
<MapContainer
center={[51.505, -0.09]}
zoom={20}
style={{ height: "100vh" }}
whenCreated={setMap}
>
<LayersControl>
<BaseLayer checked name="OpenStreetMap">
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png "
/>
</BaseLayer>
</LayersControl>
</MapContainer>
</div>
</div>
);
}
I am unable to set view of the map for the input IP address while the Marker can move to the new location on the map for given input IP address. Map seems to stay at initial location whereas the Marker moves to new location.
So, When I type in a new IP address in input, it should change the map to a new location.
import React, { useEffect, useState} from "react";
import Result from "../src/Components/Result";
import {MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
function App() {
const APP_KEY = PERSONAL_KEY;
const [IPdata, SetIPData] = useState([]);
const [search, setSearch] = useState("");
const [query, setQuery] = useState("8.8.8.8");
const [loaded, setLoaded] = useState(false);
useEffect(() => {
getIp();
setLoaded(true);
}, [query]);
async function getIp() {
const response = await fetch(`https://geo.ipify.org/api/v1?apiKey=${APP_KEY}&ipAddress=${query}`);
const data = await response.json();
console.log(data);
SetIPData(data)
}
function handleChange(event) {
setSearch(event.target.value);
console.log(event.target.value);
}
function handleSubmit(event) {
event.preventDefault();
setQuery(search);
setSearch('');
}
return (
loaded ? (
<div>
<div className="container">
<div className="input-section">
<h1 className="header"> IP Address Tracker</h1>
<form onSubmit={handleSubmit} className="search-form">
<input className="search-input" type="text" placeholder="Search for any IP address or domain" onChange={handleChange} />
<button className="search-button" type="submit"> Go! </button>
</form>
</div>
<div className="result-container">
<Result
heading={"IP Address"}
searchResult={IPdata.ip}
/>
<Result
heading={"Location"}
searchResult={IPdata?.location?.country}
/>
<Result
heading={"Timezone"}
searchResult={"UTC" + IPdata?.location?.timezone}
/>
<Result
heading={"ISP"}
searchResult={IPdata.isp}
/>
</div>
</div>
{IPdata.location && (
<MapContainer
center={[IPdata.location?.lat, IPdata.location?.lng]}
zoom={13}
scrollWheelZoom={true}
>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[IPdata?.location?.lat, IPdata?.location?.lng]}>
<Popup>Your IP Location</Popup>
</Marker>
</MapContainer>
)
}
</div>) : <p>Loading...</p>
)
}
export default App;
You cannot change the center with state because of this...
Except for its children, MapContainer props are immutable: changing
them after they have been set a first time will have no effect on the
Map instance or its container.
However, I believe it may work if you add a key prop. You can try to see if it works.
<MapContainer
center={[IPdata.location?.lat, IPdata.location?.lng]}
zoom={13}
scrollWheelZoom={true}
key={`${IPdata.location?.lat}${IPdata.location?.lng}`}
>
Updated: There's another solution provided here using setView -> React leaflet center attribute does not change when the center state changes
function ChangeView({ center, zoom }) {
const map = useMap();
map.setView(center, zoom);
return null;
}
function Map({ center, zoom }) {
return (
<div className="map">
<MapContainer center={center} zoom={zoom} scrollWheelZoom={false}>
<ChangeView center={center} zoom={zoom} />
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='© OpenStreetMap contributors'
/>
</MapContainer>
</div>
);
}
I'm using Leaflet i want to show an alert that shows latlng of the clicked location
I followed document steps in here https://leafletjs.com/examples/quick-start/
I've tried this
var mymap = L.map('mapid').setView([51.505, -0.09], 13);
function onMapClick(e) { //THE FUNCTION
alert("You clicked the map at " + e.latlng);
}
mymap.on('click', onMapClick);
and at <MapContainer> i defined it like
<MapContainer id="mapid" onClick={onMapClick}/>
but it shows nothing
here is the whole code
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet'
import React, { Component } from 'react';
import L from 'leaflet'
class UserMap extends Component {
render() {
var mymap = L.map('mapid').setView([51.505, -0.09], 13);
function onMapClick(e) {
alert("You clicked the map at " + e.latlng);
}
mymap.on('click', onMapClick);
return (
<div
id="mapid" style={{ height: '100%', width: '100%' }}>
<MapContainer
id="mapid"
center={[30.794900, 50.564580]}
zoom={13}
zoomOffset={1}
boxZoom={false}
scrollWheelZoom={true}
style={{ height: '500px', width: '100%' }}>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker
position={[30.794900, 50.564580]}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer></div>
);
}
}
export default UserMap;
onClick is not working anymore, instead you should use the useMapEvents hook (https://react-leaflet.js.org/docs/api-map/#usemapevents).
Basically, you have to create a component with the useMapEvents hook which will listen to the click and call this component in your MapContainer.
Add the following code inside your MapContainer to fix your issue:
function MyComponent() {
useMapEvents({
click(e){
alert(e.latlng)
}
})
}