/** * */Ext.define('Ext.event.gesture.Drag', { extend: 'Ext.event.gesture.SingleTouch', priority: 100, startPoint: null, previousPoint: null, lastPoint: null, handledEvents: ['dragstart', 'drag', 'dragend', 'dragcancel'], config: { /** * @cfg {Number} minDistance * The minimum distance of pixels before a touch event becomes a drag event. */ minDistance: 8 }, constructor: function() { this.callParent(arguments); this.initInfo(); }, initInfo: function() { this.info = { touch: null, previous: { x: 0, y: 0 }, x: 0, y: 0, delta: { x: 0, y: 0 }, absDelta: { x: 0, y: 0 }, flick: { velocity: { x: 0, y: 0 } }, direction: { x: 0, y: 0 }, time: 0, previousTime: { x: 0, y: 0 }, longpress: false }; }, onTouchStart: function(e) { var me = this, ret = me.callParent([e]); if (ret !== false) { me.startTime = e.time; me.startPoint = e.changedTouches[0].point; } return ret; }, tryDragStart: function(e) { var me = this, point = e.changedTouches[0].point, minDistance = me.getMinDistance(), scale = Ext.Element.getViewportScale(), // account for scale so that move distance is actual screen pixels, not page pixels distance = Math.round(Math.abs(point.getDistanceTo(me.startPoint) * scale)); if (distance >= minDistance) { me.doDragStart(e); } }, doDragStart: function(e, isLongPress) { var me = this, touch = e.changedTouches[0], point = touch.point, info = me.info, time; if (isLongPress) { time = Ext.now(); me.startTime = time; me.startPoint = point; info.longpress = true; } else { time = e.time; } me.isStarted = true; me.previousPoint = me.lastPoint = point; me.resetInfo('x', e, touch); me.resetInfo('y', e, touch); info.time = time; me.fire('dragstart', e, info); }, onTouchMove: function(e) { var me = this, touch, point; if (!me.startPoint) { return; } if (!me.isStarted) { me.tryDragStart(e); } if (!me.isStarted) { return; } touch = e.changedTouches[0]; point = touch.point; if (me.lastPoint) { me.previousPoint = me.lastPoint; } me.lastPoint = point; me.lastMoveEvent = e; me.updateInfo('x', e, touch); me.updateInfo('y', e, touch); me.info.time = e.time; me.fire('drag', e, me.info); }, onAxisDragEnd: function(axis, info) { var duration = info.time - info.previousTime[axis]; if (duration > 0) { info.flick.velocity[axis] = (info[axis] - info.previous[axis]) / duration; } }, resetInfo: function(axis, e, touch) { var me = this, value = me.lastPoint[axis], startValue = me.startPoint[axis], delta = value - startValue, capAxis = axis.toUpperCase(), info = me.info; info.touch = touch; info.delta[axis] = delta; info.absDelta[axis] = Math.abs(delta); info.previousTime[axis] = me.startTime; info.previous[axis] = startValue; info[axis] = value; info.direction[axis] = 0; info['start' + capAxis] = me.startPoint[axis]; info['previous' + capAxis] = info.previous[axis]; info['page' + capAxis] = info[axis]; info['delta' + capAxis] = info.delta[axis]; info['absDelta' + capAxis] = info.absDelta[axis]; info['previousDelta' + capAxis] = 0; info.startTime = me.startTime; }, updateInfo: function(axis, e, touch) { var me = this, value = me.lastPoint[axis], previousValue = me.previousPoint[axis], startValue = me.startPoint[axis], delta = value - startValue, info = me.info, direction = info.direction, capAxis = axis.toUpperCase(), previousFlick = info.previous[axis]; info.touch = touch; info.delta[axis] = delta; info.absDelta[axis] = Math.abs(delta); if (value !== previousFlick && value !== info[axis]) { info.previous[axis] = info[axis]; info.previousTime[axis] = info.time; } info[axis] = value; if (value > previousValue) { direction[axis] = 1; } else if (value < previousValue) { direction[axis] = -1; } info['start' + capAxis] = startValue; info['previous' + capAxis] = info.previous[axis]; info['page' + capAxis] = info[axis]; info['delta' + capAxis] = info.delta[axis]; info['absDelta' + capAxis] = info.absDelta[axis]; info['previousDelta' + capAxis] = info.previous[axis] - startValue; info.startTime = me.startTime; }, onTouchEnd: function(e) { var me = this, touch, point, info; if (me.isStarted) { touch = e.changedTouches[0]; point = touch.point; info = me.info; me.lastPoint = point; me.updateInfo('x', e, touch); me.updateInfo('y', e, touch); info.time = e.time; me.onAxisDragEnd('x', info); me.onAxisDragEnd('y', info); me.fire('dragend', e, info); } return this.callParent([e]); }, onCancel: function(e) { var me = this, touch = e.changedTouches[0], info = me.info; // if "e" is a true cancellation event (touchcancel, pointercancel) e.touches.length // will be 0. If length is anything else we can safely assume that this was called // because an additional touch was added (see SingleTouch#onTouchStart). If that // is the case we do not want to update the lastPoint because the coordinates should // be those of the last single-touch drag, not the new touch. if (!e.touches.length) { me.lastPoint = touch.point; } me.updateInfo('x', e, touch); me.updateInfo('y', e, touch); info.time = e.time; me.fire('dragcancel', e, info, true); }, reset: function() { var me = this; me.lastPoint = me.startPoint = me.previousPoint = me.lastPoint = me.lastMoveEvent = null; me.initInfo(); return me.callParent(); }}, function(Drag) { var gestures = Ext.manifest.gestures; Drag.instance = new Drag(gestures && gestures.drag);});