Using HTML5 accelerometer and gyroscope in 2020


Click here to see for yourself.

While looking to do some experiments with device motion data in HTML5, I found that there were no existing demos that would work on iOS 14. So, having spent a few hours figuring it out, I decided to write a tutorial with an up-to-date demo.

Conditions and caveats

Accelerometer and gyroscope are represented by DeviceMotionEvent and DeviceOrientationEvent accordingly;

  • Devices without API support have window.DeviceMotionEvent as undefined.
  • For some environments, listening to devicemotion is enough.
  • For environments closely following the updated specification (such as iOS 13+), the page must request a permission first by calling DeviceMotionEvent.requestPermission().
    The permission dialog can only be brought up from a user gesture (tap/click)!
    If the user had already granted the permission, you may call requestPermission without an interaction.
  • For other environments (such as all[?] Android devices as of writing this), DeviceMotionEvent.requestPermission is undefined and you may register a devicemotion listener right away.
  • Environments that can never provide accelerometer data (such as desktop computers) may dispatch devicemotion events with either acceleration, accelerationIncludingGravity, and rotationRate set to null (per-spec) or their components (XYZ/rotation) individually set to null (not per-spec but Chromium 87 does this).
  • As per security considerations, iOS will auto-decline the requestPermission call if the page is not loaded over HTTPS.

Code

So, with all of above in mind, a universal function to request accelerometer events would look as following:

/**
 * @param callback function(error)
 * @author YellowAfterlife
 **/
function requestDeviceMotion(callback) {
    if (window.DeviceMotionEvent == null) {
        callback(new Error("DeviceMotion is not supported."));
    } else if (DeviceMotionEvent.requestPermission) {
        DeviceMotionEvent.requestPermission().then(function(state) {
            if (state == "granted") {
                callback(null);
            } else callback(new Error("Permission denied by user"));
        }, function(err) {
            callback(err);
        });
    } else { // no need for permission
        callback(null);
    }
}

And subsequently could be called like

function firstClick() {
    requestDeviceMotion(function(err) {
        if (err == null) {
            window.removeEventListener("click", firstClick);
            window.removeEventListener("touchend", firstClick);
            window.addEventListener("devicemotion", function(e) {
                // access e.acceleration, etc.
            });
        } else {
            // failed; a JS error object is stored in `err`
        }
    });
}
window.addEventListener("click", firstClick);
window.addEventListener("touchend", firstClick);

(P.S.: Safari does not consider touchstart to be a user gesture event, but touchend is fine)

And for orientation, you can use the same logic, but with "orientation" instead:

/**
 * @param callback function(error)
 * @author YellowAfterlife
 **/
function requestDeviceOrientation(callback) {
    if (window.DeviceOrientationEvent == null) {
        callback(new Error("DeviceOrientation is not supported."));
    } else if (DeviceOrientationEvent.requestPermission) {
        DeviceOrientationEvent.requestPermission().then(function(state) {
            if (state == "granted") {
                callback(null);
            } else callback(new Error("Permission denied by user"));
        }, function(err) {
            callback(err);
        });
    } else { // no need for permission
        callback(null);
    }
}

(note: so far Safari combines the two so you don't have to request them independently)

Conclusion

Although the HTTPS requirement is a slight inconvenience for local tests, you can still use accelerometer and gyroscope in a reasonable way.

Related posts:

One thought on “Using HTML5 accelerometer and gyroscope in 2020

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.