У статьи есть интерактивная версия. Вы можете открыть его и поиграть с ориентацией устройства прямо с мобильного устройства.

Доступ к ориентации устройства в чистом JavaScript

В Javascript вы можете получить доступ к данным об ориентации вашего устройства, прослушивая событие deviceorientation. Это так просто:

window.addEventListener('deviceorientation', handleOrientation);

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

Вот значение углов alpha, beta и gama:

Источник изображения: newnow.co

Но! Не каждый браузер позволяет получить доступ к данным ориентации без разрешения пользователя. Например, в iOS 13 Apple ввела метод requestPermission. Он должен срабатывать при действии пользователя (щелчок, касание или аналогичный).

Пример доступа к ориентации устройства становится немного сложнее:

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

Если вы включите переключатель ориентации устройства в интерактивной версии этого поста, вы должны увидеть, под какими углами сообщает ваше устройство.

Отладка доступа к ориентации в браузере

В случае, если вы используете настольное устройство, вы можете имитировать вращение устройства на вкладке «Датчики» в dev-tools:

Прохладный! Итак, теперь у нас есть доступ к ориентации устройства, и мы даже можем протестировать это в браузере!

Хук React для доступа к ориентации устройства

Последний шаг, который я хотел бы сделать, - это придумать крючок React, который инкапсулирует для меня выборку ориентации и упростит его использование в компонентах React (например, тот, который показывает вам углы выше). ).

Вот пример ловушки useDeviceOrientation.ts, написанной на 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,
  };
};

Крючок можно использовать следующим образом:

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;

Демо

Наконец, имея доступ к ориентации устройства, давайте имитируем трехмерное пространство и возможность смотреть на объект с трехмерной перспективы, вращая мобильное устройство. Представьте, что у вас есть виртуальный товар, и вы хотите увидеть его под разными углами и с разных сторон, прежде чем положить его в корзину.

Мы будем использовать простой трехмерный куб, созданный с использованием чистого CSS с использованием свойств перспектива, перспектива-происхождение и преобразование (вы можете найти полный пример со стилями на css-tricks.com).

Вот и наш гиро-куб, который вы должны видеть под разными углами в зависимости от ориентации вашего устройства!

Если вы читаете статью с ноутбука, вот как демоверсия должна работать на мобильных устройствах, если вы запустите интерактивную версию этого поста:

Вы можете найти все примеры кода из этой статьи (включая стили Gyro-cube) в репозитории trekhleb.github.io.

Надеюсь, этот пример был вам полезен! Я также надеюсь, что вы придумаете гораздо более интересный и реалистичный вариант использования для ориентации устройства, чем Gyro-Cube, описанный выше 😄 Удачного кодирования!