react-google-maps: multiple info windows opening up - reactjs

This is probably going to be a stupidly simple react question but please bear with me.
I am trying to run a react-google-maps with multiple markers with info windows. Here is the code:
const MapWithADirectionsRenderer = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?key=AIzaSyDf-yIqxErTkbWzKhLox7nAANnrfDIY190&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `800px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withStateHandlers(() => ({
isOpen: false,
}), {
onToggleOpen: ({ isOpen }) => () => ({
isOpen: !isOpen,
})
}),
withScriptjs,
withGoogleMap,
})
)(props =>
<GoogleMap
defaultZoom={13}
defaultCenter={new google.maps.LatLng(42.357064, -71.062577)}
>
<Marker
position={{ lat: 42.3381437, lng: -71.0475773 }}
onClick={props.onToggleOpen}
>
{props.isOpen && <InfoWindow onCloseClick={props.onToggleOpen}>
<h3>South Boston</h3>
</InfoWindow>}
</Marker>
<Marker
position={{ lat: 42.3875968, lng: -71.0994968 }}
onClick={props.onToggleOpen}
>
{props.isOpen && <InfoWindow onCloseClick={props.onToggleOpen}>
<h3>Somervil</h3>
</InfoWindow>}
</Marker>
{props.directions && <DirectionsRenderer directions={props.directions} />}
</GoogleMap>
);
When I click one of the markers, the info windows for all the markers toggle open. How do I just toggle open the info window of the marker I click?

I would suggest to introduce a component:
class MarkerWithInfoWindow extends React.Component {
constructor() {
super();
this.state = {
isOpen: false
}
this.onToggleOpen = this.onToggleOpen.bind(this);
}
onToggleOpen() {
this.setState({
isOpen: !this.state.isOpen
});
}
render() {
return (<Marker
position={this.props.position}
onClick={this.onToggleOpen}>
{this.state.isOpen && <InfoWindow onCloseClick={this.onToggleOpen}>
<h3>{this.props.content}</h3>
</InfoWindow>}
</Marker>)
}
}
to control info window per marker via MarkerWithInfoWindow state:
<GoogleMap
defaultZoom={13}
defaultCenter={new google.maps.LatLng(42.357064, -71.062577)}>
<MarkerWithInfoWindow position={{ lat: 42.3381437, lng: -71.0475773 }} content="South Boston" />
<MarkerWithInfoWindow position={{ lat: 42.3875968, lng: -71.0994968 }} content="Somervil" />
</GoogleMap>
Demo

Related

Access variable outside render

I'm having a problem in my code. I already can make a marker on the map with lat and lng. But I want to display a simple span with the coordinates under the map. I try to access this.props.markerPosition and it's null in render.
What is the issue here?
https://stackblitz.com/edit/react-snxake
const WrappedMap = compose(
withStateHandlers(() => ({
isMarkerShown: false,
markerPosition: null
}), {
onMapClick: ({ isMarkerShown }) => (e) => ({
markerPosition: e.latLng,
isMarkerShown:true
})
}),
withScriptjs,
withGoogleMap
)
(props =>
<GoogleMap
defaultZoom={8}
defaultCenter={{ lat: -34.397, lng: 150.644 }}
onClick={props.onMapClick}
>
{props.isMarkerShown && <Marker position={props.markerPosition} onClick={props.onMarkerClick} defaultOptions={{ styles: mapStyles}} />}
</GoogleMap>
)
export default class ParkingSpotsSettings extends React.Component {
state = {
evaluationExecuted: false,
evaluation: false
};
constructor() {
super();
this.state = {
coordinates: [],
title: '',
description: '',
capacity: 0
}
}
componentDidMount() { }
render() {
return (
<div className="App">
<Navigation />
<div className="container-fluid">
<div className="row">
<div className="col-md-6" style={{ width: "100vw", height: "40vh" }}>
<WrappedMap googleMapURL={`https://maps.googleapis.com/maps/api/js?key=v=3.exp&libraries=geometry,drawing,places`}
loadingElement={<div style={{ height: "100%" }} />}
containerElement={<div style={{ height: "100%" }} />}
mapElement={<div style={{ height: "100%" }} />}
/>
</div>
<span>Coordinates are: {this.props.markerPosition}</span>
</div>
</div>
</div >
);
}
}
Your prop is called position not markerPosition. So you need to use this.props.position.

Show my current location icon in React google map

Do we have any way to show current location icon in google maps by using react google maps
I could not find any such props for showing current location icon in the documentation Documtation_link.
here is my component i just need to show user current location icon
const googleMapCard= compose(
withProps({
googleMapURL:
"https://maps.googleapis.com/maps/api/js?key=-----------,
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />
}),
lifecycle({
componentWillMount() {
const refs = {};
this.setState({
bounds: null,
markers: [],
onMapMounted: ref => {
refs.map = ref;
},
onBoundsChanged: () => {
this.setState({
bounds: refs.map.getBounds(),
center: refs.map.getCenter()
});
},
onSearchBoxMounted: ref => {
refs.searchBox = ref;
},
onPlacesChanged: onChange => {
const places = refs.searchBox.getPlaces();
const bounds = new window.google.maps.LatLngBounds();
}
});
}
}),
withScriptjs,
withGoogleMap
)(props => (
<GoogleMap
onClick={e => {
props.onChange([e.latLng.lng(), e.latLng.lat()]);
}}
clickableIcons={true}
defaultZoom={8}
center={{ lat: props.value[1], lng: props.value[0] }}
defaultCenter={{ lat: props.value[1], lng: props.value[0] }}
ref={props.onMapMounted}
>
<SearchBox
ref={props.onSearchBoxMounted}
// bounds={props.bounds}
controlPosition={window.google.maps.ControlPosition.TOP_LEFT}
onPlacesChanged={() => {
props.onPlacesChanged(props.onChange);
}}
>
<input
type="text"
/>
</SearchBox>
<Marker position={{ lat: props.value[1], lng: props.value[0] }} />
)}
</GoogleMap>
));
You can use the Geolocation api.
See: https://developers.google.com/maps/documentation/javascript/geolocation
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var pos = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
this.setState({ownPosition: pos})
}
It doesn't have anything to do with react-google-maps, it's a native browser api
Simpler way to write navigator-safe coordinate access, using native Geolocation Api.
navigator?.geolocation.getCurrentPosition(({coords: {latitude: lat, longitude: lng}}) => {
const pos = {lat, lng}
this.setState({currentPosition: pos})
})
This uses:
?. null access check - Read More
Destructuring
Alias
=> lambda arrow

How I can put on dynamic markers on react-google-maps when I click on a certain part of the map?

I'm trying to put marker when I click on map. react-google-maps documentation is not good and I feel confused.
class Map extends Component {
render() {
const GoogleMapExample = withGoogleMap(props => (
<GoogleMap
center={{ lat: this.props.latitude, lng: this.props.longitude }}
zoom={13}
>
{this.props.markers.map(marker => {
return <SkateMarker key={marker.title} marker={marker} />;
})}
</GoogleMap>
));
return (
<div>
<GoogleMapExample
containerElement={
<div style={{ height: `500px`, width: "1000px" }} />
}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
}
export default Map;
The following example demonstrates how to add a marker on map click using react-google-maps:
class MapWithMarkers extends React.Component {
state = {
places: []
};
addMarker(e) {
const newPlace = { id: this.state.places.length, lat: e.latLng.lat(), lng: e.latLng.lng() };
this.setState({
places: [...this.state.places,newPlace]
})
}
render() {
return (
<GoogleMap
onClick={this.addMarker.bind(this)}
defaultZoom={this.props.zoom}
defaultCenter={this.props.center}
>
{this.state.places.map(place => {
return (
<Marker
key={place.id}
position={{ lat: place.lat, lng: place.lng }}
/>
);
})}
</GoogleMap>
);
}
}
Demo

geolocation in React, use react-google-maps

How to change defaultCenter in react-google-maps ?
I need to find my geolocation and change default values lat and lng.
import React from "react";
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps";
const getLocation = () =>{
const pos = {};
const geolocation = navigator.geolocation;
if (geolocation) {
geolocation.getCurrentPosition(findLocal, showEror);
}
function findLocal(position){
pos.lat = position.coords.latitude;
pos.lng = position.coords.longitude;
}
function showEror(){console.log(Error)}
return pos;
};
const myLocation = getLocation(); // object has lat and lng
I need to transfer my data to the component MapWithAMarker next: Сenter={myLocation} and Marker position={myLocation}
class GoogleMapCenter extends React.Component{
render(){
const MapWithAMarker = withScriptjs(withGoogleMap(props =>
<GoogleMap
defaultZoom={10}
defaultCenter={{ lat: -34.397, lng: 150.644 }}>
{props.isMarkerShown && <Marker position={{ lat: -34.397, lng: 150.644 }} />}
</GoogleMap>
));
return(
<MapWithAMarker
isMarkerShown
googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg&v=3.exp"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
)
}
}
export default GoogleMapCenter;
If I use this.props, it does not work.
<MapWithAMarker
center={this.props.myLocation}
position={this.props.myLocation}
isMarkerShown
googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg&v=3.exp"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
or
<GoogleMap
defaultZoom={10}
defaultCenter={this.props.myLocation}>
{props.isMarkerShown && <Marker position={this.props.myLocation} />}
</GoogleMap>
Default properties like defaultCenter could only be set as initial state, center property could be used instead to re-render (center) the map.
The following example demonstrates how to center the map based on current location
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
currentLatLng: {
lat: 0,
lng: 0
},
isMarkerShown: false
}
}
showCurrentLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
position => {
this.setState(prevState => ({
currentLatLng: {
...prevState.currentLatLng,
lat: position.coords.latitude,
lng: position.coords.longitude
},
isMarkerShown: true
}))
}
)
} else {
error => console.log(error)
}
}
componentDidMount() {
this.showCurrentLocation()
}
render() {
return (
<div>
<MapWithAMarker
isMarkerShown={this.state.isMarkerShown}
currentLocation={this.state.currentLatLng} />
</div>
);
}
}
where
const MapWithAMarker = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withScriptjs,
withGoogleMap
)((props) =>
<GoogleMap
defaultZoom={8}
center={{ lat: props.currentLocation.lat, lng: props.currentLocation.lng }}
>
{props.isMarkerShown && <Marker position={{ lat: props.currentLocation.lat, lng: props.currentLocation.lng }} onClick={props.onMarkerClick} />}
</GoogleMap>
)
Demo (edit)

Display only one InfoWindow

I realise this has been asked before, however, I'm unable to figure out what I'm doing wrong here. I have a map that displays multiple markers and when I click on a marker it is supposed to displays the InfoWindow about that marker. The problem that when I click on a marker, all the InfoWindow boxes pop up instead of just the one I've clicked on.
const MapWithAMarkerClusterer = compose(
withProps({
googleMapURL: "MY KEY",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withHandlers({
onMarkerClustererClick: () => (markerClusterer) => {
const clickedMarkers = markerClusterer.getMarkers()
}
}),
withStateHandlers(() => ({
isOpen: false,
markerId: ''
}), {
onToggleOpen: ({ isOpen }) => (markerId) => ({
isOpen: !isOpen,
markerId: markerId
})
}),
withScriptjs,
withGoogleMap
)(props =>
<GoogleMap
defaultZoom={4}
defaultCenter={{ lat: -23.696248, lng: 133.880731 }}
>
<MarkerClusterer
onClick={props.onMarkerClustererClick}
averageCenter
enableRetinaIcons
gridSize={60}
>
{props.companies.map(company => (
<span key={company.company_name}>
<Marker
position={company.google_maps.geometry_location}
onClick={() => props.onToggleOpen(company.company_name)}
>
{props.isOpen[props.markerId] && <InfoWindow onCloseClick={props.onToggleOpen}>
<p>Test</p>
</InfoWindow>}
</Marker>
</span>
))}
</MarkerClusterer>
</GoogleMap>
);
Ok, this was a silly mistake. I've updated my code below and it works.
{props.isOpen && (props.markerId == company.company_name) && <InfoWindow onCloseClick={props.onToggleOpen}>
<p>Test</p>
</InfoWindow>}

Resources