Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Calculating Distance Using Google Maps in ASP.NET MVC

DZone's Guide to

Calculating Distance Using Google Maps in ASP.NET MVC

This article shows how I used some of the Google Map APIs to create a web app that allows mobile staff to plan their routes during their working day.

· Web Dev Zone
Free Resource

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

Introduction

Both Google and Bing maps are incredibly useful tools. The APIs they have opened to developers offer an amazing ability to add value to the solutions we provide. We don't have to use ALL OF THE THINGS, sometimes just a snippet here and there can make a big difference to our users. This article shows how I used some of the Google Map APIs to help office staff work out how to best route mobile staff during their working day.

Background

When you have a team of staff on the road, working from cars and vans, they generally fit into one of two categories. Those that are heavily pre-planned (say commercial transport delivery vehicles), and those that have an aspect of planning but need to adjust during the day as needs change. It's this last one we are interested in for this article. Take for example plumbers - sure, they have planned jobs during the day, however, in a big city and a busy service company, there may be multiple emergencies, burst pipes, water leaks, etc., during the day that need to be prioritized and transport routes carefully, but quickly planned out. One of the methods used to decide where to send personnel is a triage system that asks three questions:

  • How important/urgent is the task?
  • How close is the location of the job to one of our mobile staff?
  • What's the soonest one of our mobile staff can get from where they are, to the new location?

This understandably can get very complex very quickly, but by combining different technologies such as GPS/Geolocation on mobile phones to monitor the current location of remote workers, with the coordinates of the different places you potentially need them to go, you can put some very useful solutions together for your users.

The code I am going to describe allows the user to input the current location of a remote worker, and a list of different 'emergency call out' destinations. Using Google Maps, we will be able to display to the user the distance the worker is from each location, and the time it will take them to get to each location. Using this knowledge, they can make better decisions about what call-out job to prioritize with what remote worker.

In the production version of this sample code, I combined numerous additional pieces of information to get to the 'your best choice/route is...' algorithm. This comprised:

You can see that using all of the information above, combined with the data we are able to get from a mapping API can allow us to do some very useful and time-saving things in a solution.

Before we start into the code, as a quick aside, I discussed using the Google Maps API before in an article I wrote describing how to implement custom information window popups and markers for the Google map API in an ASP.net MVC solution. You may find that article useful to give you other ideas for functionality.

Google API Key

In order to get started, you will need to set yourself up with a Google API key. The signup process is very simple, and really, unless you are doing this in large volumes, there is no charge. At the time of writing this article you can get 25,000 map loads free per every 24 hours of usage - pretty generous, and if you need more than this, I'm sure someone somewhere is paying, so you can get a commercial license.

Here are the basics of how to get yourself a license key (note that in my sample code, you MUST replace your own key; I can't for obvious reasons let you have mine).

Getting a key is really simple. First, go to the Google Maps API page, click the 'Get API' button, give it a project name, and in a few seconds, you are ready to go!

Keep the key safe, we'll use it later on.

Settings Things up

I have written the code for this article in ASP.NET MVC targeted at .NET v4.5 in Visual Studio 2015. To get started, we create a web project, and in this case, I cleaned up the _Layout.cshtml as I didn't want any of the standard 'application login' functionality, etc., floating at the top of the demo app - this leaves us with something simple like the following:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
</head>
<body>
    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - My ASP.NET Application</p>
        </footer>
    </div>

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
</body>
</html>

In the index.cshtml page, I have HTML that allows the user to switch between the two different code demos for this article, with corresponding controllers.

<div class="row">
    <div class="col-md-12">
        <h2><a href="demo1">Example 1</a> - simple distance between two points</h2>
        <p>
            This demonstrates getting and displaying the distance between two points
        </p>


    </div>
</div>

<div class="row">
    <div class="col-md-12">
        <h2><a href="demo2">Example 2</a> - distance between one origin and multiple target destinations</h2>
        <p>
            This demonstrates getting and displaying the distance between multiple points
        </p>
    </div>
</div>

Distance and Route Between Two Points

To understand the basics, let's go to demo 1. Here we will look at setting up a Google Map and using the API to request a route and distance between two points on a map.

The first thing we will do is setup the HTML and layout the page. The page has a map, and two input boxes, allowing the user to enter the location where they are starting, and the location or destination they want to go to. To save typing in testing (ever lazy!), I have defaulted these input values to two locations in the UK.

<div class="row">
    <div class="col-md-12">
        <h2>Example 1 - simple distance between two points</h2>
        <p>
            This demonstrates getting and displaying the distance between two points
        </p>

        <div>
            <div>
                Travel From : <input id="travelfrom" type="text" name="name" value="Chichester, UK" />
                To : <input id="travelto" type="text" name="name" value="Goodwood aerodrome, UK" />
                <input type="button" value="Get Route" onclick="GetRoute()" />

            </div>
            <br />
            <div>
                <div id="dvDistance">
                </div>
            </div>

        </div>

        <div id="dvMap" style="min-height:500px"></div>

    </div>
</div>
@section scripts{

   <!--ENSURE YOU CHANGE TO YOUR OWN API KEY HERE !!! --> 
   <script src="https://maps.googleapis.com/maps/api/js?libraries=places&key=YOUR_KEY">
   </script>

...

** Important ** - You Need to Replace 'Your_key' Above, With the Key That You Generate Yourself.

The first thing we do is set up some JavaScript variables. These will contain values we use when calling the Maps API.

The key controls above are the inputs 'travelfrom', 'travelto' and the button that calls the 'GetRoute()' function.

The rest of the code is all in the script section. Here is where we start to use that API key we generated earlier:

var source, destination;
       var directionsDisplay;
       var directionsService = new google.maps.DirectionsService();


Next up, we take the div element 'dvMap' we specified int he HTML Markup earlier, and tell the Map API to use this as a container in which to draw the map. I am also using the latitude and longitude of Chichester in England to center the map. In production, I have some script that changes this center view between the main office, the remote worker, and the customer location - making it easier for the user to orientate their planning.

// initialize the location of the map on Chichester in England (ref lat and lng)
var map = new google.maps.Map(document.getElementById('dvMap'), {
    center: { lat: 50.834697, lng: -0.773792 },
    zoom: 13,
    mapTypeId: 'roadmap'
});


The Maps API is vast and has many little nuggets that really assist when coding solutions. For example, there is an API you can use to connect an input box with a 'type ahead' location look up - this makes it easier for the user to find locations. In this next snippet of code, we call the 'Searchbox' method to link our 'travelfrom' and 'travelto' input boxes to this typeahead service. There is also some code to allow the user to move the map around by clicking/dragging with their mouse.

Example 1 - Main Code

We have a core function called 'GetRoute()'. This takes as input the 'travelfrom' and 'travelto' locations, sends these to the API, and then draws the result from the API onto the visual map for the user.

The first thing we do is set up request parameters to send them to the API. We then call the 'directionsService.route' API method to draw the response for the user ('directionsDisplay.setDirections').

directionsDisplay.setMap(map);

source = document.getElementById("travelfrom").value;
destination = document.getElementById("travelto").value;

var request = {
    origin: source,
    destination: destination,
    travelMode: google.maps.TravelMode.DRIVING
};

directionsService.route(request, function (response, status) {
    if (status == google.maps.DirectionsStatus.OK) {
        directionsDisplay.setDirections(response);
    }
});

It's one thing showing the pretty map to the user, but for our purposes, we also want to get specific details on the route such as the distance between the two points, and the time it would take to travel (in this case, assuming the remote worker was traveling in a car/van). To work this out, we are going to call the 'Distance matrix service'.

Step one sets things up, giving the origin and destination locations, setting the travel mode to DRIVING, and the measurement system to METRIC.

var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
    origins: [source],
    destinations: [destination],
    travelMode: google.maps.TravelMode.DRIVING,
    unitSystem: google.maps.UnitSystem.METRIC,
    avoidHighways: false,
    avoidTolls: false

Step two handles the response from the API, extracting the values for distance and duration, and displaying them for the user into the HTML element 'dvDistance'.

  }, function (response, status) {

                if (status == google.maps.DistanceMatrixStatus.OK && 
                              response.rows[0].elements[0].status != "ZERO_RESULTS") {
                    var distance = response.rows[0].elements[0].distance.text;
                    var duration = response.rows[0].elements[0].duration.value;
                    var dvDistance = document.getElementById("dvDistance");
                    duration = parseFloat(duration / 60).toFixed(2);
                    dvDistance.innerHTML = "";
                    dvDistance.innerHTML += "Distance: " + distance + "<br />";
                    dvDistance.innerHTML += "Time:" + duration + " min";

Heres how the output looks once rendered, showing the metrics the user requires.

Distance and Route Between Multiple Points

To give the user more flexibility and allow them to plan a block of time and a remote worker's travel, we are now going to see how we can use the 'waypoint' API in Google Maps to work out the distance between multiple points, and give a visual representation of this to the user on the map view.

The first thing we are going to do is set up the UI so that the user can enter a series of possible destinations. In my production version, this is all fed automatically from a database of existing customer addresses/unassigned but pending diary appointments.

As you can see, laziness strikes again, so for testing, I have hardcoded in a starting point (Chichester) and some possible destinations (Tagmere and Bosham).

In our HTML layout, the main difference from the first version is that we add in a few things:

  1. We have an array of possible destinations in JavaScript, so there is a 'PushDestination()' method to allow us to add destinations to that array.
  2. My laziness gives us a quick way to test some locations with 'setDestination()'
  3. The 'destinations' div stores the list of destinations *before* we calculate our distances and routes.
  4. Finally, we have a table that displays the results from the API in a nicely formatted manner.
 <div> Add Destination</div>
        <div>
            <input id="travelto" type="text" name="name" value="Oving, UK" />
            <input type="button" value="Add" onclick="PushDestination()" />
            <a href="#" onclick="setDestination('Tagmere, UK')">Tagmere, UK. </a>
            <a href="#" onclick="setDestination('Bosham, UK')">Bosham, UK</a>
        </div>
        <div id="destinations"></div><br />
        Source : <input id="travelfrom" type="text" name="name" value="Chichester, UK" />   

        <input type="button" value="Calculate" onclick="GetRoute()" />
        <p></p>
        <br />
        <div id="dvDistance">
            <table id="tblResults" border="1" cellpadding="10">
                <tr>
                    <th> Start </th>
                    <th> End </th>
                    <th> Distance </th>
                    <th> Duration </th>
                </tr>
            </table>

        </div>

        <div id="dvMap" style="min-height:500px"></div>

The JavaScript builds on the previous code we have, with the same setup as before. The difference here is the addition of a 'locations' array.

var source, destination;
       var locations = [];
       var directionsDisplay;
       var directionsService = new google.maps.DirectionsService();

       // initialize the location of the map on Chichester in England (ref lat and lng)
       var map = new google.maps.Map(document.getElementById('dvMap'), {
           center: { lat: 50.834697, lng: -0.773792 },
           zoom: 13,
           mapTypeId: 'roadmap'
       });

       google.maps.event.addDomListener(window, 'load', function () {
           new google.maps.places.SearchBox(document.getElementById('travelfrom'));
           new google.maps.places.SearchBox(document.getElementById('travelto'));
           directionsDisplay = new google.maps.DirectionsRenderer({ 'draggable': true });
       });

Our array of destination locations is managed by the 'PushDestination()' method. This takes whatever value is in the 'travelto' input control, and adds it to the array. It also updates the screen adding the new item to the div 'destinations'.

function PushDestination() {
    destination = document.getElementById("travelto").value;
    locations.push(destination);
    document.getElementById("travelto").value = "";
    destinationArray = document.getElementById("destinations");
    destinationArray.innerHTML += destination + "<br />";
}

My helper method adds items to the input box and calls the PushDestination() method to keep things moving along.

function setDestination(dest)
{
    document.getElementById('travelto').value = dest;
    PushDestination();
}

The GetRoute() method starts out the same...

function GetRoute() {

    directionsDisplay.setMap(map);

    source = document.getElementById("travelfrom").value;
    destination = document.getElementById("travelto").value;

But then adds an array of 'Waypoints'.

var waypoints = [];
for (var i = 0; i < locations.length; i++) {
    var address = locations[i];
    if (address !== "") {
        waypoints.push({
            location: address,
            stopover: true
        });
    }
}

The request param is tweaked slightly as there is more than one destination involved. We add in our array of waypoints and tell the API to optimize for waypoints.

  var request = {
                origin: source,
                destination: waypoints[0].location,
                waypoints: waypoints, //an array of waypoints
                optimizeWaypoints: true, //set to true if you want Google to determine the 
                                         // shortest route or false to use the order specified.
                travelMode: google.maps.DirectionsTravelMode.DRIVING
            };


Finally, we send in the request and parse the waypoint results we get back, displaying the output into the table we have ready in the HTML. As you can see, the key here is to look into each 'LEG' of the response routes that come back and extract the information we want from there.

directionsService.route(request, function (response, status) {
    if (status == google.maps.DirectionsStatus.OK) {
        var dvDistance = document.getElementById("dvDistance");
        var distance = 0;
        var minute = 0.00;
        response.routes[0].legs.forEach(function (item, index) {
            if (index < response.routes[0].legs.length - 1) {
                distance = distance + parseInt(item.distance.text);
                minute = parseFloat(minute) + parseFloat(item.duration.value / 60);

                tbl = document.getElementById("tblResults");
                var row = tbl.insertRow(1);
                var cell = row.insertCell(0);
                cell.innerText = source;
                var cell = row.insertCell(1);
                cell.innerText = item.end_address;
                var cell = row.insertCell(2);
                cell.innerText = distance;
                var cell = row.insertCell(3);
                cell.innerText = minute.toFixed(2) + " min";
            }
        });
        directionsDisplay.setDirections(response);
    }
    else {
        //handle error
    }
})

And here's the final output - just as we want it.

This is but one way of implementing this kind of solution - I hope you find it useful. Like all of these things, APIs keep changing, so if you get an error, it's best to look at the browser console for any feedback from the API!

You can download a sample project to play with here - don't forget to get your own API key and insert it where needed!

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:
google maps api ,asp .net mvc api ,web dev ,web application development

Published at DZone with permission of Allen ONeill. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}