1

I'm building google maps based website and I'm trying to integrate a compass (get mobile absolute heading), but the problem is that I'm getting an absolute heading only for iPhone, while android always gives me relative heading to the direction I loaded the page.

How can I get android heading relative to the north?

Here is my code now:

if (window.DeviceOrientationEvent && mobile) {
    window.addEventListener('deviceorientation', function(event) {
        var dir;
        if (event.webkitCompassHeading) {
            // Apple works only with this, alpha doesn't work
            dir = event.webkitCompassHeading + 180; 
        } else { 
            //tried also event.alpha...
            dir = event.absolute;
        }

        var arrowPath = {
            path: 'M -50 120 L 50 120 L 000 170 z',
            fillColor: black,
            fillOpacity: 1,
            scale: 0.1,
            strokeOpacity: 0,
            strokeColor: 'white',
            strokeWeight: 1,
            rotation: dir
        };

        userDirection.setIcon(arrowPath);
    });
}
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
arielhasidim
  • 694
  • 10
  • 19
  • Possible duplicate of [Can I use Javascript to get the compass heading for iOS and Android?](https://stackoverflow.com/questions/16048514/can-i-use-javascript-to-get-the-compass-heading-for-ios-and-android) – Maxime Pacary Dec 18 '17 at 14:33
  • it seems that since 2016 chrome in adnroid doesn't and support absolute orientation ("in respect to Earth's coordinate frame"). https://developers.google.com/web/updates/2016/03/device-orientation-changes the alternative doesn't look that promising: https://developer.mozilla.org/en-US/docs/Web/API/Window/ondeviceorientationabsolute – arielhasidim Nov 01 '19 at 12:26

2 Answers2

2

Officially, since 2016, Chrome's DeviceOrientationEvent doesn't and support absolute orientation:

Starting with Chrome 50, the degrees included in the DeviceOrientationEvent are by default no longer absolute with respect to the Earth’s coordinate frame. This means that DeviceOrientationEvents should only be triggered when there’s actual movement, as detected by some combination of a device’s accelerometer and gyroscope. The magnetometer, and false readings due to magnetic field fluctuations, are out of the picture.

Strangely, in practice it does work for iPhone's chrome, and you can use event.webkitCompassHeading produce absolute orientation, while in Android it is relatively to the initial orientation while loading.

My solution is using DeviceOrientationAbsolute (non-standard, and non-pretty):

if (isiOS) {
    window.addEventListener('deviceorientation', manageCompass)
} else if (isAndroid) {
    window.addEventListener("deviceorientationabsolute", manageCompass, true);
}

function manageCompass(event) {
    if (event.webkitCompassHeading) {
        absoluteHeading = event.webkitCompassHeading + 180;
    } else {
        absoluteHeading = 180 - event.alpha;
    }
    console.log(absoluteHeading);
}

Another helpful answer (also works for web browser, not only Cordova).

Exampled here (in mobile)

UPDATE:

For completeness sake, as of ios13+, iphone demands asking permission only upon user gesture. Full code for ios+android:

on deviceready -

TrackOrientation() {

    // starts tracking on deviceready, updates value on currentCompass$ (fallback for ios13+ at "compassPremissioniOS13" funtion)
    if (typeof DeviceOrientationEvent['requestPermission'] !== 'function') {
      const deviceOrientationLestener = (event) => {
        if (this.globals.iphone) {
          this.currentCompass$.next(event['webkitCompassHeading']);
        } else {
          if (event.absolute) {
            this.currentCompass$.next(360 - event.alpha);
          } else {
            window.removeEventListener('deviceorientation', deviceOrientationLestener);
            window.addEventListener('deviceorientationabsolute', (eventB) => {
              this.currentCompass$.next(360 - eventB['alpha']);
            }, true);
          }
        }
      };
      window.addEventListener('deviceorientation', deviceOrientationLestener);
    } 
  }

upon user gesture -

  compassPremissioniOS13$() {
    return new Promise((resolve, reject) => {
      if (navigator.geolocation) {
        if (typeof DeviceOrientationEvent['requestPermission'] === 'function') {
          DeviceOrientationEvent['requestPermission']()
            .then(permissionState => {
              if (permissionState === 'granted') {
                window.addEventListener('deviceorientation', (event) => {
                  this.currentCompass$.next(event['webkitCompassHeading']);
                });
                resolve('User accepted');
              } else {
                reject('User declined');
              }
            })
            .catch(console.error);
        }
      } else {
        alert('deviceorientation is not supported by this browser.');
        this.sendError('deviceorientation = null ("deviceorientation is not supported by this browser.")');
      }
    });
  }
arielhasidim
  • 694
  • 10
  • 19
-1

Right now this option is unavailable in Android. Wait for the next Android update 8.0