Hide Table of Contents
View Shake gesture recognition sample in sandbox
Shake gesture recognition

Description

This sample uses gesture recognition to remove a Dynamic Map Service and reset the application to its initial default launch state. A device's accelerometer can be used to detect motion events in the x, y and z direction. An instance of the DeviceMotionEvent class is used to listen for devicemotion events. The DeviceMotionEvent can be used to determine when a significant change in the device's motion occurs. The devicemotion event type captures the rotation rate, acceleration of the device and the time interval since the last device motion event.

The acceleration data (user acceleration and gravity) for the x, y and z axis is stored and compared to previous devicemotion events every 150 milliseconds. If the change in acceleration data is greater than the user-defined setting, the application is reset to its default state.

Code

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  
  <meta name="apple-mobile-web-app-capable" content="yes">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
  
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
  <title>Gesture Shake</title>

  <link rel="stylesheet" href="https://js.arcgis.com/3.20/dijit/themes/claro/claro.css" />
  <link rel="stylesheet" href="https://js.arcgis.com/3.20/esri/css/esri.css" />

  <script src="https://js.arcgis.com/3.20/"></script>
  <script>

    require([
      "dojo/dom",
      "dojo/on",
      "dojo/parser",
      "dojo/ready",
      "esri/map",
      "esri/layers/ImageParameters",
      "esri/layers/ArcGISDynamicMapServiceLayer"
    ], function (dom, on, parser, ready, Map, ImageParameters, ArcGISDynamicMapServiceLayer) {
      var map, dynamicMapServiceLayer, lyrOpacityFlag;

      ready(function () {
        init();
      });

      function init() {
        //onorientationchange doesn't always fire in a timely manner in Android so check for both orientationchange and resize
        var supportsOrientationChange = "onorientationchange" in window,
            orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";

        window.addEventListener(orientationEvent, function () {
          orientationChanged();
        }, false);

        lyrOpacityFlag = false;
        map = new Map("map", {
          basemap:"satellite",
          center :[-97.031, 37.638],
          zoom   :4,
          slider :false
        });

        var imageParameters = new ImageParameters();
        imageParameters.format = "PNG24";
        // Takes a URL to a non cached map service.
        dynamicMapServiceLayer = new ArcGISDynamicMapServiceLayer("https://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Median_Net_Worth/MapServer", {
          "opacity"        :1.0,
          "imageParameters":imageParameters
        });
        map.addLayer(dynamicMapServiceLayer);

        // remove the dynamic map
        removeDynMapListener();
      }

      // Handle portrait and landscape mode orientation changes
      function orientationChanged() {
        if (map) {
          map.reposition();
          map.resize();
        }
      }

      function removeDynMapListener() {
        // The DeviceMotionEvent provides the acceleration and rotation data of the device
        //
        // Determine if the DeviceMotionEvent is supported using feature detection.
        if (window.DeviceMotionEvent) {
          var threshhold = 20;

          // Position variables
          var xPreTotalAcc, yPreTotalAcc, zPreTotalAcc = 0;
          var xPostTotalAcc, yPostTotalAcc, zPostTotalAcc = 0;

          // The device motion event returns data about the rotation and acceleration information
          // of the device. The event returns two properties: acceleration and accelerationIncldingGravity
          on(window, "devicemotion", function (e) {
            xPreTotalAcc = e.acceleration.x;
            yPreTotalAcc = e.acceleration.y;
            zPreTotalAcc = e.acceleration.z;
          }, false);

          // The setInterval() method calls a function or evaluates an expression at specified intervals (in milliseconds).
          setInterval(function () {
            var change = Math.abs(xPreTotalAcc - xPostTotalAcc + yPreTotalAcc - yPostTotalAcc + zPreTotalAcc - zPostTotalAcc);
            if (change > threshhold) {
              // reset the application's to its default state
              resetApp();
            }
            // Update new position
            xPostTotalAcc = xPreTotalAcc;
            yPostTotalAcc = yPreTotalAcc;
            zPostTotalAcc = zPreTotalAcc;
          }, 150);
        } else {
          alert("DeviceMotion is currently not supported on this hardware.");
        }
      }

      function resetApp() {
        map.removeAllLayers();
        map.destroy();
        init();
        clearInterval();
      }

    });
  </script>
</head>

<body class="claro">
<div id="map"></div>
</body>

</html>