How do I capture acceleration of DeviceMotionEvent after button is pressed

I want to capture and save (maybe console.log() too), the acceleration from the moment I press the start button which has startTest(). But I don't know how to do such thing as I have never used these DeviceMotionEvent. Any help on how can I start capturing the acceleration as described here and stop capturing it when I press the stop button would be highly appreciated. Thank you!

Here is my starting code with the buttons:

    <template>
      <q-page padding>
        <div class="text-center text-h5 q-mt-lg">
          {{ $t('tasks.motion.title') }}
        </div>
        <div class="row justify-center q-mt-lg">
          <q-btn
            @click="startTest"
            v-show="!isStarted"
            :label="$t('common.start')"
          />
          <q-btn
            @click="completeTest"
            v-show="isStarted"
            :label="$t('common.complete')"
          />
        </div>
      </q-page>
    </template>
    
    <script>
    import phone from 'modules/phone'
    import userinfo from 'modules/userinfo'
    import { format as Qformat } from 'quasar'
    
    const TEST_DURATION = 60
    
    export default {
      name: 'MotionOrientationPage',
      props: {
        sKey: String,
        tId: Number
      },
      data: function () {
        return {
          isSignalCheck: true,
          isStarted: false,
          isCompleted: false,
          timer: undefined,
          totalTime: TEST_DURATION,
          startedTS: undefined,
          completionTS: undefined,
          acceleration: [],
          distance: 0
        }
      },
      mounted: async function () {
      },
      methods: {
        async startTest () {
          this.isStarted = true
          this.startedTS = new Date()
          this.startTimer()
          phone.screen.forbidSleep()
        },
    
        startTimer () {
          this.totalTime = TEST_DURATION
          this.timer = setInterval(() => this.countDown(), 1000)
        },
        stopTimer () {
          clearInterval(this.timer)
        },
    
        countDown () {
          if (this.totalTime >= 1) {
            this.totalTime--
          } else {
            this.completeTest()
          }
        },
    
        completeTest () {
          this.isStarted = false
          this.completionTS = new Date()
          this.stopTimer()
          phone.screen.allowSleep()
    
          this.isCompleted = true
    
          // package the report
          const sKey = this.sKey
          const taskId = parseInt(this.taskId)
          const userKey = userinfo.user._key
          let report = {
            userKey: userKey,
            sKey: sKey,
            taskId: taskId,
            createdTS: new Date(),
            startedTS: this.startedTS,
            completionTS: this.completionTS,
            acceleration: this.acceleration,
            distance: this.distance
          }
    
          this.$router.push({ name: 'reportMotionOrientation', params: { report: report } })
        }
      },
    
      computed: {
        minutes () {
          return Qformat.pad(Math.floor(this.totalTime / 60))
        },
        seconds () {
          return Qformat.pad(this.totalTime - (this.minutes * 60))
        }
      },
    
      beforeDestroy: function () {
    this.stopTimer()
    phone.screen.allowSleep()
  }
}
</script>
Updated 2022-01-07 10:17:50Z by
Updated 2022-01-04 23:52:26Z by ga1996

Solution:

  1. Use a button to Start / Stop the test.
<button @click="toggleTest">
    {{ isTestRunning ? "Stop Test" : "Start Test" }}
</button>

// javascript > vue methods
toggleTest() {
   if (this.isTestRunning) {
       this.completeTest();
   } else {
       this.startTest();
   }
},
  1. Add a DeviceMotionEvent handler upon starting the test to track the acceleration values. window.addEventListener("devicemotion", this.reader, false)
// javascript > vue methods
startTest(){
    ...
    window.addEventListener("devicemotion", this.reader, false)
    ...
},
...
reader(event) {
    console.log(event.acceleration.x + " m/s2");
    this.accelerationX = event.acceleration.x | 0;
    // Acceleration has 3 axes (x, y, z)
    this.acceleration.push(event.acceleration.x | 0);
},
  1. And remove the DeviceMotionEvent handler upon completion of the test. window.removeEventListener("devicemotion", this.reader)
// javascript > vue methods
completeTest(){
    ...
    window.removeEventListener("devicemotion", this.reader)
    ...
},
  1. All discrete acceleration reading for X axis will be stored in the acceleration array

Example:

https://codesandbox.io/s/js-devicemotion-pjn7v

const TEST_DURATION = 60; // in seconds
const FREQUENCY = 1000; // in milliseconds

const round = function(x) {
  x = x * 1000;
  x = Math.round(x);
  x = x / 1000;
  return Math.round(x);
};

new Vue({
  el: '#app',
  data() {
    return {
      timer: undefined,
      isTestRunning: false,
      timeElapsed: 0,
      startedTS: undefined,
      completionTS: undefined,
      accelerationX: 0,
      velocityX: 0,
      distanceX: 0,
      acceleration: [],
      report: "Click on Start",
    }
  },
  methods: {
    reader(event) {
      console.log(event.acceleration.x + " m/s2");
      this.accelerationX = event.acceleration.x | 0;
      
      // Acceleration has thre axes
      this.acceleration.push(event.acceleration.x | 0);
      //this.countDown();
    },
    toggleTest() {
      if (this.isTestRunning) {
        this.completeTest();
      } else {
        this.startTest();
      }
    },
    startTest() {
      this.startedTS = new Date();
      this.completionTS = new Date();
      this.isTestRunning = true;
      this.startTimer();
      window.addEventListener("devicemotion", this.reader, false);
    },
    startTimer() {
      this.totalTime = TEST_DURATION;
      this.timer = setInterval(this.countDown, FREQUENCY);
    },
    stopTimer() {
      clearInterval(this.timer);
      this.timer = undefined;
    },
    countDown() {
      if (this.timeElapsed < TEST_DURATION) {
        let timeDuration = (new Date().getTime() - this.completionTS) / 1000;

        this.timeElapsed += timeDuration;

        //Calculating only for X Axis here
        // You may need to consider all 3 axes

        this.velocityX = round(
          this.velocityX + this.accelerationX * timeDuration
        );

        this.distanceX = round(
          this.distanceX +
          this.velocityX * timeDuration +
          0.5 * this.accelerationX * timeDuration * timeDuration
        );
        this.completionTS = new Date();
      } else {
        this.completeTest();
      }
    },
    completeTest() {
      window.removeEventListener("devicemotion", this.reader);
      this.stopTimer();
      this.completionTS = new Date();
      this.isTestRunning = false;

      // package the report
      let report = {
        createdTS: new Date(),
        startedTS: this.startedTS,
        completionTS: this.completionTS,
        accelerationX: this.accelerationX,
        velocityX: this.velocityX,
        distanceX: this.distanceX,
      };

      this.report = report;

      //uncomment below line when required
      //this.$router.push({ name: 'reportMotionOrientation', params: { report: report } })
    },
  },
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <div class="row justify-center q-mt-lg">
    <button @click="toggleTest">
      {{ isTestRunning ? "Stop Test" : "Start Test" }}
    </button>

    <div v-if="isTestRunning">
      <div>Time Elapsed :: {{ Math.round(timeElapsed) }}</div>
      <div>Distance :: {{ distanceX }}</div>
      <div>Velocity :: {{ velocityX }}</div>
      <div>Acceleration X :: {{ accelerationX }}</div>
      <div>Acceleration :: {{ acceleration }}</div>
    </div>
    <div v-else>
      {{ report }}
    </div>
  </div>
</div>

Updated 2022-01-14 09:52:37Z by
Updated 2022-01-12 19:25:19Z by Alpesh Patil