TL;DR; The below code can be added as a script to your page to implement a touchdown event detection and directly attach it to a “menu” element
async function swipedetect(el, callback, threshold=50, minimumTime=150, allowedTime=2000){
var touchsurface = el,
swipedir,
startX,
startY,
distX,
distY,
threshold = threshold, //required min distance traveled to be considered swipe in X
// restraintX = restraintX, // maximum distance allowed at the same time in perpendicular direction in X
// thresholdY = thresholdY, //required min distance traveled to be considered swipe in Y
// restraintY = restraintY, // maximum distance allowed at the same time in perpendicular direction in Y
minimumTime = minimumTime, // maximum time allowed to travel that distance
allowedTime = allowedTime, // maximum time allowed to travel that distance
elapsedTime,
startTime,
handleswipe = callback || function(swipedir){}
touchsurface.addEventListener('touchstart', function(e){
var touchobj = e.changedTouches[0]
swipedir = 'none'
dist = 0
startX = touchobj.pageX
startY = touchobj.pageY
startTime = new Date().getTime() // record time when finger first makes contact with surface
// e.preventDefault()
}, false)
touchsurface.addEventListener('touchmove', function(e){
e.preventDefault() // prevent scrolling when inside DIV
}, false)
touchsurface.addEventListener('touchend', function(e){
var touchobj = e.changedTouches[0]
distX = touchobj.pageX - startX; // get horizontal dist traveled by finger while in contact with surface
distY = touchobj.pageY - startY; // get vertical dist traveled by finger while in contact with surface
dist = distY * distY + distX * distX;
dist = Math.sqrt(dist);
elapsedTime = new Date().getTime() - startTime; // get time elapsed
// calculate the angle of the movement
angle = (Math.atan2(distY, distX) / Math.PI * 180)
// convert angle to a sector of the movement
// offsetting it by 45 degreees to get the movement easier.
// and ensuring its positive
sector = (angle + 45 + 360) % 360;
sector = Math.floor(sector/90);
if (elapsedTime >= minimumTime && elapsedTime <= allowedTime && dist >= threshold){ // first condition for a swipe met
switch (sector) {
case 0: swipedir = "right"; break;
case 1: swipedir = "up"; break;
case 2: swipedir = "left"; break;
case 3: swipedir = "down"; break;
}
}
handleswipe(swipedir)
if (dist >= threshold) {
e.preventDefault()
}
}, false)
}
async function swipe_enable(elementid='menu', table={'right':'a', 'up':'w', 'left':'d', 'down':'s', 'none': null}) {
var el = document.getElementById(elementid);
if (el) {
swipedetect(el, async function(swipedir){
//swipedir contains either "none", "left", "right", "top", or "down"
let key = table[swipedir];
document.dispatchEvent(new KeyboardEvent('keypress', {'key': key}));
})
}
}
Handling a touchdown event via vanilla JS is nothing new, and I also took the initial implementation from a website I cannot find anymore. The structure was similar to this gist and the related discussion, as in initially I simply added a touchdown but the detection of right/left/up/down was patchy until I also added the direction sector. Additionally, I did not want to attach it all the time to each element etc. but instead added another function that handles the attaching.
Now I can simply have the above in a js-lib file and source it on our data visualisation page, then call swipe_enable() in the doc.ready function and be certain that swiping is handled on the corresponding element (with selects in this case). This makes usage of the page far easier on mobile devices; highly relevant if you are in the field like in CLOUDLAB and your phone is the only thing available due to the windy/rainy/snowy weather.