could not update state after onplacechanged event occure in react js? - reactjs

__ I have used withprops in react-google-maps. i have also used searchbox from react-google-maps my problem is that when onplacechanged event occure i want i am trying to update center in state but this.setState is not accesible in onplacechabged function. i want to access this.setState from RMSelectLocation class but it could'nt accesible. is there any other to imlement google map with autocomplete searchbox in reactjs __
import React, { Component, useEffect } from "react";
import { compose, withProps, lifecycle } from "recompose";
import {
withScriptjs,
withGoogleMap,
GoogleMap,
Marker,
} from "react-google-maps";
import { get } from "lodash";
import { SearchBox } from "react-google-maps/lib/components/places/SearchBox";
var cntr = { lat: 19.993982, lng: 73.790416 };
class RMSelectLocation extends Component {
state = {
locations: "nashik",
center: { lat: 19.993982, lng: 73.790416 },
zoom: 12,
type: "",
};
componentDidMount() {}
render() {
const MapWithASearchBox = compose(
withProps({
googleMapURL:
"https://maps.googleapis.com/maps/api/js?key=AIzaSyAIVf-f5cukgHjy_ZEv32yc9Liehb4vTGQ&v=3.exp&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `200%` }} />,
}),
lifecycle({
componentWillMount() {
const refs = {};
this.setState({
bounds: null,
center: {
lat: 19.9975,
lng: 73.7898,
},
markers: [],
onMapMounted: (ref) => {
refs.map = ref;
},
onBoundsChanged: () => {
this.setState({
bounds: refs.map.getBounds(),
center: refs.map.getCenter(),
});
},
onSearchBoxMounted: (ref) => {
refs.searchBox = ref;
},
onPlacesChanged: () => {
console.log(this.state);
console.log(this.props);
const places = refs.searchBox.getPlaces();
const bounds = new window.google.maps.LatLngBounds();
places.forEach((place) => {
if (place.geometry.viewport) {
bounds.union(place.geometry.viewport);
} else {
bounds.extend(place.geometry.location);
}
});
const nextMarkers = places.map((place) => ({
position: place.geometry.location,
}));
const nextCenter = get(
nextMarkers,
"0.position",
this.state.center
);
this.setState({
center: nextCenter,
markers: nextMarkers,
});
},
});
},
}),
withScriptjs,
withGoogleMap
)((props) => (
<GoogleMap
ref={props.onMapMounted}
defaultZoom={15}
center={props.center}
onBoundsChanged={props.onBoundsChanged}
defaultMapTypeId={"hybrid"}
>
<SearchBox
ref={props.onSearchBoxMounted}
bounds={props.bounds}
controlPosition={window.google.maps.ControlPosition.TOP_RIGHT}
onPlacesChanged={props.onPlacesChanged}
>
<input
type="text"
placeholder="Customized your placeholder"
style={{
boxSizing: `border-box`,
border: `1px solid transparent`,
width: `240px`,
height: `32px`,
marginTop: `27px`,
padding: `0 12px`,
borderRadius: `3px`,
boxShadow: `0 2px 6px rgba(0, 0, 0, 0.3)`,
fontSize: `14px`,
outline: `none`,
textOverflow: `ellipses`,
}}
/>
</SearchBox>
{props.markers.map((marker, index) => (
<Marker key={index} position={marker.position} />
))}
</GoogleMap>
));
return (
<MapWithASearchBox />
);
}
}
export default RMSelectLocation;

Ciao, if this.setState is not reachable could be a this context problem as explained here. Take a look and let us know :)

Related

React-Google-Maps API: How to search current location for a search result?

I'm trying to build a similar map as on Airbnb, where you can view place markers as you drag the map around. I would like to search for "treatment centers" and place markers using the Google Places API on a map.
I have been using the new, re-written #react-google-maps/api. So far, I was able to create both a search box and an autocomplete and get their latitude and longitude, but both offer only specific locations rather than the most similar searches (ex. if you search Taco Bell on Google Maps, it shows up with several options near you). The code below displays a map with the search box:
import { GoogleMap, LoadScript, Marker, StandaloneSearchBox, Autocomplete } from '#react-google-maps/api';
class HeaderMap extends Component {
constructor (props) {
super(props)
this.autocomplete = null
this.onLoad = this.onLoad.bind(this)
this.onPlaceChanged = this.onPlaceChanged.bind(this)
this.state = {
currentLocation: {lat: 0, lng: 0},
markers: [],
zoom: 8
}
}
componentDidMount() {
navigator?.geolocation.getCurrentPosition(({coords: {latitude: lat, longitude: lng}}) => {
const pos = {lat, lng}
this.setState({currentLocation: pos})
})
}
onLoad (autocomplete) {
console.log('autocomplete: ', autocomplete)
this.autocomplete = autocomplete
}
onPlaceChanged() {
if (this.autocomplete !== null) {
let lat = this.autocomplete.getPlace().geometry.location.lat()
let long = this.autocomplete.getPlace().geometry.location.lat()
} else {
console.log('Autocomplete is not loaded yet!')
}
}
render() {
return (
<LoadScript
googleMapsApiKey="API_KEY_HERE"
libraries={["places"]}
>
<GoogleMap
id='search-box-example'
mapContainerStyle={containerStyle}
center={this.state.currentLocation}
zoom={14}
// onDragEnd={search for centers in current location}
>
<Marker key={1} position={this.state.currentLocation} />
<Autocomplete
onLoad={this.onLoad}
onPlaceChanged={this.onPlaceChanged}
>
<input
type="text"
placeholder="Customized your placeholder"
style={inputStyles}
/>
</Autocomplete>
</GoogleMap>
</LoadScript>
);
}
}
How can I automatically search the bounds of the location and get the latitude and longitude of each result based on keywords? Thanks for your help!
In your current code, it seems that you are using Autocomplete which was precoded by the library to have the functions of Places Autocomplete. You can use the StandaloneSearchBox to achieve your use case as it is implementing the Places Searchbox which returns a pick list that includes both places and predicted search terms.
Here is the code sample and code snippet below:
/*global google*/
import React from "react";
import { GoogleMap, StandaloneSearchBox, Marker } from "#react-google-maps/api";
let markerArray = [];
class Map extends React.Component {
state = {
currentLocation: { lat: 0, lng: 0 },
markers: [],
bounds: null
};
onMapLoad = map => {
navigator?.geolocation.getCurrentPosition(
({ coords: { latitude: lat, longitude: lng } }) => {
const pos = { lat, lng };
this.setState({ currentLocation: pos });
}
);
google.maps.event.addListener(map, "bounds_changed", () => {
console.log(map.getBounds());
this.setState({ bounds: map.getBounds() });
});
};
onSBLoad = ref => {
this.searchBox = ref;
};
onPlacesChanged = () => {
markerArray = [];
let results = this.searchBox.getPlaces();
for (let i = 0; i < results.length; i++) {
let place = results[i].geometry.location;
markerArray.push(place);
}
this.setState({ markers: markerArray });
console.log(markerArray);
};
render() {
return (
<div>
<div id="searchbox">
<StandaloneSearchBox
onLoad={this.onSBLoad}
onPlacesChanged={this.onPlacesChanged}
bounds={this.state.bounds}
>
<input
type="text"
placeholder="Customized your placeholder"
style={{
boxSizing: `border-box`,
border: `1px solid transparent`,
width: `240px`,
height: `32px`,
padding: `0 12px`,
borderRadius: `3px`,
boxShadow: `0 2px 6px rgba(0, 0, 0, 0.3)`,
fontSize: `14px`,
outline: `none`,
textOverflow: `ellipses`,
position: "absolute",
left: "50%",
marginLeft: "-120px"
}}
/>
</StandaloneSearchBox>
</div>
<br />
<div>
<GoogleMap
center={this.state.currentLocation}
zoom={10}
onLoad={map => this.onMapLoad(map)}
mapContainerStyle={{ height: "400px", width: "800px" }}
>
{this.state.markers.map((mark, index) => (
<Marker key={index} position={mark} />
))}
</GoogleMap>
</div>
</div>
);
}
}
export default Map;

How to make a moving marker like Uber cars?

I create a marker like this:
import React from "react";
import config from 'config';
import { compose, withProps, withState, lifecycle } from "recompose";
import {
withScriptjs,
withGoogleMap,
GoogleMap,
Marker,
DirectionsRenderer,
Polyline,
} from "react-google-maps";
const googleApiKey = config.googleApiKey;
const HistoryView = compose(
withProps({
googleMapURL: `https://maps.googleapis.com/maps/api/js?key=${googleApiKey}&v=3.exp&libraries=geometry,drawing,places`,
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `345px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withState('zoom', 'onZoomChange', 11),
withScriptjs,
withGoogleMap,
lifecycle({
componentDidMount() {
const { historyCords } = this.props;
},
componentWillMount() {
this.setState({
zoomToMarkers: map => {
//console.log("Zoom to markers");
const bounds = new google.maps.LatLngBounds();
map.props.children.forEach((child) => {
if (child.type === Marker) {
bounds.extend(new google.maps.LatLng(child.props.position.lat, child.props.position.lng));
}
})
map.fitBounds(bounds);
}
})
},
})
)(props =>
<GoogleMap
//ref={props.zoomToMarkers}
defaultZoom={8}
defaultCenter={new google.maps.LatLng(props.historyCords[0].latitude, props.historyCords[0].longitude)}
center={new google.maps.LatLng(props.latitude, props.longitude)}
zoom={17}
>
{<Polyline path={props.polylineCords}
geodesic={true}
options={{
strokeColor: "#1e9494",
strokeOpacity: 0.75,
strokeWeight: 2,
icons: [
{
icon: "lineSymbol",
offset: "0",
repeat: "20px"
}
]
}}
/>}
{<Marker
options={{icon: {url: "../../public/images/red-mark.svg", scaledSize: new window.google.maps.Size(30, 62)}}}
position={{ lat: props.latitude, lng: props.longitude }}
onClick={props.onMarkerClick} />
}
</GoogleMap>
);
export { HistoryView };
Now how do I move this marker like a car on location updates?
I use states to update the position of the marker but it doesn't animate. How do I do this?
My issue is when a latlng is updated the marker jumps from one place to another but I want it to move like a car. Have you ever tracked an Uber ride on the web? something like that.
Gif for car animation

How to make google maps work with react

I'm trying to Map with a SearchBox in react but I'm not sure what I am missing from this code below. I've never used google maps before and the docs are really confusing. The error I get is that google is no defined and I'm assuming I need to import something but research has proven to be useless. I got the code from https://github.com/tomchentw/react-google-maps.
const _ = require("lodash");
const { compose, withProps, lifecycle } = require("recompose");
const {
withScriptjs,
withGoogleMap,
GoogleMap,
Marker,
} = require("react-google-maps");
const { SearchBox } = require("react-google-
maps/lib/components/places/SearchBox");
const MapWithASearchBox = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?
key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg&v=3.exp&libraries
=geometry,draw
ing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
lifecycle({
componentWillMount() {
const refs = {}
this.setState({
bounds: null,
center: {
lat: 41.9, lng: -87.624
},
markers: [],
onMapMounted: ref => {
refs.map = ref;
},
onBoundsChanged: () => {
this.setState({
bounds: refs.map.getBounds(),
center: refs.map.getCenter(),
})
},
onSearchBoxMounted: ref => {
refs.searchBox = ref;
},
onPlacesChanged: () => {
const places = refs.searchBox.getPlaces();
const bounds = new google.maps.LatLngBounds();
places.forEach(place => {
if (place.geometry.viewport) {
bounds.union(place.geometry.viewport)
} else {
bounds.extend(place.geometry.location)
}
});
const nextMarkers = places.map(place => ({
position: place.geometry.location,
}));
const nextCenter = _.get(nextMarkers, '0.position',
this.state.center);
this.setState({
center: nextCenter,
markers: nextMarkers,
});
// refs.map.fitBounds(bounds);
},
})
},
}),
withScriptjs,
withGoogleMap
)(props =>
<GoogleMap
ref={props.onMapMounted}
defaultZoom={15}
center={props.center}
onBoundsChanged={props.onBoundsChanged}
>
<SearchBox
ref={props.onSearchBoxMounted}
bounds={props.bounds}
controlPosition={google.maps.ControlPosition.TOP_LEFT}
onPlacesChanged={props.onPlacesChanged}
>
<input
type="text"
placeholder="Customized your placeholder"
style={{
boxSizing: `border-box`,
border: `1px solid transparent`,
width: `240px`,
height: `32px`,
marginTop: `27px`,
padding: `0 12px`,
borderRadius: `3px`,
boxShadow: `0 2px 6px rgba(0, 0, 0, 0.3)`,
fontSize: `14px`,
outline: `none`,
textOverflow: `ellipses`,
}}
/>
</SearchBox>
{props.markers.map((marker, index) =>
<Marker key={index} position={marker.position} />
)}
</GoogleMap>
);
<MapWithASearchBox />
This error is caused by linter, you need to explicitly read google global variable from window by adding the below line to the top of your file:
const google = window.google;
or to disable linter:
/*global google*/

React google maps url undefined

I am trying to update the viewport bounds based on the markers coords in my react google maps component.
However when I call the following line in componentWillMount()
const bounds = new google.maps.LatLngBounds();
I get an error that says google is not defined.
To resolve this I have tried
(1) Adding the google maps script tag to the index.html
(2) Adding the line
/* eslint-disable no-undef */
to the top of my file.
(3) Adding withScriptjs, withGoogleMap inside my compose() but it produces an error that says the googleMapUrl and the loading element is not defined. To solve this I tried doing
<MapSearchBox
googleMapURL="https://maps.googleapis.com/maps/api/js?key=APIKEY&v=3.exp&libraries=geometry,drawing,places"
loadingElement={<div style={{ height: `100%` }} />}
isMarkerShown={this.state.isMarkerShown}
onMarkerClick={this.handleMarkerClick}
/>
but this did not work.
(4) Added /* global google */ to the top of my file
Also some other small changes but nothing sticks.
Please give some suggestions!
MapWithASearchBox.js
/* global google */
import React from 'react';
import { get } from 'lodash';
import { compose, withProps, lifecycle, defaultProps } from 'recompose';
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from 'react-google-maps';
import PropTypes from 'prop-types';
const { SearchBox } = require('react-google-maps/lib/components/places/SearchBox');
import { buildMarkerObj } from '../../../imports/helpers/DataHelpers';
const MapSearchBox = compose(
withProps(props => ({
googleMapURL: 'https://maps.googleapis.com/maps/api/js?key=APIKEY=3.exp&libraries=geometry,drawing,places',
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `450px` }} />,
mapElement: <div style={{ height: `100%` }} />,
})),
withScriptjs,
withGoogleMap,
defaultProps({
externalMarkers: [],
}),
lifecycle({
componentWillMount() {
const refs = {};
const { lat, lng } = this.props.coords || (this.props.place && this.props.place.coords) || {};
const initialMarker = lat !== undefined && lng !== undefined ? [buildMarkerObj({ lat, lng })] : [];
console.log('THIS PROPS');
console.log(this.props);
console.log('PROPS');
this.setState({
bounds: null,
center: {
lat: lat || 41.9,
lng: lng || -87.624,
},
markers: initialMarker,
injectedMarkers: this.props.markers || [],
onMapMounted: ref => {
refs.map = ref;
},
onBoundsChanged: () => {
},
onSearchBoxMounted: ref => {
refs.searchBox = ref;
},
onPlacesChanged: () => {
const places = refs.searchBox.getPlaces();
places.map(({ address_components, geometry: { location } }) => {
this.props.onSetLocation({
lat: location.lat(),
lng: location.lng(),
});
});
const nextMarkers = places.map(place => ({
position: place.geometry.location,
}));
const nextCenter = get(nextMarkers, '0.position', this.state.center);
this.setState({
center: nextCenter,
markers: nextMarkers,
});
// refs.map.fitBounds(bounds);
},
})
//ERROR HERE
const bounds = new google.maps.LatLngBounds();
this.props.markers.map((marker, index) => {
bounds.extend(new google.maps.LatLng(
marker.coords.lat,
marker.coords.lng
));
})
refs.map.fitBounds(bounds);
refs.map.panToBounds(bounds);
},
}),
)
((props) =>
<GoogleMap
ref={props.onMapMounted}
defaultZoom={15}
center={props.center}
onBoundsChanged={props.onBoundsChanged}
>
<SearchBox
ref={props.onSearchBoxMounted}
bounds={props.bounds}
controlPosition={google.maps.ControlPosition.TOP_LEFT}
onPlacesChanged={props.onPlacesChanged}
>
<input
type="text"
placeholder="Enter your area"
style={{
boxSizing: 'border-box',
border: '1px solid white',
width: '240px',
height: '32px',
marginTop: '12px',
padding: '0 12px',
borderRadius: '3px',
boxShadow: '0 2px 6px rgba(0, 0, 0, 0.3)',
fontSize: '14px',
outline: 'none',
textOverflow: 'ellipses',
backgroundColor: 'white',
}}
/>
</SearchBox>
{props.markers.map((marker, index) =>
<Marker key={`map-marker-${index}`} position={marker.position} />
)}
{props.externalMarkers.map((marker, index) =>
<Marker key={`external-marker-${index}`} position={marker.coords} />
)}
</GoogleMap>
)
class MapComponent extends React.PureComponent {
constructor(props) {
super(props);
this.state = { isMarkerShown: false };
}
componentDidMount() {
this.delayedShowMarker();
}
componentDidUpdate() {
console.log('COMPONENT DID UPDATE');
const bounds = new window.google.maps.LatLngBounds();
this.props.markers.map((marker, index) => {
bounds.extend(new window.google.maps.LatLng(
marker.coords.lat,
marker.coords.lng
));
})
refs.map.fitBounds(bounds);
refs.map.panToBounds(bounds);
}
delayedShowMarker = () => {
setTimeout(() => {
this.setState({ isMarkerShown: true });
}, 3000);
}
handleMarkerClick = () => {
this.setState({ isMarkerShown: false });
this.delayedShowMarker();
}
render() {
return (
<MapSearchBox
isMarkerShown={this.state.isMarkerShown}
onMarkerClick={this.handleMarkerClick}
/>
);
}
}
MapComponent.propTypes = {
className: PropTypes.string,
latitude: PropTypes.string,
longitude: PropTypes.string,
externalMarkers: PropTypes.array,
};
MapComponent.defaultProps = {
className: '',
externalMarkers: [],
};
export default MapSearchBox;
Add Google Map url script in index.html
<script src="https://maps.googleapis.com/maps/api/js?key=APIKEY=3.exp&libraries=geometry,drawing,places></script>

How to use fitBounds in react-google-map once you have bounds

Where exactly do I call fitBounds or map.fitbounds. I am confused where to put it once I have the bounds or how to use it. I have set the bounds to a local state of bounds.
I have looked at this post here react-google-maps: how to use fitBounds, panBy, panTo, panToBounds public APIs? and either I just do it different or something because it does not make much since to me.
I have created a bounds const and then each time I make a marker I have added each of those to the bounds doing bounds.extends(Marker in here)
The code is a little messy so I will point out where I do this in it. Inside the filterItemsByRadius is where I create and set the bounds. At the end of the map function I think set the state of bounds to the bounds.
/* global google */
import { default as React, Component } from 'react';
import raf from 'raf';
import canUseDOM from 'can-use-dom';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import {
withGoogleMap,
GoogleMap,
Circle,
InfoWindow,
Marker,
withScriptjs,
} from 'react-google-maps';
import geolib from 'geolib';
import { geolocated } from 'react-geolocated';
import ItemList from './ItemList';
import { Col } from 'react-bootstrap';
import Paper from 'material-ui/Paper';
import Img from 'react-image';
import RaisedButton from 'material-ui/RaisedButton';
import FontIcon from 'material-ui/FontIcon';
import CreateRadius from './CreateRadius';
import offerActions from '../../redux/actions/offerActions';
const googleMapURL =
'https://maps.googleapis.com/maps/api/js?libraries=places,geometry&key=AIzaSyA7XEFRxE4Lm28tAh44M_568fCLOP_On3k';
const isJson = str => {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
};
const GeolocationGoogleMap = withScriptjs(
withGoogleMap(props => (
<GoogleMap defaultZoom={6} zoom={props.zoom} center={props.center} onClick={props.onMapClick}>
{props.center && (
<Marker
position={props.center}
title={"User's Location"}
options={{ icon: require('./assets/blueDot.png') }}
>
{props.showCenterInfo && (
<InfoWindow>
<div>User's Location</div>
</InfoWindow>
)}
</Marker>
)}
{/* <Circle
center={props.center}
radius={props.zoom}
options={{
fillColor: 'red',
fillOpacity: 0.2,
strokeColor: 'red',
strokeOpacity: 1,
strokeWeight: 1,
}}
/> */}
{props.markers.map((marker, index) => {
const onClick = () => props.onMarkerClick(marker);
const onCloseClick = () => props.onCloseClick(marker);
return (
<Marker
key={index}
position={marker.position}
title={marker.number.toString()}
onClick={onClick}
options={{ icon: 'https://image.ibb.co/evMHxF/shopping_zone_marker_1.png' }}
>
{marker.showInfo && (
<InfoWindow onCloseClick={onCloseClick}>
<div>
<ItemList marker={marker} />
</div>
</InfoWindow>
)}
</Marker>
);
})}
</GoogleMap>
)),
);
class OfferMap extends Component {
constructor(props) {
super(props);
this.state = {
currentPosition: null,
center: null,
content: null,
radius: 15, // ACZ --> put this const in config_env.
showCenterInfo: true,
markers: [],
zoom: 6,
bounds: null,
};
this.handleMarkerClick = this.handleMarkerClick.bind(this);
this.handleCloseClick = this.handleCloseClick.bind(this);
this.handleMapClick = this.handleMapClick.bind(this);
this.filterItemsByRadius = this.filterItemsByRadius.bind(this);
this.radiusChange = this.radiusChange.bind(this);
this.zoomChange = this.zoomChange.bind(this);
}
componentWillReceiveProps(props) {
if (props.coords && !props.coords.positionError) {
this.setState({ center: { lat: props.coords.latitude, lng: props.coords.longitude } });
} else {
fetch('http://ip-api.com/json')
.then(res => res.json())
.then(data => {
this.setState({ center: { lat: data.lat, lng: data.lon } });
})
.catch(error => {
this.setState({ content: `Error: The Geolocation service failed (${error.message}).` });
});
}
this.setState({ markers: props.items });
}
handleMapClick() {
this.setState({ showCenterInfo: false });
}
handleMarkerClick(targetMarker) {
this.setState({
markers: this.state.markers.map(marker => {
if (marker._id === targetMarker._id) {
return {
...marker,
showInfo: true,
};
}
return marker;
}),
});
}
handleCloseClick(targetMarker) {
this.setState({
markers: this.state.markers.map(marker => {
if (marker._id === targetMarker._id) {
return {
...marker,
showInfo: false,
};
}
return marker;
}),
});
}
filterItemsByRadius(userRadius) {
const items = this.state.markers;
const markers = [];
const bounds = new google.maps.LatLngBounds();
items.map((item, i) => {
let itemGeolocation;
let itemDescription = 'NO DESCRIPTION';
let itemThumb;
// Should be ready - tbaustinedit
if (item) {
itemDescription = item.description;
itemThumb = item.media.mediaVault[item.media.defaultIdx] || {
mediaType: 'txt',
};
}
if (item.geolocation) {
itemGeolocation = item.geolocation.coords;
}
if (this.state.center) {
const currentLocation = {
latitude: this.state.center.lat,
longitude: this.state.center.lng,
};
const distanceArr = geolib.orderByDistance(currentLocation, [itemGeolocation]);
const miles = (distanceArr[0].distance / 1609.34).toFixed(2);
if (miles <= userRadius) {
const loc = new google.maps.LatLng(itemGeolocation.lat, itemGeolocation.lng);
bounds.extends(loc);
markers.push({
_id: item._id,
position: itemGeolocation,
number: i,
content: itemDescription,
price: item.price,
quantity: item.quantity,
currency: item.currency,
category: item.category,
title: item.title,
offer: item.offer,
thumbnail: itemThumb,
showInfo: item.showInfo || false,
});
}
}
});
this.setState({
bounds,
});
return markers;
}
radiusChange(event) {
console.log(event.target.value);
this.setState({
radius: event.target.value,
});
const { filter } = this.props.offers;
filter.radius = event.target.value;
this.props.sortOffersNew(filter);
}
zoomChange(e) {
console.log('value', e.target.value);
this.setState({ zoom: Number(e.target.value) });
}
render() {
const markers = this.filterItemsByRadius(this.state.radius);
return (
<Col xs={12} smOffset={0} mdOffset={0}>
<div>
<div style={{ fontFamily: 'Roboto', fontStyle: 'normal' }}>
Offers within radius of: {' '}
<input type="text" defaultValue={this.state.radius} onChange={this.radiusChange} /> {' '}
miles
<br />
</div>
{/* <CreateRadius
radiusChange={this.radiusChange}
numOffers={markers.length}
initRadius={this.state.zoom}
/> */}
</div>
<br />
<div
style={{
width: '100%',
height: '500px',
}}
>
<GeolocationGoogleMap
googleMapURL={googleMapURL}
loadingElement={<div style={{ height: '100%' }} />}
containerElement={<div style={{ height: '100%' }} />}
mapElement={<div style={{ height: '100%' }} />}
center={this.state.center}
showCenterInfo={this.state.showCenterInfo}
content={this.state.content}
radius={this.state.radius}
onMapClick={this.handleMapClick}
onMarkerClick={this.handleMarkerClick}
onCloseClick={this.handleCloseClick}
markers={markers}
zoom={this.state.zoom}
bounds={this.state.bounds}
/>
</div>
</Col>
);
}
}
function mapStateToProps({ browser, offers }) {
return { browser, offers };
}
const dispatchToProps = dispatch => ({
sortOffersNew: filter => dispatch(offerActions.sortOffers(filter)),
});
export default connect(mapStateToProps, dispatchToProps)(
geolocated({
positionOptions: {
enableHighAccuracy: false,
},
userDecisionTimeout: 5000,
})(OfferMap),
);
You can access fitBounds by adding a ref to the DOM element that google-maps-react generates.
first, add a ref:
<GoogleMap ref={(ref) => { this.map = ref; }}>...</GoogleMap>
Once the component is mounted, you will be able to call fitBounds using the ref.
this.map.fitBounds(bounds)
You can assign a ref to the GoogleMap Component, then call the fitBounds() function using a lifecycle hook.
import React, { useRef, useEffect } from 'react';
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps";
import { GOOGLE_API_KEY } from '../../config/config';
// =======================================================================
// GOOGLE MAPS
// =======================================================================
const RegularMap = withScriptjs(
withGoogleMap(
({ defaultCenter, markers }) => {
const mapRef = useRef(null);
// Fit bounds function
const fitBounds = () => {
const bounds = new window.google.maps.LatLngBounds();
markers.map(item => {
bounds.extend(item.position);
return item.id
});
mapRef.current.fitBounds(bounds);
};
// Fit bounds on mount, and when the markers change
useEffect(() => {
fitBounds();
}, [markers]);
return (
<GoogleMap ref={mapRef} defaultCenter={defaultCenter}>
{markers.map(
({ position }, index) => <Marker key={`marker_${index}`} position={position} />
)}
</GoogleMap>
);
})
);
// =======================================================================
// THE MAIN COMPONENT
// =======================================================================
const MapView = () => {
const markers = [
{ position: { lat: 37.778519, lng: -122.405640 } },
{ position: { lat: 6.4454594, lng: 3.449074 } }
];
return (
<RegularMap
defaultCenter={{ lat: 6.4454594, lng: 3.449074 }}
markers={markers}
googleMapURL={`https://maps.googleapis.com/maps/api/js?key=${GOOGLE_API_KEY}`}
loadingElement={<div className="loader" />}
containerElement={<div className="mapContainer" style={{ height: "400px" }} />}
mapElement={<div className="map" style={{ height: '100%' }} />}
/>
);
}
export default MapView;
You can use fitbounds in componentDidMount or render function
add ref to GoogleMap and apply fitbounds
<GoogleMap ref={map => map && map.fitBounds(bounds)}> .... </GoogleMap>
The example demonstrates how to center viewport for the given markers:
const MapWithAMarkers = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
lifecycle({
componentWillMount() {
this.setState({
zoomToMarkers: map => {
//console.log("Zoom to markers");
const bounds = new window.google.maps.LatLngBounds();
map.props.children.forEach((child) => {
if (child.type === Marker) {
bounds.extend(new window.google.maps.LatLng(child.props.position.lat, child.props.position.lng));
}
})
map.fitBounds(bounds);
}
})
},
}),
withScriptjs,
withGoogleMap
)(props =>
<GoogleMap ref={props.zoomToMarkers} defaultZoom={5} defaultCenter={{ lat: 25.0391667, lng: 121.525 }}>
{props.markers.map(marker => (
<Marker
key={marker.id}
position={{ lat: marker.lat, lng: marker.lng }}
/>
))}
</GoogleMap>
);
Demo
I wanted to restrict my map (https://developers.google.com/maps/documentation/javascript/examples/control-bounds-restriction).
I used the options property with GoogleMap component with https://www.npmjs.com/package/#react-google-maps/api library.
The library is complete re-write of the react-google-maps library
CODE:
<GoogleMap
mapContainerStyle={containerStyle}
center={center}
zoom={10}
ref={(ref) => {this.state.map = ref}}
onLoad={this.onGoogleMapLoad}
options={{
restriction: {
latLngBounds: {
north: 19.137384, // Mumbai
south: 18.510866, // Pune
west: 72.874748, // Mumbai
east: 73.879864, // Pune
},
strictBounds: false,
}
}}
>

Resources