1

I'm having an issue with google maps InfoBox in a React application. My goal is to open up an empty InfoBox on a google maps instance, and then use ReactDOM.render to put my component inside of it. The component comprises of a set of tabs, with each tab pane making an API call through redux and thunk when it's opened.

This all works fine, it displays nicely. The problem comes from actually clicking on the InfoBox. I can get it to work in one of two ways by changing the enableEventPropagation to be true or false:

  1. enableEventPropagation = true: The component works, all the tabs and buttons, but any markers underneath my InfoBox will be opened if I happen to click on the right part of the InfoBox, which completely breaks the state and flow of my application.

  2. enableEventPropagation = false: The clicks don't go through to the map, but then none of the click events in the react component work. No tabs, no buttons: nothing. Looks great but doesn't work at all.

Here's my code for creating my InfoBox and rendering to it with ReactDOM:

renderInfoBox() {
    let {map, google, infoBox} = this.props;
    let markerElement = MarkerElementService.getMarkerElement(infoBox.ui.markerId);

    this.infoBox = new this.infoBoxClass({
        content: this.refs.infoBoxHolder,
        enableEventPropagation: false,
        pixelOffset: new google.maps.Size(10, -275),
        maxWidth: 350,
        zIndex: 99999999,
        infoBoxClearance: new google.maps.Size(75, 75)
    });

    ReactDOM.render(
        <Provider store={AppStore}>
            <ThemeProvider theme={Theme}>
                <InfoBoxComponent google={google} onClose={this.closeButtonClicked.bind(this)} />
            </ThemeProvider>
        </Provider>,
        this.refs.infoBoxHolder,
        () => {
            this.infoBox.open(map, markerElement);
        }
    );
}

render() {
    return (
        <div ref="infoBoxHolder" />
    );
}

I have tried the following solutions:

  • Swapping to GoogleMaps OverLay. Exactly the same issue, in fact looking at the InfoBox addon it seems InfoBox is a wrapper to OverLay which helps remove some of these problems, but still assumes it's only going to be non-interactive.

  • Disabling event propagation at various points inside of my components, but the effect is that it disables event propagation down the DOM tree, not up, meaning child components don't work! Mad!

It seems my only option left is to somehow calculate the Lat/Lng bounds of the InfoBox once it's been rendered and then sequentially disable all markers that are in that area, but that's a hacky load of nonsense I want to avoid!

Or maybe I have completely the wrong approach?

Tom
  • 1,275
  • 1
  • 18
  • 51
  • Are you going to put up a JS fiddle? I've created a custom infobox overlay myself using googlemaps overlays, which sounds similar to this. I don't get any of the issues you describe. It's hard to say what is causing the problem without seeing more. I did wander if there is a solution using css pointer-events? – Paul Thomas May 08 '17 at 14:59
  • Similar to [this](http://stackoverflow.com/q/24374588/3125070) one and/or [this](http://stackoverflow.com/q/23544327/3125070) one? – Saravanabalagi Ramachandran May 09 '17 at 06:23

1 Answers1

2

There is a few things you could try.

First, if you don't have a lot of markers, you can definitely try to set your markers optimized flag to false. It will render them as separate DOM elements, decreasing the performance but you won't get weird behaviors like you are experiencing.

I couldn't reproduce your issue with normal markers, but was able to with the POIs ones that are added by default. To prevent openings of any marker behind your InfoBox, you can create a listener on enter and leave on your InfoBox that will set a boolean, and override the set method of InfoWindow to cancel default behavior while you are hovering. You still can see the mouse cursor changing but that can be removed using some basic CSS.

Here is an example, try clicking on the Sechelt Aquatic Center marker after clicking on the marker to open the InfoxBox, you shouldn't be able to do it.

function initialize () {

  let enableMarkers = true
  
  const set = google.maps.InfoWindow.prototype.set;
  google.maps.InfoWindow.prototype.set = function (key, val) {
    if (key === 'map') {
      if (!enableMarkers) {
        return
      }
    }
    set.apply(this, arguments)
  }

  const map = new google.maps.Map(document.getElementById('map'), {
    zoom: 15,
    center: new google.maps.LatLng(49.47216, -123.76307),
    mapTypeId: google.maps.MapTypeId.ROADMAP,
  })

  const marker = new google.maps.Marker({
    map,
    draggable: true,
    position: new google.maps.LatLng(49.47216, -123.76307),
    visible: true
  })

  const box = document.createElement('div')
  box.innerHTML = 'Hello <br> Hello <br> Hello'

  google.maps.event.addListener(marker, 'click', function (e) {
    if (!enableMarkers) { return }
    ib.open(map, this)
  })

  const ib = new InfoBox({
    content: box,
    zIndex: 10,
    pixelOffset: new google.maps.Size(-100, 0),
    boxStyle: { 
      background: 'white',
      padding: '5px',
      opacity: 0.75,
      width: '200px',
    },
    closeBoxMargin: '2px',
    closeBoxURL: 'https://www.google.com/intl/en_us/mapfiles/close.gif',
    isHidden: false,
    enableEventPropagation: true,
  })
  
  box.addEventListener('mouseenter', () => {
    enableMarkers = false
  })
  
  box.addEventListener('mouseleave', () => {
    enableMarkers = true
  })
}
<script src="https://maps.googleapis.com/maps/api/js?v=3&amp;sensor=false"></script>
<script src="https://rawgit.com/googlemaps/v3-utility-library/master/infobox/src/infobox.js"></script>

<body onload="initialize()">
  <div id="map" style="width: 100%; height: 200px"></div>
</body>

I also saw in a few places where people had the same kind of issue and had to wait for the InfoBox domready event to start binding their clicks. Don't really think that's relevant since I don't really know how you could do that using React, but still worth noting.

Preview
  • 35,317
  • 10
  • 92
  • 112
  • Damn, thanks for the answer! Your approach in general was just one I hadn't considered. The whole mouseenter and mouseleave is brilliant, I ended up solving my problem by listening to those events on my infobox and then setting a value in my redux store that is checked when a marker is clicked, indirectly disabling all other markers whenever I mouse over an InfoBox. Thanks! – Tom May 10 '17 at 13:46
  • Just discovered this approach doesn't work on mobile! – Tom Jul 24 '18 at 16:18