Use HTML5 device orientation to run Windows 8 javascript apps on Android devices

For the last year there's been a good deal of information published on how to use the sensor APIs for Windows 8 device.  However if you are interesting in having portable HTML5 code leveraging device sensors typically required a native approach or 3rd party proprietary solution.  With a bit of work I found you can leverage new device orientation  event listeners in javascript that will mostly duplicate the Windows 8 native device sensor APIs .  And because HTML5 allows you to swap code on the fly you can easily leverage both the native sensor APIs for Windows and the html5 device orientation APIs depending on the device that is running the code. In other words, the same code you have in Visual Studio can be hosted on the web and work for an Android phone or tablet. Cool stuff!

Benefit of Coding in Javascript
Javascript is fastly becoming a highly portable language that can be used to call cross platform web browser instructions or native APIs for a particular OS.  Windows 8 allows you to compile a native app with javascript.  A neat possibility of this is the exact same code can be hosted and run by mobile devices or legacy PCs in a browser.  A problem however is very apparent when you want to leverage device specific APIs for sensors like the gyrometer , and accelerometer , etc.  While these Windows 8 classes are awesomely powerful to access via javascript, only Windows can execute them.  Thankfully the HTML5 events are catching up and can allow you to capture data from the device to get the device rotation information across all 3 axis. 

With just a bit of work you can tweak the data to mimic the native sensor APIs, and plug into your core code, creating a seamless experience across devices and form factors. Note you may be able to do this using PhoneGap and other 3rd party solutions, however that is brokering the solution to another entity. That might be good, that might not.  I’m certain that point is up for debate


Device Orientation Browser Compatibility

This is a fairly new event listener, but it is pretty well adopted and can be used on Chrome, Firefox and Opera and their mobile counterparts. Note IE10 does not support, however as I show you can swap out the Windows 8 sensor events with HTML5 sensor events and visa versa. Check out the graph of support from http://caniuse.com/deviceorientation.

Sample Code - Sensor Event Listener in Windows 8 vs HTML5

In the below code I’m showing how I get data from the Windows 8 Sensor API to turn move and rotate an object in my game.  With my example app I use the variable “webapp” to determine which code to execute.
Note in this use case I'm reading sensors and assigning data to 3 variables: xAngleyAngle and zAngle. xAngle is usedto alter the X position of my object on Canvas.  yAngle alters the Y Position of an object in Canvas, and zAngle rotates my object, like a spinning top, either left of right.

if (webapp == false) { // use Windows 8 Sensor API
    gyrometer = Windows.Devices.Sensors.Gyrometer.getDefault();
    gyrometer.addEventListener("readingchanged", onGyroReadingChanged);
    accelerometer = Windows.Devices.Sensors.Accelerometer.getDefault();
    accelerometer.addEventListener("readingchanged", onAccReadingChanged);
}
 
function onGyroReadingChanged(e) { // gets data for rotation around Z Axis and assigns to zAngle
    var accelZ = e.reading.angularVelocityZ;
    zAngle = -accelZ.toFixed(2);
}
 
function onAccReadingChanged(e) { //gets the tilt information and assigns to xAngle and yAngle
    var inclX = e.reading.accelerationY.toFixed(2) * -90;
    var inclY = e.reading.accelerationX.toFixed(2) * 90;
    xAngle = inclY;
    yAngle = holdAngle + inclX; // hold angle is read or set in calibration function
}
 

Here is the  base HTML5 device orientation version of that code.  Note this isn't done, read further to understand how I have to adjust this.

 

if (webapp == true) { // use HTML5 device orientation event listener
    window.addEventListener('deviceorientation', capture_orientation, false);
}
 
function capture_orientation(event) { //set input for web browser orientation sensors
    var alpha = event.alpha;
    var beta = event.beta;
    var gamma = event.gamma;
    alphaAngle = alpha.toFixed(2)  //set the alpha number to an integer
    xAngle = gamma;
    yAngle = holdAngle + beta;;
    zAngle = -alphadelta*5 ;
}

Solving issues between Windows 8 Sensor API and HTML5 device orientation

Defining a normal Z-Axis orientation: One issues you may have is with the Z axis rotation (gyrometer vs alpha).  Unless your use case is a compass, you will find that there is no "normal" orientation for the Z axis.  For example the X & Y axis rotation, you can assume that the X & Y plane are at a normal or default position if parallel to the plane of the earth (flat on a table). Thus if your device is tilted on its side or pitched forward your app might rotate something. However a user can be holding the device anywhere on across the Z axis and assume that experience should give them a normal or default experience.  In other words if you are facing North instead of East when you start your app, for most applications you assume it’s going to be the same experience.  Thus a key to having the Z axis orientation work in your app is to turn that axis orientation into accelerated data.  That way you know the difference or speed the device is moving around a Z axis.  In other words a still device that is not spinning, is your "normal" or default orientation for the Z axis, and the data you want is how fast and in what direction are you rotating on the Z axis.  .

The device orientation event handler, however, does not provide that accelerated data directly.  You will have to interpret the difference in the change of the data to get something like the accelerated Z axis spin.  However once you do this, the data is very comparable to the gyrometer data you get from the Windows 8 native sensor API.  To fix this I determine the difference between the previous or last Alpha orientation and the current Alpha orientation. That gives me a number that almost exactly matches the gyrometer acceleration data I get from my native code.  Here’s an example this would replace the last line of our capture_orientation function

if (alphainit < 1) { //we don’t have a lastAlpha reading so we need it to equal alpha the very 1st time
        lastAlpha = alphaAngle;
        alphainit = 1; //  now have the first alpha so this code won’t run again
    }
   
    alphadelta = alphaAngle - lastAlpha; //determine the delta difference current and last alpha
    lastAlpha = alphaAngle;  //sets lastAlpha value
    zAngle = -alphadelta * 5 // this is the same as before
}
 

Swapped X & Y Axis: Another issue is that you’ll find for phones the X & Y axis (beta and gamma) data is swapped compared to tablet and PC devices.  Perhaps the default or "normal" orientation on a phone is considered portrait, and thus why beta and gamma are reversed.  For you it means that you will have to swap the gamma and beta data if you want the experience to be consistent in landscape mode across form factors. 

To manage this situation I created a variable called “mobile” and when “mobile==true” we swap of the beta and gamma data. The following code replaced our” var beta =” and “var gamma =”  lines in our capture_orientation function.

if (mobile == true) { //swap beta and gamma for mobile browsers
        var beta = event.gamma*-1;
        var gamma = event.beta;
    }
    else {
        var beta = event.beta;
        var gamma = event.gamma;
    }
    

 

Managing browser nuances: As with any web application you will have to get some information on the device, on its browser and adjust some variables. The more devices you can test your app against the more bullet proof you can make the experience.  The good thing is you only need to edit a small set of code to manage what code should be turned on or off depending on the device and browser.  Here is an example of my config.js which does this.  With it I determine information about the device and browser then I can set variables to be true or false which tailor the code to that device.  For example if the device is not a PC or tablet I set the variable mobile to be true. If it is not running MSIE (Microsoft Internet Explorer) then this is being run in a browser and set the webapp variable to be true

 

var str2 = navigator.platform;
var str3 = navigator.userAgent;
 
if (str3.indexOf("MSIE") >= 0) { //IE browser based so Windows 8 APIs
    var webapp = false;
    var tabletmode = false;
    var mobile = false;
 
}
 
else { //run as a webapp and use device orientation
    var webapp = true;
    var tabletmode = true;
 }
 
 if (str2.indexOf("Win") >= 0 || str.indexOf("Opera") >= 0 || str2.indexOf("686") >= 0) {
     //If Windows, or Opera we will not reverse the X & Y
     var mobile = false;
 }
 
 else { // this is likely a phone and we need to reverse the X & Y
     var mobile = true;
     var tabletmode = true;
 
 }
 

Try it out. Check out my test game via my pubic dropbox link. http://db.tt/4ch0jZJ4.  If you have a new PC with orientation sensors try this in Chrome, then also try on an Android tablet or phone.  Take note, if running on Android. This is the exact same code I used to compile for Windows 8 running in your browser.  Now if you have issues let me know. The more browsers and devices test the more I can optimizes the code to accommodate, which is a benefit to javascript and HTML5.

-- you can contact Bob Duffy on twitter @bobduffy

 

Пожалуйста, обратитесь к странице Уведомление об оптимизации для более подробной информации относительно производительности и оптимизации в программных продуктах компании Intel.