On mouseUp
or touchEnd
I want to get the reference of the element on which that event happened.
Demo
In this example, you need to click on one element, drag mouse and released over another element. When the mouse is released, that element's background will change to red. My code works correctly for mouse events, but not on touch devices.
When the touchStart
is on one element and the finger is released over another element, I'm getting only the reference to the first element.
What I need to change to make the touch events work exactly like the mouse events?
var isMouseDown = false;
var panel1 = document.getElementById( 'panel1' );
var panel2 = document.getElementById( 'panel2' );
panel1.onmousedown = onDocumentMouseDown;
panel1.onmouseup = onDocumentMouseUp;
panel1.onmousemove = onDocumentMouseMove;
panel1.addEventListener( 'touchstart', onDocumentTouchStart, false );
panel1.addEventListener( 'touchmove', onDocumentTouchMove, false );
panel1.addEventListener( 'touchend', onDocumentTouchEnd, false );
panel2.onmousedown = onDocumentMouseDown;
panel2.onmouseup = onDocumentMouseUp;
panel2.onmousemove = onDocumentMouseMove;
panel2.addEventListener( 'touchstart', onDocumentTouchStart, false );
panel2.addEventListener( 'touchmove', onDocumentTouchMove, false );
panel2.addEventListener( 'touchend', onDocumentTouchEnd, false );
function onDocumentMouseDown(event) {
event.preventDefault();
panel1.style.background="#2E442E";
panel2.style.background="#5D855C";
}
function onDocumentMouseUp(event) {
event.preventDefault();
this.style.background="#ff0000";
}
function onDocumentMouseMove( event ) {
}
function onDocumentTouchStart( event ) {
event.preventDefault();
panel1.style.background="#2E442E";
panel2.style.background="#5D855C";
}
function onDocumentTouchMove( event ) {
}
function onDocumentTouchEnd( event ) {
event.preventDefault();
this.style.background="#ff0000";
}
On mouseUp
or touchEnd
I want to get the reference of the element on which that event happened.
Demo
In this example, you need to click on one element, drag mouse and released over another element. When the mouse is released, that element's background will change to red. My code works correctly for mouse events, but not on touch devices.
When the touchStart
is on one element and the finger is released over another element, I'm getting only the reference to the first element.
What I need to change to make the touch events work exactly like the mouse events?
var isMouseDown = false;
var panel1 = document.getElementById( 'panel1' );
var panel2 = document.getElementById( 'panel2' );
panel1.onmousedown = onDocumentMouseDown;
panel1.onmouseup = onDocumentMouseUp;
panel1.onmousemove = onDocumentMouseMove;
panel1.addEventListener( 'touchstart', onDocumentTouchStart, false );
panel1.addEventListener( 'touchmove', onDocumentTouchMove, false );
panel1.addEventListener( 'touchend', onDocumentTouchEnd, false );
panel2.onmousedown = onDocumentMouseDown;
panel2.onmouseup = onDocumentMouseUp;
panel2.onmousemove = onDocumentMouseMove;
panel2.addEventListener( 'touchstart', onDocumentTouchStart, false );
panel2.addEventListener( 'touchmove', onDocumentTouchMove, false );
panel2.addEventListener( 'touchend', onDocumentTouchEnd, false );
function onDocumentMouseDown(event) {
event.preventDefault();
panel1.style.background="#2E442E";
panel2.style.background="#5D855C";
}
function onDocumentMouseUp(event) {
event.preventDefault();
this.style.background="#ff0000";
}
function onDocumentMouseMove( event ) {
}
function onDocumentTouchStart( event ) {
event.preventDefault();
panel1.style.background="#2E442E";
panel2.style.background="#5D855C";
}
function onDocumentTouchMove( event ) {
}
function onDocumentTouchEnd( event ) {
event.preventDefault();
this.style.background="#ff0000";
}
Share
Improve this question
edited Apr 19, 2020 at 8:23
Brian Tompsett - 汤莱恩
5,88372 gold badges61 silver badges133 bronze badges
asked Jul 11, 2012 at 7:12
SarathSarath
9,14612 gold badges54 silver badges86 bronze badges
2
- what touch devices have you tried (means) – shareef Commented Mar 13, 2013 at 9:41
- Similar Question How to find out the actual event.target of touchmove javascript event? – Rohit Commented Jul 14, 2015 at 21:10
3 Answers
Reset to default 15 +50This was a fun question to tackle. Thanks for that.
Here's what I have done. I have modified your touchmove
handler as such:
function onDocumentTouchMove(event) {
onDocumentTouchMove.x = event.changedTouches[event.changedTouches.length - 1].clientX;
onDocumentTouchMove.y = event.changedTouches[event.changedTouches.length - 1].clientY;
}
In this handler I'm saving the last co-ordinate that the user moved to. In all probability, this is the point at which the user took his finger, nose, knuckle, stylus, etc off the touch surface. These co-ordinates I then use in the handler for touchend
to find the element that surrounds them.
function onDocumentTouchEnd(event) {
event.preventDefault();
var elem = document.elementFromPoint(onDocumentTouchMove.x, onDocumentTouchMove.y);
elem.style.background = "#ff0000";
}
I have utilized the document.elementFromPoint
(mdn link) for this purpose. It is one of those golden yet fairly unknown methods provided to us by the CSSOM spec.
Here's the fiddle.
From what it seems, this is intended behavior for touch events. However, I have a workaround!
I haven't tested this extensively, but it seems to work on mobile Safari for at least touchStart
and touchEnd
events.
Basically what we are going to do is capture all touch events on the document as they are in capture-phase (see http://www.w3.org/TR/DOM-Level-3-Events/). The handler for these events will find the DOM element at this location and re-send the event with the "correct" target.
It seems that the position of touchEnd
events is not well defined, so I had to query the changedEvents
array to get the last-touched position. I am not sure if this works as-is for touchMove
events et al.
function rerouteTouch (evt) {
if (evt.passthrough) { // Ignore if already rerouted
return;
}
evt.stopPropagation();
var newevt = document.createEvent('TouchEvent');
newevt.initTouchEvent (
evt.type,
evt.bubbles,
evt.cancelable,
evt.view,
evt.detail,
evt.screenX,
evt.screenY,
evt.clientX,
evt.clientY,
evt.ctrlKey,
evt.altKey,
evt.shiftKey,
evt.metaKey,
evt.touches,
evt.targetTouches,
evt.changedTouches,
evt.scale,
evt.rotation);
newevt.passthrough = true; // Only reroute once
var target;
var x = (evt.type === 'touchend') ? evt.changedTouches[0].pageX : evt.pageX;
var y = (evt.type === 'touchend') ? evt.changedTouches[0].pageY : evt.pageY;
if (document !== (target = document.elementFromPoint(x, y))) {
target.dispatchEvent(newevt);
}
}
document.addEventListener( 'touchstart', rerouteTouch, true); // Third arg is true to indicate capture-phase
document.addEventListener( 'touchend', rerouteTouch, true);
...
// Your event handlers here
Here's a jsfiddle which works as expected on mobile safari for me: http://jsfiddle.net/DREer/12/
Perhaps if you can include jQuery into your program you can do something like this:
$('#itemId').on('touchEnd',function(){ this.trigger('mouseUp') });
I'm not sure if jQuery out of the box supports this events, but you can always try jQuery movil, hope it helped