react-google-maps
react-google-maps copied to clipboard
How to add Custom Controls?
Hi, I am using react-google maps, its great. I am showing multiple markers in the map Now I want a custom control i.e a drop down inside the map, in which If I can select a particular marker and it will only show that marker.
The only problem I am facing is I am unable to show that drop down on the map.
Is there any way to show it on the map?
Any help will be appreciated.
@tomchentw Is there anything which can be done for this?
Can we create our own custom control just like SearchBox
component?
@SyedSaifAli We can create custom controls to render on the map,
- First we need to create a div and add it into Google Maps Controls, something like below
this.map.controls[google.maps.ControlPosition.BOTTOM_RIGHT].push( showhideControlDiv //div container );
- Now you can render any component into that Div, with
ReactDom.render(<ComponentName/>, document.getElementById("showhideControlDiv "))
In the above way we are able to show dropdowns and legends on the Map
@RamYadlapalli Can you provide an example of how to implement it?
I hope this helps. https://gist.github.com/jgimbel/6a36d60e28aaf453d0093ddc47f36533
This is not totally related to this post, but I am having issues where I need to remove a custom control from google map object.
did a repo for this. https://github.com/github0013/react-google-maps-custom-control-removal
@jgimbel https://gist.github.com/jgimbel/6a36d60e28aaf453d0093ddc47f36533#file-mapcontrol-js-L15 This line tries to remove the pushed element, and I am assuming this index is from the push return value. "this.divIndex" assignment is missing from the gist.
I did like this https://github.com/github0013/react-google-maps-custom-control-removal/blob/master/src/MapControl.tsx#L20
But I am not sure if it's right since
https://developers.google.com/maps/documentation/javascript/reference/3.exp/map
this.map.controls[this.props.position]
is MVCArray<Node>
https://developers.google.com/maps/documentation/javascript/reference/3.exp/event#MVCObject
and the return value from the push method is
It's only the length
Problem
My problem is when to actually unmount the component https://github.com/github0013/react-google-maps-custom-control-removal/blob/master/src/MapContainer.tsx#L21
this error hapens.
so how did you actuall get this.divIndex
value, and remove the control element safely?
fixed
https://github.com/github0013/react-google-maps-custom-control-removal/commit/1c5467e1667254dd69285b52d1533cf73992951a
I guess the this.divIndex
can be obtained like this.
https://github.com/github0013/react-google-maps-custom-control-removal/commit/1c5467e1667254dd69285b52d1533cf73992951a#diff-1728495de7abffb586b4d385b72e588fR20
and for the exception, I wrapped the MapControl
component with a div.
ref: https://github.com/facebook/react/issues/6802
So...
I am not unmounting my custom controls, so I wrote it initially without the removeAt. Then I remembered that when I wrote custom controls for leaflet I was informed that the controls were not getting removed on unmount. So I added unmounting to the gist and I forgot to set divIndex like you mentioned. Long story short, now that react 16 has portals unmounting is less necessary than it was back when I wrote this kind of thing for leaflet.
Without calling removeAt there is a small memory leak because the mounting div is never cleaned up. If the returned value of push
is the length of the array, it sounds like you can just subtract one from it to get the correct index. Haven't tested that though.
This is how I did, a little adjust base on @jgimbel 's example.
Map.js
class Map extends React.Component {
componentDidMount() {
// add <CustomControl /> to mapControl
this.map.context[MAP].controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(this.control);
}
render() {
return (
<GoogleMap ref={(ref) => { this.map = ref; }}>
<CustomControl ref={(ref) => { this.control = ref; }} />
...
</GoogleMap>
)
}
}
CustomControl.js
export default () => (
<div>
// something want to display on control
</div>
)
@jgimbel @SyedSaifAli I was getting the same TypeError while unmounting the the map controls. this is how I fixed it : https://gist.github.com/sakhisheikh/87dd587ec126189e95396c380d49298f
@jgimbel I have updated the gist. You do a PR now.
I just did this using the constructor method instead of componentWillMount
because it is unsafe now and struggled a little to make it work because I was not passing the context
to the super
call:
constructor(props, context) {
super(props, context);
const { controlPosition } = props;
this.map = this.context[MAP];
this.control = document.createElement('div');
this.map.controls[controlPosition].push(this.control);
}
probably it is something basic, but better leave it here for future visitors.
So I ran into an error when unmounting multiple custom controls with the solution above. removeAt
will make this.divIndex
of other custom controls component no longer correct.
Here is how I fixed it for future visitors and future me:
componentWillUnmount() {
const controlArray = this.map.controls[this.props.position].getArray()
for (let index in controlArray) {
if (controlArray[index] === this.controlDiv) {
this.map.controls[this.props.position].removeAt(index);
break;
}
}
}
This should be added to the library! https://gist.github.com/jgimbel/6a36d60e28aaf453d0093ddc47f36533#gistcomment-2563894
@markmssd this library is unmaintained about a year, please look at ‘react-google-maps-api’ as replacement
@JustFly1984 Can you add link of that library? react-google-maps-api
@SyedSaifAli https://www.npmjs.com/package/react-google-maps-api
@JustFly1984 Hey, Did you add some changes around DrawingManager
in your forked library? Or do you of anyone else who managed to achieve DrawingManager public API's which are not exposed in this package?
For any other confused travelers, react-google-maps
uses React's Legacy Context API instead of the current one. This was relevant for me because I was trying to get this done in a functional component. My completed component (using React 16.8 Hooks, but using the deprecated-in-16.3 Legacy Context) looks like this:
import React, { useEffect } from 'react';
import { createPortal } from 'react-dom';
import { MAP } from 'react-google-maps/lib/constants';
import PropTypes from 'prop-types';
export default function CustomDrawingManagerControl(
{ position = window.google.maps.ControlPosition.TOP_LEFT, children },
context
) {
const map = context[MAP];
const controlDiv = document.createElement('div');
useEffect(() => {
const controls = map.controls[position];
const index = controls.length;
controls.push(controlDiv);
return () => {
controls.removeAt(index);
};
});
return createPortal(
<div style={{ marginLeft: 16, marginTop: 16 }}>{children}</div>,
controlDiv
);
}
CustomDrawingManagerControl.contextTypes = {
[MAP]: PropTypes.object,
};
To be used like this:
<GoogleMap {...props}>
<CustomMapControl position={google.maps.ControlPosition.BOTTOM_CENTER}>
<div>That was easy</div>
</CustomMapControl>
</GoogleMap>
@a8t I would advise you to look at @react-google-maps/api. We have rewritten it to typescript and new context API, as well as hooks API. https://github.com/JustFly1984/react-google-maps-api/tree/master/packages/react-google-maps-api
`<GoogleMap
id="map"
mapContainerStyle={mapContainerStyle}
zoom={8}
center={props.center}
options={{
mapTypeControlOptions: {
style: window.google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
position: window.google.maps.ControlPosition.TOP_CENTER
},
zoomControlOptions: {
position: window.google.maps.ControlPosition.LEFT_CENTER
},
streetViewControlOptions: {
position: window.google.maps.ControlPosition.LEFT_TOP
}
}}
onClick={onMapClick}
onLoad={onMapLoad}
>`