简体   繁体   English

如何使用react-google-maps访问google.maps.Map对象

[英]How to access google.maps.Map object with react-google-maps

I have a pretty simple react application using https://github.com/tomchentw/react-google-maps but I'm having difficulty understanding how to get a reference to my current map or how to access the google.maps.Map object in a custom component. 我有一个非常简单的反应应用程序使用https://github.com/tomchentw/react-google-maps但我很难理解如何获取对当前地图的引用或如何访问google.maps.Map对象在自定义组件中。

I found this on the repo, but after reading through the posts I'm still a little confused. 我在回购中找到了这个 ,但在看了帖子后我仍然有点困惑。

I'm starting my application building off of the the DirectionsRenderer example. 我正在开始构建DirectionsRenderer示例的应用程序。

What I want to do next is add my own custom components for picking the starting point and using the Google Maps autocomplete API. 我接下来要做的是添加我自己的自定义组件,用于选择起点和使用Google Maps自动完成API。

Yes, I know that the package has a component for that already, but I need to do a little more than just search for a location on the map. 是的,我知道包已有一个组件,但我需要做的不仅仅是在地图上搜索一个位置。

In order to accomplish my needs I will do something like 为了满足我的需要,我会做类似的事情

const autocomplete = new google.maps.places.Autocomplete(node);
autocomplete.bindTo('bounds', map);

Where node is the element I'm binding the autocomplete functionality and map is an instance of the google.maps.Map object. 其中node是我绑定自动完成功能的元素, mapgoogle.maps.Map对象的实例。

My application thus far: 我到目前为止的申请:

App.jsx App.jsx

const App = ({ store }) => (
  <Provider store={store}>
    <div>
      <Sidebar>
        <StartingPoint defaultText="Choose starting point&hellip;" />
      </Sidebar>
      <GoogleApiWrapper />
    </div>
  </Provider>
);

GoogleApiWrapper GoogleApiWrapper

const GoogleMapHOC = compose(
  withProps({
    googleMapURL: 'https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=__GAPI_KEY',
    loadingElement: <div style={{ height: '100vw' }} />,
    containerElement: <div style={{ height: '100vh' }} />,
    mapElement: <div style={{ height: '100%' }} />,
  }),
  withScriptjs,
  withGoogleMap,
  lifecycle({
    componentDidMount() {
      const DirectionsService = new google.maps.DirectionsService();

      // make google object available to other components
      this.props.onLoad(google);

      DirectionsService.route({
        origin: new google.maps.LatLng(41.8507300, -87.6512600),
        destination: new google.maps.LatLng(41.8525800, -87.6514100),
        travelMode: google.maps.TravelMode.DRIVING,
      }, (result, status) => {
        if (status === google.maps.DirectionsStatus.OK) {
          this.setState({
            directions: result,
          });
        } else {
          console.error(`error fetching directions ${result}`);
        }
      });
    },
  }),
)(props => (
  <GoogleMap
    ref={props.onMapMounted}
    defaultZoom={13}
    defaultCenter={new google.maps.LatLng(37.771336, -122.446615)}
  >
    {props.directions && <DirectionsRenderer directions={props.directions} />}
  </GoogleMap>
));

If I'm unable to access the google.maps.Map object outside of the wrapper I would alternatively like to access a reference to the element that contains the map so that I may instantiate a new google.maps.Map(ref_to_elem, options); 如果我无法访问包装器之外的google.maps.Map对象,我或者想要访问包含该地图的元素的引用,以便我可以实例化一个new google.maps.Map(ref_to_elem, options);

Any help would be greatly appreciated! 任何帮助将不胜感激!

You can do it by React refs: 你可以通过React refs来做到这一点:

<GoogleMap ref={(map) => this._map = map} />
function someFunc () { 
    //using, for example as:
    this._map.getCenter() 
    this._map.setZoom(your desired zoom);
}

What I did right now in my react-redux application is I assign global variable map outside of react comnponent GoogleMap: 我现在在react-redux应用程序中做的是我在react comnponent GoogleMap之外分配全局变量map:

/*global google*/

// your imports //

var map;

class GoogleMap extends Component {
  constructor(props) {
    super(props);

    this.state = {
      // your states
    };
  }

  // your functions

  componentWillReceiveProps(nextProps) {

  }

  componentDidMount() {

    // code

    // render googlemap

    map = new google.maps.Map(this.refs.map, yourMapProps);

    // add click event listener to the map

    map.addListener('click', function(e) {
      //code
    });

    //viewport listener

    map.addListener('idle', function(){
      // code
    });
  }

  render() {
      return (
        <div id="map" ref="map">
          {places.map((place) => {
             return(<Marker place={place} key={place.key} map={map} />);
          })}
        </div>
  }
}

function mapDispatchToProps(dispatch) {
   //code
}

export default connect(mapDispatchToProps)(GoogleMap);

Pass map as props into Child Component: 将地图作为道具传递到子组件:

/*global google*/

import React, { Component } from 'react';

class Marker extends Component {
  componentDidMount() {
    this.renderMarker();
  }

  renderMarker() {
    var { place, map } = this.props;
    place.setMap(map);
  }

  render() {
    return null;
  }
}

export default Marker;

I don't know is it good practice. 我不知道这是好习惯。 Bu it works. 它有效。 I tried to find the solution how to avoid setting Map Object as global windows.map reading all this stuff about singletons and so on. 我试图找到解决方案如何避免将Map Object设置为全局windows.map阅读所有关于单例的东西等等。 And then this came to my head. 然后这就出现了。 Now if I type window.map in the browser concole I get div id="map" 现在,如果我在浏览器中输入window.map,我会得到div id =“map”

import {GoogleMap, withGoogleMap} from 'react-google-maps';
import {MAP} from 'react-google-maps/lib/constants';

const MapComponent = withGoogleMap(() => (
 {/*Here you have access to google.maps.Map object*/}
     <GoogleMap ref={(map) => map.context[MAP]}/>
 ));


const Map = ({locations}) => (
  <MapComponentClass
    containerElement={MapComponent}
    mapElement={MapComponent}
    locations={locations}/>
);

export default Map;

After thoroughly reading through the react-google-maps documentation, examples, and issues I have come to learn that the package does not support a lot of the things I will need to do for my application. 在仔细阅读react-google-maps文档,示例和问题之后,我了解到该软件包不支持我需要为我的应用程序做的很多事情。

That being said, I have begun writing my own Google Maps API wrapper based off of the work done by Fullstack React . 话虽这么说,我已经开始根据Fullstack React所做的工作编写自己的Google Maps API包装器。 I've omitted a lot of the utilities used in the below mentioned as they can be found here or here . 我省略了下面提到的很多实用程序,因为它们可以在这里这里找到。

That being said my solution is to wrap the google maps container in a higher order component and expose the Map Object via the window object: 据说我的解决方案是将google maps容器包装在更高阶的组件中,并通过window对象公开Map Object:

App 应用

const App = ({ store }) => (
  <Provider store={store}>
    <div>
      <Sidebar>
        <StartingPoint />
        {/* TODO */}
      </Sidebar>
      <GoogleMap />
    </div>
  </Provider>
);

containers/GoogleMap/wrapper.jsx Google Map Higher Order Component wraps GoogleMap Container containers / GoogleMap / wrapper.jsx Google Map高阶订单组件包装GoogleMap容器

const defaultCreateCache = (options) => {
  const opts = options || {};
  const apiKey = opts.apiKey;
  const libraries = opts.libraries || ['places'];
  const version = opts.version || '3.24';
  const language = opts.language || 'en';

  return ScriptCache({
    google: GoogleApi({
      apiKey,
      language,
      libraries,
      version,
    }),
  });
};

const wrapper = options => (WrappedComponent) => {
  const createCache = options.createCache || defaultCreateCache;

  class Wrapper extends Component {
    constructor(props, context) {
      super(props, context);

      this.scriptCache = createCache(options);
      this.scriptCache.google.onLoad(this.onLoad.bind(this));

      this.state = {
        loaded: false,
        google: null,
      };
    }

    onLoad() {
      this.GAPI = window.google;

      this.setState({ loaded: true, google: this.GAPI });
    }

    render() {
      const props = Object.assign({}, this.props, {
        loaded: this.state.loaded,
        google: window.google,
      });
      const mapRef = (el) => { this.map = el; };

      return (
        <div>
          <WrappedComponent {...props} />
          <div ref={mapRef} />
        </div>
      );
    }
  }
  Wrapper.propTypes = {
    dispatchGoogleAPI: PropTypes.func,
  };
  Wrapper.defaultProps = {
    dispatchGoogleAPI: null,
  };

  return Wrapper;
};

export default wrapper;

containers/GoogleMap/index.jsx Google Map Container containers / GoogleMap / index.jsx谷歌地图容器

class Container extends Component {
  constructor(props) {
    super(props);

    this.loadMap = this.loadMap.bind(this);
    this.calcRoute = this.calcRoute.bind(this);
  }

  componentDidUpdate() {
    const { origin, destination, route } = this.props;

    this.calcRoute(origin, destination);
  }

  loadMap(node) {
    if (this.props && this.props.google) {
      const { google } = this.props;

      // instantiate Direction Service
      this.directionsService = new google.maps.DirectionsService();

      this.directionsDisplay = new google.maps.DirectionsRenderer({
        suppressMarkers: true,
      });

      const zoom = 13;
      const mapTypeId = google.maps.MapTypeId.ROADMAP;
      const lat = 37.776443;
      const lng = -122.451978;
      const center = new google.maps.LatLng(lat, lng);

      const mapConfig = Object.assign({}, {
        center,
        zoom,
        mapTypeId,
      });

      this.map = new google.maps.Map(node, mapConfig);

      this.directionsDisplay.setMap(this.map);

      // make the map instance available to other components
      window.map = this.map
    }
  }

  calcRoute(origin, destination) {
    const { google, route } = this.props;

    if (!origin && !destination && !route) return;

    const waypts = [];

    waypts.push({
      location: new google.maps.LatLng(37.415284, -122.076899),
      stopover: true,
    });

    const start = new google.maps.LatLng(origin.lat, origin.lng);
    const end = new google.maps.LatLng(destination.lat, destination.lng);

    this.createMarker(end);

    const request = {
      origin: start,
      destination: end,
      waypoints: waypts,
      optimizeWaypoints: true,
      travelMode: google.maps.DirectionsTravelMode.DRIVING,
    };

    this.directionsService.route(request, (response, status) => {
      if (status === google.maps.DirectionsStatus.OK) {
        this.directionsDisplay.setDirections(response);
        const route = response.routes[0];
        console.log(route);
      }
    });

    this.props.calculateRoute(false);
  }

  createMarker(latlng) {
    const { google } = this.props;

    const marker = new google.maps.Marker({
      position: latlng,
      map: this.map,
    });
  }

  render() {
    return (
      <div>
        <GoogleMapView loaded={this.props.loaded} loadMap={this.loadMap} />
      </div>
    );
  }
}

const GoogleMapContainer = wrapper({
  apiKey: ('YOUR_API_KEY'),
  version: '3', // 3.*
  libraries: ['places'],
})(Container);

const mapStateToProps = state => ({
  origin: state.Trip.origin,
  destination: state.Trip.destination,
  route: state.Trip.route,
});

const mapDispatchToProps = dispatch => ({
  dispatchGoogleMap: (map) => {
    dispatch(googleMap(map));
  },
  calculateRoute: (route) => {
    dispatch(tripCalculation(route));
  },
});

const GoogleMap = connect(mapStateToProps, mapDispatchToProps)(GoogleMapContainer);

export default GoogleMap;

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

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