How to calculate the distance from a known point to the closest point in a route using Google Maps API

前端 未结 1 1138
隐瞒了意图╮
隐瞒了意图╮ 2021-01-07 08:38

I am working on a project that displays a map with multiple routes. I need to be able to search by an address and return the distance to the closest point within each of the

相关标签:
1条回答
  • 2021-01-07 09:29

    One solution:

    1. extract the polylines from each route
    2. process through each of the polylines, finding the closest point (using the straight line, "as the crow flies" distance)
    // Use this new renderer with the result
    renderArray[i].setDirections(result);
    // and start the next request
    var polyline = getPolyline(result);
    var marker = new google.maps.Marker({
        position: getClosestPoint(referencePt, polyline),
        map: map,
        icon: iconArray[i]
    });
    nextRequest();
    

    proof of concept fiddle

    code snippet:

    var referencePt = "TBD";
    
    // Initialize some variables
    var directionsService = new google.maps.DirectionsService();
    var num, map, data;
    var requestArray = [],
      renderArray = [];
    var markerBounds = new google.maps.LatLngBounds();
    
    // A JSON Array containing some people/routes and the destinations/stops
    var jsonArray = {
      "Blue Run": ["300 University Ave, Plant 1 Belleville, ON K8N 5T7", "3900 West Hamlin Road Rochester Hills, MI 48309"],
      "Big Run": ["5811 - 99th Avenue Kenosha, WI 53144", "46600 Port St Plymouth, MI 48170"],
      "Slow Run": ["2155 North Talbot Road Windsor, ON N9A 6J3", "46600 Port St Plymouth, MI 48170", "2968 Waterview Rochester Hills, MI 48309", "4350 Campground Rd Louisville, KY 40216"]
    }
    
    // 16 Standard Colours for navigation polylines
    var colourArray = ['navy', 'red', 'green', 'grey', 'fuchsia', 'black', 'white', 'lime', 'maroon', 'purple', 'aqua', 'silver', 'olive', 'blue', 'yellow', 'teal'];
    
    var iconArray = [
      "http://maps.google.com/mapfiles/ms/icons/blue.png",
      "http://maps.google.com/mapfiles/ms/icons/red.png",
      "http://maps.google.com/mapfiles/ms/icons/green.png"
    ];
    
    // Let's make an array of requests which will become individual polylines on the map.
    function generateRequests() {
    
      requestArray = [];
    
      for (var route in jsonArray) {
        // This now deals with one of the people / routes
    
        // Somewhere to store the wayoints
        var waypts = [];
    
        // 'start' and 'finish' will be the routes origin and destination
        var start, finish
    
        // lastpoint is used to ensure that duplicate waypoints are stripped
        var lastpoint
    
        data = jsonArray[route]
    
        limit = data.length
        for (var waypoint = 0; waypoint < limit; waypoint++) {
          if (data[waypoint] === lastpoint) {
            // Duplicate of of the last waypoint - don't bother
            continue;
          }
    
          // Prepare the lastpoint for the next loop
          lastpoint = data[waypoint]
    
          // Add this to waypoint to the array for making the request
          waypts.push({
            location: data[waypoint],
            stopover: true
          });
        }
    
        // Grab the first waypoint for the 'start' location
        start = (waypts.shift()).location;
        // Grab the last waypoint for use as a 'finish' location
        finish = waypts.pop();
        if (finish === undefined) {
          // Unless there was no finish location for some reason?
          finish = start;
        } else {
          finish = finish.location;
        }
    
        // Let's create the Google Maps request object
        var request = {
          origin: start,
          destination: finish,
          waypoints: waypts,
          travelMode: google.maps.TravelMode.DRIVING
        };
    
        // and save it in our requestArray
        requestArray.push({
          "route": route,
          "request": request
        });
      }
    
      processRequests();
    }
    
    function processRequests() {
    
      // Counter to track request submission and process one at a time;
      var i = 0;
    
      // Used to submit the request 'i'
      function submitRequest() {
        directionsService.route(requestArray[i].request, directionResults);
      }
    
      // Used as callback for the above request for current 'i'
      function directionResults(result, status) {
        if (status == google.maps.DirectionsStatus.OK) {
    
          // Create a unique DirectionsRenderer 'i'
          renderArray[i] = new google.maps.DirectionsRenderer();
          renderArray[i].setMap(map);
    
          // Some unique options from the colorArray so we can see the routes
          renderArray[i].setOptions({
            preserveViewport: true,
            suppressInfoWindows: true,
            polylineOptions: {
              strokeWeight: 4,
              strokeOpacity: 0.8,
              strokeColor: colourArray[i]
            },
            markerOptions: {
              icon: {
                path: google.maps.SymbolPath.BACKWARD_CLOSED_ARROW,
                scale: 4,
                strokeColor: colourArray[i]
              },
              clickable: true,
              title: 'Boo yeah!'
            }
          });
    
          // Use this new renderer with the result
          renderArray[i].setDirections(result);
          // and start the next request
          var polyline = getPolyline(result);
          var marker = new google.maps.Marker({
            position: getClosestPoint(referencePt, polyline),
            map: map,
            icon: iconArray[i]
          });
          markerBounds.extend(marker.getPosition());
          nextRequest();
        }
    
      }
    
      function nextRequest() {
        // Increase the counter
        i++;
        // Make sure we are still waiting for a request
        if (i >= requestArray.length) {
          map.fitBounds(markerBounds);
          // No more to do
          return;
        }
        // Submit another request
        submitRequest();
      }
    
      // This request is just to kick start the whole process
      submitRequest();
    }
    
    function getPolyline(result) {
      var polyline = new google.maps.Polyline({
        path: []
      });
      var path = result.routes[0].overview_path;
      var legs = result.routes[0].legs;
      for (i = 0; i < legs.length; i++) {
        var steps = legs[i].steps;
        for (j = 0; j < steps.length; j++) {
          var nextSegment = steps[j].path;
          for (k = 0; k < nextSegment.length; k++) {
            polyline.getPath().push(nextSegment[k]);
          }
        }
      }
      return polyline;
    }
    
    function getClosestPoint(point, polyline) {
      var closestDistance = Number.MAX_VALUE;
      var closestPt;
      for (var i = 0; i < polyline.getPath().getLength(); i++) {
        var distance = google.maps.geometry.spherical.computeDistanceBetween(point, polyline.getPath().getAt(i));
        if (distance < closestDistance) {
          closestDistance = distance;
          closestPt = polyline.getPath().getAt(i);
        }
      }
      return closestPt;
    }
    
    // Called Onload
    function init() {
    
      var address = "320 Elizabeth St Midland, ON L4R 4L6";
      var geo = new google.maps.Geocoder;
      geo.geocode({
        'address': address
      }, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          var latitude = results[0].geometry.location.lat();
          var longitude = results[0].geometry.location.lng();
    
          // Some basic map setup (from the API docs) 
          var mapOptions = {
            //center: new google.maps.LatLng(50.677965, -3.768841),
            center: new google.maps.LatLng(latitude, longitude),
            zoom: 10,
            mapTypeControl: true,
            streetViewControl: true,
            mapTypeId: google.maps.MapTypeId.ROADMAP,
            travelMode: google.maps.TravelMode.DRIVING,
            //unitSystem: google.maps.UnitSystem.IMPERIAL
            unitSystem: google.maps.UnitSystem.METRIC
          };
    
          map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
    
          var circle = {
            strokeColor: '#AA0000',
            strokeOpacity: 0.6,
            strokeWeight: 2,
            fillColor: '#CCCCCC',
            fillOpacity: 0.35,
            map: map,
            radius: 50000,
            center: new google.maps.LatLng(latitude, longitude)
          };
          referencePt = mapOptions.center;
    
          var pickupSpot = new google.maps.Circle(circle);
    
          // Start the request making
          generateRequests()
        } else {
          alert("Geocode was not successful for the following reason: " + status);
        }
      });
    }
    
    // Get the ball rolling and trigger our init() on 'load'
    google.maps.event.addDomListener(window, 'load', init);
    html,
    body,
    #map-canvas {
      height: 100%;
      margin: 0px;
      padding: 0px
    }
    #map-canvas {
      float: left;
      width: 70%;
      height: 100%;
    }
    #panel {
      position: absolute;
      top: 5px;
      left: 50%;
      margin-left: -180px;
      z-index: 5;
      background-color: #fff;
      padding: 5px;
      border: 1px solid #999;
    }
    #control_panel {
      float: right;
      width: 30%;
      text-align: left;
      padding-top: 20px;
    }
    <script src="https://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
    <div id="map-canvas"></div>
    <div id="control_panel">
      <div class="container" style="width:auto;">
        <h1>Trips:</h1>
    
        <div class="panel panel-default">
          <div class="panel-heading">
            <h3 class="panel-title">Blue Run</h3>
    
          </div>
          <div class="panel-body">
            <ol>
              <li><strong>Autosystems (University)</strong>
                <br />300 University Ave, Plant 1 Belleville, ON K8N 5T7</li>
              <li><strong>Fanuc America</strong>
                <br />3900 West Hamlin Road Rochester Hills, MI 48309</li>
            </ol>
          </div>
        </div>
        <div class="panel panel-default">
          <div class="panel-heading">
            <h3 class="panel-title">Big Run</h3>
    
          </div>
          <div class="panel-body">
            <ol>
              <li><strong>Asyst Technologies</strong>
                <br />5811 - 99th Avenue Kenosha, WI 53144</li>
              <li><strong>Autosystems America Inc</strong>
                <br />46600 Port St Plymouth, MI 48170</li>
            </ol>
          </div>
        </div>
        <div class="panel panel-default">
          <div class="panel-heading">
            <h3 class="panel-title">Slow Run</h3>
    
          </div>
          <div class="panel-body">
            <ol>
              <li><strong>A B Automation</strong>
                <br />2155 North Talbot Road Windsor, ON N9A 6J3</li>
              <li><strong>Autosystems America Inc</strong>
                <br />46600 Port St Plymouth, MI 48170</li>
              <li><strong>Industrial Automation</strong>
                <br />2968 Waterview Rochester Hills, MI 48309</li>
              <li><strong>Arkema Inc.</strong>
                <br />4350 Campground Rd Louisville, KY 40216</li>
            </ol>
          </div>
        </div>
      </div>
    </div>
    <input type="hidden" name="lat" id="lat" value="" />
    <input type="hidden" name="lng" id="lng" value="" />

    0 讨论(0)
提交回复
热议问题