Top
craft-uikit
craft-widget-

Core/Gesture.js


/** 
 * Entry point for gesture.
 * 
 * @namespace Craft.Core.Gesture
 * @packagename Craft.Core.Gesture
 */
export var Gesture = {
	
	/** @private */
	packagename : 'Craft.Core.Gesture',
	
	/**
	 * Enable tap
	 * 
	 * @memberof Craft.Core.Gesture
	 * @method Craft.Core.Gesture.enableTap
	 * 
	 * @param {Element} options.target - target element
	 * @param {Function} options.tap - tap handler
	 * @return {Craft.Core.Gesture.Swipe} swipe handling instance (see code)
	 * 
	 * @example
	 * 
	 * Craft.Core.Gesture.enableTap({
	 *     target : this.view.querySelector('#id'),
	 *     tap    : tapHandler
	 * });
	 * 
	 */
	enableTap : function(options){
		return new Tap(options);
	},
	
	/**
	 * Enable swipe
	 * 
	 * @memberof Craft.Core.Gesture
	 * @method Craft.Core.Gesture.enableSwipe
	 * 
	 * @param {Element} options.target - target element
	 * @param {Number} options.left - swipe left hander
	 * @param {Number} options.right - swipe right hander
	 * @param {Number} options.up - swipe up hander
	 * @param {Number} options.down - swipe down hander
	 * @param {Number} options.DIFF_THRESHOLD - movement should more than this
	 * @param {Number} options.TIME_THRESHOLD - time should be more than this
	 * @param {Number} options.MULTI_THRESHOLD - last multi-touch more than before
	 * @return {Craft.Core.Gesture.Tap} tap handling instance (see code)
	 * 
	 * @example
	 * 
	 * Craft.Core.Gesture.enableSwipe({
	 *     target : this.view.querySelector('#id'),
	 *     left   : swipeLeftHandler,
	 *     right  : swipeRgihtHandler,
	 *     up     : swipeUpHandler,
	 *     down   : swipeDownHandler,
	 * });
	 * 
	 */
	enableSwipe : function(options){
		return new Swipe(options);
	}
	
};

/** 
 * Internal class for handling tap 
 * @private
 */
class Tap {
	
	/**
	 * Make tap handler instance
	 * @param {Element} options.target - target element
	 * @param {Function} options.tap - tap handler
	 */
	constructor(options){
		this.packagename = 'Craft.Core.Gesture.Tap';
		
		this.target     = options.target;
		this.tapHandler = options.tap;
		
		if( 'ontouchend' in window ){
			this.target.addEventListener('touchend', this.handleTouchEnd.bind(this), false); // mobile
		}else{
			this.target.addEventListener('mouseup', this.handleTouchEnd.bind(this), false); // pc
		}
	}
	
	/**
	 * Call by tap event
	 * @param {UIEvent} event - TouchEvent|MouseEvent
	 */
	handleTouchEnd(event){
		if( this.tapHandler ){
			this.tapHandler(event);
		}
	}
};

/** 
 * Internal clss for handling swipe 
 * @private
 */
class Swipe {
	
	/**
	 * Make swipe handler instance
	 * @param {Element} options.target - target element
	 * @param {Function} options.left - swipe left hander
	 * @param {Function} options.right - swipe right hander
	 * @param {Function} options.up - swipe up hander
	 * @param {Function} options.down - swipe down hander
	 * @param {Number} options.DIFF_THRESHOLD - movement should more than this
	 * @param {Number} options.TIME_THRESHOLD - time should be more than this
	 * @param {Number} options.MULTI_THRESHOLD - last multi-touch more than before
	 */
	constructor(options){
		this.packagename = 'Craft.Core.Gesture.Swipe';
		
		this.target = options.target;
		
		this.target.addEventListener('touchstart', this.handleTouchStart.bind(this), false);        
		this.target.addEventListener('touchmove', this.handleTouchMove.bind(this), false);
		
		this.swipeLeftHandler  = options.left;
		this.swipeRightHandler = options.right;
		this.swipeUpHandler    = options.up;
		this.swipeDownHandler  = options.down;
		
		this.DIFF_THRESHOLD  = options.DIFF_THRESHOLD  || 50;
		this.TIME_THRESHOLD  = options.TIME_THRESHOLD  || 40;
		this.MULTI_THRESHOLD = options.MULTI_THRESHOLD || 60;
		
		this.xDown = null;
		this.yDown = null;
		this.tDown = null;
		
		this.lastMultiTouch = null;
	}
	
	/**
	 * Called by touch start event
	 * @param {TouchEvent} event - TouchEvent
	 */
	handleTouchStart(event){
		let firstTouch = event.touches[0];
		this.xDown = firstTouch.clientX;
		this.yDown = firstTouch.clientY;
		this.tDown = Date.now();
	}
	
	/**
	 * Called by touch end event
	 * @param {TouchEvent} event - TouchEvent
	 */
	handleTouchMove(event){
		if( !this.xDown || !this.yDown || !this.tDown ){
			return;
		}
		if( event.touches.length > 1 ){
			this.lastMultiTouch = Date.now();
			return; // multi touch
		}
		
		let xUp = event.touches[0].clientX;
		let yUp = event.touches[0].clientY;
		
		let xDiff = this.xDown - xUp;
		let yDiff = this.yDown - yUp;
		let tDiff = Date.now() - this.tDown;
		let mDiff = Date.now() - this.lastMultiTouch;
		
		if( Math.abs(xDiff) + Math.abs(yDiff) < this.DIFF_THRESHOLD ){
			return;
		}
		if( tDiff < this.TIME_THRESHOLD ){
			return;
		}
		if( mDiff < this.MULTI_THRESHOLD ){
			return;
		}
		
		if( Math.abs( xDiff ) > Math.abs( yDiff ) ){
			if( xDiff > 0 ){
				if( this.swipeLeftHandler ){ this.swipeLeftHandler(event); }
			}else{
				if( this.swipeRightHandler ){ this.swipeRightHandler(event); }
			}
		}else{
			if( yDiff > 0 ){
				if( this.swipeUpHandler ){ this.swipeUpHandler(event); }
			}else{ 
				if( this.swipeDownHandler){ this.swipeDownHandler(event); }
			}
		}
		
		this.xDown = null;
		this.yDown = null;
		this.tDown = null;
	}
	
};