React Google Map DirectionsRenderer Issue

How do I want to create a Route from my current location to a specific marker click in React. I use the React Google Map library ( react-google-maps ) and the Direction Example to implement this , but unfortunately I cannot call the method new google.maps.DirectionsService()

in the React component. This is giving me an error as google is undefined. There is already an open issue for the same scenario ( google is undefined )

+3


source to share


2 answers


To access the google class at the window level, I created a simple javascript file.

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 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;

      

+1


source


Add:

 /* global google */

      



at the top of your react file.

0


source







All Articles