Search code examples
reactjsgoogle-mapsgoogle-directions-api

How can I check if a point/place is on or near a route (Directions API) ? - React


I am trying to check if point C falls on the route (or near the route), that is drawn between A and B. I could not find any examples on how to do it in react. I found something about creating a polyline, that follows the route and then using that with isLocationOnEdge(), but I am not sure how it can be used with my example. Below is the code, which builds the route between A and B.

Any answer would be highly appreciated. Thanks!

import React, { Component } from "react";
import {
  GoogleMap,
  LoadScript,
  DirectionsService,
  DirectionsRenderer,
} from "@react-google-maps/api";
class Directions extends Component {
  constructor(props) {
    super(props);
    this.state = {
      response: null,
      travelMode: "DRIVING",
      origin: "",
      destination: "",
    };
    this.directionsCallback = this.directionsCallback.bind(this);
    this.getOrigin = this.getOrigin.bind(this);
    this.getDestination = this.getDestination.bind(this);
    this.onClick = this.onClick.bind(this);
    this.onMapClick = this.onMapClick.bind(this);
  }
  directionsCallback(response) {
    console.log(response);
    if (response !== null) {
      if (response.status === "OK") {
        this.setState(() => ({
          response,
        }));
      } else {
        console.log("response: ", response);
      }
    }
  }
  getOrigin(ref) {
    this.origin = ref;
  }
  getDestination(ref) {
    this.destination = ref;
  }
  onClick() {
    if (this.origin.value !== "" && this.destination.value !== "") {
      this.setState(() => ({
        origin: this.origin.value,
        destination: this.destination.value,
      }));
    }
  }
  onMapClick(...args) {
    console.log("onClick args: ", args);
  }
  render() {
    return (
      <div className="map">
        <div className="map-settings">
          <hr className="mt-0 mb-3" />
          <div className="row">
            <div className="col-md-6 col-lg-4">
              <div className="form-group">
                <label htmlFor="ORIGIN">Origin</label>
                <br />
                <input
                  id="ORIGIN"
                  className="form-control"
                  type="text"
                  ref={this.getOrigin}
                />
              </div>
            </div>
            <div className="col-md-6 col-lg-4">
              <div className="form-group">
                <label htmlFor="DESTINATION">Destination</label>
                <br />
                <input
                  id="DESTINATION"
                  className="form-control"
                  type="text"
                  ref={this.getDestination}
                />
              </div>
            </div>
          </div>
          <button
            className="btn btn-primary"
            type="button"
            onClick={this.onClick}
          >
            Build Route
          </button>
        </div>
        <div className="map-container">
          <LoadScript googleMapsApiKey="MY_API_KEY">
            <GoogleMap
              id="direction-example"
              mapContainerStyle={{
                height: "400px",
                width: "900px",
              }}
              zoom={4}
              center={{
                lat: 0,
                lng: -180,
              }}
              onClick={this.onMapClick}
              onLoad={(map) => {
                console.log("DirectionsRenderer onLoad map: ", map);
              }}
              onUnmount={(map) => {
                console.log("DirectionsRenderer onUnmount map: ", map);
              }}
            >
              {this.state.destination !== "" && this.state.origin !== "" && (
                <DirectionsService
                  options={{
                    destination: this.state.destination,
                    origin: this.state.origin,
                    travelMode: this.state.travelMode,
                  }}
                  callback={this.directionsCallback}
                  onLoad={(directionsService) => {
                    console.log(
                      "DirectionsService onLoad directionsService: ",
                      directionsService
                    );
                  }}
                  onUnmount={(directionsService) => {
                    console.log(
                      "DirectionsService onUnmount directionsService: ",
                      directionsService
                    );
                  }}
                />
              )}
              {this.state.response !== null && (
                <DirectionsRenderer
                  options={{
                    directions: this.state.response,
                  }}
                  onLoad={(directionsRenderer) => {
                    console.log(
                      "DirectionsRenderer onLoad directionsRenderer: ",
                      directionsRenderer
                    );
                  }}
                  onUnmount={(directionsRenderer) => {
                    console.log(
                      "DirectionsRenderer onUnmount directionsRenderer: ",
                      directionsRenderer
                    );
                  }}
                />
              )}
            </GoogleMap>
          </LoadScript>
        </div>
      </div>
    );
  }
}
export default Directions;

Solution

  • You are right, you can use the isLocationOnEdge() to check if your third point is near or along your route polyline. To achieve this, you need to get the coordinates of your third point and use the response.routes[0].overview_path as the path for the new polyline. These two values will be passed in your isLocationOnEdge() parameters.

    How do you plan to pass the third point in your code? If you are using the coordinates it will be easier to plot it on the isLocationOnEdge() however if you will be using an address name, you need to first pass it to Geocoding API to get the coordinates.

    As for the polyline, you can do it like this:

    let routePoly = new google.maps.Polyline({
          path: this.state.response.routes[0].overview_path,
        });
    

    Here is a sample code which is implementing this without using any react library for Google Maps.