src/render/browser/render/gesture.js
function touchstartHandler(event) {

  if (Object.keys(gestures).length === 0) {
    docEl.addEventListener('touchmove', touchmoveHandler, false)
    docEl.addEventListener('touchend', touchendHandler, false)
    docEl.addEventListener('touchcancel', touchcancelHandler, false)
  }

  // record every touch
  for (var i = 0; i < event.changedTouches.length; i++) {
    var touch = event.changedTouches[i]
    var touchRecord = {}

    for (var p in touch) {
      touchRecord[p] = touch[p]
    }

    var gesture = {
      startTouch: touchRecord,
      startTime: Date.now(),
      status: 'tapping',
      element: event.srcElement || event.target,
      pressingHandler: setTimeout(function (element, touch) {
        return function () {
          if (gesture.status === 'tapping') {
            gesture.status = 'pressing'

            fireEvent(element, 'longpress', {
              // add touch data for jud
              touch: touch,
              touches: event.touches,
              changedTouches: event.changedTouches,
              touchEvent: event
            })
          }

          clearTimeout(gesture.pressingHandler)
          gesture.pressingHandler = null
        }
      }(event.srcElement || event.target, event.changedTouches[i]), 500)
    }
    gestures[touch.identifier] = gesture
  }

  if (Object.keys(gestures).length == 2) {
    var elements = []

    for (var p in gestures) {
      elements.push(gestures[p].element)
    }

    fireEvent(getCommonAncestor(elements[0], elements[1]), 'dualtouchstart', {
      touches: slice.call(event.touches),
      touchEvent: event
    })
  }
}
function touchstartHandler(event) {

  if (Object.keys(gestures).length === 0) {
    docEl.addEventListener('touchmove', touchmoveHandler, false)
    docEl.addEventListener('touchend', touchendHandler, false)
    docEl.addEventListener('touchcancel', touchcancelHandler, false)
  }

  // record every touch
  for (var i = 0; i < event.changedTouches.length; i++) {
    var touch = event.changedTouches[i]
    var touchRecord = {}

    for (var p in touch) {
      touchRecord[p] = touch[p]
    }

    var gesture = {
      startTouch: touchRecord,
      startTime: Date.now(),
      status: 'tapping',
      element: event.srcElement || event.target,
      pressingHandler: setTimeout(function (element, touch) {
        return function () {
          if (gesture.status === 'tapping') {
            gesture.status = 'pressing'

            fireEvent(element, 'longpress', {
              // add touch data for jud
              touch: touch,
              touches: event.touches,
              changedTouches: event.changedTouches,
              touchEvent: event
            })
          }

          clearTimeout(gesture.pressingHandler)
          gesture.pressingHandler = null
        }
      }(event.srcElement || event.target, event.changedTouches[i]), 500)
    }
    gestures[touch.identifier] = gesture
  }

  if (Object.keys(gestures).length == 2) {
    var elements = []

    for (var p in gestures) {
      elements.push(gestures[p].element)
    }

    fireEvent(getCommonAncestor(elements[0], elements[1]), 'dualtouchstart', {
      touches: slice.call(event.touches),
      touchEvent: event
    })
  }
}
function touchstartHandler ( event ) { if ( Object . keys ( gestures ) . length === 0 ) { docEl . addEventListener ( 'touchmove' , touchmoveHandler , false ) docEl . addEventListener ( 'touchend' , touchendHandler , false ) docEl . addEventListener ( 'touchcancel' , touchcancelHandler , false ) } // record every touch for ( var i = 0 ; i < event . changedTouches . length ; i ++ ) { var touch = event . changedTouches [ i ] var touchRecord = { } for ( var p in touch ) { touchRecord [ p ] = touch [ p ] } var gesture = { startTouch : touchRecord , startTime : Date . now ( ) , status : 'tapping' , element : event . srcElement || event . target , pressingHandler : setTimeout ( function ( element , touch ) { return function ( ) { if ( gesture . status === 'tapping' ) { gesture . status = 'pressing' fireEvent ( element , 'longpress' , { // add touch data for jud touch : touch , touches : event . touches , changedTouches : event . changedTouches , touchEvent : event } ) } clearTimeout ( gesture . pressingHandler ) gesture . pressingHandler = null } } ( event . srcElement || event . target , event . changedTouches [ i ] ) , 500 ) } gestures [ touch . identifier ] = gesture } if ( Object . keys ( gestures ) . length == 2 ) { var elements = [ ] for ( var p in gestures ) { elements . push ( gestures [ p ] . element ) } fireEvent ( getCommonAncestor ( elements [ 0 ] , elements [ 1 ] ) , 'dualtouchstart' , { touches : slice . call ( event . touches ) , touchEvent : event } ) } }
take over the touchstart events. Add new touches to the gestures.
If there is no previous records, then bind touchmove, tochend
and touchcancel events.
new touches initialized with state 'tapping', and within 500 milliseconds
if the state is still tapping, then trigger gesture 'press'.
If there are two touche points, then the 'dualtouchstart' is triggerd. The
node of the touch gesture is their cloest common ancestor.

@event
@param  {event} event
take over the touchstart events . Add new touches to the gestures . If there is no previous records then bind touchmove tochend and touchcancel events . new touches initialized with state tapping and within 500 milliseconds if the state is still tapping then trigger gesture press . If there are two touche points then the dualtouchstart is triggerd . The node of the touch gesture is their cloest common ancestor .