DEV Community

loading...
Cover image for GYRO-WEB: ACCESSING THE DEVICE ORIENTATION IN JAVASCRIPT

GYRO-WEB: ACCESSING THE DEVICE ORIENTATION IN JAVASCRIPT

trekhleb profile image Oleksii Trekhleb ・4 min read

This article has interactive version. You may open it to play around with the device orientation right from your mobile device.

Accessing device orientation in pure JavaScript

In Javascript, you may access your device orientation data by listening to the deviceorientation event. It is as easy as the following:

window.addEventListener('deviceorientation', handleOrientation);

function handleOrientation(event) {
  const alpha = event.alpha;
  const beta = event.beta;
  const gamma = event.gamma;
  // Do stuff...
}
Enter fullscreen mode Exit fullscreen mode

Here is the meaning of the alpha, beta and gama angles:

device orientation

Image source: newnow.co

But! Not every browser allows you to access the orientation data without user's permission. For example, in iOS 13 Apple has introduced the requestPermission method. It must be triggered on user action (click, tap or equivalent).

The example of accessing the device orientation becomes a bit more complicated:

function onClick() {
  if (typeof DeviceMotionEvent.requestPermission === 'function') {
    // Handle iOS 13+ devices.
    DeviceMotionEvent.requestPermission()
      .then((state) => {
        if (state === 'granted') {
          window.addEventListener('devicemotion', handleOrientation);
        } else {
          console.error('Request to access the orientation was rejected');
        }
      })
      .catch(console.error);
  } else {
    // Handle regular non iOS 13+ devices.
    window.addEventListener('devicemotion', handleOrientation);
  }
}
Enter fullscreen mode Exit fullscreen mode

If you would turn the device orientation toggle on in the interactive version of this post you should see what angles your device is reporting.

angles demo

Debugging the orientation access in the browser

In case if you're using the desktop device you may imitate the device rotation from the "Sensors" tab in dev-tools:

testing in chrome

Cool! So now we have the access to device orientation, and we can even test it in the browser!

React hook for accessing the device orientation

The last step I would like to take is to come up with the React hook, that will encapsulate the orientation fetching for me, and make it easier to use it in the React components (like the one that displayed the angles to you above).

Here is an example of the useDeviceOrientation.ts hook, that is written in TypeScript:

import { useCallback, useEffect, useState } from 'react';

type DeviceOrientation = {
  alpha: number | null,
  beta: number | null,
  gamma: number | null,
}

type UseDeviceOrientationData = {
  orientation: DeviceOrientation | null,
  error: Error | null,
  requestAccess: () => Promise<boolean>,
  revokeAccess: () => Promise<void>,
};

export const useDeviceOrientation = (): UseDeviceOrientationData => {
  const [error, setError] = useState<Error | null>(null);
  const [orientation, setOrientation] = useState<DeviceOrientation | null>(null);

  const onDeviceOrientation = (event: DeviceOrientationEvent): void => {
    setOrientation({
      alpha: event.alpha,
      beta: event.beta,
      gamma: event.gamma,
    });
  };

  const revokeAccessAsync = async (): Promise<void> => {
    window.removeEventListener('deviceorientation', onDeviceOrientation);
    setOrientation(null);
  };

  const requestAccessAsync = async (): Promise<boolean> => {
    if (!DeviceOrientationEvent) {
      setError(new Error('Device orientation event is not supported by your browser'));
      return false;
    }

    if (
      DeviceOrientationEvent.requestPermission
      && typeof DeviceMotionEvent.requestPermission === 'function'
    ) {
      let permission: PermissionState;
      try {
        permission = await DeviceOrientationEvent.requestPermission();
      } catch (err) {
        setError(err);
        return false;
      }
      if (permission !== 'granted') {
        setError(new Error('Request to access the device orientation was rejected'));
        return false;
      }
    }

    window.addEventListener('deviceorientation', onDeviceOrientation);

    return true;
  };

  const requestAccess = useCallback(requestAccessAsync, []);
  const revokeAccess = useCallback(revokeAccessAsync, []);

  useEffect(() => {
    return (): void => {
      revokeAccess();
    };
  }, [revokeAccess]);

  return {
    orientation,
    error,
    requestAccess,
    revokeAccess,
  };
};
Enter fullscreen mode Exit fullscreen mode

The hook might be used as follows:

import React from 'react';
import Toggle  from './Toggle';
import { useDeviceOrientation } from './useDeviceOrientation';

const OrientationInfo = (): React.ReactElement => {
  const { orientation, requestAccess, revokeAccess, error } = useDeviceOrientation();

  const onToggle = (toggleState: boolean): void => {
    const result = toggleState ? requestAccess() : revokeAccess();
  };

  const orientationInfo = orientation && (
    <ul>
      <li>ɑ: <code>{orientation.alpha}</code></li>
      <li>β: <code>{orientation.beta}</code></li>
      <li>γ: <code>{orientation.gamma}</code></li>
    </ul>
  );

  const errorElement = error ? (
    <div className="error">{error.message}</div>
  ) : null;

  return (
    <>
      <Toggle onToggle={onToggle} />
      {orientationInfo}
      {errorElement}
    </>
  );
};

export default OrientationInfo;
Enter fullscreen mode Exit fullscreen mode

Demo

Finally, having the access to the device orientation, let's imitate a 3D space, and a possibility to look at the object from a 3D perspective by rotating your mobile device. Imagine you have a virtual shopping item, and you want to see it from different angles and sides before putting it into your basket.

We will use a simple 3D cube which is made with pure CSS by using the perspective, perspective-origin and transform properties (you may find the full example with styles on css-tricks.com).

Here we go, here is our Gyro-Cube that you should be able to see from the different angles depending on your device orientation!

In case if you're reading the article from the laptop, here's how the demo should work on mobile devices if you would launch the interactive version of this post:

demo

You may find all the code examples from this article (including the Gyro-cube styles) in trekhleb.github.io repo.

I hope this example was useful for you! I also hope that you will come up with much more interesting and realistic use-case for the device orientation than the Gyro-Cube above 😄 Happy coding!

Discussion (6)

pic
Editor guide
Collapse
aspiiire profile image
Aspiiire

Thanks really cool feature, I remember a library that has implemented this with the parallax effect like 5 years ago; I think it was called parallax js 😅

Collapse
harshvats2000 profile image
HARSH VATS

You really are good. The cube example is just amazing. I'm definitely gonna try it. Thanks Oleksii :)

Collapse
rhymes profile image
rhymes

Really cool, thanks Oleksii!

Collapse
dastasoft profile image
dastasoft

I must try this in a PWA, the gyro cube demo looks amazing.

Thanks for sharing!

Collapse
machineno15 profile image
Tanvir Shaikh

That's great,
Cool stuff can be done in websites
excited to try this out.

Collapse
brunocampos profile image
Bruno Campos • Edited

Great! It gave me some ideas about a project for my portfolio.

Thank u, man!