Tardis Finder

Poor Doctor Who.  Always running around time and space, saving the universe … In a phone booth.  Well, okay, it’s not actually a phone booth, it is a “time and relative dimension in space” machine, or “TARDIS” for short.  But what I want to know is how, in all these different places, does The Doctor remember where he parked the Tardis?  I can’t remember where I park my car at the grocery store.  So in continuing the London-themed series of PhoneGap applications, and knowing that “there’s an app for that” I built Tardis Finder.

Screenshot of the Tardis Finder running

Tardis Finder is really a simple example of using the device compass from PhoneGap.  The code is actually pretty short and sweet.  It is also very similar to using the accelerometer.  You make a call to “navigator.compass.watchHeading()” and get a numeric identifier in return.  You can use that identifier at some later point to stop watching the compass, so keep it in a variable that will be around to reference.

var watchId = 0;

watchId = navigator.compass.watchHeading( function( heading ) {
  $( ‘#compass’ ).css( ‘-webkit-transform’, ‘rotate( ‘ + heading.magneticHeading + ‘deg )’ );
}, function( error ) {
  console.log( ‘Error’ );
}, {
  frequency: 100
} );

And of course you pass a success and error function to the “watchHeading()” call, along with an option of how often to poll the compass.  The default frequency for polling the compass is every 100 milliseconds.  When the success callback is executed, you will get an object with a variety of properties around magnetic heading, true north, and more.  Support for the options varies widely depending on operating system, so generally speaking you will want to simply use magnetic heading.

CSS3 Success and Failure

In this example, I use the heading value, which will be between 0 and 360 to rotate the compass image that many degrees.  This is done using the CSS3 transform “rotate()”, which despite being nearly 600×600 performs admirably well on my relatively dated Droid X.

You might notice that the compass has a slight drop shadow to it, and you might then assume that I use the CSS3 “box-shadow” attribute to apply that shadow.  And you’d be wrong.  It turns out that “box-shadow” works only on the containing box.  This would be fine if I wanted a drop shadow on a picture, but for the compass, which is round, it doesn’t come close to rendering the desired results.

Comparison of layering images or using CSS3 box shadow

To get around this, I separate the compass from its shadow – there’s one image for each, and I layer them on top of one another.  Positioned accurately, it looks like the compass has a nice, rounded, drop shadow.  I rotate the compass image, but not the shadow.  Thanks to transparent PNGs, this gives the desired result.

User Interface Considerations

You might notice that the compass doesn’t have a needle.  How do you know then what direction you are going?  Well, for one, if you are as smart as The Doctor, then you just know, but if you’re not, let me clue you in – the top of your phone, in the center, where the Tardis doors close, is the heading you are currently on.  Pretty intuitive right?  Maybe not, but maybe more than you think.

Once I had made the call to rotate the compass, I realized that if I had a needle, that it would essentially always be pointing towards the top of the application.  And to be fair, if I had the graphical skills to pull off a good looking needle, then I would have put it in there.  But the point remains that when it comes to compass heading you have two choices.

The first choice is to rotate the compass itself.  In which case, realistically, you should provide some fixed indicator (and if you come up with anything compelling, please send it over).  The second choice is to rotate the needle.  In this case, where the compass spills off of the screen, that wouldn’t work because you’d only know your heading about 180 degrees of the time.  So if you’re going this second route, size the user interface to include the entire compass on the screen.

You should also consider simply telling the user the heading value in a textual fashion.

I’m inclined to enjoy the second approach because to me, it more closely resembles how we actually use a compass.  You generally hold the compass fixed in front of you, with the top point directly perpendicular from your body.  The compass then is free floating and turns to always be pointing to the north.  Technically, you turn and the compass stays still, and that’s what happens in Tardis Finder.

Operating Systems and Sensors

The device I use to test my iOS applications is generally an iPod Touch.  The iPod Touch has no compass, so for this application, I targeted Android.  This brings up two interesting points.  The first is simply to check for the compass availability.  I haven’t covered the “error” blocks of most of these examples, but that’s where you’d catch that there is no compass sensor, and then take the appropriate alternative action.

The other interesting point is the viewport.  Despite the iPod Touch having a “retina” display of 640×960, as I’ve noted in other posts, working with graphics that large can still result in sub-par performance.  For this reason, I generally design for a 320×480 resolution, and let the operating system scale up the graphics.  And on iOS, this is done quite well with minimal, or altogether absent scaling artifacts.

With iOS, when targeting the smartphone form factor, I don’t even use a viewport.

Android on the other hand is nowhere near as forgiving, and it will try to scale up everything – even graphics sized for the exact resolution of a specific device.  This means that the “meta viewport” definition is really important.  Further, you can’t get away with just any viewport values either if you expect your graphics to fit the display precisely.  After a whole lot of trial and error, here is the viewport definition I used in Tardis Finder.

<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, target-densityDpi=device-dpi"/>

With this definition in place, I am free to expect that one pixel in my design will equal one pixel on the device.  In the case of Tardis Finder, my 480 pixels across the top fills the display of my Droid X exactly.  And luckily many Android devices have 480 pixels across the top … But not all of them.

And then there is the horizontal dimension to consider as well.  Early Android devices had 480×800 resolution displays.  The Droid X however has 480×854.  And a more modern device like the Motorola Atrix has a 540×960 resolution display.  This is clearly where CSS Media Queries would come into play.  I haven’t covered them here in the interest of sticking to PhoneGap features, but the bottom line is simply to test, test, test.

Conclusion

It never ceases to amaze me how something relatively simple can involve so much thought.  Here I’ve shown how to use the device compass via PhoneGap in a handful of lines of code.  But from there comes CSS considerations, UI consideration, device support considerations, resolution considerations and more.  Indeed a large percentage of the time of overall development for devices will ultimately be in testing.  Luckily, I’ve already done that footwork for the good Doctor, and now he can get back to saving the universe.

Submit a Comment

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>