The Code Train

Where Neil Crosby talks about coding on the train…

RSS Entries

Geolocation & Beer: Part 1 – Finding the user

Posted on May 5th, 2010 by Neil Crosby. Filed under Blog Posts.

I recently attended BarCamb3, a BarCamp held at the lovely Red Gate Software offices in Cambridge. My main contribution to the event was talking about a silly little weekend learning project I’ve been working on – Beer Near Me.

I’ve split the presentation I gave up into three separate blog posts, which I’ll be putting up over the next few days. This one will cover basic use of the navigator.geolocation API, with the next two showing you how to use the data that gives you to find out where the user actually is, and to plot that data using Google’s static maps API.

To start, I should explain that Beer Near Me was only ever intended to be used as a platform to be used to help me learn about the navigator.geolocation API and how it works. All the data that gets shown by the site was initially kind of secondary to me, as was the map that I use to show it off.

GeoLocation & Beer What will I talk about?

Of course, navigator.geolocation turned out to be far easier to work with than I expected.

Support for navigator.geolocation

The first thing to be aware of is that right now, support for navigator.geolocation is pretty poor. If you’re using Firefox 3.5+ or Mobile Safari you can use it out of the box, and you can turn on geolocation support in Chrome, but apart from that you’re plain out of luck. Since the idea behind Beer Near Me was to learn about navigator.geolocation that means that right now I’m not supporting any other APIs.

navigator.geolocation support Other APIs are available

It’s not all doom and gloom though. There are implementations of the API available for use in other browsers as plugins – for example Geode will get you support in earlier versions of Firefox 3, and Google Gears opens up the ability to play with geolocation in some other browsers. There’s also Loki (a Skyhook based plugin) that will get you support over a whole bunch of browsers but uses a differently specified API. Of course, I’ve not actually used any of these, so your guess is as good as mine as to whether they are any good or not. I seem to remember Loki looking interesting a couple of years ago.

Finding a location

So, how to actually use navigator.geolocation? Well, a good place to start would be checking whether the browser supports it. We’ll do this in JavaScript, since that’s the only place we can reliably perform the check.

if (navigator.geolocation) {
    // do geolocation
} else {
    // say sorry to the user
}

Pretty simple. It’s your standard JavaScript functionality check. If we have the functionality available then we can actually do something with it.

navigator.geolocation.getCurrentPosition(
    foundLocation, // a user generated function
    noLocation,    // yup, user generated too
    {
        enableHighAccuracy: true,
        maximumAge: 1800,
        timeout: 30
    }
);

Here, we’re calling getCurrentLocation() with two callback functions and some options. Once the browser (and the user) has decided whether or not to return a location, either the foundLocation or noLocation functions that you get to write are called, and the user’s location is passed into them.

GeoLocation check getCurrentPosition

Before we get to those callback functions though, lets talk for a minute about the options we’re passing into getCurrentPosition(). Essentially, what we’re saying in the code above is:

Try to give me highly accurate positioning if possible. I’d like to actually know where I am.

Oh, and if you have a position cached that’s no older than 30 minutes, could you give me that immediately please? I know that kind of contradicts what I said a moment ago, but I know better than you.

And one more thing – if it takes you longer than 30 seconds to work out where you are, just give up. There’s a good fellow.

And that’s it really, with that little bit of code we’ve set up the browser to do some magic and try and work out where it is.

Watching for changes to the user’s location

The only problem with this is that the iPhone in particular seems a bit rubbish at following these instructions. The first result it sends back seems to be uniformly Not Good, and generally quite old. So what can we do about that? Thankfully, there’s an easy answer provided to us in the API – the watchPosition() function. This uses exactly the same parameters as getCurrentLocation() and can simply be dropped in as a replacement for it.

Keep finding the user You've got a location!

watchPosition does what you’d expect it to do. Instead of finding a location once, it will keep watching the user’s location and call the success function whenever the location changes. The thing that watchPosition() is most useful for though, is getting more accurate locations as the user’s device tries different location finding techniques.

You see, different devices will try and locate themselves in different ways. Some of the techniques they’ll use will be be quick, some slow, and some very expensive when it comes to battery life. For example, here’s what the iPhone does, as I understand it:

  1. First, the iPhone will look to see if there’s a location cached in its memory and give you that if available.

  2. If you’re still watching for new locations, it will then try and grab a general location from the cell towers it knows about.

    Depending on the number of towers available, this might give you really good, or really bad accuracy. For example, in Bedford (where I live), using cell tower triangulation I get an accuracy which basically covers the entire town. Not particularly useful. It is quick though, and doesn’t really cost much in terms of power.

  3. If the cell tower triangulation wasn’t awesome then the iPhone will gather information about all the WIFI hotspots it can see.

    This data gets sent to Skyhook, which does a whole bunch of triangulation and sends back a result. This is obviously slower than just hitting the cell towers, but it can give you a really accurate result depending on where you are (better than GPS in some built up areas).

  4. Finally, if you’re still looking for a location, the iPhone will fire up the GPS.

    This is expensive, slow, and drains the battery, so is left as a last resort. It generally gives the best quality results though.

So, you see, things aren’t necessarily as simple as asking for a position. A whole bunch of stuff can be going on in the background, and grabbing the best location the user’s device knows about as time goes on can be very useful.

Using the location we’ve found

So, now that we’re requesting a location, what do we do once we actually get one? Lets have a look.

foundLocation = function(position) {
    // position.coords.latitude
    // position.coords.longitude
    // position.coords.accuracy
    // and moreā€¦
}

As you can see, the function we call on location finding success gets passed a single parameter – position. This object contains a coords object, and a timestamp representing the time the location was determined. It’s the coords object we’re interested in right now, since that contains the latitude, longitude and accuracy (measured in metres) of the user’s current location – all the information a grown chap could need for finding some beer. Other applications might make use of the altitude, heading and speed information, but that’s not vital when looking for beer, so I’m ignoring it for now.

Putting it all together

Quickly putting all this together, here’s some JavaScript you can copy and paste into a page to see this all in action.

/*global document, navigator */
var beerLocation = {
    foundLocation: function (position) {
        beerLocation.setPara(
            "Lat = " + position.coords.latitude + 
            ", lon = " + position.coords.longitude + 
            ", accuracy = " + position.coords.accuracy + "m");
    },

    noLocation: function () {
        beerLocation.setPara("Boo! You didn't share your location!");
    },

    noGeoLocation: function () {
        beerLocation.setPara(
            "Sorry, but your browser doesn't support geolocation.");
    },

    setPara: function (text) {
        var p = document.getElementById('location-info');
        if (!p) {
            p = document.createElement('p');
            p.id = 'location-info';
            document.body.appendChild(p);
        }

        p.innerHTML = text;
    }
};

if (navigator.geolocation) {
    navigator.geolocation.watchPosition(
        beerLocation.foundLocation, 
        beerLocation.noLocation,
        {
            enableHighAccuracy: true,
            maximumAge: 120000
        }
    );
} else {
    beerLocation.noGeoLocation();
}

Alternatively, take a look at it in situ and in action on my geolocation test page. The location shown by this page will keep updating as you move around or your device’s accuracy improves. For best results, try it out on an iPhone.

And finally

And that’s how easy it is to find a user’s location and keep updating it. You just need to do something with the latitude and longitude once you’ve found it.

In Beer Near Me I do two things with the location once it’s been found – I tell the user the street address of the location, and I display it on a map. And, of course, I’ll be writing about how I’m doing that in the next couple of posts.

Tags: , , , , , ,

If you enjoyed this post, subscribe to The Code Train and read more when I write more.

4 Responses to “Geolocation & Beer: Part 1 – Finding the user”

  1. Very nice. watchPosition is a good call.

    I wrote a simple geolocation normalizer that uses google if native isn’t available. Might be handy in some cases: http://gist.github.com/366184

  2. Hi,

    what happens to the javascript code that queries for GPS locations when the browser goes into the background?

    I’m trying to write a browser application that will log GPS location continuously, but it seems that it stops accessing the GPS functionality of the phone when there’s no user activity on the device and the browser goes into the background…

    Any ideas?

    Thanks!

  3. Hi Adrian,

    I’m looking for a solution for the same issue. Did you find anything? what did you eventually do? My email is eli (at) manobella.com. Appreciate any help in this subject as I could not find any solution on the web. Thanks Eli

  4. it’s helpful to know about this but I wonder with a person has no background in IT will I have to enroll online course like this http://www.tuicoding.com/ to build great stuffs mentioned in this article

Comments RSS

Leave a Reply

TheCodeTrain Theme by Neil Crosby, Powered by WordPress