Reputation: 89
I am currently working on a personal project using react-google-maps
and I am having trouble displaying custom buttons on the map. I want to create a menu button that hovers over the map, just like the top left corner of Google Maps (search bar).
From what the documentation says, you have to create a div and use the following command to put it on a specific side of the map.
map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(<div>);
However, I cannot get this to work nicely with React, as the Google docs are in vanilla js. Where is a good place to put this line of code in React? I know that in vanilla js you can pretty much put it anywhere.
I also looked into the react-google-maps docs but it doesn't seem like this particular use case is implemented in the API.
Is there a way to easily create a custom button that hovers over the map in React or with react-google-maps
? If not is there a neat hack to get this to work somehow? Or maybe a CSS trick I'm not aware of?
Here is some sample code that I currently have for the project:
MapContainer.js
import React from 'react';
import { GoogleMap, withScriptjs, withGoogleMap } from "react-google-maps";
import { compose, withProps } from "recompose";
import Menu from "./Menu";
// -----------------------------------------------------------------------------------------
// needed to construct Google Maps in React
const styles = require('../../assets/styles/GoogleMapStyles.json');
const MyMapComponent = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=YOUR_API_KEY",
loadingElement: < div style={{ height: `100%` }} />,
containerElement: < div style={{ height: `100%` }} />,
mapElement: < div style={{ height: `100%` }} />
}),
withScriptjs,
withGoogleMap
)((props) =>
<GoogleMap
defaultZoom={15}
defaultCenter={props.location}
defaultOptions={{styles: styles,
disableDefaultUI: true}}
>
<Menu /> // the hamburger icon that I want hovered over the map
</GoogleMap>
);
// -----------------------------------------------------------------------------------------
export default class MapContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
user: {
currentLocation: {lat: null, lng: null}
},
map: null
};
}
componentDidMount() {
.....
}
render() {
return(
<div id="map-container" ref="map">
<MyMapComponent
location={this.state.user.currentLocation}/>
</div>
);
}
}
Menu.js
import React from 'react';
import '@fortawesome/fontawesome-free/css/all.min.css';
export default class Menu extends React.Component {
constructor(props) {
super(props);
}
render() {
return(
<div>
<span className="menu-btn">
<i class="fas fa-bars"></i>
</span>
</div>
);
}
}
Thanks in advance for your help. Any idea/comment/insight is appreciated at this point. I've been thinking about this problem for quite some time and I'm now in a place where I cannot ignore it any longer...
Upvotes: 4
Views: 6733
Reputation: 746
There is an easy way of doing this if you are using >= React 16.0:
Using a pregenerated div and ReactDom.createPortal inside the return value of the Map component and calling onload with the map parameter to add the div like so:
import React from 'react';
import ReactDom from 'react-dom';
import { GoogleMap, withScriptjs, withGoogleMap } from "react-google-maps";
import { compose, withProps } from "recompose";
import Menu from "./Menu";
// -----------------------------------------------------------------------------------------
// needed to construct Google Maps in React
const styles = require('../../assets/styles/GoogleMapStyles.json');
const controlButtonDiv = document.createElement('div');
const handleOnLoad = map => {
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(controlButtonDiv);
};
const MyMapComponent = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=YOUR_API_KEY",
loadingElement: < div style={{ height: `100%` }} />,
containerElement: < div style={{ height: `100%` }} />,
mapElement: < div style={{ height: `100%` }} />
}),
withScriptjs,
withGoogleMap
)((props) =>
<><GoogleMap
defaultZoom={15}
defaultCenter={props.location}
defaultOptions={{styles: styles,
disableDefaultUI: true}}
onLoad={map => handleOnLoad(map)
>
</GoogleMap>,
ReactDom.createPortal(<Menu />, controlButtonDiv),
</>
);
I actually did this with google-map-react library but it is the same idea, you just need to add
yesIWantToUseGoogleMapApiInternals
onGoogleApiLoaded={({ map, maps }) => handleOnLoad(map, maps)}
as attributes and do the same thing.
Upvotes: 4