react-leaflet get current latlng onClick - reactjs

I would be realy happy if some one could help me...
I've installed react-leaflet on my react project and the map component is loaded successfully, i need to get current latlng and show it in the Popup when i click on map but I don't know how to :(
please... please... help me...
this is my code
import React from 'react'
import { Map as LeafletMap, TileLayer, Marker, Popup } from 'react-leaflet';
class Mapp extends React.Component {
componentDidMount() {
}
render() {
return (
<LeafletMap
center={[35.755229,51.304470]}
zoom={16}
maxZoom={20}
attributionControl={true}
zoomControl={true}
doubleClickZoom={true}
scrollWheelZoom={true}
dragging={true}
animate={true}
easeLinearity={0.35}
>
<TileLayer
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
/>
<Marker position={[35.755229,51.304470]}
draggable={true}
>
<Popup >
Popup for any custom information.
</Popup>
</Marker>
</LeafletMap>
);
}
}
export default Mapp;

Here is an example on how to display maker position in popup once map is clicked:
class MapExample extends Component {
constructor(props) {
super(props);
this.state = {
currentPos: null
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(e){
this.setState({ currentPos: e.latlng });
}
render() {
return (
<div>
<Map center={this.props.center} zoom={this.props.zoom} onClick={this.handleClick}>
<TileLayer
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
/>
{ this.state.currentPos && <Marker position={this.state.currentPos} draggable={true}>
<Popup position={this.state.currentPos}>
Current location: <pre>{JSON.stringify(this.state.currentPos, null, 2)}</pre>
</Popup>
</Marker>}
</Map>
</div>
)
}
}
Explanation:
currentPos state is used to keep marker position
event.latLng property of Map.onClick event handler returns mouse event location
Here is a demo for your reference

What did you try to achieve that?
This will be the start:
Use the click (see https://leafletjs.com/reference-1.4.0.html#map-click) event from the LeafletMap component and call your function, like:
<LeafletMap
center={[35.755229,51.304470]}
zoom={16}
maxZoom={20}
attributionControl={true}
zoomControl={true}
doubleClickZoom={true}
scrollWheelZoom={true}
dragging={true}
animate={true}
easeLinearity={0.35}
onclick={this.handleClick}>
>
...
</LeafletMap>
In your handleClick function you get the information of lat and lng like this:
handleClick = (e) => {
const { lat, lng } = e.latlng;
console.log(lat, lng);
}
From here on, you can create your marker / popup with the information you were looking for.
Additional hint: Please make sure your code is wrapped in correctly in your post..

If you work with react-leaflet version 3.x this does not work. In this case, use the useMapEvents hook in a dummy component that you add to the map. For example, if you want to console.log the clicked position:
const LocationFinderDummy = () => {
const map = useMapEvents({
click(e) {
console.log(e.latlng);
},
});
return null;
};
Then use the LocationFinderDummy in the map as follows:
<MapContainer
center={[0, 0]}
zoom={6}>
<LocationFinderDummy />
</MapContainer>

Related

How to ref every react leaflet popup in react class component?

I have an issue, I seem not to find how to give a ref to every popup in react class component. Here's my code:
export default class LiveTracking extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
popup: React.createRef()
};
render() {
return (
<MapContainer center={[-12.576, 140.664]} zoom={5}>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{this.state.data.map((item) => (
<Marker>
<Popup ref={this.state.popup}>
<div className="popup">
<p>This is the popup</p>
</div>
</Popup>
</Marker>
))}
</MapContainer>
);
}
}
I need to give every popup a ref so I know what popup that shows and I have to close it after a click event. Or if you know how to close all popups after clicking on react-leaflet let me know. Looking forward to your help, Regards

Nextjs react-leaflet Error: Map container is already initialized

I'm using react-leaflet in a nextjs project, after dynamically loading the map component I'm getting this error Error: Map container is already initialized. I was not getting this error in plain create-react-app project, but only when we migrated the code to nextjs.
// Location.js
import { MapContainer, TileLayer, Marker, Popup, useMap } from "react-leaflet";
function ChangeMapView({ coords, zoom }) {
const map = useMap();
map.setView(coords, zoom);
return null;
}
function Location(props) {
const position = [props.lat, props.long];
return (
<MapContainer center={position} zoom={props.placeType === "city" ? 10 : 5}>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<ChangeMapView
coords={position}
zoom={props.placeType === "city" ? 10 : 5}
/>
<Marker position={position}>
<Popup>{props.city}</Popup>
</Marker>
</MapContainer>
);
}
export default Location;
Let me know if you might need more information regarding code.
const Location = dynamic(() => import("./Location"), {
ssr: false,
});
class Calculator extends React.Component {
// some code
render() {
return (
// more code
<section className="location">
<h1>Location </h1>
{this.state.selectedCity.city ? (
<Location
lat={
this.props.router.query.zip_code
? this.state.selectedCity.latitude
: this.state.selectedCity.latitude + 0.01
}
long={
this.props.router.query.zip_code
? this.state.selectedCity.longitude
: this.state.selectedCity.longitude + 0.01
}
city={
this.props.router.query.zip_code
? this.state.selectedCity.city
: this.state.stateName
}
placeType={this.props.router.query.zip_code ? "city" : "state"}
/>
) : (
""
)}
</section>
);
}
}
export default withRouter(Calculator);
(Edit): This Error doesn't come up once I downgraded to react v17. So it seems like this issue only affects react v18

Change the height and width on a google map in React js

Hi guys i am working on a small presentation project. I need make a google map with the ability to auto search location. I found a code what does all that from a tutorial but i can't change the width and the height. I need it to be small, something like: height: 200px and width: 200px.
GoogleMap.js
import React, { Component } from 'react';
import {Map, Marker, GoogleApiWrapper} from 'google-maps-react';
import PlacesAutocomplete, {
geocodeByAddress,
getLatLng,
} from 'react-places-autocomplete';
export class MapContainer extends Component {
constructor(props) {
super(props);
this.state = {
// for google map places autocomplete
address: '',
showingInfoWindow: false,
activeMarker: {},
selectedPlace: {},
mapCenter: {
lat: 49.2827291,
lng: -123.1207375
}
};
}
handleChange = address => {
this.setState({ address });
};
handleSelect = address => {
this.setState({ address });
geocodeByAddress(address)
.then(results => getLatLng(results[0]))
.then(latLng => {
console.log('Success', latLng);
// update center state
this.setState({ mapCenter: latLng });
})
.catch(error => console.error('Error', error));
};
render() {
return (
<div id='googleMaps'>
<PlacesAutocomplete
value={this.state.address}
onChange={this.handleChange}
onSelect={this.handleSelect}
>
{({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (
<div>
<input
{...getInputProps({
placeholder: 'Search Places ...',
className: 'location-search-input',
})}
/>
<div className="autocomplete-dropdown-container">
{loading && <div>Loading...</div>}
{suggestions.map(suggestion => {
const className = suggestion.active
? 'suggestion-item--active'
: 'suggestion-item';
// inline style for demonstration purpose
const style = suggestion.active
? { backgroundColor: '#fafafa', cursor: 'pointer' }
: { backgroundColor: '#ffffff', cursor: 'pointer' };
return (
<div
{...getSuggestionItemProps(suggestion, {
className,
style,
})}
>
<span>{suggestion.description}</span>
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
<Map
google={this.props.google}
initialCenter={{
lat: this.state.mapCenter.lat,
lng: this.state.mapCenter.lng
}}
center={{
lat: this.state.mapCenter.lat,
lng: this.state.mapCenter.lng
}}
>
<Marker
position={{
lat: this.state.mapCenter.lat,
lng: this.state.mapCenter.lng
}} />
</Map>
</div>
)
}
}
export default GoogleApiWrapper({
apiKey: ('_MY_API_KEY_')
})(MapContainer)
App.js
import './App.css';
import GoogleMap from './components/GoogleMap';
function App() {
return (
<div className="App">
<h1>Google Maps App</h1>
<GoogleMap />
</div>
);
}
export default App;
I have error in the console but I don't know if they are connected with this problem.
Here they are:
Warning: Using UNSAFE_componentWillReceiveProps in strict mode is not recommended and may indicate bugs in your code. See https://reactjs.org/link/unsafe-component-lifecycles for details.
Move data fetching code or side effects to componentDidUpdate.
If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state
Please update the following components: Wrapper
Warning: Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to this.state directly or define a state = {}; class property with the desired state in the Wrapper component.
index.js:1 Warning: Using UNSAFE_componentWillReceiveProps in strict mode is not recommended and may indicate bugs in your code. See https://reactjs.org/link/unsafe-component-lifecycles for details.
Move data fetching code or side effects to componentDidUpdate.
If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state
Please update the following components: Wrapper
I saw that other people had this problem also but their solutions didn't help me. Any advice is much appreciated!
You can try to wrap the map container in a div and set it's height and width using css. I think that should work
Just have a small change in div created by the script. It should work
return (
<div id='googleMaps' style="width:200px; height:200px">
<PlacesAutocomplete

How to setState of one state using the state of another state onClick

Is there a way to setState of one state with the state of another state? For example below in _updateData()...on click the geojson state gets the state of newGeojson? The goal is to be able to change the data={geojson} on click of the button (not showing the Geojson files in the example but let's say they exist in GeoJSON and newGeojson. I pull JSON from a firebase then convert it to GeoJSON in componentDidMount to create the geojson states). Thanks for the help. Hopefully, I am approaching this the right way.
import React from 'react';
import ReactMapGL, {Source, Layer} from 'react-map-gl';
class Map extends React.Component {
state = {
geojson: null,
newGeojson: null,
};
_updateData() {
// In here set the state of geojson to the state of newGeojson so the data={geojson} updates on click, something like setState{geojson} = newGeojson
}
render() {
const {geojson} = this.state;
return (
<ReactMapGL latitude={37.78} longitude={-122.41} zoom={8}>
<Source id="my-data" type="geojson" data={geojson}>
<Layer
id="point"
type="circle"
paint={{
'circle-radius': 10,
'circle-color': '#007cbf'
}} />
</Source>
<button onClick={this._updateData()}>Update</button>
</ReactMapGL>
);
}
}
Like that:
import React, { useState } from 'react';
import ReactMapGL, {Source, Layer} from 'react-map-gl';
const Map = () => {
const [geojson, setGeojson] = useState(null)
const updateData = () => {
// for example
fetch('url').then(resp => resp.json()).then(resp => {
setGeojson(resp.data)
})
}
return (
<ReactMapGL latitude={37.78} longitude={-122.41} zoom={8}>
<Source id="my-data" type="geojson" data={geojson}>
<Layer
id="point"
type="circle"
paint={{
'circle-radius': 10,
'circle-color': '#007cbf'
}} />
</Source>
<button onClick={updateData}>Update</button>
</ReactMapGL>
);
}
It's using hooks. For old syntax you probably want this.setState({geojson: newGeojson}) (https://reactjs.org/docs/react-component.html#setstate)

Pigeon Maps Marker Issue

I am trying to integrate a map in react specifically pigeon-maps since it is an open source.But,I am not able to get the co-ordinates from the map.Can anyone give me some code examples.I have set markers and overlay.I am able to center the map but have no idea how to get the latitude and longitude from the map.
Below is the code for the mapcomponent I am trying to create
import React, { Component } from "react";
import styles from "./mapcomponent.module.css";
import Marker from "pigeon-marker";
import Map from "pigeon-maps";
import Overlay from "pigeon-overlay";
class MapComponent extends Component {
constructor(props) {
super(props);
this.state = { lat: null, long: null };
}
componentWillMount() {
this.setState(
{
lat: Number(this.props.lat),
long: Number(this.props.long)
},
() => {
console.log("HERE", this.state.lat, this.state.long);
}
);
}
render() {
return (
<div className={styles.container} width="500px" height="500px">
<Map center={[this.state.lat, this.state.long]} zoom={12}>
<Marker anchor={[this.state.lat, this.state.long]} payload={1} />
<Overlay
anchor={[this.state.lat, this.state.long]}
offset={[120, 79]}
>
<img src="pigeon.jpg" width={240} height={158} alt="" />
</Overlay>
</Map>
</div>
);
}
}
export default MapComponent;
Can anyone help me to and extend marker and manipulate its value
We have to provide the latitude and longitude to plot the marker on map or you can get latitude and longitude from the map events (like onclick)

Resources