Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Hosted-services / PhoneGap

Mobile Accelerometer Programming with Javascript and PhoneGap 3.0.0

5.00/5 (4 votes)
3 Sep 2013CPOL9 min read 37K   1.1K  
In this tutorial, we’ll build a hardware-aware application that uses Javascript to work with the device accelerometer.

This article appears in the Third Party Products and Tools section. Articles in this section are for the members only and must not be used to promote or advertise products in any way, shape or form. Please report any spam or advertising.

As the Android and iOS platforms continue to diverge, there is growing interest in libraries that allow developers to build cross platform applications. One of the most prominent of these libraries is phone gap. In this tutorial, we’ll build a hardware-aware application that uses Javascript to work with the device accelerometer.

If you haven’t yet downloaded the latest version of the PhoneGap framework it’s amazingly easy. Assuming you have NodeJS installed installation is takes a single line. Once you have PhoneGap installed we can build your application.

Step by Step

1) Create the phone gap application by typing the following in to your command line:

$ phonegap create accelerate
$ cd accelerate
$ phonegap local plugin add https://git-wip-
us.apache.org/repos/asf/cordova-plugin-device-motion.git

Note that the application will be created in what ever folder your command line is pointed to. Be sure to navigate to your destination folder first! The first two lines of command line instruction are fairly self-explanatory. They create the PhoneGap application called accelerate and navigate in to the folder just created.

The latest version of PhoneGap uses a remote plug-in architecture, so we have to manually obtain and install the accelerometer plug-in using the final line of command line code.

2) Open the accelerate folder and note the application structure includes a www folder. This is where we’re going to do our work.

 Image 1

Figure 1: PhoneGap application folder structure

The PhoneGap create command actually builds a small sample application. You can see it’s splash screen if you load the index.html page in to a browser. If you prefer you can actually run the whole application in a mobile device.

To run the sample app on an Android mobile device, connect your device to your computer via the USB to miniUSB cable. Issue the following commands with the command line path pointed at your project folder:

$ phonegap build android
$ phonegap run android

Running the sample app on an IOS device is actually more complex as the device has to be properly provisioned through XCode. To provision iOS devices for testing you must be registered with the Apple Developer program.

We’re actually going to delete the CSS folder, icon.png, the img folder and the js folder from the application. You can open index.html in your favorite text editor. Once you have the file open, remove the code relating to the sample application. You should be left with something like this:

HTML
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="format-detection" content="telephone=no" />
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
        <script type="text/javascript" src="phonegap.js"></script>
        <title>Accelerate</title>
    </head>
    <body>
	        
        
    </body>
</html>

As you can see, there are a few meta tags in the head that deal with screen size normalization. The balance of the code is standard HTML. We’ll first set up an initialization routine so that we know that the device and PhoneGap library are both ready before we run any code.

We’re going to be adding the following <script> element to the <head> of the document right before the <title>.

<script>
            window.onload = function()
            {
                //init();
                document.addEventListener("deviceready", init, false);
            }

            function init()
            {
                alert("Ready!");
            }
</script>

The init() function will be our entry point into the application. You’ll notice that the anonymous function associated with the window.onload event attaches a “deviceready” listener to the application. This event will tell us when the device and PhoneGap library are ready to interact with the user. For convenience I also comment out a call to init() in case I want to do browser testing. Since the “deviceready” event is part of the PhoneGap library, it would not function in a browser.

This is a good point to stop and test. Again, with your Android device connected and your command line pointed at your application folder issue the following command:

$ phonegap run android

If you get the expected alert box and everything else is correct, it’s time to create our UI for the application. (You might want to comment out the alert box in the init() function at this point.) We’re going to create a fairly simple UI that shows us the results generated by the accelerometer in the device. We’re going to add the following HTML inside the body element:

HTML
<footer>
<table id="footerTable">
<tr>
                    <td>X: <span id="xOut"></span></td>
                    <td>Y: <span id="yOut"></span></td>
                    <td>Z: <span id="zOut"></span></td>
            </tr>
</table>
</footer>

Add a style element in the document head to contain the CSS:

<style>
    body {
        margin: 0px;
    }

    #footerTable {
        width: 100%;
    }
    footer {
        position:absolute;
        bottom:0;
        width:100%;
        height:40px;
        background:#ccc;
        }
</style>

In the PhoneGap library the acceleration object has three methods. They are:

  • getCurrentAcceleration()
  • watchAcceleration()
  • clearWatch()

The first method, getCurrentAcceleration(), will get a snapshot of the accelerometer readings when the function is implemented. watchAcceleration() will return the readings of the accelerometer until a clearWatch() command is issued. For the purposes of our application we’re going to use watchAcceleration() so we can view the acceleration over a period of time.

The watchAcceleration() method returns an ID value that we can later use to stop the accelerometer. This is important because we don’t want the accelerometer using valuable resources when it’s no longer needed.

Edit your code so it appears as follows:

HTML
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="format-detection" content="telephone=no" />
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
        <style>
            body {
                margin: 0px;
            }
            #footerTable {
                width: 100%;
            }
            footer {
                position:absolute;
                bottom:0;
                width:100%;
                height:40px;   
                background:#ccc;
                }
        </style>
        <script type="text/javascript" src="phonegap.js"></script>
        <script>
            var watch = 0;

            window.onload = function()
            {
                //init();
                document.addEventListener("deviceready", init, false);
            }

            function init()
            {
                 watch = navigator.accelerometer.watchAcceleration(success, failure, {frequency: 100});
               

            }

            function success(accel)
            {
                document.getElementById("xOut").innerHTML = accel.x;
                document.getElementById("yOut").innerHTML = accel.y;
                document.getElementById("zOut").innerHTML = accel.z;
                   
            }

            function failure()
            {
                alert("Error");
            }
        </script>
        <title>Hello World</title>
    </head>
    <body>
        <footer>
            <table id="footerTable">
                <tr>
                    <td>X: <span id="xOut">0</span></td>
                    <td>Y: <span id="yOut">0</span></td>
                    <td>Z: <span id="zOut">0</span></td>
                </tr>
            </table>
        </footer>
        
    </body>
</html>

We’ve added in the foundational code to make the accelerometer work. You’ll notice that the init() function contains a very important line of code:

watch = navigator.accelerometer.watchAcceleration(success, failure, {frequency: 100});

This line essentially configures the accelerometer and turns it on. The three arguments in the watchAcceleration() method provide a call back if the accelerometer is successful at obtaining device movement information, a failure callback if the accelerometer fails and a frequency object which sets the frequency with which the accelerometer is sampled in miliseconds. The watch variable which is declared globally at the beginning of the script is used to capture the watch ID.

The success() and failure() call backs should appear fairly straight-forward. In the success() call back an acceleration object is passed in to the function and it contains properties which contain the readings for the x, y and z axis. The failure() callback simply outputs an error message at this point.

This would be a good time to test your application again and see if everything is working correctly up to this point. Again, to build and run your app issue the following command:

$ phonegap run android

Assuming everything is working correctly you should see the X Y and Z readouts at the bottom of your screen update as you move the device. Move the device slowly and notice how X, Y and Z react when you move the device along different axis.

Image 2

Figure 2: Note the display at the bottom of the screen

Now we’re going to make our application a little more interesting. Let’s use the accelerometer to move an object around the screen. We’ll add the object itself through the HTML and then use the accelerometer readings to determine the rate and direction of motion. To get ready, let’s add a canvas to our application and place an object on it. To add the canvas, we’re going to add a canvas element to the first line of the body.

HTML
<canvas id="myCanvas" ></canvas>

We’re also going to normalize the html and body’s width, height and margin css properties just in case. Add the following selector and rules to your CSS.

CSS
html, body
            {
                width: 100%;
                height: 100%;
                margin: 0px;
            }

I’m using an image called “crosshair.png’ for this application. We’re going to load it to the canvas dynamically in the init() event. You’ll want to set up cnv, for the canvas context, and target, for the image as globals at the top of your script. 

Revise your init() function to be coded as follows:

C#
function init()
{         
      var iW = window.innerWidth;
      var iH = window.innerHeight;
      cnv = document.getElementById('myCanvas').getContext("2d");
      cnv.canvas.width = iW;
      cnv.canvas.height = iH-40;
      target = new Image();
      target.src = "crosshair.png";
      target.onload = function()
      {
          cnv.drawImage(target, (iW-(target.width))/2, (iH-
          (target.height))/2);
       }
       watch = navigator.accelerometer.watchAcceleration(success,
           failure, {frequency: 100});
 }

There’s quite a bit going on here, so let’s break the important code down. The iW and iH variables simply contain the screen size. Obviously mobile devices vary in their specifications, so we want to be sure to create a canvas that’s flexible. The cnv variable is used to reference the context object on which we’ll do most of our work. It’s helpful to think of the canvas as an invisible layer wrapped around the canvas.

We use the context object, cnv, to set the canvas’ width and height properties. We subtract 40 from the height to allow for the output bar we’ve already created at the bottom of the display. We initialize the target variable as an Image object and provide it’s source image to the src property.

We want to make sure the image has loaded before we try to display it, so we setup an anonymous function that is called when the image object called target loads. At that point we draw the image and do some simple math to put it I the center of the screen. Finally we configure the accelerometer.

This is another excellent time to test your application on your device.

Image 3

Figure 3: Application after canvas and image have been added.

Now, we’ll make the image move as the user tilts the device and the accelerometer reacts. Most of this work will be done in the success() callback function, however, I made a few changes to the init() function to facilitate a smoother running application. Here’s the modified init() function:

C#
function init()
{     
      var iW = window.innerWidth;
      var iH = window.innerHeight;
      canvas= document.getElementById('myCanvas');
      cnv = canvas.getContext("2d");
      cnv.canvas.width = iW;
      cnv.canvas.height = iH-40;
      target = new Image();
      target.src = "crosshair.png";
      xPos = (iW-target.width)/2;
      yPos = (iH-target.height)/2;
      target.onload = function()
      {
          cnv.drawImage(target, xPos, yPos);
      }
      watch = navigator.accelerometer.watchAcceleration(success, 
          failure, {frequency: 25});      
}

Once you’ve modified your init() add canvas to your list of global declarations at the beginning of the script. You’ll also notice that xPos and yPos variables are set during the init() process to capture the initial position of the image. You’ll need to add these to your list of globals as well. Finally, I reduced the frequency value to 25 so we’re going to get results from the accelerator every 25 milliseconds. Now on to the success() callback function:

C#
function success(accel)
{
    document.getElementById("xOut").innerHTML = accel.x;
    document.getElementById("yOut").innerHTML = accel.y;
    document.getElementById("zOut").innerHTML = accel.z;
    cnv.clearRect(0, 0, canvas.width, canvas.height);
    xPos += -1*(accel.x * 1.5);
    yPos += (accel.y * 1.5);
    cnv.drawImage(target, xPos, yPos);                
}

After updating the display bar at the bottom of the screen, the clearRect() method is fired on the canvas object. This clears the canvas prior to redrawing the image in the updated position. The clearRect() method requires a starting point and width and height you’d like to clear. We’re clearing the entire canvas so we provide it’s width and height as arguments.

Next we update the xPos and yPos before redrawing. xPos has to be negated so that the image moves in the direction the user is tilting the device. Both the xPos and yPos are multiplied by 1.5 to move the image slightly faster. Finally drawImage() is called which draws the image at the new and updated position.

Test your application one more time and it should move as the device is tiled along each axis. To challenge yourself create some additional code that prevents the image from falling off the edge of the screen.

As you can see, PhoneGap makes it easy to access device hardware, like the accelerometer, and include it in your Javascript based mobile applications.

Special thanks to Adobe evangelist Raymond Camden (www.raymondcamden.com) for his generous assistance.

More Great Resources on PhoneGap 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)