My approach involves utilizing a couple of different strategies, one of which relies on a manual implementation of setTimeout to activate a specific property. While I will delve into this method shortly, it is worth considering the usage of touchstart, touchmove, and touchend events for touch devices, as well as mouseover events for desktop interactions.
In situations where event.preventDefault is called (remember that the event must not be passive for this to function with touchstart), any subsequent mouse calls will be canceled automatically, simplifying the handling process. However, if this behavior does not align with your intentions, an alternative solution can be explored using your preferred DOM manipulation library and element references:
Implementing setTimeout
library.select(elem) //select the desired element
.property("_detectTouch",function(){//establish a _detectTouch method to temporarily set a property on the element
return function(){
this._touchDetected = true;
clearTimeout(this._timeout);
this._timeout = setTimeout(function(self){
self._touchDetected = false;//adjust accordingly based on your scenario; for combined touch and desktop support, consider setting it between 300-400ms
},10000,this);
}
}).on("click",function(){
/*perform certain actions*/
}).on("mouseover",function(){
if (this._touchDetected) {
/*interaction from a touch-based device*/
} else {
/*desktop interaction*/
}
}).on("touchstart",function(){
this._detectTouch();//execute the property method defined earlier
toggleClass(document.body,"lock-scroll",true);//disable scrolling by hiding overflow-y on the body element
}).on("touchmove",function(){
disableScroll();//if the previous overflow-y adjustment fails, use another method to prevent scroll on iOS
}).on("touchend",function(){
library.event.preventDefault();//ensure event propagation is halted; note: calling this in touchstart may trigger Chrome warnings (unless explicitly declared non-passive)
this._detectTouch();
var touchObj = library.event.targetTouches &&& library.event.targetTouches.length
? library.event.targetTouches[0]
: library.event.changedTouches[0];
if (elem.contains(document.elementFromPoint(touchObj.clientX,touchObj.clientY))) {//verify if the touch remains within the designated element
this.click();//invoke click action since default has been prevented during touchend
}
toggleClass(document.body,"lock-scroll",false);//re-enable scrolling functionality
enableScroll();//restore scrolling capabilities
})
An alternative technique without relying on setTimeout involves treating mouseover as an opposite of touchstart, and mouseout as counter to touchend. By establishing properties through touch events and detecting them in subsequent mouse events, you can create a seamless transition between touch and desktop interactions:
Implementation without setTimeout
....
.on("mouseover",function(dd,ii){
if (this._touchStarted) {//triggered by touch device
this._touchStarted = false;
return;
}
/*desktop interaction*/
})
.on("mouseout",function(dd,ii){//similar concept as above
if(this._touchEnded){
this._touchEnded = false;
return;
}
})
.on("touchstart",function(dd,ii){
this._touchStarted = true;
/*perform specific actions*/
})
.on("touchend",function(dd,ii){
library.event.preventDefault();//ensure emulated events are suppressed completely at this stage, leveraging attached properties for further control
this._touchEnded = true;
/*perform additional actions*/
});
While some details have been omitted for brevity, the core concepts remain intact within these implementations.