【问题标题】:How to use fitBounds in react-google-map once you have bounds一旦有了界限,如何在 react-google-map 中使用 fitBounds
【发布时间】:2018-04-24 16:04:59
【问题描述】:

我在哪里调用 fitBounds 或 map.fitbounds。一旦我有界限或如何使用它,我很困惑把它放在哪里。我已将边界设置为本地边界状态。

我在这里react-google-maps: how to use fitBounds, panBy, panTo, panToBounds public APIs? 看过这篇文章,要么我只是做不同的事情,要么因为它对我来说没什么用。

我创建了一个bounds const,然后每次我做一个标记时,我都会将它们中的每一个都添加到执行bounds.extends(Marker in here) 的边界中

代码有点乱,所以我会指出我在哪里做的。在filterItemsByRadius 内部是我创建和设置边界的地方。在 map 函数的末尾,我认为将边界状态设置为边界。

/* global google */
import { default as React, Component } from 'react';
import raf from 'raf';
import canUseDOM from 'can-use-dom';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import {
  withGoogleMap,
  GoogleMap,
  Circle,
  InfoWindow,
  Marker,
  withScriptjs,
} from 'react-google-maps';
import geolib from 'geolib';
import { geolocated } from 'react-geolocated';
import ItemList from './ItemList';
import { Col } from 'react-bootstrap';

import Paper from 'material-ui/Paper';
import Img from 'react-image';
import RaisedButton from 'material-ui/RaisedButton';
import FontIcon from 'material-ui/FontIcon';
import CreateRadius from './CreateRadius';
import offerActions from '../../redux/actions/offerActions';

const googleMapURL =
  'https://maps.googleapis.com/maps/api/js?libraries=places,geometry&key=AIzaSyA7XEFRxE4Lm28tAh44M_568fCLOP_On3k';

const isJson = str => {
  try {
    JSON.parse(str);
  } catch (e) {
    return false;
  }
  return true;
};

const GeolocationGoogleMap = withScriptjs(
  withGoogleMap(props => (
    <GoogleMap defaultZoom={6} zoom={props.zoom} center={props.center} onClick={props.onMapClick}>
      {props.center && (
        <Marker
          position={props.center}
          title={"User's Location"}
          options={{ icon: require('./assets/blueDot.png') }}
        >
          {props.showCenterInfo && (
            <InfoWindow>
              <div>User's Location</div>
            </InfoWindow>
          )}
        </Marker>
      )}
      {/* <Circle
          center={props.center}
          radius={props.zoom}
          options={{
            fillColor: 'red',
            fillOpacity: 0.2,
            strokeColor: 'red',
            strokeOpacity: 1,
            strokeWeight: 1,
          }}
        /> */}
      {props.markers.map((marker, index) => {
        const onClick = () => props.onMarkerClick(marker);
        const onCloseClick = () => props.onCloseClick(marker);

        return (
          <Marker
            key={index}
            position={marker.position}
            title={marker.number.toString()}
            onClick={onClick}
            options={{ icon: 'https://image.ibb.co/evMHxF/shopping_zone_marker_1.png' }}
          >
            {marker.showInfo && (
              <InfoWindow onCloseClick={onCloseClick}>
                <div>
                  <ItemList marker={marker} />
                </div>
              </InfoWindow>
            )}
          </Marker>
        );
      })}
    </GoogleMap>
  )),
);

class OfferMap extends Component {
  constructor(props) {
    super(props);
    this.state = {
      currentPosition: null,
      center: null,
      content: null,
      radius: 15, // ACZ --> put this const in config_env.
      showCenterInfo: true,
      markers: [],
      zoom: 6,
      bounds: null,
    };

    this.handleMarkerClick = this.handleMarkerClick.bind(this);
    this.handleCloseClick = this.handleCloseClick.bind(this);
    this.handleMapClick = this.handleMapClick.bind(this);
    this.filterItemsByRadius = this.filterItemsByRadius.bind(this);
    this.radiusChange = this.radiusChange.bind(this);
    this.zoomChange = this.zoomChange.bind(this);
  }

  componentWillReceiveProps(props) {
    if (props.coords && !props.coords.positionError) {
      this.setState({ center: { lat: props.coords.latitude, lng: props.coords.longitude } });
    } else {
      fetch('http://ip-api.com/json')
        .then(res => res.json())
        .then(data => {
          this.setState({ center: { lat: data.lat, lng: data.lon } });
        })
        .catch(error => {
          this.setState({ content: `Error: The Geolocation service failed (${error.message}).` });
        });
    }
    this.setState({ markers: props.items });
  }

  handleMapClick() {
    this.setState({ showCenterInfo: false });
  }

  handleMarkerClick(targetMarker) {
    this.setState({
      markers: this.state.markers.map(marker => {
        if (marker._id === targetMarker._id) {
          return {
            ...marker,
            showInfo: true,
          };
        }
        return marker;
      }),
    });
  }

  handleCloseClick(targetMarker) {
    this.setState({
      markers: this.state.markers.map(marker => {
        if (marker._id === targetMarker._id) {
          return {
            ...marker,
            showInfo: false,
          };
        }
        return marker;
      }),
    });
  }

  filterItemsByRadius(userRadius) {
    const items = this.state.markers;
    const markers = [];
    const bounds = new google.maps.LatLngBounds();

    items.map((item, i) => {
      let itemGeolocation;
      let itemDescription = 'NO DESCRIPTION';
      let itemThumb;
      // Should be ready - tbaustinedit
      if (item) {
        itemDescription = item.description;
        itemThumb = item.media.mediaVault[item.media.defaultIdx] || {
          mediaType: 'txt',
        };
      }
      if (item.geolocation) {
        itemGeolocation = item.geolocation.coords;
      }
      if (this.state.center) {
        const currentLocation = {
          latitude: this.state.center.lat,
          longitude: this.state.center.lng,
        };
        const distanceArr = geolib.orderByDistance(currentLocation, [itemGeolocation]);
        const miles = (distanceArr[0].distance / 1609.34).toFixed(2);
        if (miles <= userRadius) {
          const loc = new google.maps.LatLng(itemGeolocation.lat, itemGeolocation.lng);
          bounds.extends(loc);
          markers.push({
            _id: item._id,
            position: itemGeolocation,
            number: i,
            content: itemDescription,
            price: item.price,
            quantity: item.quantity,
            currency: item.currency,
            category: item.category,
            title: item.title,
            offer: item.offer,
            thumbnail: itemThumb,
            showInfo: item.showInfo || false,
          });
        }
      }
    });
    this.setState({
      bounds,
    });
    return markers;
  }

  radiusChange(event) {
    console.log(event.target.value);
    this.setState({
      radius: event.target.value,
    });

    const { filter } = this.props.offers;
    filter.radius = event.target.value;
    this.props.sortOffersNew(filter);
  }

  zoomChange(e) {
    console.log('value', e.target.value);
    this.setState({ zoom: Number(e.target.value) });
  }

  render() {
    const markers = this.filterItemsByRadius(this.state.radius);
    return (
      <Col xs={12} smOffset={0} mdOffset={0}>
        <div>
          <div style={{ fontFamily: 'Roboto', fontStyle: 'normal' }}>
            Offers within radius of: {' '}
            <input type="text" defaultValue={this.state.radius} onChange={this.radiusChange} /> {' '}
            miles
            <br />
          </div>
          {/* <CreateRadius
            radiusChange={this.radiusChange}
            numOffers={markers.length}
            initRadius={this.state.zoom}
          /> */}
        </div>
        <br />

        <div
          style={{
            width: '100%',
            height: '500px',
          }}
        >
          <GeolocationGoogleMap
            googleMapURL={googleMapURL}
            loadingElement={<div style={{ height: '100%' }} />}
            containerElement={<div style={{ height: '100%' }} />}
            mapElement={<div style={{ height: '100%' }} />}
            center={this.state.center}
            showCenterInfo={this.state.showCenterInfo}
            content={this.state.content}
            radius={this.state.radius}
            onMapClick={this.handleMapClick}
            onMarkerClick={this.handleMarkerClick}
            onCloseClick={this.handleCloseClick}
            markers={markers}
            zoom={this.state.zoom}
            bounds={this.state.bounds}
          />
        </div>
      </Col>
    );
  }
}

function mapStateToProps({ browser, offers }) {
  return { browser, offers };
}

const dispatchToProps = dispatch => ({
  sortOffersNew: filter => dispatch(offerActions.sortOffers(filter)),
});

export default connect(mapStateToProps, dispatchToProps)(
  geolocated({
    positionOptions: {
      enableHighAccuracy: false,
    },
    userDecisionTimeout: 5000,
  })(OfferMap),
);

【问题讨论】:

    标签: reactjs google-maps google-maps-api-3 react-google-maps


    【解决方案1】:

    您可以在 componentDidMount 或渲染函数中使用 fitbounds

    将 ref 添加到 GoogleMap 并应用 fitbounds &lt;GoogleMap ref={map =&gt; map &amp;&amp; map.fitBounds(bounds)}&gt; .... &lt;/GoogleMap&gt;

    【讨论】:

      【解决方案2】:

      我想限制我的地图 (https://developers.google.com/maps/documentation/javascript/examples/control-bounds-restriction)。

      我将 options 属性与带有 https://www.npmjs.com/package/@react-google-maps/api 库的 GoogleMap 组件一起使用。 该库完全重写了 react-google-maps 库

      代码:

      <GoogleMap
              mapContainerStyle={containerStyle}
              center={center}
              zoom={10}
              ref={(ref) => {this.state.map = ref}}
              onLoad={this.onGoogleMapLoad}
              options={{
                                restriction: {
                                     latLngBounds: {
                                         north: 19.137384, // Mumbai
                                         south: 18.510866, // Pune
                                         west: 72.874748,  // Mumbai
                                         east: 73.879864,  // Pune
                                      },
                                      strictBounds: false,
                     }
               }}
      >
      

      【讨论】:

        【解决方案3】:

        您可以将 ref 分配给 GoogleMap 组件,然后使用生命周期挂钩调用 fitBounds() 函数。

        import React, { useRef, useEffect } from 'react';
        import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps";
        import { GOOGLE_API_KEY } from '../../config/config';
        
        
        // =======================================================================
        //  GOOGLE MAPS
        // =======================================================================
        const RegularMap = withScriptjs(
          withGoogleMap(
            ({ defaultCenter, markers }) => {
              const mapRef = useRef(null);
        
              // Fit bounds function
              const fitBounds = () => {
                const bounds = new window.google.maps.LatLngBounds();
                markers.map(item => {
                  bounds.extend(item.position);
                  return item.id
                });
                mapRef.current.fitBounds(bounds);
              };
        
              // Fit bounds on mount, and when the markers change
              useEffect(() => {
                fitBounds();
              }, [markers]);
        
        
              return (
                <GoogleMap ref={mapRef} defaultCenter={defaultCenter}>
                  {markers.map(
                    ({ position }, index) => <Marker key={`marker_${index}`} position={position} />
                  )}
                </GoogleMap>
              );
            })
        );
        
        
        // =======================================================================
        //  THE MAIN COMPONENT
        // =======================================================================
        
        const MapView = () => {
          const markers = [
            { position: { lat: 37.778519, lng: -122.405640 } },
            { position: { lat: 6.4454594, lng: 3.449074 } }
          ];
        
          return (
              <RegularMap
                defaultCenter={{ lat: 6.4454594, lng: 3.449074 }}
                markers={markers}
                googleMapURL={`https://maps.googleapis.com/maps/api/js?key=${GOOGLE_API_KEY}`}
                loadingElement={<div className="loader" />}
                containerElement={<div className="mapContainer" style={{ height: "400px" }} />}
                mapElement={<div className="map" style={{ height: '100%' }} />}
              />
          );
        }
        
        export default MapView;
        

        【讨论】:

        • 我收到一个错误Uncaught TypeError: mapRef.current.fitBounds is not a function
        【解决方案4】:

        该示例演示了如何将给定标记的视口居中:

        const MapWithAMarkers = compose(
            withProps({
                googleMapURL: "https://maps.googleapis.com/maps/api/js?key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg",
                loadingElement: <div style={{ height: `100%` }} />,
                containerElement: <div style={{ height: `400px` }} />,
                mapElement: <div style={{ height: `100%` }} />,
            }),
            lifecycle({
                componentWillMount() {
        
                    this.setState({
        
                        zoomToMarkers: map => {
                            //console.log("Zoom to markers");
                            const bounds = new window.google.maps.LatLngBounds();
                            map.props.children.forEach((child) => {
                                if (child.type === Marker) {
                                    bounds.extend(new window.google.maps.LatLng(child.props.position.lat, child.props.position.lng));
                                }
                            })
                            map.fitBounds(bounds);
                        }
                    })
                },
            }),
            withScriptjs,
            withGoogleMap
        )(props =>
            <GoogleMap ref={props.zoomToMarkers} defaultZoom={5} defaultCenter={{ lat: 25.0391667, lng: 121.525 }}>
                {props.markers.map(marker => (
                    <Marker
                        key={marker.id}
                        position={{ lat: marker.lat, lng: marker.lng }}
                    />
                ))}
            </GoogleMap>
            );
        

        Demo

        【讨论】:

          【解决方案5】:

          您可以通过向 google-maps-react 生成的 DOM 元素添加 ref 来访问 fitBounds。

          首先,添加一个引用: &lt;GoogleMap ref={(ref) =&gt; { this.map = ref; }}&gt;...&lt;/GoogleMap&gt;

          一旦组件被挂载,你就可以使用 ref 调用 fitBounds。 this.map.fitBounds(bounds)

          【讨论】:

          • 我可以在 componentDidMount 或其他生命周期方法中调用它吗?
          • 是的,你可以在componentDidMount中调用它
          猜你喜欢
          • 1970-01-01
          • 2017-11-13
          • 2022-07-05
          • 2018-11-24
          • 1970-01-01
          • 2020-06-29
          • 2019-05-17
          • 1970-01-01
          • 2017-07-06
          相关资源
          最近更新 更多