function Tracker(page) {
  this.page = page;
  this.moveUp = 0;
  this.moveDown = 0;
  this.startTouches = {};
  this.moveTouches = {};
  this.lastScrollY = 0;
  this.monitor = {};
  this.startThreshold = 160;
  this.moveThreshold = 10;
  this.iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
  this.pullToRefresh = window.chrome || navigator.userAgent.match('CriOS');
  this.amplitude = 16 / Math.log(2);
  this.page.ownerDocument.addEventListener( 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll', this, { passive: true } );
  /* The basic scroll event cannot be canceled, so it does not need to be set passive.*/
  this.page.ownerDocument.addEventListener('scroll', this);
  this.page.addEventListener('touchstart', this, { passive: true });
  /* Maybe we need to cancel pullToRefresh */
  this.page.addEventListener('touchmove', this, { passive: false });
  return this;
}
Tracker.prototype.handleEvent = function (e) { /* handleEvent is built-in */
  var winHeight = (this.iOS ? document.documentElement.clientHeight : window.innerHeight) | 0,
    currScrollY = window.pageYOffset | 0,
    amountScrollY = (this.lastScrollY - currScrollY) | 0,
    elHeight = this.page.offsetHeight | 0,
    elTop = -currScrollY, elBottom = winHeight - elHeight + currScrollY,
    isTop = elTop >= 0, isBottom = elBottom >= 0;
  switch (e.type) {
    case 'wheel':
    case 'onmousewheel':
    case 'mousewheel':
    case 'DOMMouseScroll':
      var wheelDelta = e.wheelDelta ? e.wheelDelta : e.deltaY ? -e.deltaY : -e.detail,
        wheelDir = (wheelDelta > 0) - (wheelDelta < 0),
        wheelUp = wheelDir < 0, wheelDown = wheelDir > 0,
        wheelAmount = 100 * wheelDir;
      if (isTop && wheelDown) {
        this.moveUp++;
        this.moveDown = 0;
      } else if (isBottom && wheelUp) {
        this.moveUp = 0;
        this.moveDown++;
      } else {
        this.moveUp = 0;
        this.moveDown = 0;
      }
      var compulsivity = this.amplitude * Math.log(Math.max(this.moveUp, this.moveDown, 0.01) * wheelAmount* wheelDir);
      this.monitor[e.type].track(wheelAmount, compulsivity);
      break;
    case 'scroll':
      /* end of scroll event for iOS,  start/end of scroll event for other browsers */
      this.lastScrollY = currScrollY;
      this.monitor[e.type].track(amountScrollY, 0);
      break;
    case 'touchstart':
      var touches = [].slice.call(e.touches), i = touches.length;
      while (i--) {
        var touch = touches[i], id = touch.identifier;
        this.startTouches[id] = touch;
        this.moveTouches[id] = touch;
      }
      break;
    case 'touchmove':
      var touches = [].slice.call(e.touches), i = touches.length, 
        currTouches = {},
        swipeUp = false, swipeDown = false,
        currMoveY = 0, totalMoveY = 0;
      while (i--) {
        var touch = touches[i], id = touch.identifier;
        currTouches[id] = touch;
        if (id in this.moveTouches) {
          currMoveY = this.moveTouches[id].screenY - touch.screenY;
        }
        if (id in this.startTouches) {
          totalMoveY = this.startTouches[id].screenY - touch.screenY;
        }
        swipeUp = currMoveY > 0 || totalMoveY > 0;
        swipeDown = currMoveY < 0 || totalMoveY < 0;
        if (this.pullToRefresh && isTop && swipeDown && e.cancelable) {
          e.preventDefault();
          console.log('Reload prevented');
        }
      }
      this.moveTouches = currTouches;
      var moveDir = (totalMoveY > 0) - (totalMoveY < 0),
        longSwipe = moveDir * totalMoveY > this.startThreshold,
        shortSwipe = moveDir * totalMoveY > this.moveThreshold,
        realSwipe = longSwipe || shortSwipe;
      if (isTop && swipeDown) {
        if (realSwipe) this.moveUp++;
        this.moveDown = 0;
      } else if (isBottom && swipeUp) {
        this.moveUp = 0;
        if (realSwipe) this.moveDown++;
      } else {
        this.moveUp = 0;
        this.moveDown = 0;
      }
      var compulsivity =  this.amplitude * Math.log(Math.max(this.moveUp, this.moveDown, 0.01) * moveDir * totalMoveY);
      this.monitor[e.type].track(currMoveY, compulsivity);
      break;
  }
};
function Monitor(events) {
  this.ctx = null;
  this.cont = null;
  this.events = events;
  this.values = [];
  this.average = 0;
  this.lastDrawTime = 0;
  this.inertiaDuration = 200;
  return this;
}
Monitor.prototype.showOn = function (container) {
  var cv = document.createElement('canvas');
  this.ctx = cv.getContext('2d');
  this.cont = document.getElementById(container);
  cv.width = this.cont.offsetWidth;
  cv.height = this.cont.offsetHeight;
  cv.style.top = 0;
  cv.style.left = 0;
  cv.style.zIndex = -1;
  cv.style.position = 'absolute';
  cv.style.backgroundColor = '#000';
  this.cont.appendChild(cv);
  var self = this;
  window.addEventListener('resize', function () {
    var cv = self.ctx.canvas, cont = self.cont;
    cv.width = cont.offsetWidth;
    cv.height = cont.offsetHeight;
  });
  return this;
};
Monitor.prototype.track = function (value, average) {
  this.average = average;
  if (this.values.push(value) > this.ctx.canvas.width) this.values.shift();
  if (value) this.lastDrawTime = new Date().getTime();
};
Monitor.prototype.draw = function () {
  if (this.ctx) {
    var cv = this.ctx.canvas, w = cv.width, h = cv.height;
    var i = this.values.length, x = w | 0, y = (0.5 * h) | 0;
    cv.style.backgroundColor = 'rgb(' + this.average + ', 0, 0)';
    this.ctx.clearRect(0, 0, w, h);
    this.ctx.strokeStyle = '#00ffff';
    this.ctx.lineWidth = 1;
    this.ctx.beginPath();
    while (i--) {
      x -= 4;
      if (x < 0) break;
      this.ctx.moveTo(x, y);
      this.ctx.lineTo(x + 1, y);
      this.ctx.lineTo(x + 1, y - this.values[i]);
    }
    this.ctx.stroke();
    var elapsed = new Date().getTime() - this.lastDrawTime;
    /* cool down */
    this.average = this.average > 0 ? (this.average * 0.9) | 0 : 0;
    if (elapsed > this.inertiaDuration) {
      this.track(0, this.average);
    }
  }
  var self = this;
  setTimeout(function () {
    self.draw();
  }, 100);
};
Monitor.prototype.connectTo = function (tracker) {
  var events = this.events.split(' '), i = events.length;
  while (i--) {
    tracker.monitor[events[i]] = this;
  }
  this.draw();
  return this;
};
function loadSomeData(target) {
  $.ajax({
    url: 'https://jsonplaceholder.typicode.com/users',
    method: 'GET',
    crossDomain: true,
    dataType: 'json',
    success: function (users) {
      var html = '', $ul = $(target).find('ul');
      $.each(users, function (i, user) {
        var item = '<li><a class="ui-alt-icon ui-nodisc-icon">';
        item += '<h2>' + user.name + '</h2>';
        item += '<p><strong>' + user.company.name + '</strong></p>';
        item += '<p>' + user.address.zipcode + ', ' + user.address.city + '</p>';
        item += '<p>' + user.phone + '</p>';
        item += '<p>' + user.email + '</p>';
        item += '<p class="ui-body-inherit ui-li-aside ui-li-count"><strong>' + user.id + '</strong></p>';
        item += '</a></li>';
        html += item;
      });
      $ul.append(html).listview('refresh');
    },
  });
}
$(document)
  .on('pagecreate', '#page-list', function (e) {
    $("[data-role='header'], [data-role='footer']").toolbar({ theme: 'a', position: 'fixed', tapToggle: false });
    loadSomeData(e.target);
  })
  .on('pageshow', '#page-list', function (e, ui) {
    var tracker = $.data(this, 'mobile-page', new Tracker(this));
    new Monitor('touchstart touchmove').connectTo(tracker).showOn('header');
    new Monitor('scroll wheel mousewheel DOMMouseScroll').connectTo(tracker).showOn('footer');
  });
.ui-page {
  touch-action: none;
}
h1, h2, h3, h4, h5, h6, p {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
/* JQM no frills */
.ui-btn,
.ui-title,
.ui-btn:hover,
.ui-btn:focus,
.ui-btn:active,
.ui-btn:visited {
  text-shadow: none !important;
}
* {
  -webkit-box-shadow: none !important;
  -moz-box-shadow: none !important;
  box-shadow: none !important;
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Compulsivity</title>
    <meta name="description" content="Compulsivity" />
    <meta name="HandheldFriendly" content="True" />
    <meta name="MobileOptimized" content="320" />
    <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, width=device-width, minimal-ui shrink-to-fit=no" />
    <meta http-equiv="cleartype" content="on" />
    <!-- Add to homescreen for Chrome on Android -->
    <meta name="mobile-web-app-capable" content="yes" />
    <!-- For iOS web apps. Delete if not needed. -->
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <meta name="apple-mobile-web-app-title" content="Compulsivity" />
    <link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" />
    <!--
    <script type="application/javascript" src="lib/touch-emulator.js"></script>
    <script> TouchEmulator(); </script>
    -->
    <script type="application/javascript" src="https://cdn.jsdelivr.net/npm/jquery@2.2.4/dist/jquery.min.js"></script>
    <script type="application/javascript" src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
  </head>
  <body>
    <div id="header" data-role="header"><h4 style="color: #fff">Compulsivity</h4></div>
    <div id="page-list" data-role="page">
      <div data-role="content" role="main">
        <ul data-role="listview" data-filter="true" data-inset="true"></ul>
      </div>
    </div>
    <div id="footer" data-role="footer"><h4 style="color: #fff">Scroll</h4></div>
  </body>
</html>