6

I have managed to get an autocomplete function to a form input with Maptiler API (OSMNames) (since I find Google Maps API even more confusing).

So here comes the actual problem, I would like to get the driving distance between two places I entered with the help of the autocomplete functions in the two inputs I have created.

I am trying to do so with the OSRM (Open Source Routing Machine) API

Here are my current scripts:

<!--AUTOCOMPLETE-->
<script>
    var autocomplete = new kt.OsmNamesAutocomplete(
    'search1', 'https://geocoder.tilehosting.com/', '#My_Maptiler_API_Code');
</script>
<script>
    var autocomplete = new kt.OsmNamesAutocomplete(
    'search2', 'https://geocoder.tilehosting.com/', '#My_Maptiler_API_Code');
</script>

<!--GET INFO-->
<script>
    function loadXMLDoc() {
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            document.getElementById("result").innerHTML =
            this.responseText;
        }

        if (this.readyState == 4 && this.status == 429) {
            document.getElementById("result").innerHTML =
            "Server overloaded, please try again later."
        }
    };
    xhttp.open("GET", "http://router.project-osrm.org/table/v1/driving/{longitude1},{latitude1};{longitude2},{latitude2}", true);
    xhttp.send();
    }
</script>

First, I need to get the coordinates of the places from the inputs with the help of the autocomplete function.

Currently, when the user clicks on one of the suggested places on the list, just the name item gets written in the input box. Instead, I would like to get the GPS coordinates written, not the name, so that I can use them to send the HTTP request (next step).

What is being written when I click:

What is being written when I click

What I need for the next step:

What I need for the next step

Btw, I have seen some answers in other related questions inviting to use "Nominatim". As I said, I am currently using "OSMNames", is there any difference? Should I change my geocoder?

Then, I would also need to get these coordinates in the HTTP GET request, as shown on the code.

And finally, I would like to get just one of the items from the OSRM response, the distance. Since otherwise, I would just get the entire response.

I try to avoid putting all the code here because I find it confusing when reading but should you need the rest of the code for any reason, please let me know!

6
  • What distance are you expecting to get? The length of a straight line between point A and point B, or the actual driving distance? If the former, you can calculate a pretty decent estimate with the lat/long for each point and some rough great circle calculations. If you need driving distance, you'll first need to calculate a route and measure that route, which is a lot more complex unless you already have a routing algorithm Commented Dec 28, 2018 at 18:53
  • Oh, that's true... I was looking for the driving distance and I thought that there were free OpenSource routing algorithms out there (easy to implement :) ). If only you guys know of any (so I can use its documentation and try to implement it) and could share it here that would be great. Thanks for your help! Gracias por la pregunta Javier, no lo había pensado! :) Commented Dec 28, 2018 at 20:48
  • 2
    Por nada! If you just need driving distance and time between points A and B but don't need (or want to deal with) driving directions or computing those by yourself you may get exactly what you need with Google's Distance matrix API but be advised it's not a free solution. It'll run you in the realm of 5 dollars per 1000 requests. Other solutions can be found on this OSM discussion thread here Commented Dec 28, 2018 at 21:10
  • Ok!! Muchíííísimas gracias!!! I am going to check the OSRM alternative then and see what I can do, I am still learning but this sounds interesting. Have a lovely day!! Commented Dec 28, 2018 at 22:18
  • 1
    OSRM returns the actual driving distance in meters. float is just the datatype.
    – scai
    Commented Jan 2, 2019 at 11:06

1 Answer 1

0

I have created a JSFiddle demo for you, which uses Nominatim to resolve a destination position and OSRM table service to calculate the distance to it:

Openstreetmap with Nominatim and OSRM

My impression is, that many geocoder plugins are not well maintained nowadays, so I just use jQuery to call Nominatim and then OSRM table service:

'use strict';

function processOsrmReply(data) {
  console.log(data);

  if (data.code !== 'Ok') {
    $('#myHint').text('OSRM error code: ' + data.code);
    return;
  }

  $('#myHint').text('Distance: ' + data.distances);
}

function sendOsrmRequest(startLat, startLng, endLat, endLng) {

  var osrmUrl = 'https://router.project-osrm.org/table/v1/driving/' +
    parseFloat(startLng).toFixed(6) + ',' + parseFloat(startLat).toFixed(6) + ';' +
    parseFloat(endLng).toFixed(6) + ',' + parseFloat(endLat).toFixed(6);

  var osrmParams = {
    sources: 0,
    destinations: 1,
    annotations: 'distance'
  };

  $('#myHint').text('Calculating driving distance between places...');
  $.get(osrmUrl, osrmParams, processOsrmReply);
}

var startPosition = [51.4661, 7.2491];
var myMap = L.map('myMap').setView(startPosition, 13);

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(myMap);

var startMarker = L.marker(startPosition)
  .bindPopup('Start: ' + startPosition)
  .addTo(myMap);

$('#myInput').autocomplete({
  source: function(request, response) {

    var nominatimUrl = 'https://nominatim.openstreetmap.org/search/';

    var nominatimParams = {
      q: request.term,
      format: 'json',
      addressdetails: 1,
      limit: 2,
      polygon_geojson: 1
    };

    $.get(nominatimUrl, nominatimParams, function(data) {
      console.log(data);

      if (data.length === 0) {
        $('#myHint').text('Nominatim returned nothing');
        return;
      }

      var autocompleteParams = data.map(n => {
        return {
          label: n.display_name,
          value: [n.lat, n.lon]
        }
      });

      response(autocompleteParams);
    });
  },
  minLength: 5,
  select: function(event, ui) {
    var finalPosition = ui.item.value;
    var finalMarker = L.marker(finalPosition)
      .bindPopup('Destination: ' + finalPosition)
      .addTo(myMap);

    var markerBounds = L.latLngBounds(startMarker.getLatLng(), finalMarker.getLatLng());
    myMap.flyToBounds(markerBounds);

    sendOsrmRequest(startPosition[0], startPosition[1], finalPosition[0], finalPosition[1]);
    return false;
  }
});
html,
body {
  padding: 0;
  margin: 0;
}

#myMap {
  position: absolute;
  top: 4em;
  left: 0;
  bottom: 0;
  right: 0;
  z-index: 1;
}

#myWidget {
  position: absolute;
  z-index: 2;
}
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet.min.css">
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-ui@1/dist/themes/redmond/jquery-ui.min.css">
<script src="https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet-src.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-ui@1/dist/jquery-ui.min.js"></script>

<div class="ui-widget ui-front" id="myWidget">
  <label>Enter destination: <input id="myInput"></label>

  <div id="myHint">Type in at least 5 letters!</div>
</div>

<div id="myMap"></div>

To keep my demo code short, I have hardcoded the starting position to my home city.

You could add a second jQuery UI Autocomplete input field to improve that.

The suggested solution does not require any API keys or payments and the license for my example code here is: public domain.

If you plan to run it in production, you should install your own osrm-backend and Nominatim instances.

Not the answer you're looking for? Browse other questions tagged or ask your own question.