Fixing iOS Safari Javascript 'deviceorientatio

2019-02-18 22:49发布

问题:

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.');
}

回答1:

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 the event.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. When event.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 the alpha value, then the beta value and finally the gamma 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.



回答2:

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.