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...
}
Here is the meaning of the alpha
, beta
and gama
angles:
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);
}
}
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.
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:
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,
};
};
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;
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:
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!
Top comments (7)
That's great,
Cool stuff can be done in websites
excited to try this out.
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 😅
You really are good. The cube example is just amazing. I'm definitely gonna try it. Thanks Oleksii :)
Hello. Thank you for the article. I am faced with the problem of taking gyroscope data on an iPhone, there are no problems with taking accelerometer data. But for some reason, even after I take the appropriate permission and subscribe to deviceorientation, nothing happens, there is no problem on androids. Tell me what this might be related to?
Really cool, thanks Oleksii!
I must try this in a PWA, the gyro cube demo looks amazing.
Thanks for sharing!
Great! It gave me some ideas about a project for my portfolio.
Thank u, man!