Twitter: raymondcamden


Address: Lafayette, LA, USA

Adding driving directions to a jQuery Mobile web site

03-09-2011 61,094 views Mobile, jQuery, ColdFusion 44 Comments

My first morning at Scotch on the Rocks was a bit rough. Despite getting to bed at a decent time (10:30 or so) so I could catch up on my sleep, I ended up waking up around 3:30 or so in the morning and tossing and turning till 6. During that time an idea popped in my head for one more demo I could do for my jQuery Mobile presentation. I was thinking about building a simple mobile web site for the hotel. I thought it would be a simple example but also pretty practical. Of course, once I figured out a simple, static plan for the site an idea occurred to me. One of the important details for a hotel - obviously - is where they are. But what if you could not only tell folks where the hotel was but how you could get there? Here's my demo which shows just that. I'll warn you now - it's brittle as heck. It's really just a proof of concept. But it works (mostly) and I think it's pretty cool. Ready?

First, I'll begin by showing a few screen shots of the application I built. This is online and I'll share that link at the end, but for now, let's just look at pretty pictures.

My hotel mobile home page has three links: Contact Us, Find Us, and About. Contact Us has the basics - a phone number and an email address.

On a mobile device, clicking that phone number will automatically call the hotel. This is probably the #1 most important "service" a mobile web site can provide. Unfortunately far too few make this as simple. Let's skip the second link now and show the 3rd link:

Yeah, nothing important here. This is where you can stick the content the marketing department insists on that is most likely 100% useless to visitors. Let's face it -you know you will need to add it to the site. At least by making it the third link it isn't as distracting and doesn't interfere with the critical information.

Now that you've seen those pages - let's look at the code behind it. I'm not going to explain everything here - that's for another blog entry - but check out how simple the code is...

view plain print about
1<!DOCTYPE html>
2<html>
3    <head>
4    <title>Apex Hotels</title>
5    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.css" />
6    <script src="http://code.jquery.com/jquery-1.5.min.js"></script>
7    <script src="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.js"></script>
8</head>
9<body>
10
11<div data-role="page" data-theme="e">
12
13    <div data-role="header">
14        <h1>Apex Hotels</h1>
15    </div>
16
17    <div data-role="content">    
18        <ul data-role="listview" data-inset="true">
19            <li data-role="list-divider">Welcome to Apex Hotels</li>
20            <li><a href="contact.html">Contact Us</a></li>
21            <li><a href="find.html">Find Us</a></li>
22            <li><a href="#about">About</a></li>
23        </ul>
24    </div>
25
26    <div data-role="footer">
27        <h4>This is NOT a real Apex Hotels page.</h4>
28    </div>
29
30</div>
31
32<div data-role="page" id="about" data-theme="e">
33
34    <div data-role="header">
35        <h1>About</h1>
36    </div>
37
38    <div data-role="content">    
39        <p>
40        This is demo content.
41        </p>
42    </div>
43
44    <div data-role="footer">
45        <h4>Page Footer</h4>
46    </div>
47
48</div>
49
50</body>
51</html>

That code covers the home page and the About page. Here is the code behind the Contact Us page.

view plain print about
1<div data-role="page" data-theme="e">
2
3    <div data-role="header">
4        <h1>Contact Us</h1>
5    </div>
6
7    <div data-role="content">    
8    <p>
9    Reservations: <a href="tel:0845 365 0000">0845 365 0000</a><br/>
10    Email: <a href="mailto:reservations@apexhotels.co.uk">reservations@apexhotels.co.uk</a><br/>
11    </p>
12    </div>
13
14    <div data-role="footer">
15        <h4>Page Footer</h4>
16    </div>
17
18</div>

Ok, now let's look at Find Us. This page does two things. First, it shows a simple map to the hotel. For this, I used the address of the hotel hosting the conference. Secondly, it provides a link that will be used for driving directions.

And here is the code behind that...

view plain print about
1<div data-role="page" id="findusPage" data-theme="e">
2
3    <div data-role="header">
4        <h1>Find Us</h1>
5    </div>
6
7    <div data-role="content">    
8    <p>
9Apex International Hotel, Edinburgh<br/>
1031-35 Grassmarket<br/>
11Edinburgh<br/>
12EH1 2HS<br/>
13Scotland<br/>
14    </p>
15    
16    <p>
17    <img src="http://maps.google.com/maps/api/staticmap?center=31-35+Grassmarket+Edinburgh+EH1+2HS+Scotland&zoom=15&size=200x200&maptype=roadmap
18&sensor=false"
>

19    </p>
20    
21    <p>
22    <a data-role="button" id="drivingButton" data-theme="a">Get driving directions</a>
23    </p>
24    
25    </div>
26
27    <div data-role="footer">
28        <h4>Page Footer</h4>
29    </div>
30
31</div>

By the way - notice that map there. It's using the static Google Maps API. Very simple, right? It would be better if I added a marker at the center address for the hotel. That wouldn't take long but for now, I'm skipping it. Ok, so how do we take that button and make it live? I went back to my main home page. This is always loaded first and therefore is a good place to store code like this. You can not - as far as I know, use $(document).ready within the page code above. This seems to work once, but not when the page is loaded again. Therefore we need to use the index page. jQuery Mobile gives us a few new events we can listen one - one of them being pagecreate. I used that and bound to the findUs page div to create the following code block:

view plain print about
1$('#findusPage').live('pagecreate',function(event){
2
3});

Ok - now let's get into the fun part. When I originally conceived of this demo, it occurred to me I couldn't do driving directions to the hotel since I was actually presenting at the hotel. That would be dumb. So while at the conference I decided to provide directions to Glasgow. Now that I'm back home, I decided on Baton Rouge instead. In order to get the directions though we need to figure out where we are. That's super easy on mobile browsers since you've got pretty universal support for geolocation:

view plain print about
1navigator.geolocation.getCurrentPosition(function(pos){
2        var lat = pos.coords.latitude;
3        var lon = pos.coords.longitude;

As you can see, I simply fire off the geolocation request and grab the latitude and longitude in the response. To get driving directions, we need Google Maps. I added this to the top of my page:

view plain print about
1<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>

And then back in my code I added a new instance of the directions service:

view plain print about
1var dirApi = new google.maps.DirectionsService();

You can find the full API reference for this service here: http://code.google.com/apis/maps/documentation/javascript/reference.html#DirectionsService. But for now, we're going to make it simple. We create an object that will be used for our request.

view plain print about
1dirReq = {};
2dirReq.destination = "Baton Rouge, LA";
3dirReq.origin = new google.maps.LatLng(lat,lon);
4dirReq.travelMode = google.maps.DirectionsTravelMode.DRIVING;

Again - the use of Baton Route here is simply to make the demo work better for me. Ok, now for the fun part. I'm going to ask the direction service to create a route. The result is very complex, but essentially contains routes which contain steps. I'm going to assume we get one route and get the steps from there. I want to work with a much smaller set of data so I basically create my own, smaller and simpler copy:

view plain print about
1dirApi.route(dirReq,function(dirResult,dirStatus) {
2        if (dirStatus != google.maps.DirectionsStatus.OK) {
3            alert("Driving API error: "+dirStatus);
4        }
5        //our steps are dirResult.routes[0].legs[0].steps
6        var steps = dirResult.routes[0].legs[0].steps;
7        var copy = dirResult.routes[0].copyrights;
8        console.dir(steps);
9        var niceSteps = [];
10        for (var i = 0; i < steps.length; i++) {
11            step = {};
12            step.text = steps[i].instructions;
13            step.distance = steps[i].distance.text;
14            step.duration = steps[i].duration.text;
15            step.endlat = steps[i].end_location.lat();
16            step.endlon = steps[i].end_location.lng();
17            niceSteps[niceSteps.length] = step;
18        }

Ok - so now we have - hopefully - a simple array of steps that include the text of the direction, the duration, the time, and even the longitude and latitude of where you end up. How do we present this to the user? We could simply dump all the steps onto the page. But that may be hard to work with on the device. What if instead we broke it into steps, like so....

Sweet, right? So how did I do it? The first thing I did was add a jQuery plugin to allow me to serialize data into JSON format. Once I did that, I was able to send the data to ColdFusion and store it:

view plain print about
1$.post("store.cfm", {data:$.toJSON(niceSteps)}, function() {
2    $.mobile.changePage("driving.cfm");
3});

All store.cfm does is take the JSON, deserialize that, and store it into the session scope.

view plain print about
1<cfparam name="form.data" default="">
2<cfset session.data = deserializeJSON(form.data)>

If you notice back in the JavaScript, when the post is done, we use a jQuery Mobile utility to load a new page. driving.cfm will simply paginate over the driving steps:

view plain print about
1<cfparam name="url.step" default="1">
2<cfset step = session.data[url.step]>
3
4<div data-role="page" data-theme="e">
5
6    <div data-role="header">
7        <h1>Driving Directions - Step <cfoutput>#url.step# of #arrayLen(session.data)#</cfoutput></h1>
8    </div>
9
10    <div data-role="content">    
11        <cfoutput>
12        <h1>Step #url.step#</h1>
13        <p>
14        <b>Duration:</b> #step.duration#<br/>
15        <b>Distance:</b> #step.distance#<br/>
16        </p>
17        <p>
18        #step.text#
19        </p>        
20
21        <p>
22        <img src="http://maps.google.com/maps/api/staticmap?center=#step.endlat#,#step.endlon#&zoom=14&size=200x200&maptype=roadmap
23&sensor=false"
>

24        </p>
25        
26        <div data-inline="true">
27            <cfif url.step is 1>
28                <a href="" data-role="button" data-theme="c" data-inline="true">Previous</a>
29            <cfelse>
30                <a href="driving.cfm?step=#url.step-1#" data-role="button" data-inline="true">Previous</a>
31            </cfif>
32            <cfif url.step is arrayLen(session.data)>
33                <a href="" data-role="button" data-theme="c" data-inline="true">Next</a>
34            <cfelse>
35                <a href="driving.cfm?step=#url.step+1#" data-role="button" data-inline="true">Next</a>
36            </cfif>
37        </cfoutput>
38        
39    </div>
40
41    <div data-role="footer">
42        <h4>Page Footer</h4>
43    </div>
44
45</div>

And that's it! As I said, this code is brittle. You will notice that if geolocation or driving directions fail we just use an Alert. There are much nicer things we could do. For example, we could ask the user where they are. If driving directions fail we could do what most places do and assume you are coming in from the closest major highway. But - hopefully you can see how easy it is to add in complex services like Google's driving directions within a simple jQuery Mobile site. To try this demo, hit the button below. But please - do not stress out if it fails for you. As I said, it is brittle, was built fast, etc, and at least kind of works.

I've included the full code for this demo as an attachment to this blog entry.

Download attached file

44 Comments

  • Chris H #
    Commented on 03-09-2011 at 7:54 AM
    I recently added the same info for a jQuery Mobile site for a client recently ;D
    One good thing to note for telephone links: They should always include the country code. So for your number (in England), that would be: <a href="tel:+448453650000">0845 365 0000</a>. If someone is crazy enough to pay for international calls, this will work no matter what country you're calling from and, of course, from England as well.
  • Commented on 03-09-2011 at 8:03 AM
    Thanks Chris - I didn't think of that but it makes perfect sense.
  • Commented on 03-09-2011 at 9:29 AM
    This is utterly off-topic, and excuse the ramble, but that hotel is next to where I had my first encounter with computers.

    While still at school in 1971 our maths teacher arranged evening sessions using Heriot-Watt University's computers, right next door to what is now Apex Hotel. Punched card input, and then a long wait until your rolled-up broadlisting printout came back with a rubber band round it. Assuming you hadn't made a typo on the punched cards.

    I find it rather nice, but also kinda scary to see this demo of yours with it's shall we say more advanced I/O, just half a lifetime later. In 1971 you'd have been burned for witchcraft. Actually they used to have public hangings in the Grassmarket, although not in the '70's as far as I can remember
  • Commented on 03-09-2011 at 9:37 AM
    That may be off topic, but it's freaking cool. Thanks for sharing that Richard!
  • Commented on 03-09-2011 at 10:05 AM
    I wonder if you can somehow send address info to Google Navigation App on the phone.
  • Commented on 03-09-2011 at 10:15 AM
    If the app responds to URL schemes (um, 'scheme' may not be the best word, but like how you can use tel:// for example), then it would definitely be possible.
  • Chris H #
    Commented on 03-09-2011 at 11:26 AM
    Well, the iPhone and Android phones will ask you how you want to open links that start with <a href="http://maps.google.at/etc">;. Either in the browser or with the Google Maps App - which can then give you the directions from your current location ;D
  • Commented on 03-10-2011 at 8:11 AM
    Well a simple link to maps.google.com/maps?q=London on the iphone opens in the native map apps, and you can get directions from there. I dunno what is the best way to do it. As a user I prefer a lot the native map app, but there may be a lot of user not used to it and even not knowing how it works...
  • Commented on 03-10-2011 at 8:19 AM
    @cedric: I could see both being options. My way at least keeps you on the site which would make marketing happy ;) but the native apps will be slicker though.
  • Commented on 05-14-2011 at 9:40 AM
    Hi im trying to make this work, as a project for school, and so far I can get it to op the direction (driving.cfm) but all I get is

    Step #url.step#

    Duration: #step.duration#
    Distance: #step.distance#

    #step.text#

    and the Jquery stuff.

    am i missing something? tried to ad a google key, and tons of other stuff.. dont really know whats wrong :-/
  • Commented on 05-14-2011 at 9:41 AM
    by the way, i live in Europe, Denmark. don't know if it affects the maps in any way

    Daniel

    btw. nice scripting, a good challenge for me :)
  • Commented on 05-14-2011 at 9:46 AM
    It requires a ColdFusion server. If you are seeing the literals like that it implies it isn't installed on your server. In theory you could port it to PHP or Ruby pretty quickly.
  • Commented on 05-15-2011 at 5:20 PM
    ahh ok, thank you.

    any hints or help about porting to php, i havent had any coldfusion before and im very new to Jquery....

    Daniel
  • Commented on 05-17-2011 at 6:49 AM
    So to be clear, you know PHP, right?
  • Emmet #
    Commented on 06-03-2011 at 1:16 PM
    Google has an official v3 plugin for jQM now. Pretty sure it didn't when you wrote this. http://code.google.com/p/jquery-ui-map/

    I was able to whip up a directions from location fairly quickly at http://m.fullcityclient.com

    If only it were this easy on Blackberry... eeeesh.
  • Commented on 06-04-2011 at 2:07 PM
    Nice. I did not know that. I assume the Driving Directions API part of my code isn't going to change though - just how you render the map. Even then - only if you want an interactive map.
  • Misty #
    Commented on 02-05-2012 at 7:52 AM
    Hi ray, I am getting Geolocation: undefined error

    any ideas
  • Commented on 02-05-2012 at 9:37 AM
    What browser?
  • Misty #
    Commented on 02-06-2012 at 2:55 AM
    Mozilla, even chrome and opera too, IE 9 does not work as expected
  • Misty #
    Commented on 02-06-2012 at 3:13 AM
    i think the reason is i am using jquery version 1.7+ and live evnt is not supported, so i tried with delegate and on events, the alert did not popped up but neither the console message was displayed too. something is seriously missing i think
  • Commented on 02-06-2012 at 6:28 AM
    Not sure what to tell you. I just tried it and it worked fine in Chrome. Geolocation, as an object, works in all modern browsers. Should work in IE9 too.
  • Misty #
    Commented on 02-06-2012 at 7:39 AM
    But i think if you can try the same wih jquery 1.7+, That might show you some issue,
  • Commented on 02-06-2012 at 8:11 AM
    Oh, well, use the version of jQuery I used then. ;)
  • Misty #
    Commented on 02-06-2012 at 8:30 AM
    btw, it may work with jquery 1.5+ but if i use the old version, my Application is breakng

    Donno why?

    Have to check, i suppose
  • Commented on 02-06-2012 at 8:31 AM
    It definitely works with the version I used. Can't you just use that? I may be missing something here.
  • Misty #
    Commented on 02-06-2012 at 8:39 AM
    i do not know, but i just changed the event instead of live it should fire the on event which is new in jquery 1.7+, still ot firing, now nothing shows up, not even console, not even alert

    $('#findusPage').on('pagecreate',function(event){

    My question: how you are getting "pagecreate", in one of your posts, you used "pageshow"

    :?
  • Misty #
    Commented on 02-06-2012 at 9:06 AM
    ok, clear abt the pageshow and pagecreate steps, i figured them out
  • Misty #
    Commented on 02-07-2012 at 12:51 AM
    Well, I dono, Your map example also do not work on 1.7 jquery version Plus
  • Commented on 02-07-2012 at 1:34 AM
    I'm sorry, what? What map example? And to be clear, I'm not sure what you are wanting me to help with here. If the code as written works with the jQuery library as written, then I'd use it... as written.
  • Misty #
    Commented on 02-07-2012 at 2:16 PM
    ok, i agree, i used jquery 1.5 and it works, but the new events in jquery 1.7 like props and other breaks when this used, all in all a good work done, but eventually to make itwork in jquery 1.7+, need to make few changes
  • mark #
    Commented on 06-08-2012 at 8:43 AM
    Please Help me i'm having a problem:
    i tried to run the DEMO on the SAMSUNG GALAXY TAB 7plus but unfortunately there was an error occured saying that DRIVING API ERROR: ZERO_RESULTS ive tried also running on desktop using all browser supported by jquery mobile but it happened again....PLEASE help me....Thanks
  • Commented on 06-08-2012 at 8:49 AM
    That means that - for whatever reason - it could not figure a way to give you directions from your location. My app should handle that nicer.
  • mark kevin #
    Commented on 06-09-2012 at 7:53 PM
    How to make it offline geolocation driving directions?because when youre not in a non wifi area you are not allowed to use the geolocation system
  • Commented on 06-09-2012 at 8:01 PM
    Offline is not the same as no wifi. Geolocation should work fine in no wifi if there is a gps device.

    If not, you are kinda screwed. You can ask the user for their location of course. Google's Driving Directions will accept that (of it not, you geolocate the address they give and use that).
  • mark #
    Commented on 06-09-2012 at 8:40 PM
    how about using jquery mobile? is jquery mobile works even if thers no wifi?
  • Commented on 06-09-2012 at 10:47 PM
    jQuery Mobile is a UI framework. It has nothing to do with being online or off.
  • Commented on 11-30-2012 at 10:19 PM
    Great Raymond! Thanks, I'm trying to implement this on my website, hope it works, I'll come back and let you know later, but I will thank you know.
  • amin #
    Commented on 12-06-2012 at 1:16 PM
    hey hi raymond,
    its really great app but it is not running on my system ,i tried in both Mozilla and chrome but not working only...
    when i clicked on "Get driving directions" button nothing is happening in url bar of a browser it just showing "this page contains elements from following site that tracking your location" expect this nothing is happening plz help me i need to impalement in my site ....
  • Commented on 12-06-2012 at 2:17 PM
    What do you see in the console?
  • Roert Astan #
    Commented on 08-28-2013 at 2:31 PM
    Hi, I am looking for someone who can replicate the customizable html5 web app featured here: http://mobilepunchcardapp.com/merchant I know it's probably a absic mobile website for developers, I have a wordpress plugin that creates a similar web app, but it's not what I need, I need the functionality advertised on the link above. Please can someone take a look, and let me know if they can do this for me? Thanks
  • ivan #
    Commented on 01-15-2014 at 10:27 AM
    Hi

    Looks nice
    Instead of using google maps....can i use my own image(ie my apartment), set markers and have directions appear lets say from my door to my room? Is this possible?
  • Commented on 01-15-2014 at 10:59 AM
    There is no reason why you couldn't skip the Google Static Map image and use your own.
  • Commented on 02-24-2014 at 10:43 AM
    Hi Raymond, and thanks for this awsome plugin.
    I have a question. There is a way to draw the route like this http://hpneo.github.io/gmaps/examples/routes_advan...

    Thanks
  • Commented on 02-24-2014 at 11:04 AM
    Yes. I'm willing to bet that plugin works with result sets from the directions API already.

Post Reply

Please refrain from posting large blocks of code as a comment. Use Pastebin or Gists instead. Text wrapped in asterisks (*) will be bold and text wrapped in underscores (_) will be italicized.

Leave this field empty