302 lines
6.8 KiB
JavaScript
302 lines
6.8 KiB
JavaScript
|
/*!
|
||
|
* Unipointer v2.3.0
|
||
|
* base class for doing one thing with pointer event
|
||
|
* MIT license
|
||
|
*/
|
||
|
|
||
|
/*jshint browser: true, undef: true, unused: true, strict: true */
|
||
|
|
||
|
( function( window, factory ) {
|
||
|
// universal module definition
|
||
|
/* jshint strict: false */ /*global define, module, require */
|
||
|
if ( typeof define == 'function' && define.amd ) {
|
||
|
// AMD
|
||
|
define( [
|
||
|
'ev-emitter/ev-emitter'
|
||
|
], function( EvEmitter ) {
|
||
|
return factory( window, EvEmitter );
|
||
|
});
|
||
|
} else if ( typeof module == 'object' && module.exports ) {
|
||
|
// CommonJS
|
||
|
module.exports = factory(
|
||
|
window,
|
||
|
require('ev-emitter')
|
||
|
);
|
||
|
} else {
|
||
|
// browser global
|
||
|
window.Unipointer = factory(
|
||
|
window,
|
||
|
window.EvEmitter
|
||
|
);
|
||
|
}
|
||
|
|
||
|
}( window, function factory( window, EvEmitter ) {
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
function noop() {}
|
||
|
|
||
|
function Unipointer() {}
|
||
|
|
||
|
// inherit EvEmitter
|
||
|
var proto = Unipointer.prototype = Object.create( EvEmitter.prototype );
|
||
|
|
||
|
proto.bindStartEvent = function( elem ) {
|
||
|
this._bindStartEvent( elem, true );
|
||
|
};
|
||
|
|
||
|
proto.unbindStartEvent = function( elem ) {
|
||
|
this._bindStartEvent( elem, false );
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Add or remove start event
|
||
|
* @param {Boolean} isAdd - remove if falsey
|
||
|
*/
|
||
|
proto._bindStartEvent = function( elem, isAdd ) {
|
||
|
// munge isAdd, default to true
|
||
|
isAdd = isAdd === undefined ? true : isAdd;
|
||
|
var bindMethod = isAdd ? 'addEventListener' : 'removeEventListener';
|
||
|
|
||
|
// default to mouse events
|
||
|
var startEvent = 'mousedown';
|
||
|
if ( window.PointerEvent ) {
|
||
|
// Pointer Events
|
||
|
startEvent = 'pointerdown';
|
||
|
} else if ( 'ontouchstart' in window ) {
|
||
|
// Touch Events. iOS Safari
|
||
|
startEvent = 'touchstart';
|
||
|
}
|
||
|
elem[ bindMethod ]( startEvent, this );
|
||
|
};
|
||
|
|
||
|
// trigger handler methods for events
|
||
|
proto.handleEvent = function( event ) {
|
||
|
var method = 'on' + event.type;
|
||
|
if ( this[ method ] ) {
|
||
|
this[ method ]( event );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// returns the touch that we're keeping track of
|
||
|
proto.getTouch = function( touches ) {
|
||
|
for ( var i=0; i < touches.length; i++ ) {
|
||
|
var touch = touches[i];
|
||
|
if ( touch.identifier == this.pointerIdentifier ) {
|
||
|
return touch;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// ----- start event ----- //
|
||
|
|
||
|
proto.onmousedown = function( event ) {
|
||
|
// dismiss clicks from right or middle buttons
|
||
|
var button = event.button;
|
||
|
if ( button && ( button !== 0 && button !== 1 ) ) {
|
||
|
return;
|
||
|
}
|
||
|
this._pointerDown( event, event );
|
||
|
};
|
||
|
|
||
|
proto.ontouchstart = function( event ) {
|
||
|
this._pointerDown( event, event.changedTouches[0] );
|
||
|
};
|
||
|
|
||
|
proto.onpointerdown = function( event ) {
|
||
|
this._pointerDown( event, event );
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* pointer start
|
||
|
* @param {Event} event
|
||
|
* @param {Event or Touch} pointer
|
||
|
*/
|
||
|
proto._pointerDown = function( event, pointer ) {
|
||
|
// dismiss right click and other pointers
|
||
|
// button = 0 is okay, 1-4 not
|
||
|
if ( event.button || this.isPointerDown ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this.isPointerDown = true;
|
||
|
// save pointer identifier to match up touch events
|
||
|
this.pointerIdentifier = pointer.pointerId !== undefined ?
|
||
|
// pointerId for pointer events, touch.indentifier for touch events
|
||
|
pointer.pointerId : pointer.identifier;
|
||
|
|
||
|
this.pointerDown( event, pointer );
|
||
|
};
|
||
|
|
||
|
proto.pointerDown = function( event, pointer ) {
|
||
|
this._bindPostStartEvents( event );
|
||
|
this.emitEvent( 'pointerDown', [ event, pointer ] );
|
||
|
};
|
||
|
|
||
|
// hash of events to be bound after start event
|
||
|
var postStartEvents = {
|
||
|
mousedown: [ 'mousemove', 'mouseup' ],
|
||
|
touchstart: [ 'touchmove', 'touchend', 'touchcancel' ],
|
||
|
pointerdown: [ 'pointermove', 'pointerup', 'pointercancel' ],
|
||
|
};
|
||
|
|
||
|
proto._bindPostStartEvents = function( event ) {
|
||
|
if ( !event ) {
|
||
|
return;
|
||
|
}
|
||
|
// get proper events to match start event
|
||
|
var events = postStartEvents[ event.type ];
|
||
|
// bind events to node
|
||
|
events.forEach( function( eventName ) {
|
||
|
window.addEventListener( eventName, this );
|
||
|
}, this );
|
||
|
// save these arguments
|
||
|
this._boundPointerEvents = events;
|
||
|
};
|
||
|
|
||
|
proto._unbindPostStartEvents = function() {
|
||
|
// check for _boundEvents, in case dragEnd triggered twice (old IE8 bug)
|
||
|
if ( !this._boundPointerEvents ) {
|
||
|
return;
|
||
|
}
|
||
|
this._boundPointerEvents.forEach( function( eventName ) {
|
||
|
window.removeEventListener( eventName, this );
|
||
|
}, this );
|
||
|
|
||
|
delete this._boundPointerEvents;
|
||
|
};
|
||
|
|
||
|
// ----- move event ----- //
|
||
|
|
||
|
proto.onmousemove = function( event ) {
|
||
|
this._pointerMove( event, event );
|
||
|
};
|
||
|
|
||
|
proto.onpointermove = function( event ) {
|
||
|
if ( event.pointerId == this.pointerIdentifier ) {
|
||
|
this._pointerMove( event, event );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
proto.ontouchmove = function( event ) {
|
||
|
var touch = this.getTouch( event.changedTouches );
|
||
|
if ( touch ) {
|
||
|
this._pointerMove( event, touch );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* pointer move
|
||
|
* @param {Event} event
|
||
|
* @param {Event or Touch} pointer
|
||
|
* @private
|
||
|
*/
|
||
|
proto._pointerMove = function( event, pointer ) {
|
||
|
this.pointerMove( event, pointer );
|
||
|
};
|
||
|
|
||
|
// public
|
||
|
proto.pointerMove = function( event, pointer ) {
|
||
|
this.emitEvent( 'pointerMove', [ event, pointer ] );
|
||
|
};
|
||
|
|
||
|
// ----- end event ----- //
|
||
|
|
||
|
|
||
|
proto.onmouseup = function( event ) {
|
||
|
this._pointerUp( event, event );
|
||
|
};
|
||
|
|
||
|
proto.onpointerup = function( event ) {
|
||
|
if ( event.pointerId == this.pointerIdentifier ) {
|
||
|
this._pointerUp( event, event );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
proto.ontouchend = function( event ) {
|
||
|
var touch = this.getTouch( event.changedTouches );
|
||
|
if ( touch ) {
|
||
|
this._pointerUp( event, touch );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* pointer up
|
||
|
* @param {Event} event
|
||
|
* @param {Event or Touch} pointer
|
||
|
* @private
|
||
|
*/
|
||
|
proto._pointerUp = function( event, pointer ) {
|
||
|
this._pointerDone();
|
||
|
this.pointerUp( event, pointer );
|
||
|
};
|
||
|
|
||
|
// public
|
||
|
proto.pointerUp = function( event, pointer ) {
|
||
|
this.emitEvent( 'pointerUp', [ event, pointer ] );
|
||
|
};
|
||
|
|
||
|
// ----- pointer done ----- //
|
||
|
|
||
|
// triggered on pointer up & pointer cancel
|
||
|
proto._pointerDone = function() {
|
||
|
this._pointerReset();
|
||
|
this._unbindPostStartEvents();
|
||
|
this.pointerDone();
|
||
|
};
|
||
|
|
||
|
proto._pointerReset = function() {
|
||
|
// reset properties
|
||
|
this.isPointerDown = false;
|
||
|
delete this.pointerIdentifier;
|
||
|
};
|
||
|
|
||
|
proto.pointerDone = noop;
|
||
|
|
||
|
// ----- pointer cancel ----- //
|
||
|
|
||
|
proto.onpointercancel = function( event ) {
|
||
|
if ( event.pointerId == this.pointerIdentifier ) {
|
||
|
this._pointerCancel( event, event );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
proto.ontouchcancel = function( event ) {
|
||
|
var touch = this.getTouch( event.changedTouches );
|
||
|
if ( touch ) {
|
||
|
this._pointerCancel( event, touch );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* pointer cancel
|
||
|
* @param {Event} event
|
||
|
* @param {Event or Touch} pointer
|
||
|
* @private
|
||
|
*/
|
||
|
proto._pointerCancel = function( event, pointer ) {
|
||
|
this._pointerDone();
|
||
|
this.pointerCancel( event, pointer );
|
||
|
};
|
||
|
|
||
|
// public
|
||
|
proto.pointerCancel = function( event, pointer ) {
|
||
|
this.emitEvent( 'pointerCancel', [ event, pointer ] );
|
||
|
};
|
||
|
|
||
|
// ----- ----- //
|
||
|
|
||
|
// utility function for getting x/y coords from event
|
||
|
Unipointer.getPointerPoint = function( pointer ) {
|
||
|
return {
|
||
|
x: pointer.pageX,
|
||
|
y: pointer.pageY
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// ----- ----- //
|
||
|
|
||
|
return Unipointer;
|
||
|
|
||
|
}));
|