UNPKG

hammerjs

Version:

A javascript library for multi-touch gestures

228 lines (185 loc) 6.49 kB
/** * @module hammer * * @class Detection * @static */ var Detection = Hammer.detection = { // contains all registred Hammer.gestures in the correct order gestures: [], // data of the current Hammer.gesture detection session current : null, // the previous Hammer.gesture session data // is a full clone of the previous gesture.current object previous: null, // when this becomes true, no gestures are fired stopped : false, /** * start Hammer.gesture detection * @method startDetect * @param {Hammer.Instance} inst * @param {Object} eventData */ startDetect: function startDetect(inst, eventData) { // already busy with a Hammer.gesture detection on an element if(this.current) { return; } this.stopped = false; // holds current session this.current = { inst: inst, // reference to HammerInstance we're working for startEvent: Utils.extend({}, eventData), // start eventData for distances, timing etc lastEvent: false, // last eventData lastCalcEvent: false, // last eventData for calculations. futureCalcEvent: false, // last eventData for calculations. lastCalcData: {}, // last lastCalcData name: '' // current gesture we're in/detected, can be 'tap', 'hold' etc }; this.detect(eventData); }, /** * Hammer.gesture detection * @method detect * @param {Object} eventData * @return {any} */ detect: function detect(eventData) { if(!this.current || this.stopped) { return; } // extend event data with calculations about scale, distance etc eventData = this.extendEventData(eventData); // hammer instance and instance options var inst = this.current.inst, inst_options = inst.options; // call Hammer.gesture handlers Utils.each(this.gestures, function triggerGesture(gesture) { // only when the instance options have enabled this gesture if(!this.stopped && inst.enabled && inst_options[gesture.name]) { // if a handler returns false, we stop with the detection if(gesture.handler.call(gesture, eventData, inst) === false) { this.stopDetect(); return false; } } }, this); // store as previous event event if(this.current) { this.current.lastEvent = eventData; } if(eventData.eventType == EVENT_END) { this.stopDetect(); } return eventData; }, /** * clear the Hammer.gesture vars * this is called on endDetect, but can also be used when a final Hammer.gesture has been detected * to stop other Hammer.gestures from being fired * @method stopDetect */ stopDetect: function stopDetect() { // clone current data to the store as the previous gesture // used for the double tap gesture, since this is an other gesture detect session this.previous = Utils.extend({}, this.current); // reset the current this.current = null; this.stopped = true; }, /** * calculate velocity, angle and direction * @method getVelocityData * @param {Object} ev * @param {Number} delta_time * @param {Number} delta_x * @param {Number} delta_y */ getCalculatedData: function getCalculatedData(ev, center, delta_time, delta_x, delta_y) { var cur = this.current , recalc = false , calcEv = cur.lastCalcEvent , calcData = cur.lastCalcData; if(calcEv && ev.timeStamp - calcEv.timeStamp > Hammer.CALCULATE_INTERVAL) { center = calcEv.center; delta_time = ev.timeStamp - calcEv.timeStamp; delta_x = ev.center.clientX - calcEv.center.clientX; delta_y = ev.center.clientY - calcEv.center.clientY; recalc = true; } if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { cur.futureCalcEvent = ev; } if(!cur.lastCalcEvent || recalc) { calcData.velocity = Utils.getVelocity(delta_time, delta_x, delta_y); calcData.angle = Utils.getAngle(center, ev.center); calcData.direction = Utils.getDirection(center, ev.center); cur.lastCalcEvent = cur.futureCalcEvent || ev; cur.futureCalcEvent = ev; } ev.velocityX = calcData.velocity.x; ev.velocityY = calcData.velocity.y; ev.interimAngle = calcData.angle; ev.interimDirection = calcData.direction; }, /** * extend eventData for Hammer.gestures * @method extendEventData * @param {Object} ev * @return {Object} ev */ extendEventData: function extendEventData(ev) { var cur = this.current , startEv = cur.startEvent , lastEv = cur.lastEvent || startEv; // update the start touchlist to calculate the scale/rotation if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { startEv.touches = []; Utils.each(ev.touches, function(touch) { startEv.touches.push(Utils.extend({}, touch)); }); } var delta_time = ev.timeStamp - startEv.timeStamp , delta_x = ev.center.clientX - startEv.center.clientX , delta_y = ev.center.clientY - startEv.center.clientY; this.getCalculatedData(ev, lastEv.center, delta_time, delta_x, delta_y); Utils.extend(ev, { startEvent: startEv, deltaTime: delta_time, deltaX: delta_x, deltaY: delta_y, distance: Utils.getDistance(startEv.center, ev.center), angle: Utils.getAngle(startEv.center, ev.center), direction: Utils.getDirection(startEv.center, ev.center), scale: Utils.getScale(startEv.touches, ev.touches), rotation: Utils.getRotation(startEv.touches, ev.touches) }); return ev; }, /** * register new gesture * @method register * @param {Object} gesture object, see `gestures/` for documentation * @return {Array} gestures */ register: function register(gesture) { // add an enable gesture options if there is no given var options = gesture.defaults || {}; if(options[gesture.name] === undefined) { options[gesture.name] = true; } // extend Hammer default options with the Hammer.gesture options Utils.extend(Hammer.defaults, options, true); // set its index gesture.index = gesture.index || 1000; // add Hammer.gesture to the list this.gestures.push(gesture); // sort the list by index this.gestures.sort(function(a, b) { if(a.index < b.index) { return -1; } if(a.index > b.index) { return 1; } return 0; }); return this.gestures; } };