【问题标题】:React Google Map DirectionsRenderer IssueReact Google Map DirectionsRenderer 问题
【发布时间】:2017-10-08 21:06:48
【问题描述】:

因为我想创建从我当前位置到 React 中特定点击标记的路线。为了实现这一点,我正在使用 React Google Map library (react-google-maps) 和它的方向示例 (Direction Example) 但不幸的是我无法在 React 组件中调用 new google.maps.DirectionsService() 方法。由于 google 未定义,这给了我错误。同一场景已经存在未解决的问题 (google is undefined)

【问题讨论】:

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


    【解决方案1】:

    添加:

     /* global google */
    

    在您的反应文件顶部。

    【讨论】:

      【解决方案2】:

      为了在窗口级别访问 google 类,我创建了纯 javascript 文件。

      UserDetails.js

      module.exports = {
         "Steepless": {
          directionsService: new google.maps.DirectionsService(),
          directionsRenderer: new google.maps.DirectionsRenderer(),
          elevationService: new google.maps.ElevationService(),
          travelMode: google.maps.TravelMode.DRIVING,
          directionStatus: google.maps.DirectionsStatus.OK,
          longestDistance: 0,
          highestElevation: 0,
          lowestElevation: Infinity,
          chartWidth: 400,
          chartBarWidth: 2
        },
        getOrigin: function (lat, lng) {
          var origin = new google.maps.LatLng(lat, lng);
          return origin;
        },
        getDestination: function (lat, lng) {
          var destination = new google.maps.LatLng(lat, lng);
          return destination;
        }
      };
      

      reactComponent.jsx

      import * as React from "react";
      var config = require("./Config");
      var $ = require('jquery');
      var _this;
      var userDetails = require("./api/UserDetails");
      var _ = require("lodash")
      var modelState = undefined;
      const { Button, Popover, Modal, Tooltip, OverlayTrigger, Accordion, Panel, Row, Col } = require("../../../../../../node_modules/react-bootstrap");
      var GoogleMapLib = require("../../../../../../node_modules/react-google-maps");
      var GoogleMap = GoogleMapLib.GoogleMap;
      var withGoogleMap = GoogleMapLib.withGoogleMap;
      var Marker = GoogleMapLib.Marker;
      var InfoWindow = GoogleMapLib.InfoWindow;
      var Direction = GoogleMapLib.DirectionsRenderer;
      var buyNow;
      
      
      import "../styles/glyphs-style.scss";
      
      import ReferFriend from "./ReferFriend";
      import SaleAlert from "./SaleAlert";
      import WishListButton from "./WishListButton";
      var ProductDetails = React.createClass({
        getInitialState: function () {
          return {
            appended: '',
            showModal: true,
            isLoding: 'none',
            cordinates: '',
            morelikethis: '',
            merchantCollection: '',
            getParent: false,
            acoordianData: '',
            markers: [{
              position: {
                lat: 40.712784, lng: -74.005941,
              },
              key: `New York`,
              defaultAnimation: 2
            }],
            center: {
              lat: parseFloat('40.712784'),
              lng: parseFloat('-74.005941'),
            },
            route: '',
            zoom: 7,
            showInfo: false,
            mywishlistLable: 'ADD TO LIST',
            saleAlertLable: 'GET SALE ALERT',
            wishListChecked: 'glyphicon-heart-empty',
            rawRelated: ''
          };
        },
      
        contextTypes: {
          router: React.PropTypes.object.isRequired
        },
      
        /*Model related stuffs */
        close() {
          userDetails.changeProductDetailsStatus(false);
          this.setState({ mywishlistLable: 'ADD TO LIST' });
          this.setState({ wishListChecked: 'glyphicon-heart-empty' });
          this.setState({ showModal: false });
          modelState = true;
        },
        open() {
          this.setState({ showModal: true });
        },
      
        /*Map related stuff*/
        handleMapLoad: function (map) {
          this._mapComponent = map;
          if (map) {
            console.log(map.getZoom());
          }
        },
      
        /*
         * This is called when you click on the map.
         * Go and try click now.
         */
        handleMapClick: function (event) {
          const nextMarkers = [
            ...this.state.markers,
            {
              position: event.latLng,
              defaultAnimation: 2
      
            },
          ];
          this.setState({
            markers: nextMarkers,
          });
      
          if (nextMarkers.length === 3) {
            this.props.toast(
              `Right click on the marker to remove it`,
              `Also check the code!`
            );
          }
        },
        // Toggle to 'true' to show InfoWindow and re-renders component
        handleMarkerClick: function (targetMarker) {
          var showType;
          var markers = this.state.markers.map(function (item, i) {
      
            if (item.key === targetMarker.key) {
              showType = true;
      
              var geoDetails = userDetails.getUserGeoInfo();
              var destination = userDetails.getDestination(targetMarker.position.lat,targetMarker.position.lng);
              var origin = userDetails.getOrigin(geoDetails.lat,geoDetails.lng);
              console.log(userDetails.Steepless.directionsService);
              userDetails.Steepless.directionsService.route({
                origin: origin,
                destination: destination,
                travelMode: userDetails.Steepless.travelMode,
              }, (result, status) => {
                if (status === userDetails.Steepless.directionStatus) {
                  this.setState({
                    route: result,
                  });
                } else {
                  console.error(`error fetching directions ${result}`);
                }
              });
      
            } else {
              showType = item.showInfo;
            }
            return {
              position: {
                lat: parseFloat(item.position.lat),
                lng: parseFloat(item.position.lng)
              },
              key: i,
              showInfo: showType,
              infoContent: (
                item.infoContent)
            }
          }.bind(this));
          this.setState({ markers: markers })
      
      
        },
        handleMarkerClose: function (targetMarker) {
          var showType;
          var markers = this.state.markers.map(function (item, i) {
            if (item.key === targetMarker.key) {
              showType = false;
            } else {
              showType = item.showInfo;
            }
            return {
              position: {
                lat: parseFloat(item.position.lat),
                lng: parseFloat(item.position.lng)
              },
              key: i,
              showInfo: showType,
              infoContent: (
                item.infoContent)
            }
          }.bind(this));
          this.setState({ markers: markers })
        },
      
        handleMarkerRightClick: function (targetMarker) {
          /*
           * All you modify is data, and the view is driven by data.
           * This is so called data-driven-development. (And yes, it's now in
           * web front end and even with google maps API.)
           */
          const nextMarkers = this.state.markers.filter(marker => marker !== targetMarker);
          this.setState({
            markers: nextMarkers,
          });
        },
      
        getInfoContents: function (item) {
      
        },
        GetModelInfo: function () {
          this.GetProdInfo();
          var geoDetails = userDetails.getUserGeoInfo();
          if (geoDetails) {
            this.setState({
              center: {
                lat: parseFloat(geoDetails.lat),
                lng: parseFloat(geoDetails.lng)
              }
            });
            var lat = geoDetails.lat;
            var lng = geoDetails.lng;
          } else {
            var lat = null;
            var lng = null;
          }
          this.setState({ cordinates: geoDetails });
          $.ajax({
            url: config.magentoBaseUrl + config.MORE_LIKE_THIS,
            dataType: 'json',
            cache: false,
            type: 'POST',
            data: {
              category_name: this.props.productInfo.category_name,
              brand: this.props.productInfo.brand,
              product_category_ids: this.props.productInfo.product_category_ids,
              _id: this.props.productInfo._id,
              lat: lat,
              lng: lng,
              merchant_id: this.props.productInfo.merchant_id,
              storename: this.props.productInfo.store_name
            },
            success: function (data) {
              if (data.productData) {
                //this.setState({morelikethis:data.productData})
                this.setState({ rawRelated: data.productData })
                var merchantData = JSON.parse(data.merchantData);
                if (merchantData) {
                  this.setState({ acoordianData: merchantData });
                  var markers = merchantData.map(function (item, i) {
                    return {
                      position: {
                        lat: parseFloat(item.latitude),
                        lng: parseFloat(item.longitude)
                      },
                      key: item.storename,
                      showInfo: false,
                      infoContent: (
                        this.getInfoContents(item))
                    }
                  }.bind(this));
                  this.setState({ markers: markers })
                }
      
              }
            }.bind(this),
            error: function (xhr, status, err) {
      
            }.bind(this)
          });
        },
        GetProdInfo: function () {
          var details = userDetails.getUserInfo();
          if (details) {
            var prodCheckData = {
              cust_id: details.id,
              skuNumber: this.props.productInfo.sku_number,
              userEmail: details.email
            }
          }
          $.ajax({
            url: config.magentoBaseUrl + config.wishlist_action + 'prod_avail/',
            dataType: 'json',
            cache: false,
            type: 'POST',
            data: prodCheckData,
            success: function (data) {
              if (data.wishdata == "exist") {
                this.setState({ mywishlistLable: 'ADDED IN LIST' });
                this.setState({ wishListChecked: 'glyphicon-heart' });
              }
            }.bind(this),
            error: function (xhr, status, err) {
      
            }.bind(this)
          });
        },
      
        getHome: function () {
          this.setState({ getParent: true });
        },
        wishListAction: function () {
          var details = userDetails.getUserInfo();
          //userDetails.changeProductDetailsStatus(false);
          if (details) {
            if (this.state.wishListChecked === "glyphicon-heart-empty") {
              this.wishListTransactcion('add/', details);
              this.setState({ wishListChecked: 'glyphicon-heart' });
              this.setState({ mywishlistLable: 'ADDED IN LIST' });
            }
            if (this.state.wishListChecked === "glyphicon-heart") {
              this.wishListTransactcion('remove/', details);
              this.setState({ wishListChecked: 'glyphicon-heart-empty' });
              this.setState({ mywishlistLable: 'ADD TO LIST' });
            }
          } else {
            this.context.router.push('/');
            userDetails.setOpenLoginModal('true');
          }
        },
        wishListTransactcion: function (action, details) {
          var wishlistData = {
            cat_id: this.props.productInfo.product_category_ids[0],
            cust_id: details.id,
            skuNumber: this.props.productInfo.sku_number,
            userEmail: details.email,
            merchantName: this.props.productInfo.store_name,
            merchantId: this.props.productInfo.merchant_id,
            aprice: this.props.productInfo.actual_price,
            dprice: this.props.productInfo.discount_price
          }, url = config.magentoBaseUrl + config.wishlist_action + action;
          $.ajax({
            url: url,
            dataType: 'json',
            cache: false,
            type: 'POST',
            data: wishlistData,
            success: function (data) {
              userDetails.setWishlistCount(data);
              this.context.router.push('/');
              this.setState({ tempState: 'true' });
      
            }.bind(this),
            error: function (xhr, status, err) {
            }.bind(this)
          });
        },
        getSavedPrice: function (aPrice, dPrice) {
          var percentDiff, convertedPrice, diff = (aPrice - dPrice) / aPrice * 100;
          percentDiff = diff.toFixed(0);
          convertedPrice = (aPrice - dPrice);
          convertedPrice = this.addCommas(convertedPrice.toFixed(2));
          return "<span class='save-price'>You Save <span>$" + (convertedPrice + " " + "(" + percentDiff + "%)");
        },
      
        addCommas: function (nStr) {
          nStr += '';
          var x = nStr.split('.');
          var x1 = x[0];
          var x2 = x.length > 1 ? '.' + x[1] : '';
          var rgx = /(\d+)(\d{3})/;
          while (rgx.test(x1)) {
            x1 = x1.replace(rgx, '$1' + ',' + '$2');
          }
          return x1 + x2;
        },
        render() {
          var containerProps = {
            className: 'items-map'
          };
          var route = this.state.route;
          const GettingStartedGoogleMap = withGoogleMap(props => (
            <GoogleMap
              ref={props.onMapLoad}
              zoom={this.state.zoom}
              center={this.state.center}
              onClick={props.onMapClick}
              >
              <Marker
                  icon={config.current_location_marker}
                  key="100"
                  position={this.state.center}
      
                  >
                </Marker>
              {this.state.markers.map((marker, index) => (
                <Marker
                  icon={config.marker}
                  key={index}
                  position={marker.position}
                  onClick={() => props.onMarkerClick(marker)}
                  >
                  {marker.showInfo && (
                    <InfoWindow onCloseClick={() => props.onMarkerClose(marker)}>
                      <div dangerouslySetInnerHTML={{ __html: marker.infoContent }}></div>
                    </InfoWindow>
                  )}
                </Marker>
              ))}
              {route ?
              <Direction
                directions={route}
                options={{ polylineOptions: { strokeColor: 'green' },suppressMarkers: true}}  />
                :
              null
               }
            </GoogleMap>
          ));
      
      
          var actualPrice = '';
          var discountPrice;
          var price_html = '';
      
          if (this.props.productInfo.discount_price == null) {
            discountPrice = 0;
          }
          if (parseFloat(this.props.productInfo.discount_price) != 0 && parseFloat(this.props.productInfo.actual_price) != 0) {
            if (parseFloat(this.props.productInfo.discount_price) < parseFloat(this.props.productInfo.actual_price)) {
      
              actualPrice = parseFloat(this.props.productInfo.actual_price).toFixed(2)
              actualPrice = this.addCommas(actualPrice);
              discountPrice = parseFloat(this.props.productInfo.discount_price).toFixed(2)
              discountPrice = this.addCommas(discountPrice);
            } else {
      
              actualPrice = parseFloat(this.props.productInfo.actual_price).toFixed(2)
              discountPrice = this.addCommas(actualPrice);
              discountPrice = '';
      
            }
          } else if (this.props.productInfo.discount_price != 0) {
            discountPrice = parseFloat(this.props.productInfo.discount_price).toFixed(2)
            discountPrice = this.addCommas(discountPrice);
            //discountPrice = '';
          } else if (this.props.productInfo.actual_price != 0) {
            actualPrice = parseFloat(this.props.productInfo.actual_price).toFixed(2)
            actualPrice = this.addCommas(actualPrice);
            discountPrice = '';
          }
          if (discountPrice != 0 && discountPrice != '') {
            var savedPrice = this.getSavedPrice(this.props.productInfo.actual_price, this.props.productInfo.discount_price);
          }
      
          return (
      
            <Modal onEnter={this.GetModelInfo} show={this.props.dataFlag === this.state.showModal ? this.props.dataFlag : this.state.showModal} onHide={this.close} bsSize="large" aria-labelledby="contained-modal-title-lg">
              <Modal.Header closeButton>
                <span onClick={this.close} data-dismiss="modal" aria-label="Close" className="visible-xs glyphicon arrow-left-css glyphicon-arrow-left"></span>
              </Modal.Header>
              <a onClick={this.close} className="hidden-xs prod-details-close"><img className="prod-details-close-img" src={require('../images/close_24.png')} /></a>
              <Modal.Body>
      
                <div>
                  {!this.state.getParent ?
                    <div>
                      <div>
                        {this.state.acoordianData ?
                          <div id="map-canvas">
      
                            <GettingStartedGoogleMap
                              containerElement={
                                <div style={{ height: `100%` }} />
                              }
                              mapElement={
                                <div style={{ height: `100%` }} />
                              }
                              center={this.state.center}
                              markers={this.state.markers}
                              onMarkerClick={this.handleMarkerClick}
                              onMarkerClose={this.handleMarkerClose}
                              />
      
                          </div>
                          : null}
                        <div className="container-fluid">
                          <div className="row">
                            <div className="hidden-xs col-sm-12 col-md-3 col-lg-3 product-store-locator-div">
                              <div className="stiky-store-locator-div filter">
                                <div className="store-locator-section-title">
                                  <span>Store Locator</span>
                                </div>
                                <hr className="store-locator-title-hr" />
      
      
                              </div>
                            </div>
                            <div className="col-sm-12 col-md-9 col-lg-9 product-details-div">
                              <div className="product-details-top-section">
                                <div className="row breadcrum-div">
                                  <div className="col-xs-12 col-sm-12 col-md-12 col-lg-12 breadcrumbs-title">
                                  </div>
                                </div>
                              </div>
      
                              <div className="row product-details-row-div">
                                <div className="col-xs-6 padding-0 col-sm-5 col-md-5 col-lg-4">
                                  <div className="product-details-image-display-div center-block">
                                    <div className="dummy-placeholder"></div>
                                    <div className="product-details-display-section-style center-block">
                                      <img src={this.props.productInfo.product_image} className="img-responsive" alt="product image" />
                                    </div>
                                  </div>
                                </div>
                                <div className="col-xs-6 col-sm-7 col-md-7 col-lg-5">
                                  <div className="product-details-outer-div" >
                                    <div className="product-details-top-div">
                                      <div className="product-brand-name-div">
                                        <div className="product-details-brand-name">{this.props.productInfo.brand} </div>
                                        <div className="product-details-product-name">{this.props.productInfo.product_name}</div>
                                      </div>
                                      <div className="product-details-store-name">{this.props.productInfo.store_name}</div>
                                      {discountPrice ?
                                        <div className="old-price">
                                          <del className="product-listing-details-old-price-div-less" dangerouslySetInnerHTML={{ __html: "$" + actualPrice }}>
      
                                          </del>&nbsp;&nbsp;
                                      <span className="product-listing-details-price-div" dangerouslySetInnerHTML={{ __html: "$" + discountPrice }}>
      
                                          </span>
                                          <div dangerouslySetInnerHTML={{ __html: savedPrice }}></div>
                                        </div>
                                        :
                                        <div className="old-price" dangerouslySetInnerHTML={{ __html: "$" + actualPrice }}></div>
                                      }
                                      <hr className="madal-hr-gray" />
                                      <div className="product-details-description">
                                        <div className="product-details-description-content">
                                          <div className="product-details-description-title">Description</div>
                                          {this.props.productInfo.long_description}
                                        </div>
                                      </div>
                                    </div>
                                    <div className="product-details-bottom-div">
                                      <div className="buy-from-retailer-btn-div">
                                        <a target="_blank" href={this.props.productInfo.retailer_url} >
                                          <button type="button" className="btn buy-from-retailer-btn">
                                            <span className="btn-detail-style">GO TO {this.props.productInfo.store_name}</span>
                                          </button>
                                        </a>
                                      </div>
                                      <div className="add-to-list-btn-div">
                                        <span className="btn add-to-list-btn get-alert-detail-page" ><SaleAlert  {...this.props.productInfo} /></span>
                                      </div>
                                      <div className="button-seprator">&nbsp;</div>
                                      <div className="add-to-list-btn-div">
                                        <button onClick={this.wishListAction} type="button" className="btn add-to-list-btn">
                                          <span className={"add-to-list-btn-span glyphicon " + this.state.wishListChecked}></span>{this.state.mywishlistLable}</button>
                                      </div>
                                    </div>
                                  </div>
                                </div>
                                <div className="col-xs-12 col-sm-12 col-md-12 col-lg-3">
      
                                </div>
                              </div>
                            </div>
      
                          </div>
                          <div className="more-from-brand-div">
                            <h1 className="more-from-brand-link">More Like This</h1>
                          </div>
                          <hr className="madal-hr-gray" />
      
                          <div className="row product-listing-row-div" id="relatedProduct-data">
                            {this.getMoreLikeThisHtml(this.state.rawRelated, this)}
      
                          </div>
                        </div>
                      </div>
                    </div>
                    :
                    null
                  }
      
      
                </div>
              </Modal.Body>
            </Modal>
          );
        }
      });
      
      export default ProductDetails;
      

      【讨论】:

        猜你喜欢
        • 2018-07-03
        • 2021-02-22
        • 2021-09-28
        • 2015-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-25
        • 2014-07-18
        相关资源
        最近更新 更多