How To: Hack Together an Accelerometer-Aware Mobile Website by Accessing Motion Sensors in JavaScript

Hack Together an Accelerometer-Aware Mobile Website by Accessing Motion Sensors in JavaScript

How to Hack Together an Accelerometer-Aware Mobile Website by Accessing Motion Sensors in JavaScript

Christian Cantrell, Adobe's Air Product Manager and Evangelist, has released a video to demo websites that take advantage of the motion sensors in a mobile phone, tablet, or laptop via JavaScript. Now, let's take a look through the code and break down the core pieces that you'll need in order to build your own sites that can determine the 2-axis tilt, 3-axis gyroscope, and compass direction of the mobile device it's being displayed on.

Let's See It in Action

First, check out the video Christian put up to demo the functionality using the accelerometer on a MacBook Pro, as well as the compass on an iPad. The same functionality is present in the latest Android browser, as well (though it's not shown in the video).

Try the Demos Yourself

You can try out each of the demos yourself here:

Digging into the Code

To see the full source code, just right-click and hit view-source on either of the demos. For now, let's break down the pieces that actually react to the motion coordinates.

The window.ondeviceorientation Event

The heart of the motion controls is in the window.ondeviceorientation event. It is partially supported in Firefox (using the MozOrientation event), Google Chrome (as of version 7.0), iOS Safari (5.0+), Opera Mobile (12.0+), and Android (4.0+). IE9 does not support it and IE10 support is still unknown.

Step 1 Listen for the Event

To be updated each time the device orientation changes, let's create an empty object. You must listen for the "deviceorientation" event using the following line of code:

window.addEventListener('deviceorientation', onDeviceOrientationChange, false); 

Step 2 Track the Current Device Orientation

To keep track of the current orientation, let's create an empty object and call it lastOrientation to hold the state. We can then add our onDeviceOrientationChange event handler to capture the event each time it fires, and update our lastOrientation object with the new state:

var lastOrientation = {};

function onDeviceOrientationChange(event) {
     lastOrientation.gamma = event.gamma;
     lastOrientation.beta = event.beta;
     if (event.webkitCompassHeading != undefined) { 
         lastOrientation.currentHeading = (360 - event.webkitCompassHeading);
     } else if (event.alpha != null) {
         lastOrientation.currentHeading =  (270 - event.alpha) * -1; 
     } else {
     
    lastOrientation.currentHeading = null;
     }
};

  • The gamma property of the event will give you the horizontal orientation (or x-axis).
  • The beta property of the event will give you the vertical orientation (or y-axis).
  • The compass heading is different depending on the browser, as it hasn't been standardized yet. To keep things simple here, we've normalized the value and stored it in a property that we'll call currentHeading. Keep in mind, not all devices support a compass heading, so if it's not available, that value will be null.

Step 3 Do Whatever You Want with the Orientation

By this point, you can now depend on your lastOrientation variable always being up to date with the current device orientation. Instead of updating your display every single time the orientation changes (this can be hundreds of times a second), it's more efficient to set an interval to execute your redrawing code a few times a second to achieve a decent frame rate. Use the following template to execute whatever code you want to with the gamma, beta, and currentHeading properties at about 30 frames per second:

setInterval(function() {
    // Write whatever code you want to here to do anything you like with the coordinates.
    // For example, this code will update a div with ID "output" to display the coordinates:
    var sOut = 'gamma: ' + lastOrientation.gamma +
        '<br/>beta: ' + lastOrientation.beta +
        '<br/>currentHeading: ' + lastOrientation.currentHeading;
    document.getElementById('output').innerHTML =  sOut;
},33);

Have any questions? Let us know in the comments. For bonus points, can any of you share with the community how to track the delta of the changes in orientation between frames?

Hint: Christian does this in his demos. If you view the source and follow along, you should be able to figure it out.

2 Comments

what are your thoughts on using the accelerometer/gyro to predict a rotation event BEFORE the actual event fires. for example, a routine to detect values just AHEAD of the values defined in iOS.. giving us in effect a "pre-event". this is somewhat of a holy grail considering the reflow issues with rotation in webapps on iOS... i would love to know what you think and how you believe this might be solved?

Good idea. This snippet could absolutely help you do that. I'd suggest starting out by hooking into the rotation events and the accelerometer events and just logging them all to the console with console.log(). That'll help you figure out what accelerometer values end up triggering the rotation event, and you can just fire your own event by storing and looking back at the past 3 accelerometer values (fired every 33 milliseconds, as in the code above) to determine the current rotation speed and predict if you're getting close to the rotation threshold. Make sense?

Share Your Thoughts

  • Hot
  • Latest