In this third article in our series on HTML5 for the mobile web, we take a look at the Device Orientation API. This API provides information about the orientation and movement of a device. Information comes from the positional sensors such as compasses, gyroscopes and accelerometers. Via this API, a web app can access and make use of information about how a device is physically oriented in space.
Use cases include game control based on device tilting, and mapping where a map is correctly aligned with the world based on the device orientation data.
The HTML5 DeviceOrientation API specifies three events, which are outlined in the table below.
Property | Description |
---|---|
deviceorientation |
fired when a significant orientation occurs |
compassneedscalibration |
fired if the compass needs calibration and calibration will provide more accuracy |
devicemotion |
fired regularly with information about the motion of the device |
The DeviceOrientation Event
This event is based around three pieces of data, detailed below
Property | Description |
---|---|
alpha |
the direction the device is facing according to the compass |
beta |
the angle in degrees the device is tilted front-to-back |
gamma |
the angle in degrees the device is tilted left-to-right |
To help visualise these values, the image below from the W3C specification document should help:
So, let’s get our hands dirty. Let’s see how easy it is to access the orientation data of the device.
Accessing Orientation Data
As with other HTML5 APIs, you should check if the browser supports the Device Orientation Events API first. This can be done with the following statement:
1 |
if(window.DeviceOrientationEvent) { //Do something } |
To access the orientation data, we need to attach an event listener to the deviceorientation
event. And in the handler function we access the data with event.alpha
, event.beta
, and event.gamma
:
1 2 3 4 5 6 |
window.addEventListener('deviceorientation', function(event) { var alpha = event.alpha; var beta = event.beta; var gamma = event.gamma; // Do something }, false); |
The DeviceMotion Event
The other main event offered by this API is the devicemotion
event. This is less well supported than the deviceorientation
event. It is fired regularly and provides acceleration and rotation rates of the device. Its properties are described below:
Property | Description |
---|---|
acceleration |
provides acceleration data, in m/s² for each of the x, y, and z axes |
acceleratonIncludingGravity |
provides same data as above, but with effects due to Earth’s gravity included |
rotationRate |
provides the rate of rotation in deg/s around each of the axes, as three values, a, b g |
interval |
time in milliseconds between samples |
To check if the devicemotion
event is supported use:
1 |
if(window.DeviceMotion) { //Do something } |
Accessing the motion data is very similar to accessing the orientation data. First we attach an event listener, and then we can read the event properties:
1 2 3 4 5 6 7 8 9 10 11 |
window.addEventListener('devicemotion', function(event) { var x = event.acceleration.x; var y = event.acceleration.y; var z = event.acceleration.z; var ralpha = event.rotationRate.alpha; var rbeta = event.rotationRate.beta; var rgamma = event.rotationRate.gamma; var interval = event.interval; }); |
For brevity, only one of acceleration
and accelerationIncludingGravity
is shown above.
Displaying Device Orientation Data on a Web Page
Now that we know how to access the device orientation data, we’ll take this data and display it on screen. First, the HTML. We’ll define a div
container for the orientation data, and another div
for the motion data.
1 2 3 4 5 6 |
<div id="dataContainerOrientation"> No device orientation data </div> <div id="dataContainerMotion"> No device motion data </div> |
There’s some placeholder text included above; this will be overwritten when we obtain the actual data.
Now, time for some JavaScript. As above, we check for browser support, attach our event listeners, and in the handler functions, we access the data we want to display.
The only new part now is to check the values we have obtained, and to display them in the container div by setting the innerHTML
property, for example for the orientation data:
1 2 3 |
if(alpha!=null || beta!=null || gamma!=null) { dataContainer.innerHTML = 'alpha: ' + alpha + '<br/>beta: ' + beta + '<br />gamma: ' + gamma; } |
We wrap all this up in a function called init
, and we trigger this function when the page is finished loading. So the full code listing is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<DOCTYPE html> <html> <head> <script> function init() { //Find our div containers in the DOM var dataContainerOrientation = document.getElementById('dataContainerOrientation'); var dataContainerMotion = document.getElementById('dataContainerMotion'); //Check for support for DeviceOrientation event if(window.DeviceOrientationEvent) { window.addEventListener('deviceorientation', function(event) { var alpha = event.alpha; var beta = event.beta; var gamma = event.gamma; if(alpha!=null || beta!=null || gamma!=null) dataContainerOrientation.innerHTML = 'alpha: ' + alpha + '<br/>beta: ' + beta + '<br />gamma: ' + gamma; }, false); } // Check for support for DeviceMotion events if(window.DeviceMotionEvent) { window.addEventListener('devicemotion', function(event) { var x = event.accelerationIncludingGravity.x; var y = event.accelerationIncludingGravity.y; var z = event.accelerationIncludingGravity.z; var r = event.rotationRate; var html = 'Acceleration:<br />'; html += 'x: ' + x +'<br />y: ' + y + '<br/>z: ' + z+ '<br />'; html += 'Rotation rate:<br />'; if(r!=null) html += 'alpha: ' + r.alpha +'<br />beta: ' + r.beta + '<br/>gamma: ' + r.gamma + '<br />'; dataContainerMotion.innerHTML = html; }); } } </script> </head> <body onload="init()"> <div id="dataContainerOrientation"> No device orientation data </div> <div id="dataContainerMotion"> No device motion data </div> </body> </html> |
Live Demo – Display raw data
Click the image to the right to activate the live demo. Depending on your device, you should be able to see the raw orientation and motion data.
Now that we’ve managed to access and display the raw orientation data, perhaps we can try to present it in a more useful way.
An HTML5 compass
Recall that the alpha
value of the deviceorientation
event corresponds to the compass bearing of the device. Suppose now, that instead of simply displaying this value, we were to rotate an image in proportion with this value. And suppose also that this image depicted a compass face. Why then, we might have something more useful: a browser-based compass.
First, we begin with the HTML. This time we must display an image. Later we’ll rotate this image by the value of the alpha
component using CSS. We won’t need any of the other data for this example.
1 2 3 |
<div id="compassContainer"> <img src="compass.jpg" id="compass"/> </div> |
Note that we give the value compass to the id
attribute of the img
element. We’ll need this when we rotate the image.
As before, we define an event handler function. This time we only need to obtain the alpha
value:
1 |
var alpha = event.alpha; |
And now we use the CSS3 transform
property to rotate the image by exactly this value:
1 |
compassContainer.style.transform = 'rotate(' + alpha + 'deg)'; |
Note that we’ll need the vendor-prefixed versions of this CSS transform for it to work on many browsers. These have been omitted here for brevity, but are included in the full code listing below.
We also include some code to handle some specific edge cases and implementation discrepancies so that it will work correctly on a wider set of devices, but this is not comprehensive, and your device may or may not be supported. These edge cases are discussed in the Browser Support section below:
- iOS: we check for the
webkitCompassHeading
property, and use it if it’s available, and reverse the direction of rotation of the compass - Android stock browser: we check for the stock Android browser, and apply an offset to the compass bearing to align it with the true compass bearings
- Firefox: we reverse the direction of rotation
We use CSS to specify the rotation origin, that is, the point around which the rotation will take place, to be the centre of the compass image. And we set the compass width to be 100% of the browser size, leaving the browser to resize the compass image (again, vendor prefixes omitted for brevity):
1 |
#compass{transform-origin: 50% 50%;width:100%} |
The whole thing looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<DOCTYPE html> <html> <head> <style> #compass{ width:100%; transform-origin: 50% 50%; -webkit-transform-origin: 50% 50%; -moz-transform-origin: 50% 50%; } </style> <script> function init() { var compass = document.getElementById('compass'); if(window.DeviceOrientationEvent) { window.addEventListener('deviceorientation', function(event) { var alpha; //Check for iOS property if(event.webkitCompassHeading) { alpha = event.webkitCompassHeading; //Rotation is reversed for iOS compass.style.WebkitTransform = 'rotate(-' + alpha + 'deg)'; } //non iOS else { alpha = event.alpha; webkitAlpha = alpha; if(!window.chrome) { //Assume Android stock (this is crude, but good enough for our example) and apply offset webkitAlpha = alpha-270; } } compass.style.Transform = 'rotate(' + alpha + 'deg)'; compass.style.WebkitTransform = 'rotate('+ webkitAlpha + 'deg)'; //Rotation is reversed for FF compass.style.MozTransform = 'rotate(-' + alpha + 'deg)'; }, false); } } </script> </head> <body onload="init()"> <div id="compassContainer"> <img src="compass.jpg" id="compass"/> </div> </body> </html> |
Click the compass image below to the activate the live compass demo. Depending on your device, you should be able to see the compass point to North as you rotate your device.
Live Demo – HTML5 compass
Browser support and Fallbacks
As can be seen from the table below there is wide support for the deviceorientation
event across most of the mobile browsers, with the exception of Internet Explorer and Opera Mini. The devicemotion
event is a different story. While the acceleration
property is reasonably well supported, the rotationRate
property doesn’t fare so well.
Android | iOS | IE Mobile | Opera Mobile | Opera Classic | Opera Mini | Firefox Mobile | Chrome for Android | |
---|---|---|---|---|---|---|---|---|
Orientation | ||||||||
Acceleration | ||||||||
Rotation | ||||||||
(Sources: caniuse.com, DeviceAtlas, mobilehtml5.org) |
Despite even the quite widespread support for the deviceorientation
event, there are still discrepencies across its various browser implementations, which developers need to be aware of.
The first type of discrepancy is around what the default 0 value for the orientation data actually means. This manifests itself across different mobile browsers as the values for alpha, beta, and gamma being offset by a certain number of degrees. The solution is to subtract the appropriate offset to get the correct value with respect to the true compass bearings.
In addition, for the three axes, the ranges of angles covered are different across implementations, and the direction of rotation is reversed in some cases.
So, for example, testing the alpha
property on some of the major mobile browsers yields the following table, based on work by AJFischer:
Android | iOS | Opera Mobile | Firefox Mobile | Chrome for Android | |
---|---|---|---|---|---|
0 deg | West(270) | East(90) | North(0) | North(0) | North(0) |
Positive rotation direction | CW | CCW | CW | CCW | CW |
Table illustrating some discrepencies across alpha(compass) implementations (C/CW: Counter/Clockwise) |
For similar tables for the other events and properties, please refer to AJFischer’s github page. He has also done some work to provide a cross-platform, normalised version of the API which will smooth over all the different implementation for the developer, although it requires the jQuery library which may not suit all projects.
The iOS implementation is also not without its peculiarities. Each time the compass is initialised, it sets the current orientation of the device to be 0 degrees, and subsequent values are reported relative to this initial bearing. A workaround for this is to use the iOS webkitCompassOrientation
property instead. This property aligns with the true compass heading, and can be used instead of the alpha
property if it is available, with something like:
1 2 3 4 5 |
var alpha; if(event.webkitCompassHeading) { alpha = event.webkitCompassHeading; } else alpha = event.alpha; |
And finally, we should also mention that older versions of Firefox Mobile supported the non-standard mozOrientation
event which offered related functionality to the deviceorienation
event. Applications targeting older browsers might need to check for this. Documentation can be found here.
Where’s North from here?
The HTML5 DeviceOrientation events API provides the web browser with access to the orientation and motion data of a device. While quite widely supported, there are discrepencies between different vendor implementations. There are also differences in terms of the extent of support. For example, the devicemotion
event is less well supported than the deviceorientation
event. However, once care is taken to observe these differences across mobile browsers, the DeviceOrientation API can indeed be usefully incorporated into your web applications.
References
Download
Download the full code samples below.
Leave a Reply