Updating Markers to Google Maps in google-map-react - javascript

onGoogleApiLoaded not invoked on locations data change, Is there any way to achieve this?
I tried to use useEffect to load markers but then I have to save map and maps objects in useRef as well as markers
Is there any easier way to achieve this?
import { useEffect, useRef } from 'react';
import GoogleMapReact from 'google-map-react';
export type SimpleMapProps = {
locations: any[];
};
export default function SimpleMap({ locations }: SimpleMapProps) {
const defaultProps =
locations.length > 0
? {
center: {
lat: locations[0].Lat,
lng: locations[0].Lon
},
zoom: 11
}
: {
center: {
lat: 0,
lng: 0
},
zoom: 11
};
const handleApiLoadData = (map: any, maps: any) => {
for (let i = 0; i < locations.length; i++) {
const { Lat, Lon, hn, cur, rate } = locations[i];
const marker = new maps.Marker({
animation: maps.Animation.DROP,
position: { lat: Lat, lng: Lon },
map
});
marker.customInfowindow = new maps.InfoWindow({
content: `<div>${hn} </br> (${cur} ${rate})</div>`
});
marker.addListener('click', () => {
marker.customInfowindow.open(map, marker);
});
}
};
return (
// Important! Always set the container height explicitly
<div style={{ height: '50vh', width: '100%' }}>
<GoogleMapReact
bootstrapURLKeys={{
key: 'XXXXXXXXXXXXXXX'
}}
center={defaultProps.center}
zoom={defaultProps.zoom}
yesIWantToUseGoogleMapApiInternals
onGoogleApiLoaded={({ map, maps }) => handleApiLoadData(map, maps)}
/>
</div>
);
}

Related

Passing Data Using Props to Display Polylines with Google Maps

Here is the reactjs code for displaying the movement of a vehicle on google map.
In the code, for the path array, latitude and longitude coordinates are assigned as hard-code values.
What I need is, how should pass latitude and longitude coordinates to "path" array from another component using props.
import React from "react";
import {
withGoogleMap,
withScriptjs,
GoogleMap,
Polyline,
Marker,
} from "react-google-maps";
class Map extends React.Component {
state = {
progress: [],
};
path = [
{ lat: 18.558908, lng: -68.389916 },
{ lat: 18.558853, lng: -68.389922 },
{ lat: 18.558375, lng: -68.389729 },
{ lat: 18.558032, lng: -68.389182 },
{ lat: 18.55805, lng: -68.388613 },
{ lat: 18.558256, lng: -68.388213 },
{ lat: 18.558744, lng: -68.387929 },
];
velocity = 5;
initialDate = new Date();
getDistance = () => {
// seconds between when the component loaded and now
const differentInTime = (new Date() - this.initialDate) / 1000; // pass to seconds
return differentInTime * this.velocity; // d = v*t -- thanks Newton!
};
componentDidMount = () => {
this.interval = window.setInterval(this.moveObject, 1000);
};
componentWillUnmount = () => {
window.clearInterval(this.interval);
};
moveObject = () => {
const distance = this.getDistance();
if (!distance) {
return;
}
let progress = this.path.filter(
(coordinates) => coordinates.distance < distance
);
const nextLine = this.path.find(
(coordinates) => coordinates.distance > distance
);
if (!nextLine) {
this.setState({ progress });
return; // it's the end!
}
const lastLine = progress[progress.length - 1];
const lastLineLatLng = new window.google.maps.LatLng(
lastLine.lat,
lastLine.lng
);
const nextLineLatLng = new window.google.maps.LatLng(
nextLine.lat,
nextLine.lng
);
// distance of this line
const totalDistance = nextLine.distance - lastLine.distance;
const percentage = (distance - lastLine.distance) / totalDistance;
const position = window.google.maps.geometry.spherical.interpolate(
lastLineLatLng,
nextLineLatLng,
percentage
);
progress = progress.concat(position);
this.setState({ progress });
};
componentWillMount = () => {
this.path = this.path.map((coordinates, i, array) => {
if (i === 0) {
return { ...coordinates, distance: 0 }; // it begins here!
}
const { lat: lat1, lng: lng1 } = coordinates;
const latLong1 = new window.google.maps.LatLng(lat1, lng1);
const { lat: lat2, lng: lng2 } = array[0];
const latLong2 = new window.google.maps.LatLng(lat2, lng2);
// in meters:
const distance = window.google.maps.geometry.spherical.computeDistanceBetween(
latLong1,
latLong2
);
return { ...coordinates, distance };
});
console.log(this.path);
};
render = () => {
return (
<GoogleMap
defaultZoom={16}
defaultCenter={{ lat: 18.559008, lng: -68.388881 }}
>
{this.state.progress && (
<>
<Polyline
path={this.state.progress}
options={{ strokeColor: "#FF0000 " }}
/>
<Marker
position={this.state.progress[this.state.progress.length - 1]}
/>
</>
)}
</GoogleMap>
);
};
}
const MapComponent = withScriptjs(withGoogleMap(Map));
export default () => (
<MapComponent
googleMapURL="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px`, width: "940px" }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
);
Here is sample data from json object, which I get from other component.I need to pass this data using props to the above path array.
[]
0: {lat: 6.8667528, lng: 79.8769134}
1: {lat: 6.8667112, lng: 79.8769667}
2: {lat: 6.8666556, lng: 79.8769856}
3: {lat: 6.8666023, lng: 79.8769823}
4: {lat: 6.8665584, lng: 79.8770412}
5: {lat: 6.8665478, lng: 79.8771573}
6: {lat: 6.8665295, lng: 79.8772695}
7: {lat: 6.8664823, lng: 79.8774434}
8: {lat: 6.8664434, lng: 79.8777684}
9: {lat: 6.8664023, lng: 79.87823}
10: {lat: 6.8663373, lng: 79.8786712}
11: {lat: 6.86628, lng: 79.87902}
12: {lat: 6.8662312, lng: 79.879335}
13: {lat: 6.8662145, lng: 79.8795562}
14: {lat: 6.8662095, lng: 79.879695}
15: {lat: 6.8661978, lng: 79.8797523}
16: {lat: 6.8659873, lng: 79.8798639}
Can anyone help me to build this? Thanks for your help!
This is a sample code Note: use your own API key for the code to work) and a code snippet below on how I implement it. In the index.js, I put the path array in json file then imported the json file to be used as an element in my map. Then in my Map.js, I set the constuctor(props) and super(props). I put the react-google-maps <GoogleMap> in the render inside the GoogleMapExample variable. Then I use this variable in the return. In the componentWillMount function of your code, you need to use this.props.path.map to get the value of your path from the props.
Index.js
import React, { Component } from "react";
import { render } from "react-dom";
import { withScriptjs } from "react-google-maps";
import Map from "./Map";
import "./style.css";
import jsonPath from "./data.json";
const App = () => {
const MapLoader = withScriptjs(Map);
return (
<MapLoader
path={jsonPath}
googleMapURL="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry,places"
loadingElement={<div style={{ height: `100%` }} />}
/>
);
};
render(<App />, document.getElementById("root"));
Map.js
import React, { Component } from "react";
import {
withGoogleMap,
GoogleMap,
Polyline,
Marker
} from "react-google-maps";
class Map extends Component {
constructor(props) {
super(props);
this.state = {
progress: []
};
}
velocity = 5;
initialDate = new Date();
getDistance = () => {
// seconds between when the component loaded and now
const differentInTime = (new Date() - this.initialDate) / 1000; // pass to seconds
return differentInTime * this.velocity; // d = v*t -- thanks Newton!
};
componentDidMount = () => {
this.interval = window.setInterval(this.moveObject, 1000);
console.log(this.props.path);
};
componentWillUnmount = () => {
window.clearInterval(this.interval);
};
moveObject = () => {
const distance = this.getDistance();
if (!distance) {
return;
}
let progress = this.path.filter(
coordinates => coordinates.distance < distance
);
const nextLine = this.path.find(
coordinates => coordinates.distance > distance
);
if (!nextLine) {
this.setState({ progress });
return; // it's the end!
}
const lastLine = progress[progress.length - 1];
const lastLineLatLng = new window.google.maps.LatLng(
lastLine.lat,
lastLine.lng
);
const nextLineLatLng = new window.google.maps.LatLng(
nextLine.lat,
nextLine.lng
);
// distance of this line
const totalDistance = nextLine.distance - lastLine.distance;
const percentage = (distance - lastLine.distance) / totalDistance;
const position = window.google.maps.geometry.spherical.interpolate(
lastLineLatLng,
nextLineLatLng,
percentage
);
progress = progress.concat(position);
this.setState({ progress });
};
componentWillMount = () => {
this.path = this.props.path.map((coordinates, i, array) => {
if (i === 0) {
return { ...coordinates, distance: 0 }; // it begins here!
}
const { lat: lat1, lng: lng1 } = coordinates;
const latLong1 = new window.google.maps.LatLng(lat1, lng1);
const { lat: lat2, lng: lng2 } = array[0];
const latLong2 = new window.google.maps.LatLng(lat2, lng2);
// in meters:
const distance = window.google.maps.geometry.spherical.computeDistanceBetween(
latLong1,
latLong2
);
return { ...coordinates, distance };
});
console.log(this.path);
};
render() {
const GoogleMapExample = withGoogleMap(props => (
<GoogleMap
defaultZoom={16}
defaultCenter={{ lat: 6.8667528, lng: 79.8769134 }}
>
{this.state.progress && (
<>
<Polyline
path={this.state.progress}
options={{ strokeColor: "#FF0000 " }}
/>
<Marker
position={this.state.progress[this.state.progress.length - 1]}
/>
</>
)}
</GoogleMap>
));
return (
<div>
<GoogleMapExample
containerElement={<div style={{ height: `500px`, width: "500px" }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
}
export default Map;

React google map is not updating

Im using react-google-map, and I add poly line every marker in the map. But every time I delete a data the marker on the map wont disappear. Here is my code below.
Googlemap.js
/*global google*/
import React, { Component } from "react";
import { Polyline } from "react-google-maps";
import {
withGoogleMap,
withScriptjs,
Marker,
GoogleMap,
DirectionsRenderer,
} from "react-google-maps";
const Map = ({ places, zoom, center }) => {
return (
<GoogleMap defaultZoom={zoom} defaultCenter={center}>
<Markers places={places} />
<Polyline
path={places}
options={{
strokeColor: "#FFE900",
strokeOpacity: 2,
strokeWeight: 3,
}}
/>
</GoogleMap>
);
};
const Markers = ({ places }) => {
return places.map((place) => {
return (
<Marker key={place.id} position={{ lat: place.lat, lng: place.lng }} />
);
});
};
class MapWithMarker extends Component {
constructor(props) {
super(props);
this.state = { places: this.props.places }; //initialize initial state from props
}
render() {
return (
<div>
<Map
center={this.props.center}
zoom={this.props.zoom}
places={this.state.places}
containerElement={<div style={{ height: `100vh`, width: "100% " }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
}
export default withScriptjs(withGoogleMap(MapWithMarker));
maploader.js
import React, { Component, useState } from "react";
import "./config";
import Map from "./googlemap";
const App = () => {
const place = places;
return (
<div>
<Map
googleMapURL="https://maps.googleapis.com/maps/api/js?key=API_KEY"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100vh` }} />}
mapElement={<div style={{ height: `100%` }} />}
center={{ lat: 14.6091, lng: 121.0223 }}
zoom={12}
places={places}
/>
</div>
);
};
export default App;
Config.js
places = [
{
name: "Manila",
title: "Newcastle",
lat: 14.6091,
lng: 121.0223,
id: 1,
},
{
name: "Taguig",
title: "Sydney",
lat: 14.5135352,
lng: 121.0303829,
id: 2,
},
{
name: "Makati",
title: "Melbourne",
lat: 14.554592,
lng: 121.0156802,
id: 3,
},
];
And here is the sample code of my button in my map.js. This the button that will delete the last object in array. Everytime i delete a data it should be reflected in the map which is not working but working in console.
function clickSubmit(e) {
places.pop();
}
Any help would be appreciated. :)
In removing a marker in Google Maps JavaScript API, you should call the setMap() method and pass a null argument. However, as you are using react-google-maps library which setMap() method seems to be not included per their documentation.
You can implement your use case without using a library such as this sample code. Please use your API Key in Maps.js file for the code to work.
Please see code snippet with inline comments of the component that shows this:
import React, { Component } from "react";
import { render } from "react-dom";
import Map from "./Map";
import "./style.css";
import "./config";
class App extends Component {
render() {
return (
<div id="container">
<input type="button" value="Delete " id="myBtn" />
<Map
id="myMap"
options={{
center: { lat: 14.6091, lng: 121.0223 },
zoom: 12,
}}
onMapLoad={(map) => {
let placeArray = [];
let markersArray = [];
let polylinePath = [];
let polyline;
//putting the places from config.js in an array
{
places.map((markerJson) => placeArray.push(markerJson));
}
//Adding Marker for each coordinate in the array
for (let i = 0; i < placeArray.length; i++) {
addMarker({ lat: placeArray[i].lat, lng: placeArray[i].lng });
}
//function for creating polyline
createPolyline();
document.getElementById("myBtn").addEventListener("click", function () {
//Removing marker of the last coordinate in the map
markersArray[placeArray.length - 1].setMap(null);
//removing last object in the place and marker array
placeArray.pop();
markersArray.pop();
//Removing polyline in the map
polyline.setMap(null);
//function for creating new polyline using the path that does not include the deleted coordinate
createPolyline();
})
function createPolyline() {
//clearing polyline Path array
polylinePath = [];
//putting the coordinates in the polylinepath array to be used as the path of polyline
for (let i = 0; i < placeArray.length; i++) {
polylinePath.push({
lat: placeArray[i].lat,
lng: placeArray[i].lng,
});
}
//creating polyline
polyline = new google.maps.Polyline({
path: polylinePath,
geodesic: true,
strokeColor: "#FF0000",
strokeOpacity: 1.0,
strokeWeight: 2,
})
//showing polyline in the map
polyline.setMap(map);
}
// Adds a marker to the map and push to the array.
function addMarker(location) {
//creating new marker
const marker = new google.maps.Marker({
position: location,
map: map,
});
//putting the created marker in the markers array to be easily deleted in the map
markersArray.push(marker);
}
}}
/>
</div>
);
}
}
export default App;

Why can I not delete Google Markers?

I have methods of rendering Markers as shown below. I'm passing markers array from props and rendering it each time componentDidUpdate triggered. The problem is my old markers is not removing from maps. For example if I had 1 coordinates inside my parent component and update it with new ones, the new one appears and the old one stands still.
`
import React from 'react';
const google = window.google;
export class GMap extends React.Component {
mapRef = React.createRef();
directionsService
directionsRenderer
map;
componentDidMount() {
this.initMap();
const { onClick } = this.props;
onClick && this.onMapClick();
}
componentDidUpdate() {
const { markers } = this.props;
this.calcRoute();
if (markers && markers.length > 0) {
this.clear(markers);
this.renderMarkers(markers);
}
}
initMap() {
this.directionsService = new google.maps.DirectionsService();
this.directionsRenderer = new google.maps.DirectionsRenderer();
const mapOptions = {
zoom: 13,
center: { lat: 40.386119, lng: 49.860925 }
}
const map = new google.maps.Map(document.getElementById('map'), mapOptions);
this.map = map;
this.directionsRenderer.setMap(map);
}
onMapClick() {
this.map.addListener('click', (e) => {
this.props.onClick(e);
})
}
renderMarkers(markers) {
markers.forEach(position => {
const marker = new google.maps.Marker({ position });
marker.setMap(this.map);
})
}
calcRoute() {
const { directions } = this.props;
if (directions) {
const [{ lat: fLat, lng: fLng }, { lat: tLat, lng: tLng }] = directions;
if (fLat && fLng && tLat && tLng) {
var request = {
origin: { lat: fLat, lng: fLng },
destination: { lat: tLat, lng: tLng },
travelMode: 'DRIVING'
};
this.directionsService.route(request, (result, status) => {
if (status === 'OK') {
this.directionsRenderer.setDirections(result);
}
});
}
}
}
render() {
return (
<div id='map' ref={this.mapRef} />
)
}
}
`
How are you removing the markers? All I can see in the posted code is this.clear(markers) with no reference to clear. Try doing something like this:
clear(markers) {
for(let i = 0; i < markers.length; i++) {
markers[i].setMap(null);
}
}
Hope this helps!

Adding multiple markers to react google maps while using geocoder

What I'm trying to do is send in an array of addresses to a component, use google's geocoder to convert those addresses into lat / long coordinates, and then plat those places on a google map with markers using the google maps api react wrapper. I followed this tutorial pretty closely (https://dev.to/jessicabetts/how-to-use-google-maps-api-and-react-js-26c2) with the biggest difference being that I worked in geocoder. Because geocoder is asynchronous, I can't get the map to re-render with the newly converted coordinates after the promise is resolved. Below is the code I have right now:
import React, { Component } from 'react';
import {Map, InfoWindow, Marker, GoogleApiWrapper} from 'google-maps-react';
const mapStyles = {
width: '100%',
height: '300px'
};
let geocoder;
let addressData = [{location: "146 Pierrepont St, Brooklyn, NY, USA"}, {location: "153 Remsen St, Brooklyn, NY, USA"}];
export class MapContainer extends Component {
constructor (props) {
super(props);
this.onMarkerClick = this.onMarkerClick.bind(this);
this.displayMarkers = this.displayMarkers.bind(this);
this.state = {
lat: 40.6946768,
lng: -73.99161700000002,
showingInfoWindow: false,
activeMarker: {},
selectedPlace: {},
places: [],
stores: [{latitude: 47.49855629475769, longitude: -122.14184416996333},
{latitude: 47.359423, longitude: -122.021071},
{latitude: 47.2052192687988, longitude: -121.988426208496},
{latitude: 47.6307081, longitude: -122.1434325},
{latitude: 47.3084488, longitude: -122.2140121},
{latitude: 47.5524695, longitude: -122.0425407}]
}
}
componentDidMount () {
this.plotPoints()
}
plotPoints () {
let locations = this.getPoints(geocoder)
let places = new Array()
Promise.all(locations)
.then(function(returnVals) {
returnVals.forEach(function(latLng) {
let place = {latitude: latLng[0], longitude: latLng[1]}
places.push(place)
})
})
this.setState (() => {
return {
places: places
}
});
}
getPoints(geocoder) {
let locationData = [];
for (let i = 0; i < addressData.length; i++) {
locationData.push(this.findLatLang(addressData[i].location, geocoder))
}
return locationData // array of promises
}
findLatLang(address, geocoder) {
return new Promise(function(resolve, reject) {
geocoder.geocode({
'address': address
}, function(results, status) {
if (status === 'OK') {
console.log(results);
resolve([results[0].geometry.location.lat(), results[0].geometry.location.lng()]);
} else {
reject(new Error('Couldnt\'t find the location ' + address));
}
})
})
}
displayMarkers (stores) {
return stores.map((place, index) => {
return <Marker key={index} id={index} position={{
lat: place.latitude,
lng: place.longitude
}}
onClick={() => console.log("You clicked me!")} />
})
}
onMarkerClick (props, marker, e) {
this.setState({
selectedPlace: props,
activeMarker: marker,
showingInfoWindow: true
});
};
render() {
geocoder = new this.props.google.maps.Geocoder();
return (
<div className="container place-map">
<div className="row">
<div className="col-md-12">
<Map
google={this.props.google}
zoom={14}
style={mapStyles}
initialCenter={{
lat: this.state.lat,
lng: this.state.lng
}}
>
{this.displayMarkers(this.state.stores)}
{this.displayMarkers(this.state.places)}
<InfoWindow
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}
>
<div>Your Location Here!</div>
</InfoWindow>
</Map>
</div>
</div>
</div>
);
}
}
export default GoogleApiWrapper({
apiKey: 'AIzaSyCOJDrZ_DXmHzbzSXv74mULU3aMu3rNrQc'
})(MapContainer);
The array of "stores" renders markers on the map since there are coordinates available at the initial render of the map - but the coordinates that get pushed onto the "places" array never render. If I put a log statement of the "places" into render() I can see that I am getting back valid coordinates from geocoder.
Help! Been banging my head on this for forever (as you can tell by the current sloppy state of the code).
You need to move the setState for places into the Promise.all callback.
You are calling it when the array is still empty and before the promises have resolved
Promise.all(locations)
.then((returnVals) =>{
returnVals.forEach((latLng) => {
let place = {
latitude: latLng[0],
longitude: latLng[1]
}
places.push(place)
})
// places now populated
this.setState(() => {
return {
places: places
}
});
});

How can I use React with Google Places API, to display place markers on a Google map?

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 display "hotel" markers from the Google Places API on a map.
Using the following JavaScript code from Google Maps, I can display hotels on the Google map, but I would like to do this with React, using react-google-maps.
<!DOCTYPE html>
<html>
<head>
<title>Place searches</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
<script>
// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">
var map;
var infowindow;
function initMap() {
var pyrmont = {lat: -33.867, lng: 151.195};
map = new google.maps.Map(document.getElementById('map'), {
center: pyrmont,
zoom: 15
});
infowindow = new google.maps.InfoWindow();
var service = new google.maps.places.PlacesService(map);
service.nearbySearch({
location: pyrmont,
radius: 500,
type: ['hotel']
}, callback);
}
function callback(results, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
createMarker(results[i]);
}
}
}
function createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(place.name);
infowindow.open(map, this);
});
}
</script>
</head>
<body>
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap" async defer></script>
</body>
</html>
react-google-maps has an example of showing the search input field. So with that I'm able to search and show markers by searching, e.g., "hotels in London". But instead of searching for places, I would like to immediately show the markers for hotels. (The API key in the example below is from the react-google-maps example.)
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,drawing,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 />
I have been trying to figure this out for many days now, and have been looking for tutorials, but I couldn't find a solution. I understand that I should use:
new google.maps.places.PlacesService()
And add options:
const center = new google.maps.LatLng(37.422, -122.084068);
const options = {
location: center
radius: '500',
types: ['hotel']
};
And when using the react-google-maps, I need to use the withScriptjs. But how do I put all of this together?
How can I use react-google-maps with Google Places API, to display "hotel" markers from Google on the map?
You can do that by passing a ref of your GoogleMap to new google.maps.places.PlacesService() to create a service and then with that service you can use nearbySearch() to search for hotels, restaurants, etc. As the Google Places Nearby Search API docs says:
A Nearby Search lets you search for places within a specified area by keyword or type.
To fire the fetchPlaces() method you can use both onTilesLoaded prop from GoogleMap component or componentDidMount(). In the example below I also passed fetchPlaces to onBoundChanged since I am basing my search on bounds so it can give me new places every time I move the map, note here:
const bounds = refs.map.getBounds();
const service = new google.maps.places.PlacesService(refs.map.context.__SECRET_MAP_DO_NOT_USE_OR_YOU_WILL_BE_FIRED);
const request = {
bounds: bounds,
type: ['hotel']
};
Here is my example using recompose:
/*global google*/
import React from "react"
import { compose, withProps, withHandlers, withState } from "recompose"
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps"
const MyMapComponent = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withScriptjs,
withGoogleMap,
withState('places', 'updatePlaces', ''),
withHandlers(() => {
const refs = {
map: undefined,
}
return {
onMapMounted: () => ref => {
refs.map = ref
},
fetchPlaces: ({ updatePlaces }) => {
let places;
const bounds = refs.map.getBounds();
const service = new google.maps.places.PlacesService(refs.map.context.__SECRET_MAP_DO_NOT_USE_OR_YOU_WILL_BE_FIRED);
const request = {
bounds: bounds,
type: ['hotel']
};
service.nearbySearch(request, (results, status) => {
if (status == google.maps.places.PlacesServiceStatus.OK) {
console.log(results);
updatePlaces(results);
}
})
}
}
}),
)((props) => {
return (
<GoogleMap
onTilesLoaded={props.fetchPlaces}
ref={props.onMapMounted}
onBoundsChanged={props.fetchPlaces}
defaultZoom={8}
defaultCenter={{ lat: 51.508530, lng: -0.076132 }}
>
{props.places && props.places.map((place, i) =>
<Marker key={i} position={{ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }} />
)}
</GoogleMap>
)
})
export default class MyFancyComponent extends React.PureComponent {
render() {
return (
<MyMapComponent />
)
}
}

Categories

Resources