Table of Contents

JavaScript Sensor Access

About

  • This demo page should be run from a mobile phone or a tablet.
  • This demo page on iOS Safari should be run in https (possibly in other browsers as well). This site is not currently in https mode.

This demo page shows how websites can access sensor data from mobile devices using deviceorientation and devicemotion events.

deviceorientation provides alpha, beta and gamma components which correspond to orientation along the Z, X and Y axes, respectively.

devicemotion provides acceleration and rotation rate along three axes using MEMS accelerometers and gyroscopes.

The sensor data shown below does not leave your browser: it is not collected, shared or transmitted. However this may not be true for other websites that you visit. For more information, see the companion page for our study: "The Web's Sixth Sense: A Study of Scripts Accessing Smartphone Sensors".

Demo

Start demo

Num. of datapoints: 0

Orientation

  • X-axis (β): 0°
  • Y-axis (γ): 0°
  • Z-axis (α): 0°

Accelerometer

  • X-axis: 0 m/s2
  • Y-axis: 0 m/s2
  • Z-axis: 0 m/s2
  • Data Interval: 0 ms

Accelerometer Including Gravity

  • X-axis: 0 m/s2
  • Y-axis: 0 m/s2
  • Z-axis: 0 m/s2

Gyroscope

  • X-axis: 0°/s
  • Y-axis: 0°/s
  • Z-axis: 0°/s

The Code

HTML

<div id="demo-div">
  <a id="start_demo" class="button" href="#" role="button">Start demo</a>

  <p>Num. of datapoints: <span id="num-observed-events">0</span></p>

  <h3>Orientation</h3>
  <ul>
    <li>X-axis (β): <span id="Orientation_b">0</span><span>°</span></li>
    <li>Y-axis (γ): <span id="Orientation_g">0</span><span>°</span></li>
    <li>Z-axis (α): <span id="Orientation_a">0</span><span>°</span></li>
  </ul>

  <h3>Accelerometer</h3>
  <ul>
    <li>X-axis: <span id="Accelerometer_x">0</span><span> m/s<sup>2</sup></span></li>
    <li>Y-axis: <span id="Accelerometer_y">0</span><span> m/s<sup>2</sup></span></li>
    <li>Z-axis: <span id="Accelerometer_z">0</span><span> m/s<sup>2</sup></span></li>
    <li>Data Interval: <span id="Accelerometer_i">0</span><span> ms</span></li>
  </ul>

  <h3>Accelerometer including gravity</h3>
  <ul>
    <li>X-axis: <span id="Accelerometer_gx">0</span><span> m/s<sup>2</sup></span></li>
    <li>Y-axis: <span id="Accelerometer_gy">0</span><span> m/s<sup>2</sup></span></li>
    <li>Z-axis: <span id="Accelerometer_gz">0</span><span> m/s<sup>2</sup></span></li>
  </ul>

  <h3>Gyroscope</h3>
  <ul>
    <li>X-axis: <span id="Gyroscope_x">0</span><span>°/s</span></li>
    <li>Y-axis: <span id="Gyroscope_y">0</span><span>°/s</span></li>
    <li>Z-axis: <span id="Gyroscope_z">0</span><span>°/s</span></li>
  </ul>
</div>

JavaScript

function handleOrientation(event) {
  updateFieldIfNotNull('Orientation_a', event.alpha);
  updateFieldIfNotNull('Orientation_b', event.beta);
  updateFieldIfNotNull('Orientation_g', event.gamma);
  incrementEventCount();
}

function incrementEventCount(){
  let counterElement = document.getElementById("num-observed-events")
  let eventCount = parseInt(counterElement.innerHTML)
  counterElement.innerHTML = eventCount + 1;
}

function updateFieldIfNotNull(fieldName, value, precision=10){
  if (value != null)
    document.getElementById(fieldName).innerHTML = value.toFixed(precision);
}

function handleMotion(event) {
  updateFieldIfNotNull('Accelerometer_gx', event.accelerationIncludingGravity.x);
  updateFieldIfNotNull('Accelerometer_gy', event.accelerationIncludingGravity.y);
  updateFieldIfNotNull('Accelerometer_gz', event.accelerationIncludingGravity.z);

  updateFieldIfNotNull('Accelerometer_x', event.acceleration.x);
  updateFieldIfNotNull('Accelerometer_y', event.acceleration.y);
  updateFieldIfNotNull('Accelerometer_z', event.acceleration.z);

  updateFieldIfNotNull('Accelerometer_i', event.interval, 2);

  updateFieldIfNotNull('Gyroscope_z', event.rotationRate.alpha);
  updateFieldIfNotNull('Gyroscope_x', event.rotationRate.beta);
  updateFieldIfNotNull('Gyroscope_y', event.rotationRate.gamma);
  incrementEventCount();
}

let is_running = false;
let demo_button = document.getElementById("start_demo");
demo_button.onclick = function(e) {
  e.preventDefault();

  // Request permission for iOS 13+ devices
  if (
    DeviceMotionEvent &&
    typeof DeviceMotionEvent.requestPermission === "function"
  ) {
    DeviceMotionEvent.requestPermission();
  }

  if (is_running){
    window.removeEventListener("devicemotion", handleMotion);
    window.removeEventListener("deviceorientation", handleOrientation);
    demo_button.innerHTML = "Start demo";
    demo_button.classList.add('btn-success');
    demo_button.classList.remove('btn-danger');
    is_running = false;
  }else{
    window.addEventListener("devicemotion", handleMotion);
    window.addEventListener("deviceorientation", handleOrientation);
    document.getElementById("start_demo").innerHTML = "Stop demo";
    demo_button.classList.remove('btn-success');
    demo_button.classList.add('btn-danger');
    is_running = true;
  }
};

Special Thanks

This page is comprised of my own additions and either partially or heavily modified elements from the following source(s):