简体   繁体   English

Google-map-react - reactjs:如何在点击标记后动态显示弹出窗口

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

I am building a boat visualizer using AISHub.我正在使用 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. 1)我发现这篇文章对理解程序很有用。 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: 2)我也发现这个非常有用,但有两个问题使我无法使用它:a)信息框不是动态的,b)我正在使用google-map-react但帖子不是'吨:

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: 3)最后,我尝试编写自己的组件InfoWindowBox.js ,下面是我到目前为止所做的,但不知道我是否朝着正确的方向前进,以及是否应该在初始代码中实现:

InfoWindowBox.js信息窗口框.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.请有没有人经历过这个,当我没有想法时,请指导解决它的正确方向。

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).我能说的最好的是,有两种方法可以添加到弹出窗口,这两种方法都不是google-map-react包(建议在地图上使用 react 组件)的原生方法。 You can position <Popup /> either position: absolute , or by passing lng and lat to <Popup /> .您可以将<Popup /> position: absoluteposition: absolute ,或者通过将lnglat传递给<Popup />

Step 1: Create a standard react component, lets call it <Popup /> .第 1 步:创建一个标准的react组件,我们称之为<Popup />

Step 2, Option A: Position with CSS第 2 步,选项 A:使用 CSS 定位

Assign position: absolute to <Popup /> .position: absolute分配给<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 .<Popup /><GoogleMapReact> (同级)相邻放置,并将父容器指定为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第 2 步,选项 B:使用地图 lat/lng 定位

Alternatively, you can pass lat and lng as props to <Popup /> .或者,您可以将latlng作为道具传递给<Popup /> For this to work, Popup should be child of <GoogleMapReact> .为此, Popup应该是<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>

I created this successfully in reactjs however I did not used google-map-react.我在 reactjs 中成功创建了这个,但是我没有使用 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您可以在提供的链接中看到它,然后才能看到它的工作,您必须在此行中更改 API 密钥

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.注意:有时我的代码在 Stackblitz 中显示“google is not defined”错误,但是如果你在任何地方放置一个空格,你仍然可以继续。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM