Touch Gestures

Traditionally, Web relies on a mouse and a keyboard as the only input devices, while mobile devices are mostly controlled by touch. Mobile Web started with a bit touchy solution of translating touch events to mouse events like mousedown.

Newer HTML5 approach is to embrace touch as the first-class input mean, allowing Web applications to intercept and identify complex multitouch gestures, free-hand drawing etc. Unfortunately, the support is twofold - either via touch events like touchstart that were first introduced by Apple and standardized later as a de-facto solution, when other vendors went the same route, or via the newer, more general Pointer Events specification, initiated by Microsoft.

API glimpse

Touch Events API

element.addEventListener('touchstart', listener)
An event triggered when the finger has been placed on a DOM element.
element.addEventListener('touchmove', listener)
An event triggered when the finger has been dragged along a DOM element.
element.addEventListener('touchend', listener)
An event triggered when the finger has been removed from a DOM element.

Pointer Events API

element.addEventListener('pointerdown', listener)
An event triggered when the finger has been placed on a DOM element.
element.addEventListener('pointermove', listener)
An event triggered when the finger has been dragged along a DOM element.
element.addEventListener('pointerup', listener)
An event triggered when the finger has been removed from a DOM element.

Live Demo

Drag me with one finger
Drag me with another finger
Drag me too

Based on demo from QuirksMode.org.

  • function startDrag(e) {
      this.ontouchmove = this.onmspointermove = moveDrag;
    
      this.ontouchend = this.onmspointerup = function () {
        this.ontouchmove = this.onmspointermove = null;
        this.ontouchend = this.onmspointerup = null;
      }
    
      var pos = [this.offsetLeft, this.offsetTop];
      var that = this;
      var origin = getCoors(e);
    
      function moveDrag(e) {
        var currentPos = getCoors(e);
        var deltaX = currentPos[0] - origin[0];
        var deltaY = currentPos[1] - origin[1];
        this.style.left = (pos[0] + deltaX) + 'px';
        this.style.top = (pos[1] + deltaY) + 'px';
        return false; // cancels scrolling
      }
    
      function getCoors(e) {
        var coors = [];
        if (e.targetTouches && e.targetTouches.length) {
          var thisTouch = e.targetTouches[0];
          coors[0] = thisTouch.clientX;
          coors[1] = thisTouch.clientY;
        } else {
          coors[0] = e.clientX;
          coors[1] = e.clientY;
        }
        return coors;
      }
    }
    
    var elements = document.querySelectorAll('.test-element');
    [].forEach.call(elements, function (element) {
      element.ontouchstart = element.onmspointerdown = startDrag;
    });
    
    document.ongesturechange = function () {
      return false;
    }
  • <div class="test-element">Drag me with one finger</div>
    <div class="test-element">Drag me with another finger</div>
    <div class="test-element">Drag me too</div>
    
    <p><small>Based on demo from <a href="https://www.quirksmode.org/m/tests/drag2.html">QuirksMode.org</a>.</small></p>
  • .test-element {
      height: 100px;
      background-color: black;
      width: 100px;
      z-index: 5;
      position: absolute;
      top: 15px;
      left: 15px;
      color: white;
      text-align: center;
      -ms-touch-action: none;
    }
    
    .test-element:nth-child(2) {
      top: 150px;
      left: 150px;
    }
    
    .test-element:nth-child(3) {
      top: 50px;
      left: 100px;
    }

Resources