diff --git a/src/full.js b/src/full.js index 20009bf..593d7c0 100644 --- a/src/full.js +++ b/src/full.js @@ -1,6 +1,8 @@ import WebSlides from './modules/webslides'; import Scroll from './plugins/scroll'; +import Touch from './plugins/touch'; WebSlides.registerPlugin('Scroll', Scroll); +WebSlides.registerPlugin('Touch', Touch); window.WebSlides = WebSlides; diff --git a/src/plugins/touch.js b/src/plugins/touch.js new file mode 100644 index 0000000..eeaea10 --- /dev/null +++ b/src/plugins/touch.js @@ -0,0 +1,151 @@ +import MobileDetector from '../utils/mobile-detector'; + +const EVENTS = { + touch: { + START: 'touchstart', + MOVE: 'touchmove', + END: 'touchend' + }, + pointer: { + START: 'pointerdown', + MOVE: 'pointermove', + END: 'pointerup' + } +}; + +const SLIDE_OFFSET = 50; + +export default class Touch { + /** + * @param {WebSlides} wsInstance The WebSlides instance + */ + constructor(wsInstance) { + /** + * @type {WebSlides} + * @private + */ + this.ws_ = wsInstance; + + /** + * Start position for the X coord. + * @type {number} + * @private + */ + this.startX_ = 0; + + /** + * Start position for the Y coord. + * @type {number} + * @private + */ + this.startY_ = 0; + + /** + * Start position for the X coord. + * @type {number} + * @private + */ + this.endX_ = 0; + + /** + * Start position for the Y coord. + * @type {number} + * @private + */ + this.endY_ = 0; + + /** + * Whether is enabled or not. Only enabled for touch devices. + * @type {boolean} + * @private + */ + this.isEnabled = false; + + let events; + + if (MobileDetector.isAny()) { + // Likely IE + if (window.PointerEvent && ( + MobileDetector.isWindows() || MobileDetector.isWindowsPhone())) { + events = EVENTS.pointer; + } else { + events = EVENTS.touch; + } + + this.isEnabled = true; + document.addEventListener(events.START, this.onStart_.bind(this), false); + document.addEventListener(events.MOVE, this.onMove_.bind(this), false); + document.addEventListener(events.MOVE, this.onMove_.bind(this), false); + document.addEventListener(events.END, this.onStop_.bind(this), false); + } + } + + /** + * Start touch handler. Saves starting points. + * @param event + * @private + */ + onStart_(event) { + const info = Touch.normalizeEventInfo(event); + + this.startX_ = info.x; + this.startY_ = info.y; + this.endX_ = info.x; + this.endY_ = info.y; + } + + /** + * Move touch handler. Saves end points. + * @param event + * @private + */ + onMove_(event) { + const info = Touch.normalizeEventInfo(event); + + this.endX_ = info.x; + this.endY_ = info.y; + } + + /** + * Stop touch handler. Checks if it needs to make any actions. + * @private + */ + onStop_() { + const diffX = this.startX_ - this.endX_; + const diffY = this.startY_ - this.endY_; + + // It's an horizontal drag + if (Math.abs(diffX) > Math.abs(diffY)) { + if(diffX < -SLIDE_OFFSET) { + this.ws_.goPrev(); + } else if(diffX > SLIDE_OFFSET) { + this.ws_.goNext(); + } + } + } + + /** + * Normalizes an event to deal with differences between PointerEvent and + * TouchEvent. + * @param event + * @return {*} + */ + static normalizeEventInfo(event) { + let x; + let y; + let touchEvent = { pageX : 0, pageY : 0}; + + if (typeof event.changedTouches !== 'undefined'){ + touchEvent = event.changedTouches[0]; + } + else if (typeof event.originalEvent !== 'undefined' && + typeof event.originalEvent.changedTouches !== 'undefined'){ + touchEvent = event.originalEvent.changedTouches[0]; + } + + x = event.offsetX || event.layerX || touchEvent.pageX; + y = event.offsetY || event.layerY || touchEvent.pageY; + + return { x, y }; + } +}; diff --git a/src/utils/mobile-detector.js b/src/utils/mobile-detector.js new file mode 100644 index 0000000..83d403f --- /dev/null +++ b/src/utils/mobile-detector.js @@ -0,0 +1,64 @@ +const UA = window.navigator.userAgent; + +export default class MobileDetector { + /** + * Whether the device is Android or not. + * @return {Boolean} + */ + static isAndroid() { + return !!UA.match(/Android/i); + } + + /** + * Whether the device is BlackBerry or not. + * @return {Boolean} + */ + static isBlackBerry() { + return !!UA.match(/BlackBerry/i); + } + + /** + * Whether the device is iOS or not. + * @return {Boolean} + */ + static isiOS() { + return !!UA.match(/iPhone/i); + } + + /** + * Whether the device is Opera or not. + * @return {Boolean} + */ + static isOpera() { + return !!UA.match(/Opera Mini/i); + } + + /** + * Whether the device is Windows or not. + * @return {Boolean} + */ + static isWindows() { + return !!UA.match(/IEMobile/i); + } + + /** + * Whether the device is Windows Phone or not. + * @return {Boolean} + */ + static isWindowsPhone() { + return !!UA.match(/Windows Phone/i); + } + + /** + * Whether the device is any mobile device or not. + * @return {Boolean} + */ + static isAny() { + return MobileDetector.isAndroid() || + MobileDetector.isBlackBerry() || + MobileDetector.isiOS() || + MobileDetector.isOpera() || + MobileDetector.isWindows() || + MobileDetector.isWindowsPhone(); + } +}