Skip to content

Instantly share code, notes, and snippets.

@jtangelder
Last active January 17, 2024 21:55
Show Gist options
  • Save jtangelder/361052976f044200ea17 to your computer and use it in GitHub Desktop.
Save jtangelder/361052976f044200ea17 to your computer and use it in GitHub Desktop.
PreventGhostClick
/**
* Prevent click events after a touchend.
*
* Inspired/copy-paste from this article of Google by Ryan Fioravanti
* https://developers.google.com/mobile/articles/fast_buttons#ghost
*
* USAGE:
* Prevent the click event for an certain element
* ````
* PreventGhostClick(myElement);
* ````
*
* Prevent clicks on the whole document (not recommended!!) *
* ````
* PreventGhostClick(document);
* ````
*
*/
(function(window, document, exportName) {
var coordinates = [];
var threshold = 25;
var timeout = 2500;
// no touch support
if(!("ontouchstart" in window)) {
window[exportName] = function(){};
return;
}
/**
* prevent clicks if they're in a registered XY region
* @param {MouseEvent} ev
*/
function preventGhostClick(ev) {
for (var i = 0; i < coordinates.length; i++) {
var x = coordinates[i][0];
var y = coordinates[i][1];
// within the range, so prevent the click
if (Math.abs(ev.clientX - x) < threshold && Math.abs(ev.clientY - y) < threshold) {
ev.stopPropagation();
ev.preventDefault();
break;
}
}
}
/**
* reset the coordinates array
*/
function resetCoordinates() {
coordinates = [];
}
/**
* remove the first coordinates set from the array
*/
function popCoordinates() {
coordinates.splice(0, 1);
}
/**
* if it is an final touchend, we want to register it's place
* @param {TouchEvent} ev
*/
function registerCoordinates(ev) {
// touchend is triggered on every releasing finger
// changed touches always contain the removed touches on a touchend
// the touches object might contain these also at some browsers (firefox os)
// so touches - changedTouches will be 0 or lower, like -1, on the final touchend
if(ev.touches.length - ev.changedTouches.length <= 0) {
var touch = ev.changedTouches[0];
coordinates.push([touch.clientX, touch.clientY]);
setTimeout(popCoordinates, timeout);
}
}
/**
* prevent click events for the given element
* @param {EventTarget} el
*/
window[exportName] = function(el) {
el.addEventListener("touchstart", resetCoordinates, true);
el.addEventListener("touchend", registerCoordinates, true);
};
document.addEventListener("click", preventGhostClick, true);
})(window, document, 'PreventGhostClick');
@kosich
Copy link

kosich commented Apr 2, 2015

please, check this one
its based not on blocking some square on the screen, but rather blocking events from other device (after touch interaction mouse events are blocked for some period and vice versa)
note: its a draft for angular-hammer use, so one would need to modify it a little to use with native elements ( atm it accepts jQuery element and addresses dom via element[0] )

@singleclown
Copy link

It's great, but I don't know how to restore it. How about restoring it with removeEventListener?

Copy link

ghost commented Jun 17, 2019

using PreventGhostClick(document) disables all anchor <a href="valid-link-here">, is there a solution to make it work?

Copy link

ghost commented Jul 4, 2019

What about using this instead (for tap/click)?
https://github.com/ftlabs/fastclick/blob/master/lib/fastclick.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment