Reputation: 115
I read about touchenter and touchleave events, at mozilla website and w3 website, but can not find any browser to support it or any javascript library that mimics that effect.
Please suggest what could be done as there workaround, as I am working for some mouseover like effect , event gets triggered when fingers enter the element, not when user lifts and touches elements again.
Thanks :)
Upvotes: 10
Views: 19338
Reputation: 373
This works for me. In callbacks I just need the element; not the mouse/touch event and not the context (don't use 'this' in callback).
pointer.ts
/**
* Simulate touchenter and touchleave by tracking touchmove. See https://stackoverflow.com/questions/23111671/touchenter-and-touchleave-events-support
*/
const touchEventSimulator = {
// enterElementCallback stores element as key and callback as value
enterElementCallback: new Map(),
leaveElementCallback: new Map(),
previousElement: null,
init: function() {
window.addEventListener('touchmove', event => {
var currentElement = document.elementFromPoint(event.touches[0].clientX, event.touches[0].clientY)
if (currentElement !== this.previousElement) {
// touch leave
const leaveCallback = this.leaveElementCallback.get(this.previousElement)
if (leaveCallback) {
leaveCallback.call(null, this.previousElement)
}
// touch enter
const enterCallback = this.enterElementCallback.get(currentElement)
if (enterCallback) {
enterCallback.call(null, currentElement)
}
// Current element will be the previous one, next time we check.
this.previousElement = currentElement;
}
});
},
onEnter(element, callback) {
this.enterElementCallback.set(element, callback);
},
onLeave(element, callback) {
this.leaveElementCallback.set(element, callback);
}
}
const mouseAvailable = matchMedia('(pointer:fine)').matches;
/**
* Pointer is a wrapper for mouse and (simulated) touch events
*/
export const pointer = {
mouseAvailable,
init() {
if (!mouseAvailable) {
touchEventSimulator.init()
}
},
onEnter: (element, callback) => {
if (mouseAvailable) {
element.addEventListener('mouseenter', ()=>callback.call(null, element))
} else {
touchEventSimulator.onEnter(element, callback)
}
},
onLeave: (element, callback) => {
if (mouseAvailable) {
element.addEventListener('mouseleave', ()=>callback.call(null, element))
} else {
touchEventSimulator.onLeave(element, callback)
}
}
}
example.ts
import {pointer} from './pointer';
pointer.init();
const element = document.getElementById('test');
pointer.onEnter(anchor, element=>{
console.log('enter', element)
})
pointer.onLeave(anchor, element=>{
console.log('leave', element)
})
Upvotes: 0
Reputation: 2369
Currently, there is no support for such events at core, however it is possible to simulate them.
I Created a small script to make onTouchEnter and onTouchLeave methods available. Very simple use (To test the snippet activate the mobile version of this website, or use it at a smartphone browser)
onTouchEnter('.some-selector', function(element,event){/*DO ANYTHING*/})
onTouchLeave('.some-selector', function(element,event){/*DO ANYTHING*/})
The script bellow uses document.elementFromPoint to make the magic.
let onTouchLeaveEvents = [];
let onTouchEnterEvents = [];
const onTouchEnter = function (selector, fn) {
onTouchEnterEvents.push([selector, fn]);
return function () {
onTouchEnterEvents.slice().map(function (e, i) {
if (e[0] === selector && e[1] === fn) {
onTouchEnterEvents.splice(1, i);
}
});
};
};
const onTouchLeave = function (selector, fn) {
onTouchLeaveEvents.push([selector, fn]);
return function () {
onTouchLeaveEvents.slice().map(function (e, i) {
if (e[0] === selector && e[1] === fn) {
onTouchLeaveEvents.splice(1, i);
}
});
};
};
let lastTouchLeave;
let lastTouchEnter;
document.addEventListener('touchmove', function (e) {
var el = document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY);
if (!el) return;
onTouchLeaveEvents.map((event) => {
if (el!=lastTouchEnter && lastTouchEnter && lastTouchEnter.matches(event[0])) {
if (lastTouchEnter !== lastTouchLeave ) {
event[1](lastTouchEnter, e);
lastTouchLeave = lastTouchEnter;
lastTouchEnter = null
}
}
});
onTouchEnterEvents.map((event) => {
if (el.matches(event[0]) && el!==lastTouchEnter) {
lastTouchEnter = el;
lastTouchLeave = null;
event[1](el, e);
}
});
});
onTouchEnter('.area',function(el,e){
el.classList.add('hover')
})
onTouchLeave('.area',function(el,e){
el.classList.remove('hover')
})
.area {
width:100px;
height:100px;
margin:2px ;
font-size:12px;
display:flex;
align-items:center;
justify-content:center;
float:left;
}
.area.hover{
background-color:#333 !important;
color:#fff;
}
#div-1{background-color:#f00;}
#div-2{background-color:#0f0;}
#div-3{background-color:#00f;}
body{
overflow:hidden
}
<div id="div-1" class="area">DIV 1</div>
<div id="div-2" class="area">DIV 2</div>
<div id="div-3" class="area">DIV 3</div>
This GIST contains the same code as above, for improvements, please create comments there.
Upvotes: 0
Reputation: 12955
W3C removed ontouchenter and ontouchleave, so that we can only do these(with zepto.js, touch.js, ontouchmove, elementFromPoint):
var last_touched_button='';
$('#container,#button1,#button2').on('touchmove',function(e){
var ele=document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY);
if (ele==document.getElementById('button1'))
{last_touched_button='button1';
}
else if (ele==document.getElementById('button2'))
{last_touched_button='button2';
}
});
$('#container,#button1,#button2').on('swipeLeft',function(e){
console.log('the button '+last_touched_button+' triggered swipe_into_left_side event or swipe_out_from_left_side event!');
});
Upvotes: 1
Reputation: 1740
You're referencing an old draft, the latest one removed the touchenter and touchleave events.
Upvotes: 11
Reputation: 383
I suggest that you use
document.elementFromPoint(touch.x, touch.y);
on touchmove event.
Upvotes: 24
Reputation: 3113
There is a list here stating the version-wise compatibility. Currently Chrome, Opera, iOS Safari, Android Browser, Blackberry Browser, Opera Mobile, Chrome for Android, Firefox for android support this feature
Upvotes: 1