Reputation: 2394
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?
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.
Upvotes: 2
Views: 10302
Reputation: 9441
Best I can tell, there are 2 ways to add to Popups, neither is native to the google-map-react
package (which recommends using react components on the map). You can position <Popup />
either position: absolute
, or by passing lng
and lat
to <Popup />
.
Step 1: Create a standard react
component, lets call it <Popup />
.
Step 2, Option A: Position with CSS
Assign position: absolute
to <Popup />
. This will allow you to avoid the math to determine when popup renders off-screen/outside viewport). Place the <Popup />
adjacent to (sibling of) <GoogleMapReact>
, and assign the parent container as position: relative
.
<div style={{ height: '100vh', width: '100%', position: 'relative' }}>
<GoogleMapReact
bootstrapURLKeys={{ key: 'SECRETS' }}
defaultCenter={defaults.center}
defaultZoom={defaults.zoom}
>
{markers.map((marker) => (
<Marker
key={marker.id}
lat={marker.latitude}
lng={marker.longitude}
onClick={() => setPopupInfo(marker)}
/>
))}
</GoogleMapReact>
{popupInfo && (<Popup store={popupInfo} style={{ position: 'absolute', top: 0, left: 0, width: '200px' }} />)}
</div>
Step 2, Option B: Position with map lat/lng
Alternatively, you can pass lat
and lng
as props to <Popup />
. For this to work, Popup
should be child of <GoogleMapReact>
.
<div>
<GoogleMapReact
bootstrapURLKeys={{ key: 'SECRETS' }}
defaultCenter={defaults.center}
defaultZoom={defaults.zoom}
>
{markers.map((marker) => (
<Marker
key={marker.id}
lat={marker.latitude}
lng={marker.longitude}
onClick={() => setPopupInfo(marker)}
/>
))}
{popupInfo && (<Popup
store={popupInfo}
lat={popupInfo.latitude}
lng={popupInfo.longitude}
/>)}
</GoogleMapReact>
</div>
Upvotes: 6
Reputation: 2977
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.
Upvotes: 0