google map shows random location as center, even when center is specified - reactjs

I'm using the package google-maps-react to show gmaps in my react app. Everything works fine, except for the fact that the map initially shows a random location as the center, even when I've specified co-ordinates for the center and initial center. How can I fix this so that the map centers on the co-ordinates I've specified initially?
const MapContainer = React.memo((props) => {
const [map, setMap] = useState();
const [center, setCenter] = useState({ lat: 59.913, lng: 10.752 });
var bounds = new props.google.maps.LatLngBounds();
const setMapObj = (mapProps, map) => {
setMap(map);
};
useDeepCompareEffect(() => {
if (props.markers.length === 1) {
setCenter(props.markers[0]);
}
for (var i = 0; i < props.markers.length; i++) {
bounds.extend(
new props.google.maps.LatLng(props.markers[i].lat, props.markers[i].lng)
);
}
if (map) {
map.fitBounds(bounds);
}
}, [props.markers, map]);
return (
<div className={props.className}>
{/* TODO -> Store api key in .env file */}
{console.log(center)}
<Map
google={props.google}
style={{ borderRadius: "10px" }}
center={center}
initialCenter={center}
onReady={setMapObj}
zoom={4}
bounds={bounds}
>
{props.markers.map((item, index) => {
if (item.lat && item.lng)
return (
<Marker key={index} position={{ lat: item.lat, lng: item.lng }} />
);
})}
</Map>
</div>
);
});

Your code is trying to set a center AND fit a particular bounds. The latter will cause the center to change in order to fit all of the markers in the viewport.

Related

Need To back draggable marker's lat and lang to the main page from where it called

I want to work with draggable marker to collect lat and lang and after marker moving, want to take lat and lng from select using marker. My googlemap react js code is
class GoogleMaps extends Component {
constructor(props) {
super(props);
this.getLangLat = this.getLangLat.bind(this);
}
loadMap = (map, maps) => {
let marker = new maps.Marker({
position: { lat: 40.856795, lng: -73.954298 },
map,
draggable: true
});
};
getLangLat(e) {
//this.lat = e
console.log("Lat",e.lat);
console.log("Lng",e.lng);
this.lat = e.lat
this.lng = e.lng
// this.props.lat = e.lat;
//this.props.lng = e.lng;
}
render() {
return (
<div style={{ height: "400px", width: "400px" }}>
<GoogleMapReact
bootstrapURLKeys={{ key: "xxxxxxx" }}
defaultCenter={{ lat: 40.756795, lng: -73.954298 }}
defaultZoom={10}
onClick={this.getLangLat}
yesIWantToUseGoogleMapApiInternals
onGoogleApiLoaded={({ map, maps }) => this.loadMap(map, maps)}
/>
</div>
);
}
}
export default GoogleMaps;
My another page, from where is called
import GoogleMaps from './GoogleMaps';
const SignUp = ({ handleChange, newState, alert }) => {
return(
<GoogleMaps></GoogleMaps>
)
}
How can I get lang and lat from draggable marker in google map? In react Js

Google Maps fitBounds not centering and showing markers in google-maps-react

I'm using google-maps-react in my react app to use GMaps. This is the code I got:
function MapContainer(props) {
var bounds = new props.google.maps.LatLngBounds();
const [markers, setMarkers] = useState([
{
lat: 55.378,
lng: 3.436
},
{
lat: 37.0902,
lng: 95.712
}
]);
const adjustMap = (mapProps, map) => {
const { google } = mapProps;
markers.forEach(marker => {
bounds.extend(new google.maps.LatLng(marker.lat, marker.lng));
});
map.fitBounds(bounds);
}
return (
<>
<div className={props.className}>
<Map
google={props.google}
style={{ borderRadius: '10px'}}
zoom={7}
onReady={adjustMap}
bounds={bounds}
initialCenter={{ lat: 47.444, lng: -122.176}}
>
{
markers.map((item) => {
return (
<Marker position={{lat: item.lat, lng: item.lng}}/>
)
})
}
</Map>
</div>
<button onClick={(e) => { e.preventDefault(); const newMap = [...markers, {lat: 59.913, lng: 10.752}]; setMarkers(newMap)}}>Add marker</button>
</>
);
}
So initially, the map is centered properly, as it shows the two markers. But when I click on the button to add another marker, it just shows a random area where none of the markers are visible.
I referred to what tidyline suggested in this thread modified it slightly to fix the errors, but that didn't work. - https://github.com/fullstackreact/google-maps-react/issues/63
How can I fix this to show all the markers when other markers are added?
There are two issues going on:
onReady={adjustMap} will only execute once and not after adding more markers
you click handler sets a hard coded location for the marker and the bounds of the map is not updated with this new marker. maybe call adjustMap from the handler?

How can implement react-google-maps DirectionsRenderer in my project

I am building a simple project that if a user clicks a button it should show directions from the user's location to the destination which I mark. Here is my code.
I have just implemented some parts but I did not understand how to implement DirectionsRenderer and could not learn from articles, docs. Now I have no idea what to do. Can anyone explain me in a easier way? Thank you!
GoogleMap,
withGoogleMap,
withScriptjs,
DirectionsRenderer,
} from 'react-google-maps';
import Marker from 'react-google-maps/lib/components/Marker';
function Map() {
return (
<div className='App'>
<GoogleMap
defaultZoom={10}
defaultCenter={{ lat: 51.507351, lng: -0.127758 }}
>
<Marker position={{ lat: 51.4666, lng: -0.213 }} />
</GoogleMap>
</div>
);
}
const DirectionsService = new window.google.maps.DirectionsService();
DirectionsService.route({
origin: new window.google.maps.LatLng(41.85073, -87.65126),
destination: new window.google.maps.LatLng(41.85258, -87.65141),
travelMode: window.google.maps.TravelMode.DRIVING,
});
const WrappedMap = withScriptjs(withGoogleMap(Map));
function App() {
return (
<div style={{ width: '100vw', height: '100vh' }}>
<WrappedMap
googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${process.env.REACT_APP_MAP_KEY}`}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100%` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
export default App;
Here are the steps I made to achieve your use-case:
Use the browser's HTML5 Geolocation feature to get the user's current position inside the componentDidMount.
Then use state variables to hold the value of the current location. You also put the value of the user current location state to center parameter of your GoogleMap object so that the map will show the area of the map where the user is. This will be used as the origion of your Directions service.
3.Also use another state to hold the user current location. This is to be used as state to put a marker in the user current location.
Call a function inside the onClick parameter of your GoogleMap object. Then use another state variable that will hold the value of the clicked coordinates. This will be used as the destination of the Directions Service.
Put a button on top of your map div and call a function inside its OnClick parameter.The function will call the GoogleMaps directionsService and will calculate a route between your origin and destination. If there's a route, you use another state variable to hold the result of the Directions service.
Use the DirectionsRenderer object inside the GoogleMap object to display the polyline of the route.
Here's the sample code (Note: Make sure to put your API key in the index.js for the sample to work) and the code snippet below:
/*global google*/
import React, { Component } from 'react';
import Button from 'react-bootstrap/Button';
import {
withGoogleMap,
Marker,
GoogleMap,
DirectionsRenderer
} from 'react-google-maps';
class Map extends Component {
state = {
directions: null,
markerPos: null,
centerMarker: null,
currentLocation: null
};
componentDidMount = () => {
navigator?.geolocation.getCurrentPosition(
({ coords: { latitude: lat, longitude: lng } }) => {
const pos = { lat, lng };
this.setState({ currentLocation: pos, centerMarker: pos });
}
);
};
onMapClick = e => {
this.setState({ markerPos: e.latLng });
};
getDirections = () => {
const directionsService = new google.maps.DirectionsService();
const origin = this.state.currentLocation;
const destination = this.state.markerPos;
if (origin !== null && destination !== null) {
directionsService.route(
{
origin: origin,
destination: destination,
travelMode: google.maps.TravelMode.DRIVING
},
(result, status) => {
if (status === google.maps.DirectionsStatus.OK) {
this.setState({
directions: result
});
} else {
console.error(`error fetching directions ${result}`);
}
}
);
} else {
console.log('Please mark your destination in the map first!');
}
};
render() {
const GoogleMapExample = withGoogleMap(props => (
<GoogleMap
defaultCenter={{ lat: 40.756795, lng: -73.954298 }}
defaultZoom={13}
center={this.state.currentLocation}
onClick={this.onMapClick}
>
{this.state.centerMarker !== null && (
<Marker position={this.state.centerMarker} label={'userloc'} />
)}
{this.state.markerPos !== null && (
<Marker position={this.state.markerPos} />
)}
{this.state.directions !== null && (
<DirectionsRenderer
directions={this.state.directions}
defaultOptions={{
suppressMarkers: true
}}
/>
)}
</GoogleMap>
));
return (
<div>
<Button onClick={this.getDirections}>Get Direction</Button>
<GoogleMapExample
containerElement={<div style={{ height: `500px`, width: '500px' }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
}
export default Map;

React - hovering over dynamically generated component calls render method

My app contains a google map that displays markers based on coordinates from an API. Upon the loading the app, an API request is made and a few coordinates are grabbed to be displayed on the screen. The API data is mapped to a <Marker /> component.
Problem: Upon hovering over any Marker, the render method gets called again and the Markers quickly flash. Why?
Map.js
state = {
center: { lat, lng },
zoom: defaultZoom,
showingInfoWindow: false,
selectedMarker: ""
};
onMarkerHover = (e, marker) => {
this.setState({
selectedMarker: marker.recordid,
showingInfoWindow: true
});
this.onSendMarkerInfoToParent();
};
render() {
const data = this.props.searchedResponse;
console.log("rerendering"); // printed in console on every hover event
const Markers = props =>
data
? data.data.records.map(marker => {
return (
<Marker
position={{ lat: marker.fields.geom.coordinates[1], lng: marker.fields.geom.coordinates[0] }}
key={marker.recordid}
onClick={e => this.onMarkerClick(e, marker)}
onMouseOver={e => this.onMarkerHover(e, marker)}
>
{this.state.showingInfoWindow && this.state.selectedMarker === marker.recordid && (
<InfoWindow
className="info-window"
position={{ lat: marker.fields.geom.coordinates[1], lng: marker.fields.geom.coordinates[0] }}
>
<div>{rateTimeCalc(marker)}</div>
</InfoWindow>
)}
</Marker>
);
})
: null;
return (
<div className="map-container">
<LoadScript googleMapsApiKey={process.env.REACT_APP_GOOGLE_KEY}>
<GoogleMap id="map" center={this.state.center} zoom={this.state.zoom}>
<Markers />
</GoogleMap>
</LoadScript>
</div>
);
}
App.js
onSendMarkerInfoToParent = e => {
console.log("parent", e);
};
This is because of Lifecycle of React app.
You have mapped the onHover method in your code that set the state.
onMouseOver={e => this.onMarkerHover(e, marker)}
onMarkerHover = (e, marker) => {
this.setState({
selectedMarker: marker.recordid,
showingInfoWindow: true
});
this.onSendMarkerInfoToParent();
};
This setState causes re-render.
In React, whenever you set the state of a component. The render method will be executed automatically.
You can read this article for reference: https://medium.com/react-ecosystem/react-components-lifecycle-ce09239010df.
Solution for google-maps-react and Markers re-rendering:
1.Create Wrapper PureComonent for all Markers.
2.Maintain one InfoWindow for all Markers.
Working example:
https://codesandbox.io/s/falling-wave-kjcee

Integrating the google map component with the react HOC?

import React,{Component } from 'react';
import {
withGoogleMap,
GoogleMap,
withScriptjs,
Marker,
InfoWindow,
} from 'react-google-maps';
import {compose, withProps, withStateHandlers} from 'recompose';
import places from 'places.json';
class MapComponent extends Component {
constructor (props) {
super (props);
this.state = {
zoom: 11,
center: {lat: 29.969516, lng: -90.103866},
markers: [],
lat:'',
lng:'',
markersLoaded: false,
};
}
componentDidMount () {
let geocoder = new window.google.maps.Geocoder ();
geocoder.geocode ({address: 'Bakerstreet, 2'}, function (results, status) {
if (status == 'OK') {
this.setState ({
lat: results[0].geometry.location.lat (),
lng: results[0].geometry.location.lng (),
});
} else {
console.log (
'Geocode was not successful for the following reason:',
status
);
}
});
}
render () {
const { lat, lng } = this.state;
const GoogleMapExample = withGoogleMap (props => (
<GoogleMap
defaultZoom={props.zoom}
defaultCenter={props.center}
options={{styles: props.mapdynamic ? darkThemeStyle : lightThemeStyle}}
>
{props.places &&
props.places.map ((place, i) => {
let lat = parseFloat (place.latitude, 10);
let lng = parseFloat (place.longitude, 10);
return (
<Marker
id={place.id}
key={place.id}
position={{lat: lat, lng: lng}}
icon="http://maps.google.com/mapfiles/ms/icons/blue-dot.png"
onMouseOver={props.onToggleOpen.bind (this, i)}
>
{props.infoWindows[i].isOpen &&
<InfoWindow onCloseClick={props.onToggleOpen.bind (i)}>
<div>{place.name}</div>
</InfoWindow>}
</Marker>
);
})}
</GoogleMap>
));
return (
<div>
<GoogleMapExample
center={{lat: 40.6451594, lng: -74.0850826}}
zoom={10}
places={places} />
</div>
);
}
}
export default compose (
withProps ({
googleMapURL: 'https://maps.googleapis.com/maps/api/js?key=YOUR KEY&libraries=geometry,drawing,places',
loadingElement: <div style={{height: `100%`}} />,
containerElement: (
<div style={{height: '100%', width: '100%', padding: '10px'}} />
),
mapElement: <div style={{height: '100%'}} />,
}),
withStateHandlers (
props => ({
infoWindows: props.places.map (p => {
return {isOpen: false};
}),
}),
{
onToggleOpen: ({infoWindows}) => selectedIndex => ({
infoWindows: infoWindows.map ((iw, i) => {
iw.isOpen = selectedIndex === i;
return iw;
}),
}),
}
),
withScriptjs,
withGoogleMap
) (MapComponent);
I am here by writing the google map component using the react order component.
But when I am trying to run this I am getting some kind of error.
Could you some one take a look into it and let me know what are the
issues here. I am getting following error like Invariant Violation:
Required props containerElement or mapElement is missing. You need to
provide both of them. The google.maps.Map instance will be
initialized on mapElement and it's wrapped by containerElement. You
need to provide both of them since Google Map requires the DOM to have
height when initialized.
Regards
You have additionally used withGoogleMap hoc in render method which you don't need
render () {
const { lat, lng } = this.state;
return (
<GoogleMap
defaultZoom={10}
defaultCenter={{lat: 40.6451594, lng: -74.0850826}}
options={{styles: props.mapdynamic ? darkThemeStyle : lightThemeStyle}}
>
{places &&
places.map ((place, i) => {
let lat = parseFloat (place.latitude, 10);
let lng = parseFloat (place.longitude, 10);
return (
<Marker
id={place.id}
key={place.id}
position={{lat: lat, lng: lng}}
icon="http://maps.google.com/mapfiles/ms/icons/blue-dot.png"
onMouseOver={props.onToggleOpen.bind (this, i)}
>
{props.infoWindows[i].isOpen &&
<InfoWindow onCloseClick={props.onToggleOpen.bind (i)}>
<div>{place.name}</div>
</InfoWindow>}
</Marker>
);
})}
</GoogleMap>
);
}

Resources