Detect phone rotation in Javascript Windows Phone mobile application

1.6k views Asked by At

I am writing a mobile application for Windows Phone in HTML5. I want to detect the phone's rotation around the z-axis (I mean the rotation that is used for example in Doodle jump to make the character jump to the left or to the right).

In my application, a line that is vertical in the screen must remain vertical (absolute position in the real world) if I rotate the screen to the left or to the right. To accomplish this, I use the relative values of the angle: each time the screen is rotated a little, I rotate the points of the line by the same amount, but negative.

This works PERFECTLY if the phone is laying on a table or almost horizontal, but the behaviour is much less precise if for example I watch the phone in front of me. Anyway this is not a big problem of course because most users watch the phone from up to down, but a game like doodle jump behaves perfectly also in this situation.

Here is part of the code:

window.addEventListener("deviceorientation", handleOrientation, true);

function handleOrientation(event) {

    alphaDiff = Math.floor(event.alpha) - alphaOld;
    alphaOld = Math.floor(event.alpha);

    //Rotation of the vertical line (x1,y1) - (x2,y2) around the center of the screen

    var newPoint = rotate(225, 400, x1, y1, alphaDiff);

    x1 = newPoint[0];
    y1 = newPoint[1];

    newPoint = rotate(225, 400, x2, y2, alphaDiff);

    x2 = newPoint[0];
    y2 = newPoint[1];
}

function rotate(cx, cy, x, y, angle) {

    var radians = (Math.PI / 180) * angle;
    cos = Math.cos(radians);
    sin = Math.sin(radians);
    nx = (cos * (x - cx)) - (sin * (y - cy)) + cx;
    ny = (sin * (x - cx)) + (cos * (y - cy)) + cy;

    return [nx, ny];
}
2

There are 2 answers

3
u01jmg3 On

Have you tried beta (for the x-axis) or gamma (for the y-axis)?

e.g.

function handleOrientation(event) {
    var absolute = event.absolute;
    var alpha    = event.alpha; // z-axis
    var beta     = event.beta;  // x-axis
    var gamma    = event.gamma; // y-axis

    // Do stuff with the new orientation data
}

Orientation Values Explained

The value reported for each axis indicates the amount of rotation around a given axis in reference to a standard coordinate frame.

  • The DeviceOrientationEvent.alpha value represents the motion of the device around the z-axis, represented in degrees with values ranging from 0 to 360.
  • The DeviceOrientationEvent.beta value represents the motion of the device around the x-axis, represented in degrees with values ranging from -180 to 180. This represents a front to back motion of the device.
  • The DeviceOrientationEvent.gamma value represents the motion of the device around the y-axis, represented in degrees with values ranging from -90 to 90. This represents a left to right motion of the device.

Explanation


It also worth checking browser compatibility for this API.


As well as deviceorientation, you can check compassneedscalibration and devicemotion. For more details on deviceorientation see MDN.

4
Rei On

A combination of beta and gamma seems to give pretty good results. Basically, I normalize the values to a specific range and get the ratio.

window.addEventListener("deviceorientation", function(event){
    var b = Math.abs(event.beta)/90;
    if(b>1) b = 2-b;

    var g = event.gamma/90;
    if(Math.abs(event.beta)>90) g = -g;

    var x = g/Math.max(0.25,b);
});

The final value is in x, positive means right, negative means left. It works with the phone held horizontally or at any angle facing you.

Update: To make the detection work in a vertical position, the code calculates how much the phone is leaning and to which direction. The value in x is always positive if the phone is leaning right and negative if leaning left.

This example shows a blue box in the middle of the screen and moves it to whichever direction the phone is leaning:

<!DOCTYPE html>
<html>
    <head><meta name="viewport" content="width=1000,user-scalable=no"/></head>
    <body style="margin:0">
        <pre id="log" style="font-size:4em;"></pre>
        <div id="box" style="background:#69c;width:100px;height:100px;position:relative;left:450px"></div>
        <script>
            var box = document.getElementById("box");
            var log = document.getElementById("log");
            var smoothx = 0;
            window.addEventListener("deviceorientation", function(event){
                var b = Math.abs(event.beta)/90;
                if(b>1) b = 2-b;

                var g = event.gamma/90;
                if(Math.abs(event.beta)>90) g = -g;

                var x = g/Math.max(0.25,b);
                smoothx = smoothx*0.7+x*0.3;

                box.style.left = Math.max(0, Math.min(900, smoothx*500+450))+"px";
                log.innerText = x.toFixed(1)+"\n"+smoothx.toFixed(1);
            });
        </script>
    </body>
</html>

Because the sensor seems to be very sensitive to movement, I implemented a simple smoothing that gives a steadier value in smoothx. Use x for immediate value without smoothing.