I’m trying to implement a simple custom scrolling method in my mobile web app. I’m having trouble with the vertical scrolling where I’d like to have a little momentum effect if the page is ‘flicked’.
The problem is detecting a “flick” gesture, (the velocity and perhaps length of that gesture) after a dragging gesture, changing direction and what not. Hope you understand what I mean, you can drag the page up or down and at the end of that drag, I’d like to detect if there is also a flick..
How do you separate the two? How does such a logic look?
Many thanks for any help.
The code: (sorry if this excerpt is a bit of a mess)
var Device = function() {
//define some private variablees
var startY,
startX,
startTime,
deltaY = 0,
deltaX = 0,
lastY,
currentPage,
nextPage,
prevPage,
directionY,
lastTime,
pages,
pane,
offsetX = 0,
offsetY = 0,
isPanning,
isScrolling,
isTouch = "ontouchstart" in window;
return {
init: function() {
document.getElementById('frame').addEventListener(isTouch ? 'touchstart' : 'mousedown', Device.onTouchStart, false);
//get all panes in an array
panes = document.querySelectorAll('.pane');
},
onTouchStart: function (evt) {
//get X and Y of the touch event
var touch = isTouch ? event.touches[0] : event;
startY = touch.clientY;
//add listener for touch move and end
document.addEventListener(isTouch ? 'touchmove' : 'mousemove', Device.onTouchMove, false);
document.addEventListener(isTouch ? 'touchend' : 'mouseup', Device.onTouchEnd, false);
startTime = new Date();
},
onTouchMove: function (evt) {
//get X and Y of the touch event
var touch = isTouch ? event.touches[0] : event;
currentY = touch.clientY;
//calc touch length
deltaY = currentY - startY;
//Detect if scroll is bigger than threshold 5px
if (Math.abs(deltaY) > 5 && !isPanning) {
isScrolling = true;
//get the element
pane = panes[0];
//set new position
offsetY = pane.lastOffset + deltaY;
//call animation
Device.scrollTo(pane,0,offsetY);
}
//detect last direction
directionY = (lastY >= currentY) ? 1 : 0;
//roll over last variables
lastY = currentY;
lastTime = new Date();
},
onTouchEnd: function () {
//timing
var endTime = new Date();
var velocity = (endTime - lastTime).toFixed(0);
console.log('velocity: ' + velocity);
//TEMPORARY
pane.lastOffset = offsetY;
isScrolling = false;
//housekeeping
document.removeEventListener(isTouch ? 'touchmove' : 'mousemove', Device.onTouchMove, false);
document.removeEventListener(isTouch ? 'touchend' : 'mouseup', Device.onTouchEnd, false);
//call for momentum
Device.doMomentum(velocity);
},
scrollTo: function(el,x,y) {
if (el) {
el.style['-webkit-transition-timing-function'] = '';
el.style['-webkit-transition-duration'] = '0ms';
el.style[ 'WebkitTransform' ] = 'translate3d('+x+'px,'+y+'px, 0px)';
}
},
animateTo: function(el,x,y) {
if (el) {
el.style['-webkit-transition-timing-function'] = 'cubic-bezier(0,0,0.25,1)';
el.style['-webkit-transition-duration'] = '300ms';
el.style[ 'WebkitTransform' ] = 'translate3d('+x+'px,'+y+'px, 0px)';
}
},
doMomentum: function(velocity) {
console.log((directionY == 1) ? 'up': 'down');
console.log('pane.lastOffset: ' + pane.lastOffset);
var endPosition;
if (directionY == 1) {
endPosition = pane.lastOffset - velocity;
} else {
endPosition = parseFloat(pane.lastOffset) + parseFloat(velocity);
}
console.log(endPosition);
Device.animateTo(pane,0,endPosition);
pane.lastOffset = endPosition;
}
FYI, what I ended up doing was simply using the time elapsed between
onTouchMove-event and theonTouchEnd-event.Basically, I have a date variable that continuously overwrites itself in the
onTouchMovecallback:And then
onTouchEndI get an endTime value and evaluate the difference. If this time is very low, then I assume there was a “flick” at the end.This is very simple but actually works reasonably well.