javascript 如何使用 React 和 Google Places API,在 Google 地图上显示地点标记?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47114169/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 07:12:37  来源:igfitidea点击:

How to use React with Google Places API, to display place markers on a Google map?

javascriptreactjsgoogle-maps-api-3google-places-apireact-google-maps

提问by userden

I'm trying to build a similar map as on Airbnb, where you can view place markers as you drag the map around. I would like to display "hotel" markers from the Google Places API on a map.

我正在尝试构建与Airbnb类似的地图,您可以在其中拖动地图时查看位置标记。我想在地图上显示来自 Google Places API 的“酒店”标记。

Using the following JS code from Google MapsI can display hotels on the google map, but I would like to do this with React, using react-google-maps.

使用以下来自谷歌地图的JS 代码,我可以在谷歌地图上显示酒店,但我想用 React 来做到这一点,使用react-google-maps

<!DOCTYPE html>
<html>
  <head>
    <title>Place searches</title>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
    <meta charset="utf-8">
    <style>
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map {
        height: 100%;
      }
      /* Optional: Makes the sample page fill the window. */
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
    <script>
      // This example requires the Places library. Include the libraries=places
      // parameter when you first load the API. For example:
      // <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">

      var map;
      var infowindow;

      function initMap() {
        var pyrmont = {lat: -33.867, lng: 151.195};

        map = new google.maps.Map(document.getElementById('map'), {
          center: pyrmont,
          zoom: 15
        });

        infowindow = new google.maps.InfoWindow();
        var service = new google.maps.places.PlacesService(map);
        service.nearbySearch({
          location: pyrmont,
          radius: 500,
          type: ['hotel']
        }, callback);
      }

      function callback(results, status) {
        if (status === google.maps.places.PlacesServiceStatus.OK) {
          for (var i = 0; i < results.length; i++) {
            createMarker(results[i]);
          }
        }
      }

      function createMarker(place) {
        var placeLoc = place.geometry.location;
        var marker = new google.maps.Marker({
          map: map,
          position: place.geometry.location
        });

        google.maps.event.addListener(marker, 'click', function() {
          infowindow.setContent(place.name);
          infowindow.open(map, this);
        });
      }
    </script>
  </head>
  <body>
    <div id="map"></div>
    <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap" async defer></script>
  </body>
</html>

react-google-mapshas an example of showing the search input field. So with that I'm able to search and show markers by searching e.g. "hotels in London". But instead of searching for places, I would like to immediately show the markers for hotels. (The API key in the example below is from the react-google-maps example).

react-google-maps有一个显示搜索输入字段的示例。因此,我可以通过搜索例如“伦敦的酒店”来搜索和显示标记。但不是搜索地点,我想立即显示酒店的标记。(以下示例中的 API 密钥来自 react-google-maps 示例)。

const _ = require("lodash");
const { compose, withProps, lifecycle } = require("recompose");
const {
  withScriptjs,
  withGoogleMap,
  GoogleMap,
  Marker,
} = require("react-google-maps");
const { SearchBox } = require("react-google-maps/lib/components/places/SearchBox");

const MapWithASearchBox = compose(
  withProps({
    googleMapURL: "https://maps.googleapis.com/maps/api/js?key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg&v=3.exp&libraries=geometry,drawing,places",
    loadingElement: <div style={{ height: `100%` }} />,
    containerElement: <div style={{ height: `400px` }} />,
    mapElement: <div style={{ height: `100%` }} />,
  }),
  lifecycle({
    componentWillMount() {
      const refs = {}

      this.setState({
        bounds: null,
        center: {
          lat: 41.9, lng: -87.624
        },
        markers: [],
        onMapMounted: ref => {
          refs.map = ref;
        },
        onBoundsChanged: () => {
          this.setState({
            bounds: refs.map.getBounds(),
            center: refs.map.getCenter(),
          })
        },
        onSearchBoxMounted: ref => {
          refs.searchBox = ref;
        },
        onPlacesChanged: () => {
          const places = refs.searchBox.getPlaces();
          const bounds = new google.maps.LatLngBounds();

          places.forEach(place => {
            if (place.geometry.viewport) {
              bounds.union(place.geometry.viewport)
            } else {
              bounds.extend(place.geometry.location)
            }
          });
          const nextMarkers = places.map(place => ({
            position: place.geometry.location,
          }));
          const nextCenter = _.get(nextMarkers, '0.position', this.state.center);

          this.setState({
            center: nextCenter,
            markers: nextMarkers,
          });
          // refs.map.fitBounds(bounds);
        },
      })
    },
  }),
  withScriptjs,
  withGoogleMap
)(props =>
  <GoogleMap
    ref={props.onMapMounted}
    defaultZoom={15}
    center={props.center}
    onBoundsChanged={props.onBoundsChanged}
  >
    <SearchBox
      ref={props.onSearchBoxMounted}
      bounds={props.bounds}
      controlPosition={google.maps.ControlPosition.TOP_LEFT}
      onPlacesChanged={props.onPlacesChanged}
    >
      <input
        type="text"
        placeholder="Customized your placeholder"
        style={{
          boxSizing: `border-box`,
          border: `1px solid transparent`,
          width: `240px`,
          height: `32px`,
          marginTop: `27px`,
          padding: `0 12px`,
          borderRadius: `3px`,
          boxShadow: `0 2px 6px rgba(0, 0, 0, 0.3)`,
          fontSize: `14px`,
          outline: `none`,
          textOverflow: `ellipses`,
        }}
      />
    </SearchBox>
    {props.markers.map((marker, index) =>
      <Marker key={index} position={marker.position} />
    )}
  </GoogleMap>
);

<MapWithASearchBox />

I have been trying to figure this out for many days now, and have been looking for tutorials, but couldn't find a solution. I understand that I should use:

我已经尝试解决这个问题很多天了,并且一直在寻找教程,但找不到解决方案。我明白我应该使用:

new google.maps.places.PlacesService()

and add options:

并添加选项:

 const center = new google.maps.LatLng(37.422, -122.084068);
 const options = {
   location: center
   radius: '500',
   types: ['hotel']
 };

And when using the react-google-maps, I need to use the withScriptjs. But I still don't understand how to put all of this together?

当使用 react-google-maps 时,我需要使用withScriptjs。但我仍然不明白如何将所有这些放在一起?

How to use react-google-maps with Google Places API, to display "hotel" markers from Google on the map?

如何将 react-google-maps 与Google Places API 一起使用,以在地图上显示来自 Google 的“酒店”标记?

hotel markers on google map

谷歌地图上的酒店标记

采纳答案by Tiago Alves

You can do that by passing a ref of your GoogleMapto new google.maps.places.PlacesService()to create a service and then with that service you can use nearbySearch()to search for hotels, restaurants, etc. As the Google Places Nearby Search API docssays:

你可以通过传递您的裁判GoogleMapnew google.maps.places.PlacesService()创建一个服务,然后与该服务,您可以使用nearbySearch()搜索酒店,餐馆等作为谷歌的地方搜索附近的API文档说:

A Nearby Search lets you search for places within a specified area by keyword or type.

附近搜索可让您按关键字或类型搜索指定区域内的地点。

To fire the fetchPlaces()method you can use both onTilesLoadedprop from GoogleMapcomponent or componentDidMount(). In the example below I also passed fetchPlacesto onBoundChangedsince I am basing my search on boundsso it can give me new places every time I move the map, note here:

要触发该fetchPlaces()方法,您可以使用GoogleMap组件中的onTilesLoadedprop或. 在下面的示例中,我也传递了,因为我是基于搜索的,因此每次移动地图时它都能为我提供新的位置,请注意:componentDidMount()fetchPlacesonBoundChangedbounds

const bounds = refs.map.getBounds();
const service = new google.maps.places.PlacesService(refs.map.context.__SECRET_MAP_DO_NOT_USE_OR_YOU_WILL_BE_FIRED);
const request = {
  bounds: bounds,
  type: ['hotel']
};

Here is my example using recompose:

这是我使用的示例recompose

/*global google*/
import React from "react"
import { compose, withProps, withHandlers, withState } from "recompose"
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps"

const MyMapComponent = compose(
    withProps({
        googleMapURL: "https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places",
        loadingElement: <div style={{ height: `100%` }} />,
        containerElement: <div style={{ height: `400px` }} />,
        mapElement: <div style={{ height: `100%` }} />,
    }),
    withScriptjs,
    withGoogleMap,
    withState('places', 'updatePlaces', ''),
    withHandlers(() => {
        const refs = {
            map: undefined,
        }

        return {
            onMapMounted: () => ref => {
                refs.map = ref
            },
            fetchPlaces: ({ updatePlaces }) => {
                let places;
                const bounds = refs.map.getBounds();
                const service = new google.maps.places.PlacesService(refs.map.context.__SECRET_MAP_DO_NOT_USE_OR_YOU_WILL_BE_FIRED);
                const request = {
                    bounds: bounds,
                    type: ['hotel']
                };
                service.nearbySearch(request, (results, status) => {
                    if (status == google.maps.places.PlacesServiceStatus.OK) {
                        console.log(results);
                        updatePlaces(results);
                    }
                })
            }
        }
    }),
)((props) => {
    return (
        <GoogleMap
            onTilesLoaded={props.fetchPlaces}
            ref={props.onMapMounted}
            onBoundsChanged={props.fetchPlaces}
            defaultZoom={8}
            defaultCenter={{ lat: 51.508530, lng: -0.076132 }}
        >
            {props.places && props.places.map((place, i) =>
                <Marker key={i} position={{ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }} />
            )}
        </GoogleMap>
    )
})

export default class MyFancyComponent extends React.PureComponent {
    render() {
        return (
            <MyMapComponent />
        )
    }
}