docs: function(touches, timeStamp, scale) {
      if (timeStamp instanceof Date) {
        timeStamp = timeStamp.valueOf();
      }
      if (typeof timeStamp !== "number") {
        timeStamp = Date.now();
      }
  
      var self = this;
  
      // Ignore event when tracking is not enabled (event might be outside of element)
      if (!self.__isTracking) {
        return;
      }
  
      var currentTouchLeft, currentTouchTop;
  
      // Compute move based around of center of fingers
      if (touches.length === 2) {
        currentTouchLeft = Math.abs(touches[0].pageX + touches[1].pageX) / 2;
        currentTouchTop = Math.abs(touches[0].pageY + touches[1].pageY) / 2;
  
        // Calculate scale when not present and only when touches are used
        if (!scale && self.options.zooming) {
          scale = self.__getScale(self.__initialTouches, touches);
        }
      } else {
        currentTouchLeft = touches[0].pageX;
        currentTouchTop = touches[0].pageY;
      }
  
      var positions = self.__positions;
  
      // Are we already is dragging mode?
      if (self.__isDragging) {
          self.__decStopped = false;
  
        // Compute move distance
        var moveX = currentTouchLeft - self.__lastTouchLeft;
        var moveY = currentTouchTop - self.__lastTouchTop;
  
        // Read previous scroll position and zooming
        var scrollLeft = self.__scrollLeft;
        var scrollTop = self.__scrollTop;
        var level = self.__zoomLevel;
  
        // Work with scaling
        if (scale != null && self.options.zooming) {
  
          var oldLevel = level;
  
          // Recompute level based on previous scale and new scale
          level = level / self.__lastScale * scale;
  
          // Limit level according to configuration
          level = Math.max(Math.min(level, self.options.maxZoom), self.options.minZoom);
  
          // Only do further compution when change happened
          if (oldLevel !== level) {
  
            // Compute relative event position to container
            var currentTouchLeftRel = currentTouchLeft - self.__clientLeft;
            var currentTouchTopRel = currentTouchTop - self.__clientTop;
  
            // Recompute left and top coordinates based on new zoom level
            scrollLeft = ((currentTouchLeftRel + scrollLeft) * level / oldLevel) - currentTouchLeftRel;
            scrollTop = ((currentTouchTopRel + scrollTop) * level / oldLevel) - currentTouchTopRel;
  
            // Recompute max scroll values
            self.__computeScrollMax(level);
  
          }
        }
  
        if (self.__enableScrollX) {
  
          scrollLeft -= moveX * self.options.speedMultiplier;
          var maxScrollLeft = self.__maxScrollLeft;
  
          if (scrollLeft > maxScrollLeft || scrollLeft < 0) {
  
            // Slow down on the edges
            if (self.options.bouncing) {
  
              scrollLeft += (moveX / 2 * self.options.speedMultiplier);
  
            } else if (scrollLeft > maxScrollLeft) {
  
              scrollLeft = maxScrollLeft;
  
            } else {
  
              scrollLeft = 0;
  
            }
          }
        }
  
        // Compute new vertical scroll position
        if (self.__enableScrollY) {
  
          scrollTop -= moveY * self.options.speedMultiplier;
          var maxScrollTop = self.__maxScrollTop;
  
          if (scrollTop > maxScrollTop || scrollTop < 0) {
  
            // Slow down on the edges
            if (self.options.bouncing || (self.__refreshHeight && scrollTop < 0)) {
  
              scrollTop += (moveY / 2 * self.options.speedMultiplier);
  
              // Support pull-to-refresh (only when only y is scrollable)
              if (!self.__enableScrollX && self.__refreshHeight != null) {
  
                // hide the refresher when it's behind the header bar in case of header transparency
                if (scrollTop < 0) {
                  self.__refreshHidden = false;
                  self.__refreshShow();
                } else {
                  self.__refreshHide();
                  self.__refreshHidden = true;
                }
  
                if (!self.__refreshActive && scrollTop <= -self.__refreshHeight) {
  
                  self.__refreshActive = true;
                  if (self.__refreshActivate) {
                    self.__refreshActivate();
                  }
  
                } else if (self.__refreshActive && scrollTop > -self.__refreshHeight) {
  
                  self.__refreshActive = false;
                  if (self.__refreshDeactivate) {
                    self.__refreshDeactivate();
                  }
  
                }
              }
  
            } else if (scrollTop > maxScrollTop) {
  
              scrollTop = maxScrollTop;
  
            } else {
  
              scrollTop = 0;
  
            }
          } else if (self.__refreshHeight && !self.__refreshHidden) {
            // if a positive scroll value and the refresher is still not hidden, hide it
            self.__refreshHide();
            self.__refreshHidden = true;
          }
        }
  
        // Keep list from growing infinitely (holding min 10, max 20 measure points)
        if (positions.length > 60) {
          positions.splice(0, 30);
        }
  
        // Track scroll movement for decleration
        positions.push(scrollLeft, scrollTop, timeStamp);
  
        // Sync scroll position
        self.__publish(scrollLeft, scrollTop, level);
  
      // Otherwise figure out whether we are switching into dragging mode now.
      } else {
  
        var minimumTrackingForScroll = self.options.locking ? 3 : 0;
        var minimumTrackingForDrag = 5;
  
        var distanceX = Math.abs(currentTouchLeft - self.__initialTouchLeft);
        var distanceY = Math.abs(currentTouchTop - self.__initialTouchTop);
  
        self.__enableScrollX = self.options.scrollingX && distanceX >= minimumTrackingForScroll;
        self.__enableScrollY = self.options.scrollingY && distanceY >= minimumTrackingForScroll;
  
        positions.push(self.__scrollLeft, self.__scrollTop, timeStamp);
  
        self.__isDragging = (self.__enableScrollX || self.__enableScrollY) && (distanceX >= minimumTrackingForDrag || distanceY >= minimumTrackingForDrag);
        if (self.__isDragging) {
          self.__interruptedAnimation = false;
          self.__fadeScrollbars('in');
        }
  
      }
  
      // Update last touch positions and time stamp for next event
      self.__lastTouchLeft = currentTouchLeft;
      self.__lastTouchTop = currentTouchTop;
      self.__lastTouchMove = timeStamp;
      self.__lastScale = scale;
  
    }