This is part 3 in my series on Windows 8 apps for the PhoneGap developer. Here we are going to focus on writing apps that respond to the various ways a user can move the device around.

The basic accelerometer code in PhoneGap is generally used to determine the orientation of the device with respect to gravity. This lets you create tilting games like marble mazes. It also can be used to test in what orientation the device is being held. To a small degree it can detect motion – but since it’s based on acceleration and not velocity, it’s not nearly as responsive as it needs to be to create something like, say, an augmented reality type application.

With PhoneGap you can obtain the accelerometer reading (x,y,z) at a given moment or you can set up a watcher with a callback, and specify the frequency of callbacks to occur. This usually gives you code that looks something like this:

var watchAccelID;
var watchAccel = function () {

// Success callback
var success = function (a) {
document.getElementById('x').innerHTML = roundNumber(a.x);
document.getElementById('y').innerHTML = roundNumber(a.y);
document.getElementById('z').innerHTML = roundNumber(a.z);
};

// Fail callback
var fail = function (e) {
//display some error message
};

// Update acceleration every 1 sec
var opt = {};
opt.frequency = 50;
watchAccelId = navigator.accelerometer.watchAcceleration(success, fail, opt);

};


The equivalent in Windows 8 is to call GetCurrentReading for a single check of the accelerometer readings, or to add an eventListener for the ReadingChanged event on the accelerometer with a suitable ReportInterval to control the frequency of the callbacks. An interesting point is that in Windows 8 you can determine the MinimumReportInterval from the hardware so you can make sure you’re not asking for something the hardware/os can’t provide. Here’s an example of that.

var accelerometer;
function onDataChanged(e) {
var reading = e.reading;

document.getElementById('x').innerHTML = reading.accelerationX.toFixed(2);
document.getElementById('y').innerHTML = reading.accelerationY.toFixed(2);
document.getElementById('z').innerHTML = reading.accelerationZ.toFixed(2);
}

function watchAccel() {
if (accelerometer) {
return;
}
accelerometer = Windows.Devices.Sensors.Accelerometer.getDefault();


// Choose a report interval supported by the sensor
var minimumReportInterval = accelerometer.minimumReportInterval;
var reportInterval = minimumReportInterval > 16 ? minimumReportInterval : 16;
accelerometer.reportInterval = reportInterval;

accelerometer.addEventListener("readingchanged", onDataChanged);

}
}

There are some differences in the values returned to PhoneGap apps and Windows 8 apps. PhoneGap’s values for X,Y and Z are reported with the actual acceleration numbers (as in 9.8 m/s2 (1g) and positive values meaning "down”), whereas Windows 8 reports 1g pull towards the earth as the value -1. In addition, on a phone, X,Y and Z are based on portrait orientation and on a Windows 8 device, X, Y and Z are based on landscape orientation. Confused? I thought so. Here’s a table to help.

  X,Y,Z PhoneGap X,Y,Z Windows 8
Portrait 0, 9.8, 0 1, 0, 0 (rotated clockwise)
Landscape -9.8, 0, 0 (rotated clockwise) 0, –1, 0
Flat on a desk 0, 0, 9.8 0, 0, –1

Pretty simple to accommodate the differences in your code though.

Another thing to consider is the fact that typical phone and Windows 8 UI rotates to stay upright as the user rotates the device – but the XYZ coordinate system does not. Meaning if you have a physics type game calculating movement of something on the screen based on X&Y, those will swap if the device is rotated. Y becomes left and right and X becomes up and down (assuming you hold the device more or less straight up in front of you). You basically have two choices. The easiest is to prevent the app from reorienting itself upon device rotation. That’s super simple in Windows 8. Just go into the app manifest file and check the box under the orientation you want to support. If all the boxes are unchecked, the app supports all orientations and will rotate automatically to stay upright to the user.

OrientationSettings

If you do want to allow the app to orient to the user, you can put some tests in your code processing the accelerometer values to test the orientation of the device, and together with that information, update your UI correctly. Here’s how you can have your app notified when the user changes the device orientation.

var orientationSensor;
function init() {
orientationSensor = Windows.Devices.Sensors.SimpleOrientationSensor.getDefault();
orientationSensor.addEventListener("orientationchanged", onDataChanged);
}

//Possible values for orientation are notRotated, rotated90DegreesCounterclockwise,
//rotated180DegreesCounterclockwise, rotated270DegreesCounterclockwise,
//faceup or facedown

var currentOrientation = Windows.Devices.Sensors.SimpleOrientation.notRotated;

function onDataChanged(e) {
currentOrientation = e.orientation;
}

Use the value saved in currentOrientation in your accelerometer calculations. Or, even if you’re not using accelerometer data in your application, use it to rearrange the UI as needed if the user rotates the device. However, use that only as a last resort because one of the cool things about Windows 8 JavaScript apps is you can use media queries in style sheets to do most of that rearranging for you. Media queries is a great topic, and in fact is great for IE browser apps as well as Windows 8 JavaScript apps on rotatable devices. They’re well explained in this blog post by Stephen Walther, but I digress…

A final useful tidbit while we’re talking about accelerometers is the availability in the WinJS library of a shaken event. Using that event, you can have the OS determine when a shake gesture has occurred, so you don’t have to calculate it from a bunch of accelerometer changes.

var accelerometer;
var shakeCount = 0;


//Init Accelerometer
function initAccel() {
accelerometer = Windows.Devices.Sensors.Accelerometer.getDefault();
if (accelerometer) {
accelerometer.addEventListener("shaken", onShaken);
} else {
document.getElementById("shakeOutput").innerHTML = "No accelerometer found";
}
}

function onShaken(e){

shakeCount++;
document.getElementById("shakeOutput").innerHTML = shakeCount;
};

Another sensor PhoneGap lets you tap into is the compass (if the device has one) to get the current heading of the device. There’s also a watching event for the compass to get continuous readings. Combining these with the accelerometer can give you some sense of the devices position is space, but it can be tricky to calculate.

In Windows 8 JavaScript apps, you can get the compass heading as well, either one time through the GetCurrentReading method, or by subscribing to the Readingchanged event.

Some Windows 8 devices coming out will have more advanced sensors like gyroscopes and inclinometers in them. There are some great possibilities there for advanced gaming or augmented reality apps. Check out the whole quickstart series on them for more information.

The last tip I’ll leave you with is around power optimization. All those callbacks to your app from the sensors can nibble into battery life. So it’s a good idea to remove the event handlers and dispose of the sensors when you don’t need them. The more optimized and better performing your app is on Windows 8, the more users will love the experiences you create for them.