@odopod/odo-pointer
Advanced tools
Comparing version 1.2.0 to 1.2.1
@@ -45,10 +45,2 @@ import { Coordinate, clamp, events, noop } from '@odopod/odo-helpers'; | ||
var inherits = function (subClass, superClass) { | ||
@@ -70,12 +62,2 @@ if (typeof superClass !== "function" && superClass !== null) { | ||
var possibleConstructorReturn = function (self, call) { | ||
@@ -82,0 +64,0 @@ if (!self) { |
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@odopod/odo-helpers'), require('tiny-emitter'), require('@odopod/odo-device')) : | ||
typeof define === 'function' && define.amd ? define(['@odopod/odo-helpers', 'tiny-emitter', '@odopod/odo-device'], factory) : | ||
(global.OdoPointer = factory(global.OdoHelpers,global.TinyEmitter,global.OdoDevice)); | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@odopod/odo-helpers'), require('tiny-emitter'), require('@odopod/odo-device')) : | ||
typeof define === 'function' && define.amd ? define(['@odopod/odo-helpers', 'tiny-emitter', '@odopod/odo-device'], factory) : | ||
(global.OdoPointer = factory(global.OdoHelpers,global.TinyEmitter,global.OdoDevice)); | ||
}(this, (function (odoHelpers,TinyEmitter,OdoDevice) { 'use strict'; | ||
TinyEmitter = TinyEmitter && TinyEmitter.hasOwnProperty('default') ? TinyEmitter['default'] : TinyEmitter; | ||
OdoDevice = OdoDevice && OdoDevice.hasOwnProperty('default') ? OdoDevice['default'] : OdoDevice; | ||
TinyEmitter = TinyEmitter && TinyEmitter.hasOwnProperty('default') ? TinyEmitter['default'] : TinyEmitter; | ||
OdoDevice = OdoDevice && OdoDevice.hasOwnProperty('default') ? OdoDevice['default'] : OdoDevice; | ||
/** @enum {string} */ | ||
var Direction = { | ||
RIGHT: 'right', | ||
LEFT: 'left', | ||
UP: 'up', | ||
DOWN: 'down', | ||
NONE: 'no_movement' | ||
}; | ||
/** @enum {string} */ | ||
var Direction = { | ||
RIGHT: 'right', | ||
LEFT: 'left', | ||
UP: 'up', | ||
DOWN: 'down', | ||
NONE: 'no_movement' | ||
}; | ||
/** @enum {string} */ | ||
var Axis = { | ||
X: 'x', | ||
Y: 'y', | ||
BOTH: 'xy' | ||
}; | ||
/** @enum {string} */ | ||
var Axis = { | ||
X: 'x', | ||
Y: 'y', | ||
BOTH: 'xy' | ||
}; | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
}; | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
}; | ||
var createClass = function () { | ||
function defineProperties(target, props) { | ||
for (var i = 0; i < props.length; i++) { | ||
var descriptor = props[i]; | ||
descriptor.enumerable = descriptor.enumerable || false; | ||
descriptor.configurable = true; | ||
if ("value" in descriptor) descriptor.writable = true; | ||
Object.defineProperty(target, descriptor.key, descriptor); | ||
var createClass = function () { | ||
function defineProperties(target, props) { | ||
for (var i = 0; i < props.length; i++) { | ||
var descriptor = props[i]; | ||
descriptor.enumerable = descriptor.enumerable || false; | ||
descriptor.configurable = true; | ||
if ("value" in descriptor) descriptor.writable = true; | ||
Object.defineProperty(target, descriptor.key, descriptor); | ||
} | ||
} | ||
} | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
var inherits = function (subClass, superClass) { | ||
if (typeof superClass !== "function" && superClass !== null) { | ||
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); | ||
} | ||
subClass.prototype = Object.create(superClass && superClass.prototype, { | ||
constructor: { | ||
value: subClass, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
} | ||
}); | ||
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; | ||
}; | ||
}(); | ||
var possibleConstructorReturn = function (self, call) { | ||
if (!self) { | ||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); | ||
} | ||
return call && (typeof call === "object" || typeof call === "function") ? call : self; | ||
}; | ||
function isXAxis(axis) { | ||
return axis === Axis.X; | ||
} | ||
function isYAxis(axis) { | ||
return axis === Axis.Y; | ||
} | ||
function isBothAxis(axis) { | ||
return axis === Axis.BOTH; | ||
} | ||
function hasDirection(direction) { | ||
return direction !== Direction.NONE; | ||
} | ||
function finiteOrZero(velocity) { | ||
return Number.isFinite(velocity) ? velocity : 0; | ||
} | ||
/** | ||
* Calculate the velocity between two points. | ||
* | ||
* @param {number} deltaTime Change in time. | ||
* @param {number} deltaX Change in x. | ||
* @param {number} deltaY Change in y. | ||
* @return {Coordinate} Velocity of the drag. | ||
*/ | ||
var inherits = function (subClass, superClass) { | ||
if (typeof superClass !== "function" && superClass !== null) { | ||
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); | ||
function getVelocity(deltaTime, deltaX, deltaY) { | ||
return new odoHelpers.Coordinate(finiteOrZero(deltaX / deltaTime), finiteOrZero(deltaY / deltaTime)); | ||
} | ||
subClass.prototype = Object.create(superClass && superClass.prototype, { | ||
constructor: { | ||
value: subClass, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
function getTheDirection(value1, value2, isGreater, isLess, isEqual) { | ||
if (value1 - value2 > 0) { | ||
return isGreater; | ||
} else if (value1 - value2 < 0) { | ||
return isLess; | ||
} | ||
}); | ||
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; | ||
}; | ||
return isEqual; | ||
} | ||
/** | ||
* angle to direction define. | ||
* @param {Coordinate} coord1 The starting coordinate. | ||
* @param {Coordinate} coord2 The ending coordinate. | ||
* @return {string} Direction constant. | ||
*/ | ||
function getDirection(coord1, coord2) { | ||
if (Math.abs(coord1.x - coord2.x) >= Math.abs(coord1.y - coord2.y)) { | ||
return getTheDirection(coord1.x, coord2.x, Direction.LEFT, Direction.RIGHT, Direction.NONE); | ||
} | ||
return getTheDirection(coord1.y, coord2.y, Direction.UP, Direction.DOWN, Direction.NONE); | ||
} | ||
function isOnAxis(axis, direction) { | ||
var isXAndLeftOrRight = isXAxis(axis) && (direction === Direction.LEFT || direction === Direction.RIGHT); | ||
var isYAndUpOrDown = isYAxis(axis) && (direction === Direction.UP || direction === Direction.DOWN); | ||
var isBothAndNotNone = isBothAxis(axis) && hasDirection(direction); | ||
return isXAndLeftOrRight || isYAndUpOrDown || isBothAndNotNone; | ||
} | ||
function didMoveOnAxis(axis, direction, deltaX, deltaY) { | ||
// X axis and deltaX > 0 | ||
return isXAxis(axis) && Math.abs(deltaX) > 0 || | ||
// Y axis and deltaY > 0 | ||
isYAxis(axis) && Math.abs(deltaY) > 0 || | ||
var possibleConstructorReturn = function (self, call) { | ||
if (!self) { | ||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); | ||
// Both axis, as long as it actually moved. | ||
isBothAxis(axis) && hasDirection(direction); | ||
} | ||
return call && (typeof call === "object" || typeof call === "function") ? call : self; | ||
}; | ||
function getAxisDirection(axis, start, end) { | ||
var _start = Object.assign({}, start); | ||
var _end = Object.assign({}, end); | ||
function isXAxis(axis) { | ||
return axis === Axis.X; | ||
} | ||
if (isXAxis(axis)) { | ||
_start.y = 0; | ||
_end.y = 0; | ||
} else if (isYAxis(axis)) { | ||
_start.x = 0; | ||
_end.x = 0; | ||
} | ||
function isYAxis(axis) { | ||
return axis === Axis.Y; | ||
} | ||
return getDirection(_start, _end); | ||
} | ||
function isBothAxis(axis) { | ||
return axis === Axis.BOTH; | ||
} | ||
var PointerEvent = function () { | ||
/** | ||
* Object representing a drag event. | ||
* @param {Object} options Options object. | ||
* @param {string} options.type Event type. | ||
* @param {Element} options.target Element the event is happening on. | ||
* @param {Coordinate} options.delta Total movement of the pointer (with friction | ||
* already applied to it). | ||
* @param {Coordinate} options.currentVelocity Calculated velocity since the last interval. | ||
* @constructor | ||
*/ | ||
function PointerEvent(options) { | ||
classCallCheck(this, PointerEvent); | ||
function hasDirection(direction) { | ||
return direction !== Direction.NONE; | ||
} | ||
this.type = options.type; | ||
function finiteOrZero(velocity) { | ||
return Number.isFinite(velocity) ? velocity : 0; | ||
} | ||
/** | ||
* @type {Element} | ||
*/ | ||
this.target = options.target; | ||
/** | ||
* Calculate the velocity between two points. | ||
* | ||
* @param {number} deltaTime Change in time. | ||
* @param {number} deltaX Change in x. | ||
* @param {number} deltaY Change in y. | ||
* @return {Coordinate} Velocity of the drag. | ||
*/ | ||
/** | ||
* @type {Element} | ||
*/ | ||
this.currentTarget = options.currentTarget; | ||
function getVelocity(deltaTime, deltaX, deltaY) { | ||
return new odoHelpers.Coordinate(finiteOrZero(deltaX / deltaTime), finiteOrZero(deltaY / deltaTime)); | ||
} | ||
/** | ||
* Starting location of the pointer. | ||
* @type {Coordinate} | ||
*/ | ||
this.start = options.start; | ||
function getTheDirection(value1, value2, isGreater, isLess, isEqual) { | ||
if (value1 - value2 > 0) { | ||
return isGreater; | ||
} else if (value1 - value2 < 0) { | ||
return isLess; | ||
} | ||
/** | ||
* Ending location of the pointer. | ||
* @type {Coordinate} | ||
*/ | ||
this.end = options.end; | ||
return isEqual; | ||
} | ||
/** | ||
* Change in position since the start of the drag. | ||
* @type {Coordinate} | ||
*/ | ||
this.delta = options.delta; | ||
/** | ||
* angle to direction define. | ||
* @param {Coordinate} coord1 The starting coordinate. | ||
* @param {Coordinate} coord2 The ending coordinate. | ||
* @return {string} Direction constant. | ||
*/ | ||
function getDirection(coord1, coord2) { | ||
if (Math.abs(coord1.x - coord2.x) >= Math.abs(coord1.y - coord2.y)) { | ||
return getTheDirection(coord1.x, coord2.x, Direction.LEFT, Direction.RIGHT, Direction.NONE); | ||
} | ||
/** | ||
* Time elapsed from mouse/touch down to mouse/touch up. | ||
* @type {number} | ||
*/ | ||
this.deltaTime = options.deltaTime; | ||
return getTheDirection(coord1.y, coord2.y, Direction.UP, Direction.DOWN, Direction.NONE); | ||
} | ||
/** | ||
* Velocity of the whole drag. | ||
* @type {Coordinate} | ||
*/ | ||
this.velocity = getVelocity(this.deltaTime, this.delta.x, this.delta.y); | ||
function isOnAxis(axis, direction) { | ||
var isXAndLeftOrRight = isXAxis(axis) && (direction === Direction.LEFT || direction === Direction.RIGHT); | ||
/** | ||
* The velocity in the last 100 milliseconds. | ||
* @type {Coordinate} | ||
*/ | ||
this.currentVelocity = options.currentVelocity; | ||
var isYAndUpOrDown = isYAxis(axis) && (direction === Direction.UP || direction === Direction.DOWN); | ||
/** | ||
* Distance dragged. | ||
* @type {number} | ||
*/ | ||
this.distance = odoHelpers.Coordinate.distance(options.start, options.end); | ||
var isBothAndNotNone = isBothAxis(axis) && hasDirection(direction); | ||
/** | ||
* Direction of drag. | ||
* @type {Direction} | ||
*/ | ||
this.direction = getDirection(options.start, options.end); | ||
return isXAndLeftOrRight || isYAndUpOrDown || isBothAndNotNone; | ||
} | ||
/** | ||
* Whether the drag direction is on the axis of the draggable element. | ||
* @type {boolean} | ||
*/ | ||
this.isDirectionOnAxis = isOnAxis(options.axis, this.direction); | ||
function didMoveOnAxis(axis, direction, deltaX, deltaY) { | ||
// X axis and deltaX > 0 | ||
return isXAxis(axis) && Math.abs(deltaX) > 0 || | ||
/** | ||
* Whether the draggable element moved along the dragging axis at all. | ||
* @type {boolean} | ||
*/ | ||
this.didMoveOnAxis = didMoveOnAxis(options.axis, this.direction, this.delta.x, this.delta.y); | ||
// Y axis and deltaY > 0 | ||
isYAxis(axis) && Math.abs(deltaY) > 0 || | ||
/** | ||
* Direction of drag which excludes directions not on its axis. | ||
* @type {Direction} | ||
*/ | ||
this.axisDirection = getAxisDirection(options.axis, options.start, options.end); | ||
// Both axis, as long as it actually moved. | ||
isBothAxis(axis) && hasDirection(direction); | ||
} | ||
/** @type {{pixel: Coordinate, percent: Coordinate}} */ | ||
this.position = options.position; | ||
function getAxisDirection(axis, start, end) { | ||
var _start = Object.assign({}, start); | ||
var _end = Object.assign({}, end); | ||
/** @type {boolean} Whether `preventDefault` has been called. */ | ||
this.defaultPrevented = false; | ||
} | ||
if (isXAxis(axis)) { | ||
_start.y = 0; | ||
_end.y = 0; | ||
} else if (isYAxis(axis)) { | ||
_start.x = 0; | ||
_end.x = 0; | ||
} | ||
PointerEvent.prototype.preventDefault = function preventDefault() { | ||
this.defaultPrevented = true; | ||
}; | ||
return getDirection(_start, _end); | ||
} | ||
return PointerEvent; | ||
}(); | ||
var PointerEvent = function () { | ||
/** | ||
* Object representing a drag event. | ||
* @param {Object} options Options object. | ||
* @param {string} options.type Event type. | ||
* @param {Element} options.target Element the event is happening on. | ||
* @param {Coordinate} options.delta Total movement of the pointer (with friction | ||
* already applied to it). | ||
* @param {Coordinate} options.currentVelocity Calculated velocity since the last interval. | ||
* @constructor | ||
* @fileoverview An abstraction for pointer, mouse, and touch events. | ||
* | ||
* @author Glen Cheney <glen@odopod.com> | ||
*/ | ||
function PointerEvent(options) { | ||
classCallCheck(this, PointerEvent); | ||
this.type = options.type; | ||
var Pointer = function (_TinyEmitter) { | ||
inherits(Pointer, _TinyEmitter); | ||
/** | ||
* @type {Element} | ||
* An abstraction layer for adding pointer events and calculating drag values. | ||
* @param {HTMLElement} element Element to watch. | ||
* @param {PointerOptions} options Options object. | ||
* @throws {TypeError} Throws when the element parameter isn't an element. | ||
*/ | ||
this.target = options.target; | ||
function Pointer(element) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
classCallCheck(this, Pointer); | ||
/** | ||
* @type {Element} | ||
*/ | ||
this.currentTarget = options.currentTarget; | ||
var _this = possibleConstructorReturn(this, _TinyEmitter.call(this)); | ||
/** | ||
* Starting location of the pointer. | ||
* @type {Coordinate} | ||
*/ | ||
this.start = options.start; | ||
if (!element || element.nodeType !== 1) { | ||
throw new TypeError('OdoPointer requires an element.'); | ||
} | ||
/** | ||
* Ending location of the pointer. | ||
* @type {Coordinate} | ||
*/ | ||
this.end = options.end; | ||
/** | ||
* @type {PointerOptions} | ||
*/ | ||
_this.options = Object.assign({}, Pointer.Defaults, options); | ||
/** | ||
* Change in position since the start of the drag. | ||
* @type {Coordinate} | ||
*/ | ||
this.delta = options.delta; | ||
/** | ||
* The draggable element. | ||
* @type {HTMLElement} | ||
* @private | ||
*/ | ||
_this.element = element; | ||
/** | ||
* Time elapsed from mouse/touch down to mouse/touch up. | ||
* @type {number} | ||
*/ | ||
this.deltaTime = options.deltaTime; | ||
/** | ||
* Starting location of the drag. | ||
* @type {Coordinate} | ||
*/ | ||
_this.pageStart = new odoHelpers.Coordinate(); | ||
/** | ||
* Velocity of the whole drag. | ||
* @type {Coordinate} | ||
*/ | ||
this.velocity = getVelocity(this.deltaTime, this.delta.x, this.delta.y); | ||
/** | ||
* Current position of mouse or touch relative to the document. | ||
* @type {Coordinate} | ||
*/ | ||
_this.page = new odoHelpers.Coordinate(); | ||
/** | ||
* The velocity in the last 100 milliseconds. | ||
* @type {Coordinate} | ||
*/ | ||
this.currentVelocity = options.currentVelocity; | ||
/** | ||
* Current position of drag relative to target's parent. | ||
* @type {Coordinate} | ||
*/ | ||
_this.delta = new odoHelpers.Coordinate(); | ||
/** | ||
* Distance dragged. | ||
* @type {number} | ||
*/ | ||
this.distance = odoHelpers.Coordinate.distance(options.start, options.end); | ||
/** | ||
* Used to track the current velocity. It is updated when the velocity is. | ||
* @type {Coordinate} | ||
* @private | ||
*/ | ||
_this._lastPosition = new odoHelpers.Coordinate(); | ||
/** | ||
* Direction of drag. | ||
* @type {Direction} | ||
*/ | ||
this.direction = getDirection(options.start, options.end); | ||
/** | ||
* Friction to apply to dragging. A value of zero would result in no dragging, | ||
* 0.5 would result in the draggable element moving half as far as the user | ||
* dragged, and 1 is a 1:1 ratio with user movement. | ||
* @type {number} | ||
*/ | ||
_this._friction = 1; | ||
/** | ||
* Whether the drag direction is on the axis of the draggable element. | ||
* @type {boolean} | ||
*/ | ||
this.isDirectionOnAxis = isOnAxis(options.axis, this.direction); | ||
/** | ||
* Flag indicating dragging has happened. It is set on dragmove and reset | ||
* after the draggableend event has been dispatched. | ||
* @type {boolean} | ||
*/ | ||
_this.hasDragged = false; | ||
/** | ||
* Whether the draggable element moved along the dragging axis at all. | ||
* @type {boolean} | ||
*/ | ||
this.didMoveOnAxis = didMoveOnAxis(options.axis, this.direction, this.delta.x, this.delta.y); | ||
/** | ||
* Whether the user is locked in place within the draggable element. This | ||
* is set to true when `preventDefault` is called on the move event. | ||
* @type {boolean} | ||
* @private | ||
*/ | ||
_this._isLocked = false; | ||
/** | ||
* Direction of drag which excludes directions not on its axis. | ||
* @type {Direction} | ||
*/ | ||
this.axisDirection = getAxisDirection(options.axis, options.start, options.end); | ||
/** | ||
* Whether dragging is enabled internally. If the user attempts to scroll | ||
* in the opposite direction of the draggable element, this is set to true | ||
* and no more drag move events are counted until the user releases and | ||
* starts dragging again. | ||
* @type {boolean} | ||
* @private | ||
*/ | ||
_this._isDeactivated = false; | ||
/** @type {{pixel: Coordinate, percent: Coordinate}} */ | ||
this.position = options.position; | ||
/** | ||
* Whether dragging is currently enabled. | ||
* @type {boolean} | ||
* @private | ||
*/ | ||
_this._enabled = true; | ||
/** @type {boolean} Whether `preventDefault` has been called. */ | ||
this.defaultPrevented = false; | ||
} | ||
/** | ||
* Id from setInterval to update the velocity. | ||
* @type {number} | ||
* @private | ||
*/ | ||
_this._velocityTrackerId = null; | ||
PointerEvent.prototype.preventDefault = function preventDefault() { | ||
this.defaultPrevented = true; | ||
}; | ||
/** | ||
* Time in milliseconds when the drag started. | ||
* @type {number} | ||
*/ | ||
_this.startTime = 0; | ||
return PointerEvent; | ||
}(); | ||
/** | ||
* Length of the drag in milliseconds. | ||
* @type {number} | ||
*/ | ||
_this.deltaTime = 0; | ||
/** | ||
* @fileoverview An abstraction for pointer, mouse, and touch events. | ||
* | ||
* @author Glen Cheney <glen@odopod.com> | ||
*/ | ||
/** | ||
* Used to keep track of the current velocity, it's updated with every velocity update. | ||
* @type {number} | ||
* @private | ||
*/ | ||
_this._lastTime = 0; | ||
var Pointer = function (_TinyEmitter) { | ||
inherits(Pointer, _TinyEmitter); | ||
/** | ||
* The current velocity of the drag. | ||
* @type {Coordinate} | ||
*/ | ||
_this.velocity = new odoHelpers.Coordinate(); | ||
/** | ||
* An abstraction layer for adding pointer events and calculating drag values. | ||
* @param {HTMLElement} element Element to watch. | ||
* @param {PointerOptions} options Options object. | ||
* @throws {TypeError} Throws when the element parameter isn't an element. | ||
*/ | ||
function Pointer(element) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
classCallCheck(this, Pointer); | ||
/** | ||
* Whether the velocity has been tracked at least once during the drag. | ||
* @type {boolean} | ||
*/ | ||
_this._hasTrackedVelocity = false; | ||
var _this = possibleConstructorReturn(this, _TinyEmitter.call(this)); | ||
/** | ||
* The element to which the move and up events will be bound to. If a pointer | ||
* is being used inside a modal which stops events from bubbling to the body, | ||
* this property should be changed to an element which *will* receive the events. | ||
* @type {Document|Element} | ||
*/ | ||
_this.dragEventTarget = document; | ||
if (!element || element.nodeType !== 1) { | ||
throw new TypeError('OdoPointer requires an element.'); | ||
var touchAction = Pointer.TouchActionSupport[_this.options.axis]; | ||
/** | ||
* Whether the browser supports the `touch-action` property associated with | ||
* the axis. | ||
* @type {boolean} | ||
*/ | ||
_this._isTouchActionSupported = !!touchAction; | ||
// If the browser supports the touch action property, add it. | ||
if (_this.options.preventEventDefault && _this._isTouchActionSupported) { | ||
_this.element.style[touchAction] = Pointer.TouchAction[_this.options.axis]; | ||
} else if (_this.options.preventEventDefault && OdoDevice.HAS_TOUCH_EVENTS) { | ||
window.addEventListener(odoHelpers.events.TOUCHMOVE, odoHelpers.noop); | ||
} | ||
_this.listen(); | ||
return _this; | ||
} | ||
/** | ||
* @type {PointerOptions} | ||
*/ | ||
_this.options = Object.assign({}, Pointer.Defaults, options); | ||
Pointer.prototype.listen = function listen() { | ||
this._onStart = this._handleDragStart.bind(this); | ||
/** | ||
* The draggable element. | ||
* @type {HTMLElement} | ||
* @private | ||
*/ | ||
_this.element = element; | ||
if (OdoDevice.HAS_POINTER_EVENTS) { | ||
this.element.addEventListener(odoHelpers.events.POINTERDOWN, this._onStart); | ||
} else { | ||
this.element.addEventListener(odoHelpers.events.MOUSEDOWN, this._onStart); | ||
/** | ||
* Starting location of the drag. | ||
* @type {Coordinate} | ||
*/ | ||
_this.pageStart = new odoHelpers.Coordinate(); | ||
if (OdoDevice.HAS_TOUCH_EVENTS) { | ||
this.element.addEventListener(odoHelpers.events.TOUCHSTART, this._onStart); | ||
} | ||
} | ||
/** | ||
* Current position of mouse or touch relative to the document. | ||
* @type {Coordinate} | ||
*/ | ||
_this.page = new odoHelpers.Coordinate(); | ||
// Prevent images, links, etc from being dragged around. | ||
// http://www.html5rocks.com/en/tutorials/dnd/basics/ | ||
this.element.addEventListener(odoHelpers.events.DRAGSTART, Pointer._preventDefault); | ||
}; | ||
/** | ||
* Current position of drag relative to target's parent. | ||
* @type {Coordinate} | ||
* Get whether dragger is enabled. | ||
* @return {boolean} Whether dragger is enabled. | ||
*/ | ||
_this.delta = new odoHelpers.Coordinate(); | ||
/** | ||
* Used to track the current velocity. It is updated when the velocity is. | ||
* @type {Coordinate} | ||
* @private | ||
* @return {boolean} Whether the draggable axis is the x direction. | ||
*/ | ||
_this._lastPosition = new odoHelpers.Coordinate(); | ||
Pointer.prototype.isXAxis = function isXAxis() { | ||
return this.options.axis === Pointer.Axis.X; | ||
}; | ||
/** | ||
* Friction to apply to dragging. A value of zero would result in no dragging, | ||
* 0.5 would result in the draggable element moving half as far as the user | ||
* dragged, and 1 is a 1:1 ratio with user movement. | ||
* @type {number} | ||
* @return {boolean} Whether the draggable axis is the y direction. | ||
*/ | ||
_this._friction = 1; | ||
Pointer.prototype.isYAxis = function isYAxis() { | ||
return this.options.axis === Pointer.Axis.Y; | ||
}; | ||
/** | ||
* Flag indicating dragging has happened. It is set on dragmove and reset | ||
* after the draggableend event has been dispatched. | ||
* @type {boolean} | ||
* @return {boolean} Whether the draggable axis is for both axis. | ||
*/ | ||
_this.hasDragged = false; | ||
Pointer.prototype.isBothAxis = function isBothAxis() { | ||
return this.options.axis === Pointer.Axis.BOTH; | ||
}; | ||
/** | ||
* Whether the user is locked in place within the draggable element. This | ||
* is set to true when `preventDefault` is called on the move event. | ||
* @type {boolean} | ||
* @private | ||
* Retrieve the friction value. | ||
* @return {number} | ||
*/ | ||
_this._isLocked = false; | ||
/** | ||
* Whether dragging is enabled internally. If the user attempts to scroll | ||
* in the opposite direction of the draggable element, this is set to true | ||
* and no more drag move events are counted until the user releases and | ||
* starts dragging again. | ||
* @type {boolean} | ||
* @private | ||
* Apply a friction value to a coordinate, reducing its value. | ||
* This modifies the coordinate given to it. | ||
* @param {Coordinate} coordinate The coordinate to scale. | ||
* @return {Coordinate} Position multiplied by friction. | ||
*/ | ||
_this._isDeactivated = false; | ||
Pointer.prototype.applyFriction = function applyFriction(coordinate) { | ||
return coordinate.scale(this.friction); | ||
}; | ||
/** | ||
* Whether dragging is currently enabled. | ||
* @type {boolean} | ||
* If draggable is enabled and it's a left click with the mouse, | ||
* dragging can start. | ||
* @param {TouchEvent|MouseEvent|PointerEvent} evt Event object. | ||
* @return {boolean} | ||
* @private | ||
*/ | ||
_this._enabled = true; | ||
Pointer.prototype._canStartDrag = function _canStartDrag(evt) { | ||
return this.isEnabled && (Pointer.isTouchEvent(evt) || evt.button === 0); | ||
}; | ||
/** | ||
* Id from setInterval to update the velocity. | ||
* @type {number} | ||
* Whether drag move should happen or exit early. | ||
* @return {boolean} | ||
* @private | ||
*/ | ||
_this._velocityTrackerId = null; | ||
/** | ||
* Time in milliseconds when the drag started. | ||
* @type {number} | ||
*/ | ||
_this.startTime = 0; | ||
/** | ||
* Length of the drag in milliseconds. | ||
* @type {number} | ||
*/ | ||
_this.deltaTime = 0; | ||
Pointer.prototype._canContinueDrag = function _canContinueDrag() { | ||
return this.isEnabled && !this._isDeactivated; | ||
}; | ||
/** | ||
* Used to keep track of the current velocity, it's updated with every velocity update. | ||
* @type {number} | ||
* Drag start handler. | ||
* @param {TouchEvent|MouseEvent|PointerEvent} evt The drag event object. | ||
* @private | ||
*/ | ||
_this._lastTime = 0; | ||
/** | ||
* The current velocity of the drag. | ||
* @type {Coordinate} | ||
*/ | ||
_this.velocity = new odoHelpers.Coordinate(); | ||
/** | ||
* Whether the velocity has been tracked at least once during the drag. | ||
* @type {boolean} | ||
*/ | ||
_this._hasTrackedVelocity = false; | ||
Pointer.prototype._handleDragStart = function _handleDragStart(evt) { | ||
// Clear any active tracking interval. | ||
clearInterval(this._velocityTrackerId); | ||
/** | ||
* The element to which the move and up events will be bound to. If a pointer | ||
* is being used inside a modal which stops events from bubbling to the body, | ||
* this property should be changed to an element which *will* receive the events. | ||
* @type {Document|Element} | ||
*/ | ||
_this.dragEventTarget = document; | ||
// Must be left click to drag. | ||
if (!this._canStartDrag(evt)) { | ||
return; | ||
} | ||
var touchAction = Pointer.TouchActionSupport[_this.options.axis]; | ||
this._setDragStartValues(Pointer._getPageCoordinate(evt)); | ||
/** | ||
* Whether the browser supports the `touch-action` property associated with | ||
* the axis. | ||
* @type {boolean} | ||
*/ | ||
_this._isTouchActionSupported = !!touchAction; | ||
// Give a hook to others | ||
var isPrevented = this._emitEvent(this._createEvent(Pointer.EventType.START, evt)); | ||
// If the browser supports the touch action property, add it. | ||
if (_this.options.preventEventDefault && _this._isTouchActionSupported) { | ||
_this.element.style[touchAction] = Pointer.TouchAction[_this.options.axis]; | ||
} else if (_this.options.preventEventDefault && OdoDevice.HAS_TOUCH_EVENTS) { | ||
window.addEventListener(odoHelpers.events.TOUCHMOVE, odoHelpers.noop); | ||
} | ||
if (!isPrevented) { | ||
this._addDragHandlers(evt.type); | ||
_this.listen(); | ||
return _this; | ||
} | ||
// Every interval, calculate the current velocity of the drag. | ||
this._velocityTrackerId = setInterval(this._trackVelocity.bind(this), Pointer.VELOCITY_INTERVAL); | ||
} | ||
}; | ||
Pointer.prototype.listen = function listen() { | ||
this._onStart = this._handleDragStart.bind(this); | ||
/** | ||
* Drag move, after applyDraggableElementPosition has happened | ||
* @param {TouchEvent|MouseEvent|PointerEvent} evt The dragger event. | ||
* @private | ||
*/ | ||
if (OdoDevice.HAS_POINTER_EVENTS) { | ||
this.element.addEventListener(odoHelpers.events.POINTERDOWN, this._onStart); | ||
} else { | ||
this.element.addEventListener(odoHelpers.events.MOUSEDOWN, this._onStart); | ||
if (OdoDevice.HAS_TOUCH_EVENTS) { | ||
this.element.addEventListener(odoHelpers.events.TOUCHSTART, this._onStart); | ||
Pointer.prototype._handleDragMove = function _handleDragMove(evt) { | ||
if (!this._canContinueDrag()) { | ||
return; | ||
} | ||
} | ||
// Prevent images, links, etc from being dragged around. | ||
// http://www.html5rocks.com/en/tutorials/dnd/basics/ | ||
this.element.addEventListener(odoHelpers.events.DRAGSTART, Pointer._preventDefault); | ||
}; | ||
this._setDragMoveValues(Pointer._getPageCoordinate(evt)); | ||
/** | ||
* Get whether dragger is enabled. | ||
* @return {boolean} Whether dragger is enabled. | ||
*/ | ||
var isPrevented = this._emitEvent(this._createEvent(Pointer.EventType.MOVE, evt)); | ||
// Abort if the developer prevented default on the custom event or if the | ||
// browser supports touch-action (which will do the "locking" for us). | ||
if (!isPrevented && this.options.preventEventDefault && !this._isTouchActionSupported) { | ||
this._finishDragMove(evt); | ||
} | ||
}; | ||
/** | ||
* @return {boolean} Whether the draggable axis is the x direction. | ||
*/ | ||
Pointer.prototype.isXAxis = function isXAxis() { | ||
return this.options.axis === Pointer.Axis.X; | ||
}; | ||
/** | ||
* Finish the drag move function. | ||
* @param {TouchEvent|MouseEvent|PointerEvent} evt Event object. | ||
* @private | ||
*/ | ||
/** | ||
* @return {boolean} Whether the draggable axis is the y direction. | ||
*/ | ||
Pointer.prototype._finishDragMove = function _finishDragMove(evt) { | ||
// Possibly lock the user to only dragging. | ||
this._maybeLock(); | ||
Pointer.prototype.isYAxis = function isYAxis() { | ||
return this.options.axis === Pointer.Axis.Y; | ||
}; | ||
// Possibly stop draggable from affecting the element. | ||
this._maybeDeactivate(); | ||
/** | ||
* @return {boolean} Whether the draggable axis is for both axis. | ||
*/ | ||
// Locked into dragging. | ||
if (this._isLocked) { | ||
evt.preventDefault(); | ||
} | ||
// Disregard drags and velocity. | ||
if (this._isDeactivated) { | ||
clearInterval(this._velocityTrackerId); | ||
this.velocity.x = 0; | ||
this.velocity.y = 0; | ||
} | ||
}; | ||
Pointer.prototype.isBothAxis = function isBothAxis() { | ||
return this.options.axis === Pointer.Axis.BOTH; | ||
}; | ||
/** | ||
* Dragging ended. | ||
* @private | ||
*/ | ||
/** | ||
* Retrieve the friction value. | ||
* @return {number} | ||
*/ | ||
Pointer.prototype._handleDragEnd = function _handleDragEnd(evt) { | ||
clearInterval(this._velocityTrackerId); | ||
this.deltaTime = Date.now() - this.startTime; | ||
/** | ||
* Apply a friction value to a coordinate, reducing its value. | ||
* This modifies the coordinate given to it. | ||
* @param {Coordinate} coordinate The coordinate to scale. | ||
* @return {Coordinate} Position multiplied by friction. | ||
*/ | ||
Pointer.prototype.applyFriction = function applyFriction(coordinate) { | ||
return coordinate.scale(this.friction); | ||
}; | ||
// If this was a quick drag, the velocity might not have been tracked once. | ||
if (!this._hasTrackedVelocity) { | ||
this._trackVelocity(); | ||
} | ||
/** | ||
* If draggable is enabled and it's a left click with the mouse, | ||
* dragging can start. | ||
* @param {TouchEvent|MouseEvent|PointerEvent} evt Event object. | ||
* @return {boolean} | ||
* @private | ||
*/ | ||
// Prevent mouse events from occurring after touchend. | ||
this._removeDragHandlers(); | ||
var endEvent = this._createEvent(Pointer.EventType.END, evt); | ||
endEvent.isCancelEvent = Pointer._isCancelEvent(evt); | ||
Pointer.prototype._canStartDrag = function _canStartDrag(evt) { | ||
return this.isEnabled && (Pointer.isTouchEvent(evt) || evt.button === 0); | ||
}; | ||
// Emit an event. | ||
var isPrevented = this._emitEvent(endEvent); | ||
/** | ||
* Whether drag move should happen or exit early. | ||
* @return {boolean} | ||
* @private | ||
*/ | ||
if (isPrevented) { | ||
evt.preventDefault(); | ||
} | ||
this.hasDragged = false; | ||
this._isDeactivated = false; | ||
this._isLocked = false; | ||
}; | ||
Pointer.prototype._canContinueDrag = function _canContinueDrag() { | ||
return this.isEnabled && !this._isDeactivated; | ||
}; | ||
/** | ||
* Set the starting values for dragging. | ||
* @param {Coordinate} pagePosition The page position coordinate. | ||
* @private | ||
*/ | ||
/** | ||
* Drag start handler. | ||
* @param {TouchEvent|MouseEvent|PointerEvent} evt The drag event object. | ||
* @private | ||
*/ | ||
Pointer.prototype._setDragStartValues = function _setDragStartValues(pagePosition) { | ||
this.pageStart = pagePosition; | ||
this.page = pagePosition; | ||
this._lastPosition = pagePosition; | ||
this.delta = new odoHelpers.Coordinate(); | ||
this.velocity = new odoHelpers.Coordinate(); | ||
this._hasTrackedVelocity = false; | ||
Pointer.prototype._handleDragStart = function _handleDragStart(evt) { | ||
// Clear any active tracking interval. | ||
clearInterval(this._velocityTrackerId); | ||
this.startTime = Date.now(); | ||
this._lastTime = Date.now(); | ||
this.deltaTime = 0; | ||
}; | ||
// Must be left click to drag. | ||
if (!this._canStartDrag(evt)) { | ||
return; | ||
} | ||
/** | ||
* Set the values for dragging during a drag move. | ||
* @param {Coordinate} pagePosition The page position coordinate. | ||
* @private | ||
*/ | ||
this._setDragStartValues(Pointer._getPageCoordinate(evt)); | ||
// Give a hook to others | ||
var isPrevented = this._emitEvent(this._createEvent(Pointer.EventType.START, evt)); | ||
Pointer.prototype._setDragMoveValues = function _setDragMoveValues(pagePosition) { | ||
// Get the distance since the last move. | ||
var lastDelta = odoHelpers.Coordinate.difference(pagePosition, this.page); | ||
if (!isPrevented) { | ||
this._addDragHandlers(evt.type); | ||
// Apply friction to the distance since last move. | ||
this.applyFriction(lastDelta); | ||
// Every interval, calculate the current velocity of the drag. | ||
this._velocityTrackerId = setInterval(this._trackVelocity.bind(this), Pointer.VELOCITY_INTERVAL); | ||
} | ||
}; | ||
// Update the total delta value. | ||
this.delta.translate(lastDelta); | ||
/** | ||
* Drag move, after applyDraggableElementPosition has happened | ||
* @param {TouchEvent|MouseEvent|PointerEvent} evt The dragger event. | ||
* @private | ||
*/ | ||
this.page = pagePosition; | ||
this.deltaTime = Date.now() - this.startTime; | ||
this.hasDragged = true; | ||
}; | ||
/** | ||
* Once the user has moved past the lock threshold, keep it locked. | ||
* @private | ||
*/ | ||
Pointer.prototype._handleDragMove = function _handleDragMove(evt) { | ||
if (!this._canContinueDrag()) { | ||
return; | ||
} | ||
this._setDragMoveValues(Pointer._getPageCoordinate(evt)); | ||
Pointer.prototype._maybeLock = function _maybeLock() { | ||
if (!this._isLocked) { | ||
// Prevent scrolling if the user has moved past the locking threshold. | ||
this._isLocked = this._shouldLock(this.delta); | ||
} | ||
}; | ||
var isPrevented = this._emitEvent(this._createEvent(Pointer.EventType.MOVE, evt)); | ||
/** | ||
* Once the user has moved past the drag threshold, keep it deactivated. | ||
* @private | ||
*/ | ||
// Abort if the developer prevented default on the custom event or if the | ||
// browser supports touch-action (which will do the "locking" for us). | ||
if (!isPrevented && this.options.preventEventDefault && !this._isTouchActionSupported) { | ||
this._finishDragMove(evt); | ||
} | ||
}; | ||
/** | ||
* Finish the drag move function. | ||
* @param {TouchEvent|MouseEvent|PointerEvent} evt Event object. | ||
* @private | ||
*/ | ||
Pointer.prototype._maybeDeactivate = function _maybeDeactivate() { | ||
if (!this._isDeactivated) { | ||
// Disable dragging if the user is attempting to go the opposite direction | ||
// of the draggable element. | ||
this._isDeactivated = this._shouldDeactivate(this.delta); | ||
} | ||
}; | ||
/** | ||
* @param {Coordinate} delta Amount the pointer has moved since it started. | ||
* @return {boolean} Whether Draggable should lock the user into draggable only. | ||
* @private | ||
*/ | ||
Pointer.prototype._finishDragMove = function _finishDragMove(evt) { | ||
// Possibly lock the user to only dragging. | ||
this._maybeLock(); | ||
// Possibly stop draggable from affecting the element. | ||
this._maybeDeactivate(); | ||
Pointer.prototype._shouldLock = function _shouldLock(delta) { | ||
var pastX = this.isXAxis() && Math.abs(delta.x) > Pointer.LOCK_THRESHOLD; | ||
var pastY = this.isYAxis() && Math.abs(delta.y) > Pointer.LOCK_THRESHOLD; | ||
return this.isBothAxis() || pastX || pastY; | ||
}; | ||
// Locked into dragging. | ||
if (this._isLocked) { | ||
evt.preventDefault(); | ||
} | ||
/** | ||
* @param {Coordinate} delta Amount the pointer has moved since it started. | ||
* @return {boolean} Whether Draggable should stop affecting the draggable element. | ||
* @private | ||
*/ | ||
// Disregard drags and velocity. | ||
if (this._isDeactivated) { | ||
clearInterval(this._velocityTrackerId); | ||
this.velocity.x = 0; | ||
this.velocity.y = 0; | ||
} | ||
}; | ||
/** | ||
* Dragging ended. | ||
* @private | ||
*/ | ||
Pointer.prototype._shouldDeactivate = function _shouldDeactivate(delta) { | ||
var pastX = this.isXAxis() && Math.abs(delta.y) > Pointer.DRAG_THRESHOLD; | ||
var pastY = this.isYAxis() && Math.abs(delta.x) > Pointer.DRAG_THRESHOLD; | ||
return !this._isLocked && (this.isBothAxis() || pastX || pastY); | ||
}; | ||
/** | ||
* Make a new event with data. | ||
* @param {Pointer.EventType} type Event type. | ||
* @param {Event} evt Native event object. | ||
* @return {!Pointer.Event} | ||
* @private | ||
*/ | ||
Pointer.prototype._handleDragEnd = function _handleDragEnd(evt) { | ||
clearInterval(this._velocityTrackerId); | ||
this.deltaTime = Date.now() - this.startTime; | ||
// If this was a quick drag, the velocity might not have been tracked once. | ||
if (!this._hasTrackedVelocity) { | ||
this._trackVelocity(); | ||
} | ||
Pointer.prototype._createEvent = function _createEvent(type, evt) { | ||
return new Pointer.Event({ | ||
type: type, | ||
pointerId: this.id, | ||
currentTarget: this.element, | ||
target: evt.target, | ||
axis: this.options.axis, | ||
deltaTime: this.deltaTime, | ||
delta: this.delta, | ||
start: this.pageStart, | ||
end: this.page, | ||
currentVelocity: this.velocity | ||
}); | ||
}; | ||
// Prevent mouse events from occurring after touchend. | ||
this._removeDragHandlers(); | ||
/** | ||
* Binds events to the document for move, end, and cancel (if cancel events | ||
* exist for the device). | ||
* @param {string} startType The type of event which started the drag. It | ||
* is important that the mouse events are not bound when a touch event | ||
* is triggered otherwise the events could be doubled. | ||
* @private | ||
*/ | ||
var endEvent = this._createEvent(Pointer.EventType.END, evt); | ||
endEvent.isCancelEvent = Pointer._isCancelEvent(evt); | ||
// Emit an event. | ||
var isPrevented = this._emitEvent(endEvent); | ||
Pointer.prototype._addDragHandlers = function _addDragHandlers(startType) { | ||
var target = this.dragEventTarget; | ||
this._onMove = this._handleDragMove.bind(this); | ||
this._onEnd = this._handleDragEnd.bind(this); | ||
if (isPrevented) { | ||
evt.preventDefault(); | ||
} | ||
switch (startType) { | ||
case odoHelpers.events.POINTERDOWN: | ||
target.addEventListener(odoHelpers.events.POINTERMOVE, this._onMove); | ||
target.addEventListener(odoHelpers.events.POINTERUP, this._onEnd); | ||
target.addEventListener(odoHelpers.events.POINTERCANCEL, this._onEnd); | ||
break; | ||
case odoHelpers.events.MOUSEDOWN: | ||
target.addEventListener(odoHelpers.events.MOUSEMOVE, this._onMove); | ||
target.addEventListener(odoHelpers.events.MOUSEUP, this._onEnd); | ||
break; | ||
case odoHelpers.events.TOUCHSTART: | ||
target.addEventListener(odoHelpers.events.TOUCHMOVE, this._onMove); | ||
target.addEventListener(odoHelpers.events.TOUCHEND, this._onEnd); | ||
target.addEventListener(odoHelpers.events.TOUCHCANCEL, this._onEnd); | ||
break; | ||
// no default | ||
} | ||
}; | ||
this.hasDragged = false; | ||
this._isDeactivated = false; | ||
this._isLocked = false; | ||
}; | ||
/** | ||
* Removes the events bound during drag start. The draggable namespace can be | ||
* used to remove all of them because the drag start event is still bound | ||
* to the actual element. | ||
*/ | ||
/** | ||
* Set the starting values for dragging. | ||
* @param {Coordinate} pagePosition The page position coordinate. | ||
* @private | ||
*/ | ||
Pointer.prototype._removeDragHandlers = function _removeDragHandlers() { | ||
var target = this.dragEventTarget; | ||
target.removeEventListener(odoHelpers.events.POINTERMOVE, this._onMove); | ||
target.removeEventListener(odoHelpers.events.POINTERUP, this._onEnd); | ||
target.removeEventListener(odoHelpers.events.POINTERCANCEL, this._onEnd); | ||
target.removeEventListener(odoHelpers.events.MOUSEMOVE, this._onMove); | ||
target.removeEventListener(odoHelpers.events.MOUSEUP, this._onEnd); | ||
target.removeEventListener(odoHelpers.events.TOUCHMOVE, this._onMove); | ||
target.removeEventListener(odoHelpers.events.TOUCHEND, this._onEnd); | ||
target.removeEventListener(odoHelpers.events.TOUCHCANCEL, this._onEnd); | ||
}; | ||
Pointer.prototype._setDragStartValues = function _setDragStartValues(pagePosition) { | ||
this.pageStart = pagePosition; | ||
this.page = pagePosition; | ||
this._lastPosition = pagePosition; | ||
this.delta = new odoHelpers.Coordinate(); | ||
this.velocity = new odoHelpers.Coordinate(); | ||
this._hasTrackedVelocity = false; | ||
/** | ||
* Every 100 milliseconds, calculate the current velocity with a moving average. | ||
* http://ariya.ofilabs.com/2013/11/javascript-kinetic-scrolling-part-2.html | ||
* @private | ||
*/ | ||
this.startTime = Date.now(); | ||
this._lastTime = Date.now(); | ||
this.deltaTime = 0; | ||
}; | ||
/** | ||
* Set the values for dragging during a drag move. | ||
* @param {Coordinate} pagePosition The page position coordinate. | ||
* @private | ||
*/ | ||
Pointer.prototype._trackVelocity = function _trackVelocity() { | ||
var now = Date.now(); | ||
var elapsed = now - this._lastTime; | ||
var delta = odoHelpers.Coordinate.difference(this.page, this._lastPosition); | ||
this.applyFriction(delta); | ||
this._lastTime = now; | ||
this._lastPosition = this.page; | ||
// velocity = delta / time. | ||
// Clamp the velocity to avoid outliers. | ||
var maxVelocity = Pointer.MAX_VELOCITY; | ||
this.velocity.x = odoHelpers.clamp(delta.x / elapsed, -maxVelocity, maxVelocity); | ||
this.velocity.y = odoHelpers.clamp(delta.y / elapsed, -maxVelocity, maxVelocity); | ||
Pointer.prototype._setDragMoveValues = function _setDragMoveValues(pagePosition) { | ||
// Get the distance since the last move. | ||
var lastDelta = odoHelpers.Coordinate.difference(pagePosition, this.page); | ||
this._hasTrackedVelocity = true; | ||
}; | ||
// Apply friction to the distance since last move. | ||
this.applyFriction(lastDelta); | ||
/** | ||
* Determine whether the draggable event has enough velocity to be | ||
* considered a swipe. | ||
* @param {Object} velocity Object with x and y properties for velocity. | ||
* @param {number} [threshold] Threshold to check against. Defaults to the swipe | ||
* velocity constant. Must be zero or a positive number. | ||
* @return {boolean} | ||
*/ | ||
// Update the total delta value. | ||
this.delta.translate(lastDelta); | ||
this.page = pagePosition; | ||
this.deltaTime = Date.now() - this.startTime; | ||
this.hasDragged = true; | ||
}; | ||
Pointer.prototype.hasVelocity = function hasVelocity(velocity) { | ||
var threshold = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Pointer.SWIPE_VELOCITY; | ||
/** | ||
* Once the user has moved past the lock threshold, keep it locked. | ||
* @private | ||
*/ | ||
if (this.isYAxis()) { | ||
return Math.abs(velocity.y) > threshold; | ||
} | ||
if (this.isXAxis()) { | ||
return Math.abs(velocity.x) > threshold; | ||
} | ||
Pointer.prototype._maybeLock = function _maybeLock() { | ||
if (!this._isLocked) { | ||
// Prevent scrolling if the user has moved past the locking threshold. | ||
this._isLocked = this._shouldLock(this.delta); | ||
} | ||
}; | ||
// Otherwise check both axis for velocity. | ||
return Math.abs(velocity.x) > threshold || Math.abs(velocity.y) > threshold; | ||
}; | ||
/** | ||
* Once the user has moved past the drag threshold, keep it deactivated. | ||
* @private | ||
*/ | ||
/** | ||
* Emits a event on this instance. | ||
* @param {PointerEvent} event Event object with data. | ||
* @return {boolean} Whether preventDefault was called on the event. | ||
*/ | ||
Pointer.prototype._maybeDeactivate = function _maybeDeactivate() { | ||
if (!this._isDeactivated) { | ||
// Disable dragging if the user is attempting to go the opposite direction | ||
// of the draggable element. | ||
this._isDeactivated = this._shouldDeactivate(this.delta); | ||
} | ||
}; | ||
Pointer.prototype._emitEvent = function _emitEvent(event) { | ||
this.emit(event.type, event); | ||
return event.defaultPrevented; | ||
}; | ||
/** | ||
* @param {Coordinate} delta Amount the pointer has moved since it started. | ||
* @return {boolean} Whether Draggable should lock the user into draggable only. | ||
* @private | ||
*/ | ||
/** | ||
* Remove event listeners and element references. | ||
*/ | ||
Pointer.prototype._shouldLock = function _shouldLock(delta) { | ||
var pastX = this.isXAxis() && Math.abs(delta.x) > Pointer.LOCK_THRESHOLD; | ||
var pastY = this.isYAxis() && Math.abs(delta.y) > Pointer.LOCK_THRESHOLD; | ||
return this.isBothAxis() || pastX || pastY; | ||
}; | ||
Pointer.prototype.dispose = function dispose() { | ||
clearInterval(this._velocityTrackerId); | ||
this._removeDragHandlers(); | ||
/** | ||
* @param {Coordinate} delta Amount the pointer has moved since it started. | ||
* @return {boolean} Whether Draggable should stop affecting the draggable element. | ||
* @private | ||
*/ | ||
// Remove pointer/mouse/touch events. | ||
this.element.removeEventListener(odoHelpers.events.POINTERDOWN, this._onStart); | ||
this.element.removeEventListener(odoHelpers.events.MOUSEDOWN, this._onStart); | ||
this.element.removeEventListener(odoHelpers.events.TOUCHSTART, this._onStart); | ||
if (this._isTouchActionSupported) { | ||
this.element.style[Pointer.TouchActionSupport[this.options.axis]] = ''; | ||
} else if (this.options.preventEventDefault && OdoDevice.HAS_TOUCH_EVENTS) { | ||
window.removeEventListener(odoHelpers.events.TOUCHMOVE, odoHelpers.noop); | ||
} | ||
Pointer.prototype._shouldDeactivate = function _shouldDeactivate(delta) { | ||
var pastX = this.isXAxis() && Math.abs(delta.y) > Pointer.DRAG_THRESHOLD; | ||
var pastY = this.isYAxis() && Math.abs(delta.x) > Pointer.DRAG_THRESHOLD; | ||
return !this._isLocked && (this.isBothAxis() || pastX || pastY); | ||
}; | ||
this.element = null; | ||
this.dragEventTarget = null; | ||
}; | ||
/** | ||
* Make a new event with data. | ||
* @param {Pointer.EventType} type Event type. | ||
* @param {Event} evt Native event object. | ||
* @return {!Pointer.Event} | ||
* @private | ||
*/ | ||
/** | ||
* Whether the event is from a touch. | ||
* @param {object} evt Event object. | ||
* @return {boolean} | ||
*/ | ||
Pointer.prototype._createEvent = function _createEvent(type, evt) { | ||
return new Pointer.Event({ | ||
type: type, | ||
pointerId: this.id, | ||
currentTarget: this.element, | ||
target: evt.target, | ||
axis: this.options.axis, | ||
deltaTime: this.deltaTime, | ||
delta: this.delta, | ||
start: this.pageStart, | ||
end: this.page, | ||
currentVelocity: this.velocity | ||
}); | ||
}; | ||
Pointer.isTouchEvent = function isTouchEvent(evt) { | ||
return !!evt.changedTouches; | ||
}; | ||
/** | ||
* Binds events to the document for move, end, and cancel (if cancel events | ||
* exist for the device). | ||
* @param {string} startType The type of event which started the drag. It | ||
* is important that the mouse events are not bound when a touch event | ||
* is triggered otherwise the events could be doubled. | ||
* @private | ||
*/ | ||
/** | ||
* Whether the event is from a pointer cancel or touch cancel. | ||
* @param {TouchEvent|MouseEvent|PointerEvent} evt Event object. | ||
* @return {boolean} | ||
* @private | ||
*/ | ||
Pointer.prototype._addDragHandlers = function _addDragHandlers(startType) { | ||
var target = this.dragEventTarget; | ||
this._onMove = this._handleDragMove.bind(this); | ||
this._onEnd = this._handleDragEnd.bind(this); | ||
Pointer._isCancelEvent = function _isCancelEvent(evt) { | ||
return evt.type === odoHelpers.events.POINTERCANCEL || evt.type === odoHelpers.events.TOUCHCANCEL; | ||
}; | ||
switch (startType) { | ||
case odoHelpers.events.POINTERDOWN: | ||
target.addEventListener(odoHelpers.events.POINTERMOVE, this._onMove); | ||
target.addEventListener(odoHelpers.events.POINTERUP, this._onEnd); | ||
target.addEventListener(odoHelpers.events.POINTERCANCEL, this._onEnd); | ||
break; | ||
case odoHelpers.events.MOUSEDOWN: | ||
target.addEventListener(odoHelpers.events.MOUSEMOVE, this._onMove); | ||
target.addEventListener(odoHelpers.events.MOUSEUP, this._onEnd); | ||
break; | ||
case odoHelpers.events.TOUCHSTART: | ||
target.addEventListener(odoHelpers.events.TOUCHMOVE, this._onMove); | ||
target.addEventListener(odoHelpers.events.TOUCHEND, this._onEnd); | ||
target.addEventListener(odoHelpers.events.TOUCHCANCEL, this._onEnd); | ||
break; | ||
// no default | ||
} | ||
}; | ||
/** | ||
* Retrieve the page x and page y based on an event. It normalizes | ||
* touch events, mouse events, and pointer events. | ||
* @param {TouchEvent|MouseEvent|PointerEvent} evt Event object. | ||
* @return {!Coordinate} The pageX and pageY of the press. | ||
* @private | ||
*/ | ||
/** | ||
* Removes the events bound during drag start. The draggable namespace can be | ||
* used to remove all of them because the drag start event is still bound | ||
* to the actual element. | ||
*/ | ||
Pointer._getPageCoordinate = function _getPageCoordinate(evt) { | ||
var pagePoints = void 0; | ||
Pointer.prototype._removeDragHandlers = function _removeDragHandlers() { | ||
var target = this.dragEventTarget; | ||
target.removeEventListener(odoHelpers.events.POINTERMOVE, this._onMove); | ||
target.removeEventListener(odoHelpers.events.POINTERUP, this._onEnd); | ||
target.removeEventListener(odoHelpers.events.POINTERCANCEL, this._onEnd); | ||
target.removeEventListener(odoHelpers.events.MOUSEMOVE, this._onMove); | ||
target.removeEventListener(odoHelpers.events.MOUSEUP, this._onEnd); | ||
target.removeEventListener(odoHelpers.events.TOUCHMOVE, this._onMove); | ||
target.removeEventListener(odoHelpers.events.TOUCHEND, this._onEnd); | ||
target.removeEventListener(odoHelpers.events.TOUCHCANCEL, this._onEnd); | ||
}; | ||
// Use the first touch for the pageX and pageY. | ||
if (Pointer.isTouchEvent(evt)) { | ||
pagePoints = evt.changedTouches[0]; // eslint-disable-line prefer-destructuring | ||
} else { | ||
pagePoints = evt; | ||
} | ||
/** | ||
* Every 100 milliseconds, calculate the current velocity with a moving average. | ||
* http://ariya.ofilabs.com/2013/11/javascript-kinetic-scrolling-part-2.html | ||
* @private | ||
*/ | ||
return new odoHelpers.Coordinate(pagePoints.pageX, pagePoints.pageY); | ||
}; | ||
Pointer._preventDefault = function _preventDefault(evt) { | ||
evt.preventDefault(); | ||
}; | ||
Pointer.prototype._trackVelocity = function _trackVelocity() { | ||
var now = Date.now(); | ||
var elapsed = now - this._lastTime; | ||
var delta = odoHelpers.Coordinate.difference(this.page, this._lastPosition); | ||
this.applyFriction(delta); | ||
this._lastTime = now; | ||
this._lastPosition = this.page; | ||
createClass(Pointer, [{ | ||
key: 'isEnabled', | ||
get: function get$$1() { | ||
return this._enabled; | ||
} | ||
// velocity = delta / time. | ||
// Clamp the velocity to avoid outliers. | ||
var maxVelocity = Pointer.MAX_VELOCITY; | ||
this.velocity.x = odoHelpers.clamp(delta.x / elapsed, -maxVelocity, maxVelocity); | ||
this.velocity.y = odoHelpers.clamp(delta.y / elapsed, -maxVelocity, maxVelocity); | ||
/** | ||
* Set whether dragger is enabled. | ||
* @param {boolean} enabled Whether dragger is enabled. | ||
*/ | ||
, | ||
set: function set$$1(enabled) { | ||
this._enabled = enabled; | ||
} | ||
}, { | ||
key: 'friction', | ||
get: function get$$1() { | ||
return this._friction; | ||
} | ||
this._hasTrackedVelocity = true; | ||
}; | ||
/** | ||
* Set the friction value. | ||
* @param {number} friction A number between [1, 0]. | ||
*/ | ||
, | ||
set: function set$$1(friction) { | ||
this._friction = friction; | ||
} | ||
}]); | ||
return Pointer; | ||
}(TinyEmitter); | ||
/** | ||
* Determine whether the draggable event has enough velocity to be | ||
* considered a swipe. | ||
* @param {Object} velocity Object with x and y properties for velocity. | ||
* @param {number} [threshold] Threshold to check against. Defaults to the swipe | ||
* velocity constant. Must be zero or a positive number. | ||
* @return {boolean} | ||
*/ | ||
/** @enum {string} */ | ||
Pointer.prototype.hasVelocity = function hasVelocity(velocity) { | ||
var threshold = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Pointer.SWIPE_VELOCITY; | ||
Pointer.Direction = Direction; | ||
if (this.isYAxis()) { | ||
return Math.abs(velocity.y) > threshold; | ||
} | ||
/** @enum {string} */ | ||
Pointer.Axis = Axis; | ||
if (this.isXAxis()) { | ||
return Math.abs(velocity.x) > threshold; | ||
} | ||
/** @enum {string} */ | ||
Pointer.EventType = { | ||
START: 'odopointer:start', | ||
MOVE: 'odopointer:move', | ||
END: 'odopointer:end' | ||
}; | ||
// Otherwise check both axis for velocity. | ||
return Math.abs(velocity.x) > threshold || Math.abs(velocity.y) > threshold; | ||
/** @enum {string|boolean} */ | ||
Pointer.TouchActionSupport = { | ||
x: OdoDevice.prefixed('touchAction', 'pan-y'), | ||
y: OdoDevice.prefixed('touchAction', 'pan-x'), | ||
xy: OdoDevice.prefixed('touchAction', 'none') | ||
}; | ||
/** @enum {string} */ | ||
Pointer.TouchAction = { | ||
x: 'pan-y', | ||
y: 'pan-x', | ||
xy: 'none' | ||
}; | ||
/** | ||
* Emits a event on this instance. | ||
* @param {PointerEvent} event Event object with data. | ||
* @return {boolean} Whether preventDefault was called on the event. | ||
* @typedef {{axis: Axis, preventEventDefault: boolean}} PointerOptions | ||
*/ | ||
Pointer.prototype._emitEvent = function _emitEvent(event) { | ||
this.emit(event.type, event); | ||
return event.defaultPrevented; | ||
/** @type {PointerOptions} */ | ||
Pointer.Defaults = { | ||
axis: 'xy', | ||
preventEventDefault: true | ||
}; | ||
/** | ||
* Remove event listeners and element references. | ||
* The current velocity property will be clamped to this value (pixels/millisecond). | ||
* @const {number} | ||
*/ | ||
Pointer.MAX_VELOCITY = 12; | ||
/** | ||
* When the pointer is down, an interval starts to track the current velocity. | ||
* @const {number} | ||
*/ | ||
Pointer.VELOCITY_INTERVAL = 100; | ||
Pointer.prototype.dispose = function dispose() { | ||
clearInterval(this._velocityTrackerId); | ||
this._removeDragHandlers(); | ||
// Remove pointer/mouse/touch events. | ||
this.element.removeEventListener(odoHelpers.events.POINTERDOWN, this._onStart); | ||
this.element.removeEventListener(odoHelpers.events.MOUSEDOWN, this._onStart); | ||
this.element.removeEventListener(odoHelpers.events.TOUCHSTART, this._onStart); | ||
if (this._isTouchActionSupported) { | ||
this.element.style[Pointer.TouchActionSupport[this.options.axis]] = ''; | ||
} else if (this.options.preventEventDefault && OdoDevice.HAS_TOUCH_EVENTS) { | ||
window.removeEventListener(odoHelpers.events.TOUCHMOVE, odoHelpers.noop); | ||
} | ||
this.element = null; | ||
this.dragEventTarget = null; | ||
}; | ||
/** | ||
* Whether the event is from a touch. | ||
* @param {object} evt Event object. | ||
* @return {boolean} | ||
* Velocity required for a movement to be considered a swipe. | ||
* @const {number} | ||
*/ | ||
Pointer.SWIPE_VELOCITY = 0.6; | ||
Pointer.isTouchEvent = function isTouchEvent(evt) { | ||
return !!evt.changedTouches; | ||
}; | ||
/** | ||
* Whether the event is from a pointer cancel or touch cancel. | ||
* @param {TouchEvent|MouseEvent|PointerEvent} evt Event object. | ||
* @return {boolean} | ||
* @private | ||
* The scroll/drag amount (pixels) required on the draggable axis before | ||
* stopping further page scrolling/movement. | ||
* @const {number} | ||
*/ | ||
Pointer.LOCK_THRESHOLD = 6; | ||
Pointer._isCancelEvent = function _isCancelEvent(evt) { | ||
return evt.type === odoHelpers.events.POINTERCANCEL || evt.type === odoHelpers.events.TOUCHCANCEL; | ||
}; | ||
/** | ||
* Retrieve the page x and page y based on an event. It normalizes | ||
* touch events, mouse events, and pointer events. | ||
* @param {TouchEvent|MouseEvent|PointerEvent} evt Event object. | ||
* @return {!Coordinate} The pageX and pageY of the press. | ||
* @private | ||
* The scroll/drag amount (pixels) required on the opposite draggable axis | ||
* before dragging is deactivated for the rest of the interaction. | ||
* @const {number} | ||
*/ | ||
Pointer.DRAG_THRESHOLD = 5; | ||
Pointer.Event = PointerEvent; | ||
Pointer._getPageCoordinate = function _getPageCoordinate(evt) { | ||
var pagePoints = void 0; | ||
// Use the first touch for the pageX and pageY. | ||
if (Pointer.isTouchEvent(evt)) { | ||
pagePoints = evt.changedTouches[0]; // eslint-disable-line prefer-destructuring | ||
} else { | ||
pagePoints = evt; | ||
} | ||
return new odoHelpers.Coordinate(pagePoints.pageX, pagePoints.pageY); | ||
}; | ||
Pointer._preventDefault = function _preventDefault(evt) { | ||
evt.preventDefault(); | ||
}; | ||
createClass(Pointer, [{ | ||
key: 'isEnabled', | ||
get: function get$$1() { | ||
return this._enabled; | ||
} | ||
/** | ||
* Set whether dragger is enabled. | ||
* @param {boolean} enabled Whether dragger is enabled. | ||
*/ | ||
, | ||
set: function set$$1(enabled) { | ||
this._enabled = enabled; | ||
} | ||
}, { | ||
key: 'friction', | ||
get: function get$$1() { | ||
return this._friction; | ||
} | ||
/** | ||
* Set the friction value. | ||
* @param {number} friction A number between [1, 0]. | ||
*/ | ||
, | ||
set: function set$$1(friction) { | ||
this._friction = friction; | ||
} | ||
}]); | ||
return Pointer; | ||
}(TinyEmitter); | ||
/** @enum {string} */ | ||
Pointer.Direction = Direction; | ||
/** @enum {string} */ | ||
Pointer.Axis = Axis; | ||
/** @enum {string} */ | ||
Pointer.EventType = { | ||
START: 'odopointer:start', | ||
MOVE: 'odopointer:move', | ||
END: 'odopointer:end' | ||
}; | ||
/** @enum {string|boolean} */ | ||
Pointer.TouchActionSupport = { | ||
x: OdoDevice.prefixed('touchAction', 'pan-y'), | ||
y: OdoDevice.prefixed('touchAction', 'pan-x'), | ||
xy: OdoDevice.prefixed('touchAction', 'none') | ||
}; | ||
/** @enum {string} */ | ||
Pointer.TouchAction = { | ||
x: 'pan-y', | ||
y: 'pan-x', | ||
xy: 'none' | ||
}; | ||
/** | ||
* @typedef {{axis: Axis, preventEventDefault: boolean}} PointerOptions | ||
*/ | ||
/** @type {PointerOptions} */ | ||
Pointer.Defaults = { | ||
axis: 'xy', | ||
preventEventDefault: true | ||
}; | ||
/** | ||
* The current velocity property will be clamped to this value (pixels/millisecond). | ||
* @const {number} | ||
*/ | ||
Pointer.MAX_VELOCITY = 12; | ||
/** | ||
* When the pointer is down, an interval starts to track the current velocity. | ||
* @const {number} | ||
*/ | ||
Pointer.VELOCITY_INTERVAL = 100; | ||
/** | ||
* Velocity required for a movement to be considered a swipe. | ||
* @const {number} | ||
*/ | ||
Pointer.SWIPE_VELOCITY = 0.6; | ||
/** | ||
* The scroll/drag amount (pixels) required on the draggable axis before | ||
* stopping further page scrolling/movement. | ||
* @const {number} | ||
*/ | ||
Pointer.LOCK_THRESHOLD = 6; | ||
/** | ||
* The scroll/drag amount (pixels) required on the opposite draggable axis | ||
* before dragging is deactivated for the rest of the interaction. | ||
* @const {number} | ||
*/ | ||
Pointer.DRAG_THRESHOLD = 5; | ||
Pointer.Event = PointerEvent; | ||
return Pointer; | ||
}))); | ||
//# sourceMappingURL=odo-pointer.js.map |
{ | ||
"name": "@odopod/odo-pointer", | ||
"description": "An abstraction for pointer, mouse, and touch events.", | ||
"version": "1.2.0", | ||
"version": "1.2.1", | ||
"main": "dist/odo-pointer.js", | ||
@@ -18,4 +18,4 @@ "module": "dist/odo-pointer.esm.js", | ||
"dependencies": { | ||
"@odopod/odo-device": "^1.2.0", | ||
"@odopod/odo-helpers": "^2.0.1", | ||
"@odopod/odo-device": "^1.3.0", | ||
"@odopod/odo-helpers": "^2.0.2", | ||
"tiny-emitter": "^2.0.1" | ||
@@ -22,0 +22,0 @@ }, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
223868
Updated@odopod/odo-device@^1.3.0
Updated@odopod/odo-helpers@^2.0.2