Track swipes with Google Analytics - javascript

I have a swipe functionality on my mobile page, and I want to used touchstart, touchend, and touchmove to track the swipe functionality across the device without affecting the scrolling.
Here is my code.
jQuery('.first-frame').bind('touchmove', function(event) {
_gaq.push(['_trackEvent', 'Landing-Page', 'Swipe-Toggle-Color', '0259_2190']);
});

If it's possible to only monitor the swipeleft and swiperight events in jQuery Mobile instead, do so.
Otherwise, you can set a global variable on the scroll event that resets after, say, 0.2 seconds. Then have the touchmove event check if that variable is set, and if it is, don't trigger Google Analytics.
window.is_scrolling = false; // global variable
window.timeout_id = 0;
window.onscroll = function() {
window.is_scrolling = true;
clearTimeout(window.timeout_id);
window.timeout_id = setTimeout(function() {
window.is_scrolling = false;
}, 200); // milliseconds
};
jQuery('.first-frame').bind('touchmove', function(event) {
if (!window.is_scrolling)
_gaq.push(['_trackEvent', 'Landing-Page', 'Swipe-Toggle-Color', '0259_2190']);
});

I know you asked for a touchmove, touchend, and touchstart example but I would use a combination of HammerJS (https://github.com/EightMedia/hammer.js/) and custom Google events to take the guess work out of it.
var element = $(".first-frame")[0];
var trackswipe = Hammer(element, {
drag: false,
transform: false,
swipe: true,
swipeVelocityX: 0 // Adjust to liking...
}).on("swipe", function(event) {
if (event.gesture.direction === "left") {
// Track Something
return false;
} else if (event.gesture.direction === "right") {
// Track something else.
return false;
}
return false;
});

Related

track-pad tap event in javascript/jquery

Is there any way to handle tap from track pad of mac?
I need to handle 'tap' and 'click' on track-pad, especially on mac.
I tried
$.event.special.tap = {
setup: function(data, namespaces) {
var $elem = $(this);
$elem.bind('touchstart', $.event.special.tap.handler)
.bind('touchmove', $.event.special.tap.handler)
.bind('touchend', $.event.special.tap.handler);
},
teardown: function(namespaces) {
var $elem = $(this);
$elem.unbind('touchstart', $.event.special.tap.handler)
.unbind('touchmove', $.event.special.tap.handler)
.unbind('touchend', $.event.special.tap.handler);
},
handler: function(event) {
event.preventDefault();
var $elem = $(this);
$elem.data(event.type, 1);
if (event.type === 'touchend' && !$elem.data('touchmove')) {
event.type = 'tap';
$.event.handle.apply(this, arguments);
} else if ($elem.data('touchend')) {
$elem.removeData('touchstart touchmove touchend');
}
}
};
$('.thumb img').bind('tap', function() {
//bind tap event to an img tag with the class thumb
}
Which didn't work.
How to capture tap event on the track-pad?
I'm having this same concern. It appears that the trackpad on the MacBook (for example) doesn't fire TouchEvents like an actual touch device would. It is instead converting gestures into MouseEvents.
document.addEventListener('mousewheel', function(e) {
console.log(e.wheelDelta);
});
document.addEventListener('touchstart', function(e) {
console.log(e);
});
In the above example, when I attempt to capture the "pinch/zoom" gesture on a trackpad, I'm actually getting back Delta from a scroll wheel as if I'd held down CTRL and then scrolled up or down, returning a wheelDelta value of 120 or -120. Putting event listeners on for 'touchstart' doesn't not write to the console as I prescribe unless it's on a touch device like a tablet or smart phone.
Obviously, the MackBook can detect when you've touched the trackpad since it's able to then detect your movement, but it does not appear to be available through the document.

Temporarily disable touchstart event

I have a mobile based web application. Currently I am encountering an issue when ajax calls are being made. The wait spinner which is enclosed in a div can be clicked through on the ipad device. The javascript event being triggered is touchstart. Is there anyway to prevent this event from going through normal processing?
Tried to call the following, however it did not work.
Disable
document.ontouchstart = function(e){ e.preventDefault(); }
Enable
document.ontouchstart = function(e){ return true; }
How touchstart is handled
$(document).on('touchstart', function (eventObj) {
//toggle for view-icon
if (eventObj.target.id == "view-icon") {
$("#view-dropdown").toggle();
} else if ($(eventObj.target).hasClass("view-dropdown")) {
$("#view-dropdown").show();
} else {
$("#view-dropdown").hide();
}
});
As user3032973 commented, you can use a touchLocked variable, which is working perfectly.
I have used it in combination with the Cordova Keyboard-Plugin. Scrolling will be disabled the time the keyboard is shown up and reenabled the time the keyboard is hiding:
var touchLocked = false;
Keyboard.onshowing = function () {
touchLocked = true;
};
Keyboard.onhiding = function () {
touchLocked = false;
};
document.ontouchstart = function(e){
if(touchLocked){
e.preventDefault();
}
};

Define moving direction javascript (Android device)

I am writing PhoneGap application, and use swipe and scroll on one view. For scroll I use native scroll (I have tried to use iScroll, but there are many inputs in my view, so the better solution that I found it is a native scroll). For defining direction of moving I am gathering first 10 touchmove events in array and check clientX and clienY values and than define average value. And all should be good, but in Android touchmove event does not work is scroll view without preventDefault(). So, according this issue, I use preventDefault() for first ten touchmove events and than depending on direction continue use preventDefault() and make swipe, or don't use preventDefault() and make scroll. But when I make scroll nothing happens(. There is an example:
var list = document.querySelector('ul');
var arr = [];
var ev = document.createEvent('UIEvent');
var evEnd = document.createEvent('UIEvent');
var evCancel = document.createEvent('UIEvent');
var flag = false;
ev.initUIEvent("touchstart", true, true);
evEnd.initUIEvent("touchend", true, true);
evCancel.initUIEvent("touchcancel", true, true);
list.addEventListener('touchstart', startMove, false)
list.addEventListener('touchend', endMove, false)
function startMove(e){
list.addEventListener('touchmove', move, false)
}
function move(e){
if(flag){
return;
}
e.preventDefault();
arr.push(e);
if(arr.length>10){
flag = true;
list.dispatchEvent(evEnd);
list.dispatchEvent(evCancel);
list.dispatchEvent(ev);
return;
}
}
function endMove(e){
list.removeEventListener('touchmove', move, false)
list.removeEventListener('touchend', endMove, false)
}
http://jsfiddle.net/tnqHQ/17/

Javascript: Any workarounds for getting Chrome for Android to fire off touchmove and touchend event listeners other than using event.preventDefault()?

When using event listeners with the touchmove and touchend events, I can't get Chrome for Android to acknowledge those events unless I first use event.preventDefault(); earlier in the code. If I'm not wanting to block the default scroll functionality, is there any other workaround I can use to get Chrome for Android to acknowledge these events?
Sample code:
$(document).ready(function () {
// Bind touch event listeners.
var elem = $('html').get(0);
elem.addEventListener('touchstart', function (e) { console.info('"touchstart" detected. Coordinates - ' + getCoord(e)); });
elem.addEventListener('touchmove', function (e) { console.info('"touchmove" detected. Coordinates - ' + getCoord(e)); });
elem.addEventListener('touchend', function (e) { console.info('"touchend" detected. Coordinates - ' + getCoord(e)); });
function getCoord(e) {
var touch = false;
if (e.touches.length > 0) {
touch = e.touches[0];
} else {
touch = e.changedTouches[0];
}
if (touch) {
return 'x: ' + touch.pageX + ', y: ' + touch.pageY;
}
}
Example fiddle here: http://jsfiddle.net/jQ2VS/1/
Google Chrome will fire a touchcancel event about 200 milliseconds after touchstart if it thinks the user is panning/scrolling and you do not call event.preventDefault().
Assuming that you want to intercept horizontal touch events and let vertical touch events cause panning/scrolling, a workaround would be:
On touchstart, store the coordinates in a variable, and set iteration to 0.
For each touchmove event, set iteration to iteration+1.
When iteration is equal to 4 (just a "magic number" I found to be reliable on my set-up), calculate the total touch offset deltas for x- and y- axes.
EDIT: on mobile devices you'll only receive one touchmove without event.preventDefault()
If x-axis offset > y-axis offset * 3 then fire event.preventDefault(). (This ensures the the gesture is pretty much horizontal)
The down-side for this is that user can only either swipe left/right or scroll up/down.
Finally I found the solution (pure js) even in case you might want use it for swipe:
var swipe = function() {
var touchX, touchY, movX, movY, go;
function prevent(e){
e.preventDefault();
}
function start(e) {
go = false;
document.addEventListener("touchmove", prevent, false);
touchX = e.touches[0].pageX;
touchY = e.touches[0].pageY;
}
function move(e) {
movX = e.touches[0].pageX - touchX;
movY = e.touches[0].pageY - touchY;
if(!go) {
(Math.abs(movY) < Math.abs(movX)) ? go = true : stop(e);
} else {
/* *************** */
// cast your spell
/* *************** */
}
}
function stop(e) {
document.removeEventListener("touchmove", prevent, false);
}
document.addEventListener("touchstart", start, true);
document.addEventListener("touchmove", move, true);
document.addEventListener("touchend", stop, true);
document.addEventListener("touchleave", stop, true);
document.addEventListener("touchcancel", stop, true);
}
Hope this help.
The simplest answer is that you have to preventDefault on the first touchmove event otherwise they will be cancelled.
I found that preventing the touchcancel worked fine.
The accepted answer is not correct.
On Android if preventDefault is not set on touchstart the device assumes native scrolling and no more touch events are sent to webview. If preventDefault is set all native scrolling is disabled.
There is a shim to provide swipe events with native scrolling here : https://github.com/TNT-RoX/android-swipe-shim

how to prevent jumping site when scrolling?

I'm trying to write mechanism on site which prevents users to scroll normally. When user scrolls down or up the site is smoothscrolling to next or previous slide (depends on scrolling direction) and stops there (like when you click on a navbar). See live preview: CLICK HERE
But there's an annoying problem. It works almost good in FF (no jumping), but breaks in another browsers (Chrome, Safari, IE)- it jumps. How can I prevent this?Here are snippets from my code.
I have a ScrollControl object where I prevent scrolling:
scrollControl = {
keys : [32, 37, 38, 39, 40],
scrollTimer : 0,
lastScrollFireTime : 0,
preventDefault : function(e){
e = e || window.event;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
},
keydown : function(e){
for (var i = scrollControl.keys.length; i--;) {
if (e.keyCode === scrollControl.keys[i]) {
scrollControl.preventDefault(e);
return;
}
}
},
wheel : function(e){
scrollControl.preventDefault(e);
},
disableScroll : function(){
if (window.addEventListener) {
window.addEventListener('DOMMouseScroll', scrollControl.wheel, false);
}
window.onmousewheel = document.onmousewheel = scrollControl.wheel;
document.onkeydown = scrollControl.keydown;
},
enableScroll : function(){
if (window.removeEventListener) {
window.removeEventListener('DOMMouseScroll', scrollControl.wheel, false);
}
window.onmousewheel = document.onmousewheel = document.onkeydown = null;
}
}
Then I'm listening if mousewheel occurs and trying to execute function only once (I'm using this plugin to detect mousewheel PLUGIN )
$(window).mousewheel(function(objEvent, intDelta){
var minScrollTime = 1000;
var now = new Date().getTime();
function processScroll() {
console.log("scrolling");
if(intDelta>0){
$.smoothScroll({
speed:med.effectDuration,
easing:med.scrollEase,
scrollTarget:med.prevPage,
afterScroll: function(){
med.currentPage = med.prevPage;
med.setActiveNav();
med.setSlides();
med.runAnimations();
}});
}else if(intDelta<0){
//scrollControl.disableScroll();
$.smoothScroll({
speed:med.effectDuration,
easing:med.scrollEase,
scrollTarget:med.nextPage,
afterScroll: function(){
med.currentPage = med.nextPage;
med.setActiveNav();
med.setSlides();
med.runAnimations();
}});
}
}
if (!scrollControl.scrollTimer) {
if (now - scrollControl.lastScrollFireTime > (3 * minScrollTime)) {
processScroll(); // fire immediately on first scroll
scrollControl.lastScrollFireTime = now;
}
scrollTimer = setTimeout(function() {
scrollControl.scrollTimer = null;
scrollControl.lastScrollFireTime = new Date().getTime();
processScroll();
}, minScrollTime);
}
});
I'm executing scrollControl.disableScroll function on DOM ready event when users starts website. And actually scrolling once prevention doesn't works prefectly and sometimes it triggers smoothscrolling twice. What am I doing wrong? Thanks in advance for any suggestions!
I had the same issue the Mouse Wheel Event was fired Twice.
function wheelDisabled(event){
event.preventDefault();
event.stopImmediatePropagation();
return false;
}
Also you might use both of these Events.
window.addEventListener('DOMMouseScroll', wheel, false);
window.addEventListener('mousewheel', wheel, false);
Instead of trying to prevent scrolling with Javascript, I would try a different approach. This approach includes CSS and Javascript to make sure the website is never bigger then the viewport (hence no scrollbars!).
Use CSS to force the main wrapping div (a div that wraps all the content on the site) to have overflow: hidden. Then use Javascript to dynamically ensure that the height and width of this div is always equal to the viewport's height and width.
In this scenario, if you want to implement scrolling in a predefined way you choose you can dynamically add negative margin-top (or negative margin-left for horizontal scrolling) to the parent wrapping div to give it the appearance that it is scrolling.

Categories