Created
November 26, 2012 18:34
-
-
Save malko/4149808 to your computer and use it in GitHub Desktop.
touch events support
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* minimal jquery/zepto compatibility layer | |
* be aware that won't mimic jquery/zepto at all but offer a similar api for basic stuffs as querySelectorAll and addEventListener ... | |
* @author jgotti at modedemploi dot fr for agence-modedemploi.com | |
* @licence Dual licence LGPL / MIT | |
* @changelog | |
* - 2012-11-28 - more jquery like syntax and some events related stuffs | |
*/ | |
(function($){ | |
"use strict"; | |
/*jshint expr:true*/ | |
if(! $){ | |
/** | |
* can be used as querySelectorAll (selector as first parameter and optionaly domElement used as context passed as second parameter ) | |
* or if first parameter is a function just a shorthand of $.ready | |
*/ | |
$ = function(selector,context){ // not supporting IE | |
if( selector instanceof Function ){ | |
return $.ready(selector); | |
} | |
var c; | |
if( selector === window || selector===document || (selector instanceof Element) ){ | |
c = [selector]; | |
}else if( selector instanceof Array ){ | |
c = selector; | |
}else if(! (context instanceof Array) ){ | |
context === window && (context = document); | |
c = Array.prototype.slice.call((context||document).querySelectorAll(selector),0) || []; | |
}else{ | |
c = []; | |
$.each(context,function(k,v){ | |
$(selector,v).each(function(k,v){ | |
c.push(v); | |
}); | |
}); | |
} | |
$.each($.fn,function(k,v){ | |
c[k] = v; | |
}); | |
return c; | |
}; | |
/** | |
* take a callback to execute when dom is ready | |
*/ | |
$.ready = function(cb){ // not supporting IE | |
if(document.readyState.match(/complete|loaded|interactive/)){ | |
cb(); | |
}else{ | |
document.addEventListener('DOMContentLoaded', function(){ cb();}, false); | |
} | |
return this; | |
}; | |
/** | |
* first parameter is destination object to extend or boolean forcing deep extension. | |
* all others parameters are object to copy property from to destination object | |
*/ | |
$.extend = function(){ | |
var A=arguments | |
, deepPassed = typeof A[0] === 'boolean' ? true : false | |
, deep = deepPassed ? A[0] : false | |
, dest = A[deepPassed?1:0] | |
, a = deepPassed?2:1 | |
, al = A.length | |
, p | |
; | |
if( a ===2 ){ | |
dest = A[1]; | |
} | |
for(;a<al;a++){ | |
for(p in A[a]){ | |
if( A[a].hasOwnProperty(p) ){ | |
if( deep && typeof(A[a][p]) === 'object' ){ | |
dest[p] = dest[p] || {}; | |
$.extend(deep,dest[p],A[a][p]); | |
}else{ | |
dest[p] = A[a][p]; | |
} | |
} | |
} | |
} | |
return dest; | |
}; | |
/** | |
* bind callback on given event to given element | |
* don't support namespaced events | |
*/ | |
$.on = (window.document.addEventListener ? | |
function(type, e, cb){ $.each(type.split(/\s+/),function(){e.addEventListener(this, cb, false);}); } | |
: function(type, e, cb){ $.each(type.split(/\s+/),function(){ e.attachEvent('on' + this, cb);}); } | |
); | |
/** | |
* unbind callback on given event to given element | |
* don't support namespaced events | |
*/ | |
$.off = (window.document.removeEventListener ? | |
function(type, e, cb){ $.each(type.split(/\s+/),function(){e.removeEventListener(this, cb, false);}); } | |
: function(type, e, cb){$.each(type.split(/\s+/),function(){e.detachEvent('on' + this, cb);}); } | |
); | |
/** | |
* iterate over collection using a given callback (cb) | |
*/ | |
$.each = function(collection, cb){ | |
var i,l,key; | |
if((collection instanceof Array) || (collection instanceof NodeList) ) { | |
for(i=0,l=collection.length; i<l;i++){ | |
if(cb.call(collection[i], i, collection[i]) === false){ | |
return collection; | |
} | |
} | |
}else{ | |
for(key in collection){ | |
if(collection.hasOwnProperty(key) && cb.call(collection[key],key,collection[key]) === false){ | |
return collection; | |
} | |
} | |
} | |
return collection; | |
}; | |
$.Event=function(type,props){ | |
var event = document.createEvent(type.match(/^(click|mousedown|mouseup|mousemove)$/) ? 'MouseEvents':'Events'); | |
props && $.extend(event,props); | |
event.initEvent(type, (props && props.bubbles===false)?false:true, true, null, null, null, null, null, null, null, null, null, null, null, null); | |
return event; | |
}; | |
$.fn = { | |
each:function(cb){ $.each(this,cb); return this; } | |
,on:function(type,cb){ return $.each(this,function(k,v){ $.on(type,v,cb); }); } | |
,off:function(type,cb){ return $.each(this,function(k,v){ $.off(type,v,cb); }); } | |
,trigger:function(event, data){ | |
if( typeof event === 'string' ){ | |
event = $.Event(event); | |
} | |
data && (event.data = data); | |
return $.each(this,function(k,v){ | |
if( 'dispatchEvent' in v){ v.dispatchEvent(event);} | |
}); | |
} | |
}; | |
window.$ = $; | |
}})(typeof $ !== 'undefined'? $ : false); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML> | |
<html> | |
<head> | |
<!-- | |
<script src="zepto.js"></script> | |
--> | |
<script src="basic-compat.js"></script> | |
<script src="tutechie.js"></script> | |
<style> | |
#galleryTest, #galleryTest2{ overflow: hidden;width:400px;height:200px;position:relative;background: #333;} | |
#galleryTest img, #galleryTest2 img{ position:absolute; left:0;right:0;} | |
</style> | |
</head> | |
<body> | |
<h2>Testing Swipe right/left</h2> | |
<div id="galleryTest" > | |
<img src="http://lorempixel.com/400/200/abstract"> | |
<img src="http://lorempixel.com/400/200/nature"> | |
<img src="http://lorempixel.com/400/200/city"> | |
<img src="http://lorempixel.com/400/200/technics"> | |
<img src="http://lorempixel.com/400/200/people"> | |
</div> | |
Tap and long Tap me to see a message appear in the console on the right | |
<br /> | |
<h2>Testing drag </h2> | |
<div id="galleryTest2" > | |
<img src="http://lorempixel.com/400/200/abstract"> | |
<img src="http://lorempixel.com/400/200/nature"> | |
<img src="http://lorempixel.com/400/200/city"> | |
<img src="http://lorempixel.com/400/200/technics"> | |
<img src="http://lorempixel.com/400/200/people"> | |
</div> | |
zoomin/out activable by pinch or mousewheel | |
<pre style="position:absolute;right:10px;top:10px; width:300px;height:600px;border:solid silver 1px" id="pre"></pre> | |
<script> | |
/*global $*/ | |
/*jshint expr:true,browser:true*/ | |
//--initilaise gallery | |
/** | |
* code is made abnormally complex to manage compatibility between jQuery/Zepto/basic-compat libraries. | |
*/ | |
function log(){ | |
var p = $('#pre')[0]; | |
p.innerHTML += Array.prototype.join.call(arguments,', ')+'\n'; | |
} | |
function gallery(container,draggable){ | |
if( ! (this instanceof gallery) ){ | |
return new gallery(container,draggable); | |
} | |
var g = this; | |
g.draggable = draggable; | |
g.container = $(container); | |
g.zoom = 1; | |
g.offset = {left:this.container[0].left,top:this.container[0].top}; | |
g.currentSlide = 0; | |
g.width = window.getComputedStyle(g.container[0]).width; | |
g.slides = []; | |
$('img',g.container).each(function(k,v){ | |
v.setAttribute('data-slideId',k); | |
v.setAttribute('draggable',false); | |
if(k){ | |
v.style.left = g.width; | |
} | |
g.slides.push($(v)); | |
}); | |
g.lastSlideId = parseInt($('img:last-child',g.container)[0].getAttribute('data-slideId'),10); | |
g.container.on('Touchstart',function(e){ | |
e.preventDefault(); | |
}); | |
if( !draggable ){ | |
g.container | |
.on('Tap',function(){ | |
log('you just tapped me'); | |
}) | |
.on('Heldtap',function(){ | |
log('you just tapped me so long'); | |
}) | |
.on('Swipe',function(e){ | |
if( e.direction ==='left'){ | |
g.goNext(); | |
}else if( e.direction === 'right'){ | |
g.goPrev(); | |
} | |
log('swiped '+e.direction); | |
}) | |
; | |
}else{ | |
g.container.on('Move',function(e){ | |
var w = parseInt(g.width,10) | |
,prev = g.getSlide(g.currentSlide === 0 ? g.lastSlideId : (g.currentSlide-1))[0] | |
,next = g.getSlide(g.currentSlide === g.lastSlideId ? 0 : (g.currentSlide+1))[0] | |
,current = g.getSlide(g.currentSlide)[0] | |
,distanceX = Math.min(w,Math.max(-w,e.distanceX)) | |
; | |
$([prev,current,next]).each(function(){ | |
this.setAttribute('style',''); | |
}); | |
current.style.left = distanceX+'px'; | |
prev.style.left = (distanceX-w)+'px'; | |
next.style.left = (distanceX+w)+'px'; | |
}); | |
g.container.on('Moveend',function(e){ | |
var treshold = parseInt(g.width,10)*0.33; | |
if( Math.abs(e.distanceX) > treshold ){ | |
e.distanceX > 0 ? g.goPrev() : g.goNext(); | |
}else{ | |
g.getSlide(g.currentSlide)[0].setAttribute('style','left:0;-webkit-transition: left '+(500*(Math.abs(e.distanceX)/treshold))+'ms linear;z-index:1'); | |
} | |
}); | |
} | |
g.container | |
.on('Zoomin',function(e){ | |
e.preventDefault(); | |
e.stopPropagation(); | |
var factor = e.isTouchEvent ? 0.02 : 0.1; | |
(g.zoom+=factor) > 2 && (g.zoom = 2); | |
g.container[0].style.webkitTransform = 'scale('+g.zoom+')'; | |
g.container[0].style.transform = 'scale('+g.zoom+')'; | |
}) | |
.on('Zoomout',function(e){ | |
e.preventDefault(); | |
e.stopPropagation(); | |
var factor = e.isTouchEvent ? 0.02 : 0.1; | |
(g.zoom-=factor) < 0.5 && (g.zoom = 0.5); | |
g.container[0].style.webkitTransform = 'scale('+g.zoom+')'; | |
g.container[0].style.transform = 'scale('+g.zoom+')'; | |
}) | |
; | |
} | |
gallery.prototype.getSlide = function(id){ | |
return this.slides[id]; | |
}; | |
gallery.prototype.goNext=function(){ | |
var g=this,next = g.currentSlide+1; | |
if( next > g.lastSlideId){ | |
next = 0; | |
} | |
if( $.fn.animate ){ | |
g.getSlide(g.currentSlide).animate({left:'-'+g.width},500); | |
(! g.draggable) && g.getSlide(next).css('left',g.width); | |
g.getSlide(next).animate({left:0},500); | |
}else{ | |
(function(cur,next){ | |
(! g.draggable) && next.setAttribute('style','left:'+g.width); | |
setTimeout(function(){ | |
next.setAttribute('style','left:0; -webkit-transition: left 500ms linear'); | |
cur.setAttribute('style','left:-'+g.width+'; -webkit-transition: left 500ms linear'); | |
},0); | |
})(g.getSlide(g.currentSlide)[0],g.getSlide(next)[0]); | |
} | |
g.currentSlide=next; | |
}; | |
gallery.prototype.goPrev=function(){ | |
var g=this, next = g.currentSlide-1; | |
if( next < 0 ){ | |
next = g.lastSlideId; | |
} | |
if( $.fn.animate ){ | |
g.getSlide(g.currentSlide).animate({left:g.width},500); | |
(! g.draggable) && g.getSlide(next).css('left','-'+g.width); | |
g.getSlide(next).animate({left:0},500); | |
}else{ | |
(function(cur,next){ | |
(! g.draggable) && next.setAttribute('style','left:-'+g.width); | |
setTimeout(function(){ | |
next.setAttribute('style','left:0; -webkit-transition: left 500ms linear'); | |
cur.setAttribute('style','left:'+g.width+'; -webkit-transition: left 500ms linear'); | |
},0); | |
})(g.getSlide(g.currentSlide)[0],g.getSlide(next)[0]); | |
} | |
g.currentSlide=next; | |
}; | |
gallery('#galleryTest',false); | |
gallery('#galleryTest2',true); | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*global $*/ | |
/*jshint expr:true*/ | |
/** | |
* Tutechie.js is a library made to support some basic touch/mouse events cross browser (depending on the underlying library u use). | |
* it can be used with basic-compat.js or zepto or even jquery | |
* it add following custom events : | |
* - Touchstart: triggered at touch start or mousedown if no touchStart event is enabled on android you should preventDefault the event emitted to track down further events | |
* - Tap: triggered when no movement occured and touch event is released before a Heldtap is triggered | |
* - Heldtap: this is a tap which duration was longer than longDelay it doesn't require to be ended to get triggered (no need to release the touchEvent) | |
* - Move: triggered after a Touchstart when moving arround more than treshold (extra event properties: pageX,pageY,distanceX,distanceY) | |
* - Moveend: triggered after a Move event occured when the user release the touch event (same extra properties as Move events) | |
* - Swipe: triggered when a user Move more than treshold px in a given direction (extra event properties: direction) | |
* - Zoomin/Zoomout: this is a pinch open/close or a mousewheel event (extra event properties: isTouchEvent) | |
* @param {Object} $ Description | |
* @returns {Object} Description | |
* @author jgotti at modedemploi dot fr for agence-modedemploi.com | |
* @licence Dual licence LGPL / MIT | |
*/ | |
(function($){ | |
"user strict"; | |
var tcEvent= {} | |
, startPosition={} | |
, currentPosition = {} | |
, distance = {} | |
, treshold = 20 | |
, longDelay = 500 | |
, longDelayCb = null | |
, b = $(document) | |
, scale = 1 | |
, emulateGesture = 'ongesturestart' in window ? false : {} | |
, touchCapable = 'ontouchstart' in window ? true : false | |
, scrollDetection = (emulateGesture && touchCapable) ? {interval:null,lastPos:[]} : false | |
; | |
function extendEvent(e,props){ | |
var type,event; | |
if( typeof props === 'string' ){ | |
type = props; | |
props = {}; | |
}else{ | |
type = props.type || e.type; | |
delete props.type; | |
} | |
props.originalEvent = e; | |
event = $.Event(type,props); | |
event.preventDefault = function(){ | |
if( e.preventDefault ){ | |
e.preventDefault(); | |
}else{ | |
e.returnValue=false; | |
} | |
}; | |
event.stopPropagation = function(){ | |
if( e.stopPropagation ){ | |
e.stopPropagation(); | |
} | |
e.cancelBubble = true; | |
}; | |
return event; | |
} | |
function resetEvent(e){ | |
tcEvent = {target:null,type:null,touchEvent:false,running:false}; | |
startPosition = {x:0,y:0}; | |
currentPosition = {x:0,y:0}; | |
distance = {x:0,y:0}; | |
if( longDelayCb ){ | |
clearTimeout(longDelayCb); | |
longDelayCb = null; | |
} | |
if( scrollDetection ){ | |
scrollDetection.interval && clearInterval(scrollDetection.interval); | |
scrollDetection.lastPos=[]; | |
scrollDetection.interval = null; | |
} | |
if( e && e.target ){ | |
tcEvent.target = e.target; | |
tcEvent.running = true; | |
var p = getPositionHolder(e),p2; | |
startPosition.x = p.pageX; | |
startPosition.y = p.pageY; | |
currentPosition = {x:startPosition.x,y:startPosition.y}; | |
if( emulateGesture && (p2=getPositionHolder(e,1)) && p2.pageX){ | |
startPosition.x2 = p2.pageX; | |
startPosition.y2 = p2.pageY; | |
startPosition.distance = Math.sqrt(Math.pow(startPosition.x2 - startPosition.x,2) + Math.pow(startPosition.y2 - startPosition.y,2)); | |
} | |
if( scrollDetection ){ | |
scrollDetection.lastPos = [window.pageXOffset,window.pageYOffset]; | |
scrollDetection.interval=setInterval(function(){ | |
if( window.pageXOffset !== scrollDetection.lastPos[0] || window.pageYOffset!==scrollDetection.lastPos[1]){ | |
b.off('touchmove',moveEvent); | |
resetEvent(); | |
} | |
},50); | |
} | |
} | |
} | |
function getTouches(e){ | |
return e.changedTouches || (e.originalEvent && e.originalEvent.changedTouches) || null; | |
} | |
function getPositionHolder(e,touchPos){ | |
touchPos !== undefined || (touchPos = 0); | |
var holder=e, touches = getTouches(e); | |
if( touches && touches.length ){ | |
tcEvent.touchEvent = true; | |
holder = touches[touchPos]; | |
}else{ | |
tcEvent.touchEvent = false; | |
} | |
return holder; | |
} | |
function setXYFromEvent(e){ | |
var p = getPositionHolder(e); | |
currentPosition.x=p.pageX; | |
currentPosition.y=p.pageY; | |
distance.x = currentPosition.x - startPosition.x; | |
distance.y = currentPosition.y - startPosition.y; | |
return currentPosition; | |
} | |
function fillEmulateGesture(e){ | |
var pos=getPositionHolder(e,1),lastDistance=emulateGesture.distance||startPosition.distance; | |
emulateGesture = { | |
x:pos.pageX | |
,y:pos.pageY | |
,distance: Math.sqrt(Math.pow(pos.pageX - currentPosition.x,2) + Math.pow(pos.pageY - currentPosition.y,2)) | |
}; | |
if( Math.abs(emulateGesture.distance - lastDistance) < treshold/2 ){ | |
emulateGesture.distance = lastDistance; | |
} | |
emulateGesture.scale = emulateGesture.distance / startPosition.distance; | |
} | |
function eventStart(e){ | |
var touches = getTouches(e); | |
if( touches && touches.length ){ | |
tcEvent.touchEvent = true; | |
}else{ | |
if( e.button !== 0){ return; } // don't track non left mouse button events | |
tcEvent.touchEvent = false; | |
} | |
if( tcEvent && tcEvent.type ){ | |
return; | |
} | |
resetEvent(e); | |
var event = extendEvent(e,'Touchstart'); | |
$(tcEvent.target).trigger(event); | |
longDelayCb = setTimeout(function(){ tcEvent.running && (tcEvent.type === null) && longTapEnd(); },longDelay); | |
} | |
function eventEnd(e){ | |
if( tcEvent.touchEvent===false && e.button !== 0){ return; } // don't track non left mouse button events | |
if(! tcEvent.running ){ return; } | |
setXYFromEvent(e); | |
if( tcEvent.type === null && Math.abs(distance.x) < treshold && Math.abs(distance.y) < treshold ){ | |
$(tcEvent.target).trigger(extendEvent(e,'Tap')); | |
//moveEnd(e); | |
resetEvent(); | |
return; | |
} | |
if( tcEvent.type !== 'Move'){ | |
tcEvent.type === 'gesture' && gestureEventEnd(e); | |
return; | |
} | |
var eventData; | |
if( Math.abs(distance.x) > Math.abs(distance.y)){ | |
eventData={direction:distance.x < 0 ? 'left' : 'right'}; | |
}else{ | |
eventData={direction:distance.y < 0 ? 'up' : 'down'}; | |
} | |
eventData.type = 'Swipe'; | |
$(tcEvent.target).trigger(extendEvent(e,eventData)); | |
moveEnd(e); | |
resetEvent(); | |
} | |
function longTapEnd(){ | |
if(tcEvent.type !== null || ! tcEvent.running ){ return; } | |
if( treshold > Math.abs(distance.x) && treshold > Math.abs(distance.y) ){ // this is a longtap event | |
b.off(tcEvent.touchEvent?'touchmove':'mousemove',moveEvent); // stop tracking movement | |
tcEvent.type = 'Heldtap'; | |
$(tcEvent.target).trigger('Heldtap'); | |
resetEvent(); | |
} | |
} | |
function moveEvent(e){ | |
setXYFromEvent(e); | |
if(! tcEvent.running ){ return; } | |
var touches = getTouches(e); | |
if( tcEvent.type !== 'gesture' && tcEvent.touchEvent && emulateGesture && touches && touches.length > 1){ // we consider to be in a gestureEvent | |
return gestureEventStart(e); | |
} | |
if( emulateGesture && tcEvent.type === 'gesture'){ | |
return gestureEvent(e); | |
} | |
if( Math.abs(distance.x) < treshold && Math.abs(distance.y) < treshold){ | |
return; | |
}else if(tcEvent.type && tcEvent.type !== 'Move'){ | |
return; | |
} | |
tcEvent.type = 'Move'; | |
$(tcEvent.target).trigger(extendEvent(e,{ | |
type:'Move' | |
,pageX:currentPosition.x | |
,pageY:currentPosition.y | |
,distanceX:distance.x | |
,distanceY:distance.y | |
})); | |
} | |
function moveEnd(e){ | |
setXYFromEvent(e); | |
if(! tcEvent.running){ return;} | |
/*if( tcEvent.type==='gesture'){ | |
return gestureEventEnd(e); | |
}*/ | |
if( tcEvent.type !== 'Move'){ return; } | |
$(tcEvent.target).trigger(extendEvent(e,{ | |
type:'Moveend' | |
,pageX:currentPosition.x | |
,pageY:currentPosition.y | |
,distanceX:distance.x | |
,distanceY:distance.y | |
})); | |
} | |
function gestureEventStart(e){ | |
if( tcEvent.type !== null ){ | |
return; | |
} | |
if( 'scale' in e){ | |
scale = e.scale; | |
}else{ | |
fillEmulateGesture(e); | |
scale = 1; | |
} | |
resetEvent(e); | |
tcEvent.type = 'gesture'; | |
} | |
function gestureEvent(e){ | |
var direction,event; | |
if( e.wheelDelta ){ | |
direction = e.wheelDelta > 0 ?'in':'out'; | |
event = extendEvent(e,{ | |
type: 'Zoom'+direction | |
,direction: direction | |
,isTouchEvent:false | |
}); | |
}else if( e.detail ){ | |
direction = e.detail < 0 ?'in':'out'; | |
event = extendEvent(e,{ | |
type: 'Zoom'+direction | |
,direction: direction | |
,isTouchEvent:false | |
}); | |
}else if( e.scale !== scale ){ | |
if( emulateGesture ){ | |
fillEmulateGesture(e); | |
e.scale = emulateGesture.scale; | |
if( scale === e.scale){ return; } | |
} | |
direction = e.scale > scale ?'in':'out'; | |
event = extendEvent(e,{ | |
type: 'Zoom'+direction | |
,direction: direction | |
,isTouchEvent:true | |
}); | |
scale = e.scale; | |
} | |
if(direction){ | |
$(tcEvent.target).trigger(event); | |
(event.type = 'Zoom') && $(e.target).trigger(event); | |
} | |
} | |
function gestureEventEnd(e){ | |
scale = 1; | |
emulateGesture && (emulateGesture={}); | |
resetEvent(); | |
} | |
$(function(){ | |
if(! emulateGesture){ | |
b.on('gesturestart',gestureEventStart) | |
.on('gesturechange',gestureEvent) | |
.on('gestureend',gestureEventEnd) | |
; | |
}else if(! touchCapable) { | |
if('onmousewheel' in window){ | |
b.on('mousewheel',function(e){ | |
!e && (e = window.event); | |
gestureEventStart(e); | |
gestureEvent(e); | |
gestureEventEnd(e); | |
}); | |
}else{ | |
b.on('DOMMouseScroll',function(e){ | |
gestureEventStart(e); | |
gestureEvent(e); | |
gestureEventEnd(e); | |
}); | |
} | |
} | |
if( touchCapable){ | |
b | |
.on('touchstart',function(e){ | |
b.on('touchmove',moveEvent); | |
eventStart(e); | |
}) | |
.on('touchend',function(e){ | |
b.off('touchmove',moveEvent); | |
eventEnd(e); | |
}) | |
.on('blur touchcancel',function(){ //stop tracking touch events when loosing focus | |
b.off('touchmove',moveEvent); | |
resetEvent(); | |
}) | |
; | |
}else{ | |
b | |
.on('mousedown',function(e){ | |
b.on('mousemove',moveEvent); | |
eventStart(e); | |
}) | |
.on('mouseup',function(e){ | |
b.off('mousemove',moveEvent); | |
eventEnd(e); | |
}) | |
.on('blur',function(){ //stop tracking touch events when loosing focus | |
b.off('mousemove',moveEvent); | |
resetEvent(); | |
}) | |
; | |
} | |
}); | |
})($); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment