3
votes

We are building a simple React application that uses google maps to display various events on the map. We are using this repo: https://github.com/tomchentw/react-google-maps

This is the scenario that we are tying to create: Have a bunch of markers shown on the map and have a custom OverlayView shown at all times above the markers.

This is the problem: We are also using google MarkerClusterer. While the markers get clustered when we zoom out the custom Overlays are still shown.

What we need: Have the custom Overlays hide when the markers are clustered.

Here is the code showing the rendering of our google maps. See the <OverlayView> component. It does not display anything in this example. Is there a way using react to detect when the markers are no longer visible on the map and then set the visibility of the custom Overlay to hidden?

Thank you.

 return ( < div >
   < GoogleMapLoader containerElement = { < div {...this.props
     }
     style = {
       {
         height: "70vh"
       }
     }
     />}
                    googleMapElement={
                        <GoogleMap
                            containerProps={{...this.props}}
                            ref="map"
                            onBoundsChanged={this.handleBoundsChanged}
                            defaultZoom={12}
                            center={
                                center ? center: userPosition
                            }
                        >{contents}
                          <MarkerClusterer
                            averageCenter={true}
                            enableRetinaIcons={true}
                            gridSize={20}>

                                {this.data.Missions.map((marker, index) => {
    const position = marker.startLocationGeo ? {lat:marker.startLocationGeo.latitude, lng: marker.startLocationGeo.longitude} : null;
    const ref = `marker_${index}`;
    if(position){
        let icon = '';
    switch (marker.type) {
        case "hit":
         icon = "https:/ / www.dropbox.com / s / likbnwqx8y5kywv / shooting.png ? dl = 1 ";
         break;
         case "
     transport ":
         icon = "
     https: //www.dropbox.com/s/r22dfeh8lutpwv1/fourbyfour.png?dl=1";
       break;
     default: icon = "https://www.dropbox.com/s/dfjpx65j5v3wlih/pirates.png?dl=1";
     break;
   }
   return ( < Marker key = {
       ref
     }
     ref = {
       ref
     }
     icon = {
       icon
     }
     position = {
       position
     }
     title = {
       marker.title
     }
     onClick = {
       this.handleMarkerClick.bind(this, marker)
     }
     onShapeChanged = {
       this.testFunction.bind(this, marker)
     } >

     { < OverlayView > THIS COMPONENT SHOULD NOT BE VISIBLE WHEN MARKERS ARE CLUSTERED < /OverlayView>}
                

                {<InfoWindow key={`infoWindow_${index}`} position={position} content={marker.value} ref={`infoWindow_${index}`}/ >
     } {
       this.state.openedMissions.indexOf(marker.id.objectId) > -1 ? this.renderInfoWindow(ref, marker) : null
     } < /Marker>
    );
    }
})}
                            </MarkerClusterer >
     < SearchBox bounds = {
       this.state.bounds
     }
     controlPosition = {
       google.maps.ControlPosition.TOP_LEFT
     }
     onPlacesChanged = {
       this.handlePlacesChanged
     }
     ref = "searchBox"
     placeholder = "Search address"
     style = {
       inputStyle
     }
     />
                        </GoogleMap >
   }
   />
            </div >
 )
1

1 Answers

4
votes

I've faced with the same problem and want to post my answer even after almost 1,5 years. I hope that my experience will help someone!

So, what did I do: 1) I created react ccustom marker react component

showMarkerContent() {
    this.setState({
        isShown: true
    });
}

hideMarkerContent() {
    this.setState({
        isShown: false
    });
}

render() {
    return (
        <Marker
            key={this.props.key}
            position={this.props.position}
            icon={this.props.icon}
        >
            {
                this.state.isShown &&
                <OverlayView
                    /* https://github.com/tomchentw/react-google-maps/issues/482 */
                    key={ Math.random() }
                    position={this.props.position}
                    mapPaneName={"overlayMouseTarget"}
                    getPixelPositionOffset={this._getPixelPositionOffset}
                >
                    <div style={this.props.styles}>
                        {this.props.children}
                    </div>
                </OverlayView>
            }
        </Marker>
    );
}

2) In my map component I added all markers and in MarkerClusterer I implemented 2 hooks

<MarkerClusterer
    onClusteringBegin={this._handleClusteringBegin}
    onClusteringEnd={this._handleClusteringEnd}
>
    {markers}
</MarkerClusterer>

3) Hooks looks something like that: clear all Overlay contents before clustering

_handleClusteringBegin() {
    this.markers.forEach((marker) => {
        if(!marker) {
            return;
        }
        marker.hideMarkerContent();
    });
}

4) And draw overlay contents if there is only 1 ,arker in cluster

_handleClusteringEnd(event) {
    const clusters = event.clusters_;
    clusters.forEach((cluster) => {
        if (cluster.markers_.length == 1) {
            const notClusteredMarker = cluster.markers_[0];
            const notClusteredMarkerPosition = notClusteredMarker.position;
            this.markers.forEach((marker) => {
                if(!marker) {
                    return;
                }
                const markerPosition = new google.maps.LatLng(marker.props.position.lat, marker.props.position.lng);
                if (
                    markerPosition.lat() == notClusteredMarkerPosition.lat()
                    && markerPosition.lng() == notClusteredMarkerPosition.lng()
                ) {
                    marker.showMarkerContent();
                }
            });
        }
    });
}

I hope this will help!