Mobile app internals

This page describes how to measure angles using a phone's accelerometer.

Accelerometer

The core thing that provides information about the orientation of the smartphone is the Accelerometer sensor.
Good references about sensors can be found here: Sensor APIs, Accelerometer and Sensors for the web.

In this particular implementation, accessing the accelerometer from the JavaScript is quite simple:


if ('Accelerometer' in window) {
    try {
        const accelerometer = new Accelerometer({frequency});
        accelerometer.onerror = ({error}) => handleError(error);
        accelerometer.onreading = () => handleValue(accelerometer);
        accelerometer.start();
        return accelerometer;
    } catch (error) {
        handleError(error);
    }
} else {
    handleError({name: 'NotSupported'});
}
    

At the given frequency, the accelerometer triggers the "handleValue function and passes gravity values:


const handleValue = ({x, y}) => {
    const normalized = normalizeGravity(x, y);
    const newDegrees = Math.atan2(normalized.y, normalized.x) * 180 / Math.PI;
    if (Math.abs(newDegrees - degrees) > precision) {
        degrees = newDegrees;
        changeCallback(degrees);
    }
};
    

Where "x" and "y" are values from -9.8 to 9.8, depends on how the device is rotated.

Rotated phone

In addition to the physical rotation, there is a logical orientation (the screen can rotate automatically when you move a device between portrait and landscape orientation). In this case it is necessary to invert gravity values to compensate screen rotation:


const normalizeGravity = (x, y) => {
    switch (screen.orientation.type) {
        case 'portrait-secondary':
            return {x: -x, y: -y};
        case 'landscape-primary':
            return {x: -y, y: x};
        case 'landscape-secondary':
            return {x: y, y: -x};
        default:
            return {x, y};
    }
};
    

After that these "x" and "y" values can be converted to radians: radians = Math.atan2(y, x), and to degrees degrees = radians * 180 / Math.PI". Then this angle is used to rotate the vector arrow in the SVG image:


pointerLine.setAttribute('transform', `rotate(${-degrees})`);
pointerMarker.setAttribute('transform', `rotate(${-degrees})`);
    

Complete code can be found at github



← Angle meter
© 2019-2023 Xantorohara