Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Google Map DirectionsRenderer Issue

As I want to create Route from my current location to a particular clicked marker in React. For Implementing this I am using React Google Map library (react-google-maps) and it's direction example (Direction Example) but unfortunately I am unable to call new google.maps.DirectionsService() method in React component. It is giving me error as google is undefined.There is already open issue for the same scenario (google is undefined)

like image 218
UIseeker Avatar asked Oct 18 '22 12:10

UIseeker


2 Answers

Add :

 /* global google */

at the top your react file.

like image 159
moni sogani Avatar answered Oct 21 '22 05:10

moni sogani


To get access to google class at window level, I have created plain 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'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;
like image 24
UIseeker Avatar answered Oct 21 '22 05:10

UIseeker