PGCompass: PhoneGap Compass
It is very easy to read the compass device in PhoneGap. When you combine it with a png file and a bit of CSS3 you can quickly build a nice looking compass similar to that built in on the iPhone and other devices.
All of the magic of the compass is contained one simple function:
watchId = navigator.compass.watchHeading(success, error, [options])
This call sets up two functions, one to receive a successful callback, the other to receive an error callback, and finally some options, the only one truly supported is the frequency in milliseconds.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// next two lines for JS-Lint | |
"use strict"; | |
var $, navigator, alert, document; | |
// create our namespace | |
var RocknCoder = RocknCoder || {}; | |
// event handlers for the compass stuff, | |
// one for updating the header text | |
// the other for rotating the compass | |
RocknCoder.Compass = (function () { | |
var lastHeading = -1, | |
// cache the jQuery selectors | |
$headText = $("header > h1"), | |
$compass = $("#compass"), | |
// displays the degree | |
updateHeadingText = function (event, heading) { | |
event.preventDefault(); | |
$headText.html(heading + "°"); | |
return false; | |
}, | |
// adjusts the rotation of the compass | |
updateCompass = function (event, heading) { | |
event.preventDefault(); | |
// to make the compass dial point the right way | |
var rotation = 360 - heading, | |
rotateDeg = 'rotate(' + rotation + 'deg)'; | |
// TODO: fix - this code only works on webkit browsers, not wp7 | |
$compass.css('-webkit-transform', rotateDeg); | |
return false; | |
}; | |
// bind both of the event handlers to the "newHeading" event | |
$("body").bind("newHeading", updateCompass).bind("newHeading", updateHeadingText); | |
}()); | |
// hook the compass watch | |
// normally I would un-hook an event, but this is a quick tutorial | |
document.addEventListener('deviceready', function () { | |
RocknCoder.Compass.watchId = navigator.compass.watchHeading(function (heading) { | |
// only magnetic heading works universally on iOS and Android | |
// round off the heading then trigger newHeading event for any listeners | |
var newHeading = Math.round(heading.magneticHeading); | |
$("body").trigger("newHeading", [newHeading]); | |
}, function (error) { | |
// if we get an error, show its code | |
alert("Compass error: " + error.code); | |
}, {frequency : 100}); | |
}); |
If the call is successful it passes back a heading object. It can contain several properties:
- magneticHeading
- trueHeading
- headingAccuracy
- timestamp
The property that we are interested in is the magneticHeading. While trueHeading may seem more attractive it is not support on Android, so I choose not to use it.
In the example code, I implement publisher/subscriber pattern for handling the success callback. It may be a bit of overkill, but I like the separation of concerns it gives me. One listener handles the updating of the degree text, the other rotating the compass face. This is accomplished using a CSS3 transform on the <img> tag holding the compass face.
One thing that we should do, but are not is to stop the watcher. This is relatively easy to do. The watchId that is returned from the watchHeading method is simply passed to another method:
navigator.compass.clearWatch(watchId);
This will turn off the listener. That is it for this quick tutorial. The code is on GitHub. Next up everyones favorite device, the camera. I will show how to take a picture and manipulate the image in PhoneGap. Until then, happy coding.
PGCompass Source Code on GitHub
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>pg-compass</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1" /> | |
<meta name="apple-mobile-web-app-capable" content="yes"/> | |
<meta http-equiv="Content-Type" content="text/html" charset="utf-8"/> | |
<link href="content/jquery.mobile-1.1.0.min.css" rel="stylesheet" type="text/css" /> | |
<link href="content/style.css" rel="stylesheet" type="text/css" /> | |
<script type="text/javascript" charset="utf-8" src="cordova-1.7.0.js"></script> | |
<script src="scripts/jquery-1.7.1.min.js" type="text/javascript"></script> | |
<script src="scripts/jquery.mobile-1.1.0.min.js" type="text/javascript"></script> | |
</head> | |
<body> | |
<div id="page1" data-role="page"> | |
<header data-role="header" data-position="fixed"> | |
<h1></h1> | |
</header> | |
<section data-role="content" style="padding: 10px 0;"> | |
<img id="compass" class="Center" src="images/compass320.png" /> | |
</section> | |
</div> | |
<script src="scripts/app.js" type="text/javascript"></script> | |
</body> | |
</html> |