I've been using 'deviceorientation' for my project and when testing on iPhone/iPad, it behaves normally in landscape mode, but has an irregularity in portrait mode.
Here are the steps to repeat:
Open this JSFiddle on your iPad/iPhone in portrait mode -
Move the device as though you are looking through the camera and panning from looking at your feet, to looking at the horizon, to looking at the sky
event.beta will go from 0 -> +/-90 -> 0
Notice how the event.gamma jumps when the device reaches the horizon, around when event.beta = 90
Q1: How can I adjust for this behaviour?
Q2: Is there any way to get a definitive value (eg. 0-180) for movement in this direction, from ground to sky?
HTML
<b>e.alpha :</b> <span id='alpha'></span><br/>
<b>e.beta :</b> <span id='beta'></span><br/>
<b>e.gamma :</b> <span id='gamma'></span><br/>
JS
function deviceOrientationHandler(e){
var a = document.getElementById('alpha');
var b = document.getElementById('beta');
var g = document.getElementById('gamma');
a.innerText = e.alpha;
b.innerText = e.beta;
g.innerText = e.gamma;
}
if (window.DeviceOrientationEvent) {
window.addEventListener('deviceorientation', deviceOrientationHandler, false);
}else{
console.error('Device orientation not supported in this browser.');
}
The alpha, beta and gamma values when combined together produce a direction vector that indicates in which direction a device is 'pointing'.
In your example, when the
event.beta
value tips over +/-90 degrees then theevent.alpha
value will invert itself.event.alpha
is the heading of the device pointing out of the top of the screen so the heading of the device flips when you hit the horizon. Whenevent.alpha
inverts then another angle inversion MUST be simultaneously applied to one of the other angles to ensure that the direction vector continues to point in the right direction.Let's use a worked example and say our starting deviceorientation is
{alpha: 270, beta: 89.9, gamma: 0}
. We can determine the direction vector by first rotating around thealpha
value, then thebeta
value and finally thegamma
value. If I now rotate my device above the horizon, according to the instructions you provided above, then the heading of the device will flip from 270 degrees to 90 degrees.In this new orientation the data can NOT be
{alpha: 90, beta: 89.9, gamma: 0}
because if we use these values to determine the direction vector (in the same way we did above) we will notice that the direction vector now points in the opposite direction to where it should be. Thus, implementations perform a simultaneous flip of another axis to account for this flip of one axis to ensure the direction vector continues to 'point' in the right direction.The iOS implementation thus sets the data in this new orientation to
{alpha: 90, beta: 89.9, gamma: 180}
and then the direction vector continues to point in the correct direction.This is the reason you have observed a flip on the raw
event.gamma
value and this is the correct behaviour and not an irregularity.this is a 'gimbal lock' problem of Euler angles. It happens when two of the rotation rings get too close in angle(this case, gamma and alpha), the gyroscope returns value in Euler angles, in some situation though the 3d azimuth data stays relatively correct, one single gamma could get far away, and it would come back at another axis, so you find gamma and alpha changing just at same time but their sum stays still.
one way to solve it is to make a vector and set the rotation order just same as the gyroscope, track the vector and get rid of the dimensions you don't need, thus you get the correct gamma.
the idea is don't just focus on gamma itself, the 3d data is after all not wrong, the presenting form causes the problem, you can hardly skip or change the return form of DeviceOrienationEvent, the only way left is to recalculate the correct value in respect of the other two dimensions.
forgive my poor English, hope can help you.