I'm using the react-google-maps package to render a Google Map in my react application. I would like to disable street view.
From the documentation, I see there are props for:
defaultStreetView
streetView
I have tried using both with false - but neither works. Does anyone know how to disable street view functionality via this package?
Code snippet here:
import React, { Component } from 'react';
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps";
import PropTypes from 'prop-types';
const Map = withScriptjs(withGoogleMap((props) => {
return(
<GoogleMap
defaultZoom={17}
defaultCenter={{ lat: props.lat, lng: props.lng }}
// defaultStreetView={false}
// streetView={false}
>
{props.isMarkerShown && <Marker position={{ lat: props.lat, lng: props.lng }} />}
</GoogleMap>
)
}))
Map.propTypes = {
lat: PropTypes.number.isRequired,
lng: PropTypes.number.isRequired,
isMarkerShown: PropTypes.bool.isRequired
}
export default Map;
It seems the props defaultStreetView and streetView were actually not relevant in this case.
The way to implement this is to pass { streetViewControl: false } to the options prop.
Correct code:
import React, { Component } from 'react';
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps";
import PropTypes from 'prop-types';
const Map = withScriptjs(withGoogleMap((props) => {
return(
<GoogleMap
defaultZoom={17}
defaultCenter={{ lat: props.lat, lng: props.lng }}
options={{streetViewControl: false}}
>
{props.isMarkerShown && <Marker position={{ lat: props.lat, lng: props.lng }} />}
</GoogleMap>
)
}))
Map.propTypes = {
lat: PropTypes.number.isRequired,
lng: PropTypes.number.isRequired,
isMarkerShown: PropTypes.bool.isRequired
}
export default Map;
Related
I am trying to use google-map-react library to locate the user's current location on Google Maps. I managed to use react-geolocated to get coordinates and fed them into the Latitude and Longitude props in the GoogleMapReact component but it was very far from accurate. I am now seeking an alternative on how to use Google Maps API to get more accurate coordinates and focus on the area on a map where the user is located. Using handleApiLoaded method which I failed to understand how to use to achieve this.
Below is some of the code that I wrote to try and solve this
import React from "react";
import GoogleMapReact from "google-map-react";
import { geolocated } from "react-geolocated";
import LocateMeButton from "./Button";
import "./App.css";
const Marker = () => (
<img
src={
"http://icons.iconarchive.com/icons/paomedia/small-n-flat/256/map-marker-icon.png"
}
alt="MyPin"
/>
);
const Map = props => {
const [state, stateUpdater] = React.useState({
lat: "",
lng: "",
text: ""
});
const getGeolocationCordinates = () => {
return !props.isGeolocationAvailable
? stateUpdater({ text: "unsupported browser" })
: !props.isGeolocationEnabled
? stateUpdater({ text: "Geolocation not enabled" })
: props.coords
? stateUpdater({
lng: props.coords.longitude,
lat: props.coords.latitude
})
: "Getting the location";
};
return (
<div className=" map-container">
<LocateMeButton Click={() => getGeolocationCordinates()} />
<GoogleMapReact
bootstrapURLKeys={{
key: "API_KEY",
language: "en"
}}
yesIWantToUseGoogleMapApiInternals
defaultCenter={{ lat: 0.3211264, lng: 32.5910528 }}
defaultZoom={11}
>
<Marker lat={state.lat} lng={state.lng} />
</GoogleMapReact>
</div>
);
};
export default geolocated({
positionOptions: {
enableHighAccuracy: true
},
userDecisionTimeout: 5000
})(Map);
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<!-- end snippet -->
import React from "react";
import GoogleMapReact from "google-map-react";
import { geolocated } from "react-geolocated";
import LocateMeButton from "./Button";
import "./App.css";
const Marker = () => (
<img
src={
"http://icons.iconarchive.com/icons/paomedia/small-n-flat/256/map-marker-icon.png"
}
alt="MyPin"
/>
);
const Map = props => {
const [state, stateUpdater] = React.useState({
lat: "",
lng: "",
text: ""
});
const getGeolocationCordinates = () => {
return !props.isGeolocationAvailable
? stateUpdater({ text: "unsupported browser" })
: !props.isGeolocationEnabled
? stateUpdater({ text: "Geolocation not enabled" })
: props.coords
? stateUpdater({
lng: props.coords.longitude,
lat: props.coords.latitude
})
: "Getting the location";
};
return (
<div className=" map-container">
<LocateMeButton Click={() => getGeolocationCordinates()} />
<GoogleMapReact
bootstrapURLKeys={{
key: "AIzaSyBtgM1mf0N-Pcsko7Dc5Q2La-K460a9IsA",
language: "en"
}}
yesIWantToUseGoogleMapApiInternals
defaultCenter={{ lat: 0.3211264, lng: 32.5910528 }}
defaultZoom={11}
>
<Marker lat={state.lat} lng={state.lng} />
</GoogleMapReact>
</div>
);
};
export default geolocated({
positionOptions: {
enableHighAccuracy: true
},
userDecisionTimeout: 5000
})(Map);
I removed the API key that you included in your question. In the future, make sure that you won't post your API key in a public site to protect it.
You can implement this use case using your browser's HTML5 Geolocation feature along with the Maps JavaScript API.
Here is a sample code and code snippet below that implements this in google-map-react library.
import React, { Component } from "react";
import GoogleMapReact from "google-map-react";
import "./style.css";
class GoogleMaps extends Component {
constructor(props) {
super(props);
this.state = {
currentLocation: { lat: 40.756795, lng: -73.954298 }
};
}
render() {
console.log(this.state.inputRad);
const apiIsLoaded = (map, maps) => {
navigator?.geolocation.getCurrentPosition(
({ coords: { latitude: lat, longitude: lng } }) => {
const pos = { lat, lng };
this.setState({ currentLocation: pos });
}
);
};
return (
<div>
<div style={{ height: "400px", width: "100%" }}>
<GoogleMapReact
bootstrapURLKeys={{
key: "YOUR_API_KEY",
libraries: ["places"]
}}
defaultCenter={{ lat: 40.756795, lng: -73.954298 }}
defaultZoom={10}
center={this.state.currentLocation}
yesIWantToUseGoogleMapApiInternals
onGoogleApiLoaded={({ map, maps }) => apiIsLoaded(map, maps)}
/>
</div>
</div>
);
}
}
export default GoogleMaps;
How can i re render this using useeffect geo value getting updated from parent?
import React from 'react'
import { compose } from 'recompose'
import { withGoogleMap, GoogleMap as ReactGoogleMap } from 'react-google-maps'
import Marker from './Marker'
const GoogleMap = compose(withGoogleMap)(({ geo }) => {
console.log(geo)
return (
<ReactGoogleMap
center={{ lat: geo.latitude, lng: geo.longitude }}
options={{
streetViewControl: false,
fullscreenControl: false,
gestureHandling: 'cooperative',
zoom: 18,
}}
>
<Marker loc={geo} />
</ReactGoogleMap>
)
})
export default GoogleMap
I try to display gmaps with a direction route between 2 points. So I built:
A container class:
import React, { Component } from 'react';
import { DirectionsRenderer } from 'react-google-maps';
import Map from './Map';
class MapContainer extends Component {
constructor(props) {
super(props);
this.state = { directions: null };
}
componentWillMount() {
const DirectionsService = new google.maps.DirectionsService();
DirectionsService.route(
{
origin: new google.maps.LatLng(41.85073, -87.65126),
destination: new google.maps.LatLng(41.85258, -87.65141),
travelMode: google.maps.TravelMode.DRIVING
},
(result, status) => {
if (status === google.maps.DirectionsStatus.OK) {
this.setState({
directions: result
});
} else {
console.error(`error fetching directions ${result}`);
}
}
);
}
render() {
return (
<Map
googleMapURL={`https://maps.googleapis.com/maps/api/js?key=<APIKEY>&v=3.exp&libraries=geometry,drawing,places`}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `600px`, width: `100%` }} />}
mapElement={<div style={{ height: `100%` }} />}
directions={this.state.directions}
/>
);
}
}
export default MapContainer;
It detects the REACT lifecycle and fetches the JS code from GMaps API and then passes it down to the Map component:
import React, { Component } from 'react';
import {
withScriptjs,
withGoogleMap,
GoogleMap,
Marker,
DirectionsRenderer
} from 'react-google-maps';
import package_ico from '../img/package.png';
const Map = withScriptjs(
withGoogleMap(props => {
const marker_package = (
<Marker
position={{
lat: 41.85073,
lng: -87.65126
}}
icon={package_ico}
/>
);
const marker_destination = (
<Marker
position={{
lat: 41.85258,
lng: -87.65141
}}
/>
);
if (props.directions != null) {
console.log('renderdir');
console.log(props.directions);
return (
<GoogleMap defaultZoom={14} center={{ lat: 41.85073, lng: -87.65126 }}>
{marker_package}
{marker_destination}
{props.directions && (
<DirectionsRenderer directions={props.directions} />
)}
</GoogleMap>
);
} else {
console.log('rendernodirec');
return (
<GoogleMap defaultZoom={14} center={{ lat: 41.85073, lng: -87.65126 }}>
{marker_package}
{marker_destination}
</GoogleMap>
);
}
})
);
export default Map;
The data passes correctly from the MapContainer down to the Map but then it seems like the DirectionsRenderer component that is suppose to manage the result doesn't ingest the data correctly and I get the below error message.
57 Uncaught Fc {message: "not a LatLngBounds or LatLngBoundsLiteral: unknown property f", name: "InvalidValueError", stack: "Error↵ at new Fc (https://maps.googleapis.com/m…3.exp&libraries=geometry,drawing,places:170:4324)"}
message: "not a LatLngBounds or LatLngBoundsLiteral: unknown property f"
name: "InvalidValueError"
What am I doing wrong?
I tried to follow the example: https://tomchentw.github.io/react-google-maps/#directionsrenderer but I would like to avoid using recompose since I found it quite confusing...
Thanks for your feedback.
I wasn't able to reproduce the same error, but it could be the sequence of loading the Google Maps script. Since you are using withScriptJs, your call to google.maps.* should be within the component that is wrapped by withScriptJs, where in your example it is outside. Try moving your componentWillMount function into the Map component as in the example below.
If this resolves the issue, it is a race condition caused by the Google Maps script not being loaded before componentWillMount is fired and google.maps.* would be unavailable.
I have a working example on CodeSandbox here. Most of the code is copied from your examples above. Just put in your API key.
import React, { Component } from "react";
import {
withScriptjs,
withGoogleMap,
GoogleMap,
Marker,
DirectionsRenderer
} from "react-google-maps";
class Map extends React.Component {
constructor(props) {
super(props);
this.state = { directions: null };
}
componentWillMount() {
const DirectionsService = new google.maps.DirectionsService();
DirectionsService.route(
{
origin: new google.maps.LatLng(41.85073, -87.65126),
destination: new google.maps.LatLng(41.85258, -87.65141),
travelMode: google.maps.TravelMode.DRIVING
},
(result, status) => {
if (status === google.maps.DirectionsStatus.OK) {
this.setState({
directions: result
});
} else {
console.error(`error fetching directions ${result}`);
}
}
);
}
render() {
const marker_package = (
<Marker
position={{
lat: 41.85073,
lng: -87.65126
}}
/>
);
const marker_destination = (
<Marker
position={{
lat: 41.85258,
lng: -87.65141
}}
/>
);
if (this.state.directions != null) {
console.log("renderdir");
console.log(this.state.directions);
return (
<GoogleMap defaultZoom={14} center={{ lat: 41.85073, lng: -87.65126 }}>
{marker_package}
{marker_destination}
{this.state.directions && (
<DirectionsRenderer directions={this.state.directions} />
)}
</GoogleMap>
);
} else {
console.log("rendernodirec");
return (
<GoogleMap defaultZoom={14} center={{ lat: 41.85073, lng: -87.65126 }}>
{marker_package}
{marker_destination}
</GoogleMap>
);
}
}
}
export default withScriptjs(withGoogleMap(Map));
when I trying to include geoocoder api code it shows an error of "TypeError: Cannot read property 'maps' of undefined".
this is my code
import React from 'react';
import { compose, withProps,withHandlers } from "recompose"
import { withScriptjs, withGoogleMap, GoogleMap, Marker,InfoWindow,GeoCoder } from "react-google-maps"
import { MarkerClusterer } from 'react-google-maps/lib/components/addons/MarkerClusterer';
import { connect } from 'react-redux';
let geocoder = new google.maps.Geocoder();
const MyMapComponent = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?AIzaSyAoaDS6fIKlYvEHeTaakCxXqp-UwnggoEgv=3&sensor=true&callback=init",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withHandlers({
onMarkerClustererClick: () => (markerClusterer) => {
const clickedMarkers = markerClusterer.getMarkers()
console.log(`Current clicked markers length: ${clickedMarkers.length}`)
console.log(clickedMarkers)
},
}),
withScriptjs,
withGoogleMap
)((props) =>{
return ( <GoogleMap
zoom={props.maps.zoom}
center={{ lat:props.maps.lat, lng:props.maps.lng }}
heading={5}
>
<MarkerClusterer
onClick={props.onMarkerClustererClick}
averageCenter
enableRetinaIcons
gridSize={60}
>
{props.markers.map(marker => (
<Marker
key={marker.photo_id}
position={{ lat: marker.latitude, lng: marker.longitude }}
/>
))}
</MarkerClusterer>
<Marker
position={{lat:props.maps.lat, lng:props.maps.lng }}
>
<InfoWindow>
<p>gdgd</p>
</InfoWindow>
</Marker>
</GoogleMap>
)});
export default class DemoApp extends React.Component {
componentWillMount() {
this.setState({ markers: [] })
}
componentDidMount() {
console.log("+mymap++++++++");
console.log(this.props.myMap);
this.setState({markers:[{photo_id:1,longitude:76.911270,latitude:11.032595},
{photo_id:2,longitude:75.806682,latitude:11.259169},
{photo_id:3,longitude:77.213780,latitude:28.617671},
{photo_id:4,longitude:78.138991,latitude:9.903245}]})
}
render() {
return (
<MyMapComponent markers={this.state.markers} maps={this.props.myMap} />
)
}
}
In the above code when I trying to create a geocoder variable it shows the error.Here I am trying to get the location name from the latitude and longitude positions of the map using geocoder api.
You might have included google in your index.html, so the google variable is not accessible in your component as it is a window variable.
Try using window.google.maps.xxx, then it must resolve your TypeError
For your particular case
import React from 'react';
...
let geocoder = new window.google.maps.Geocoder(); // edited
const MyMapComponent = compose(
...
The main issue with your code was this fragment:
<MyMapComponent markers={this.state.markers} maps={this.props.myMap} />
I assume that DemoApp was the main application component that you were mounting in the index.js file. You haven't passed any props to the DemoApp component therefore in MyMapComponent a maps prop was undefined. Using props.maps.lat inside of that component caused the TypeError: Cannot read property 'maps' of undefined error to appear.
I noticed some other minor issues:
this code is unnecessary:
import { ..., GeoCoder } from 'react-google-maps';
react-google-maps doesn't even export the component with that name. Maybe it used to, but it no longer does. You can check that in the documentation
this also isn't required:
let geocoder = new google.maps.Geocoder();
and I changed the googleMapURL to the one from the docs:
googleMapURL: 'https://maps.googleapis.com/maps/api/js?key=your_key_goes_here&v=3.exp&libraries=geometry,drawing,places'
You can skip generating the key for now, but there will be a warning in the console.
Working code below:
import React, { Component } from 'react';
import { compose, withProps, withHandlers } from 'recompose';
import { withScriptjs, withGoogleMap, GoogleMap, Marker, InfoWindow } from 'react-google-maps';
import { MarkerClusterer } from 'react-google-maps/lib/components/addons/MarkerClusterer';
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%' }} />
}),
withHandlers({
onMarkerClustererClick: () => (markerClusterer) => {
const clickedMarkers = markerClusterer.getMarkers();
console.log(`Current clicked markers length: ${clickedMarkers.length}`);
console.log(clickedMarkers);
}
}),
withScriptjs,
withGoogleMap
)(props => (
<GoogleMap
zoom={props.maps.zoom}
center={{ lat: props.maps.lat, lng: props.maps.lng }}
heading={5}
>
<MarkerClusterer
onClick={props.onMarkerClustererClick}
averageCenter
enableRetinaIcons
gridSize={60}
>
{props.markers.map(marker => (
<Marker key={marker.photo_id} position={{ lat: marker.latitude, lng: marker.longitude }} />
))}
</MarkerClusterer>
<Marker position={{ lat: props.maps.lat, lng: props.maps.lng }}>
<InfoWindow>
<p>test text</p>
</InfoWindow>
</Marker>
</GoogleMap>
));
export default class DemoApp extends Component {
render() {
const markers = [
{ photo_id: 1, longitude: 76.91127, latitude: 11.032595 },
{ photo_id: 2, longitude: 75.806682, latitude: 11.259169 },
{ photo_id: 3, longitude: 77.21378, latitude: 28.617671 }
];
const myMap = {
lng: 78.138991,
lat: 9.903245,
zoom: 6
};
return <MyMapComponent markers={markers} maps={myMap} />;
}
}
I had similar error when were referencing to window.google.maps.Size and this line fixed it.
import { OverlayView } from '#react-google-maps/api'
I am trying to open a infowindow on a specific marker on click, however when i click one it appears that all of them are opening instead, and showing me this error:
React.Children.only expected to receive a single React element child.
This is what my code looks like right now:
import React, { Component } from 'react';
import { GoogleMap, Marker, withGoogleMap, withScriptjs, InfoWindow } from 'react-google-maps'
class Map extends Component {
state = {
isOpen: false
}
handleMarkerClick = () => {
this.setState({ isOpen: true})
}
render() {
return(
<div>
<GoogleMap
defaultZoom={13}
defaultCenter={{ lat: -22.9034778, lng: -43.1264636 }}
>{this.props.markers.map((marker, index) =>(
<Marker
key={index}
position={marker.location}
onClick={this.handleMarkerClick}
>{this.state.isOpen && <InfoWindow onCloseClick={this.handleMarkerClick}/>}
</Marker>
))}
</GoogleMap>
</div>
)
}
}
export default withScriptjs(withGoogleMap(Map))
Start of Edit
I made some changes to try and address the comment, however it isn't working yet, can you give me some hints on what i'm doing wrong, since i made some changes to the top component i will paste it here too:
import React, { Component } from 'react';
import Map from './Map.js'
import List from './List.js'
import escapeRegExp from 'escape-string-regexp'
import sortBy from 'sort-by'
class App extends Component {
state ={
locations:[
{
name: "Paróquia Nossa Senhora das Dores do Ingá",
location: {
lat: -22.9038875,
lng: -43.1252873
},
isOpen:false,
},
{
name: "Museu de Arte Contemporanea de Niteroi",
location: {
lat: -22.9078182,
lng: -43.1262919
},
isOpen:false,
},
{
name: "UFF - Faculdade de Direito",
location: {
lat: -22.9038469,
lng: -43.126024
},
isOpen:false,
},
{
name: "Ponte Rio-Niterói",
location: {
lat: -22.8701,
lng: -43.167
},
isOpen:false,
},
{
name: "Fundação Oscar Niemeyer",
location: {
lat: -22.888533927137285,
lng: -43.12815992250511
},
isOpen:false,
},
{
name: "Campo de São Bento",
location: {
lat: -22.905279,
lng: -43.107759
},
isOpen:false,
}
],
query:''
}
onToggleOpen = (location) => {
this.setState({ isOpen: !this.isOpen })
}
updateQuery = (query) => {
this.setState({ query: query.trim() })
console.log(query)
}
componentDidMount() {}
render() {
const { query, locations } = this.state
let filteredMarkers
if(query) {
const match = new RegExp(escapeRegExp(query), 'i')
filteredMarkers = locations.filter((location) => match.test(location.name))
}else {
filteredMarkers = locations
}
filteredMarkers.sort(sortBy('name'))
return (
<div className="App">
<div style={{height:`5vh`}}>
<input
type='text'
placeholder='Search locations'
value={query}
onChange={(event) => this.updateQuery(event.target.value)}
/>
</div>
<List
markers={filteredMarkers}
/>
<Map
onToggle={this.onToggleOpen}
googleMapURL="https://maps.googleapis.com/maps/api/js?&key=AIzaSyAiqO5W1p5FAFf8RZD11PGigUXSlmVHguQ&v=3"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `80vh` }} />}
mapElement={<div style={{ height: `100%` }} />}
className="Map"
markers={filteredMarkers}
/>
</div>
);
}
}
export default App;
Map.js
import React, { Component } from 'react';
import { GoogleMap, Marker, withGoogleMap, withScriptjs, InfoWindow } from 'react-google-maps'
class Map extends Component {
render() {
return(
<div>
<GoogleMap
defaultZoom={13}
defaultCenter={{ lat: -22.9034778, lng: -43.1264636 }}
>{this.props.markers.map((marker, index) =>(
<Marker
key={index}
position={marker.location}
onClick={() => this.props.onToggle(marker)}
>{marker.isOpen && <InfoWindow onCloseClick={this.ontoggleOpen}>Hello</InfoWindow>}
</Marker>
))}
</GoogleMap>
</div>
)
}
}
export default withScriptjs(withGoogleMap(Map))
The problem i was having with React.Children.only expected to receive a single React element child. was being caused because i didn't set a div inside the infowindow, so simply by adding it this particular problem was solved.
Here is what it used to look like:
<InfoWindow onCloseClick={this.handleMarkerClick}/>
here is what it should look like:
<InfoWindow onCloseClick={()=>this.props.onToggle(marker)}><div>Hello</div></InfoWindow>
or something along these lines.