javascriptreactjsgoogle-map-react

Google-map-react - reactjs: How to dynamically show pop-up window after clicking on a marker


I am building a boat visualizer using AISHub. I was able to locate the vessels I wanted using latitude/longitude and show them on a map. However there are too many vessel (markers) and I don't know who is who.

The problem: How do I show a pop-up window dynamically after clicking on a marker like below?

marker

Below the most important part of the code I am using:

class BoatMap extends Component {
    constructor(props) {
        super(props);
        this.state = {
            buttonEnabled: true,
            buttonClickedAt: null,
            progress: 0,
            ships: [],
            type: 'All',
            shipTypes: [],
            activeShipTypes: [],
            logoMap: {}
        };
        this.updateRequest = this.updateRequest.bind(this);
        this.countDownInterval = null;
    }

// ... other operations
// ... other operations

    render() {
        return (
            <div className="google-map">
                <GoogleMapReact
                    bootstrapURLKeys={{ key: 'My_KEY' }}
                    center={{
                        lat: this.props.activeShip ? this.props.activeShip.latitude : 42.4,
                        lng: this.props.activeShip ? this.props.activeShip.longitude : -71.1
                    }}
                    zoom={8}
                >
                    {/* Rendering all the markers here */}
                    {this.state.ships.map((ship) => (
                        <Ship
                            ship={ship}
                            key={ship.CALLSIGN}
                            lat={ship.LATITUDE}
                            lng={ship.LONGITUDE}
                            logoMap={this.state.logoMap}
                        />
                    ))}

                    <select className="combo-companies" onClick={this.props.handleDropdownChange}>
                        <option value="All">All</option>

                        {this.state.shipTypes.map((type) => (
                            <option
                                className={this.state.activeShipTypes.includes(type) ? 'active' : ''}
                                key={type}
                                value={type}
                            >
                                {type}
                            </option>
                        ))}
                    </select>
                </GoogleMapReact>
            </div>
        );
    }
}

What I have done so far:

1) I found this post which was useful to understand the procedure. But unfortunately I was not able to solve it.

2) Also I found this one which is very useful, but there are two problems that are keeping me from using it: a) the info box is not dynamic, and b) I am using google-map-react but the post isn't:

3) Lastly I tried to write my own component InfoWindowBox.js and below is what I have done so far but have no idea if I am going in the right direction or not and if that should be implemented in the initial code:

InfoWindowBox.js

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { InfoWindow } from 'google-maps-react';

export default class InfoWindowEx extends Component {
    constructor(props) {
        super(props);
        this.infoWindowRef = React.createRef();
        this.contentElement = document.createElement(`div`);
    }

    componentDidUpdate(prevProps) {
        if (this.props.children !== prevProps.children) {
            ReactDOM.render(React.Children.only(this.props.children), this.contentElement);
            this.infoWindowRef.current.infowindow.setContent(this.contentElement);
        }
    }

    render() {
        return <InfoWindow ref={this.infoWindowRef} {...this.props} />;
    }
}

Please is anyone has gone though this, guide to the right direction for solving it as I am running out of ideas.


Solution

  • I created this successfully in reactjs however I did not used google-map-react. I just plainly used some of the snippets from this answer and use it in my sample react code. You can see it in the link provided before you can see it work, you must change the API key in this line

    const API_KEY = "CHANGE_YOUR_API_KEY";
    

    For your reference, here is how I implemented it in my code:

    import React from "react";
    import ReactDOM from 'react-dom';
    
    var map;
    var markers=[];
    var infowindow;
    const API_KEY = "CHANGE_YOUR_API_KEY" ;
    
    class Map extends React.Component {
      constructor(props) { 
        super(props);
        this.onScriptLoad = this.onScriptLoad.bind(this);
      }
    
    
      onScriptLoad() {
          var locations = [
                ['Bondi Beach', -33.890542, 151.274856, 4],
                ['Coogee Beach', -33.923036, 151.259052, 5],
                ['Cronulla Beach', -34.028249, 151.157507, 3],
                ['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
                ['Maroubra BeachManly Beach Manly Beach Manly Beach', -33.950198, 151.259302, 1]
            ];
          var mapOptions = {
                zoom: 10,
                center: new google.maps.LatLng(locations[0][1], locations[0][2]),
                scrollwheel: true,
            };   
        map = new window.google.maps.Map(document.getElementById(this.props.id), mapOptions);
        this.props.onMapLoad(map)
    
           for (var count = 0; count < locations.length; count++) {
             var name = locations[count][0];
             var loc =  new google.maps.LatLng(locations[count][1], locations[count][2]);
                this.createMarker(name,loc);
            }
      }
    
      componentDidMount() {
        if (!window.google) {
          const script = document.createElement('script');
          script.type = 'text/javascript';
          script.src = `https://maps.googleapis.com/maps/api/js?key=`+API_KEY+`&libraries=places,geometry`;
          script.id = 'googleMaps';
          script.async = true;
          script.defer = true;
          document.body.appendChild(script);
          script.addEventListener('load', e => {
            this.onScriptLoad()
          })
        }
        else {
          this.onScriptLoad()
        }
        var marker = new google.maps.Marker({
          position: { lat: -25.344, lng: 131.036 },
          map: map
        });
      }
    
      createMarker(name,loc) {
        var marker = new google.maps.Marker({
          map: map,
          position: loc,
          title: name
    
        });
        markers.push(marker);
    
        infowindow = new google.maps.InfoWindow();
        var content =
          'Location: ' + name +
          '<br/>Lat: ' + loc.lat() +
          '<br/>Long: ' + loc.lng() ;
    
        marker.addListener('click', ()=>{     
          infowindow.setContent(content);  
          infowindow.open(map, marker); 
        });
      }
    
      render() {
        return (
          <div id="root">
          <div className="map" id={this.props.id} />
          </div>
        )
      }
    }
    
    export default Map;
    
    

    Note: there are times that my code is showing 'google is not defined' error in Stackblitz, however you can still continue if you put a space anywhere.