What is the best way to handle touch/pointer events on a surface tablet? I find its behavior quite confusing.
I wrote a script that just set all the event handlers to figure out how the events are fired (setting native event handlers, using jQuery for the UI):
$.each([
"touchstart","touchmove","touchend",
"mousedown","mousemove","mouseup",
"pointerdown","pointermove","pointerup",
"MSPointerDown","MSPointerMove","MSPointerUp"
], function(i,eventname) {
tester.addEventListener(this, function(e) {
msg(eventname,e);
if ($("#prevent").is(":checked")) {
e.preventDefault();
}
if ($("#stop").is(":checked")) {
e.stopPropagation();
}
if ($("#stopimmediate").is(":checked")) {
e.stopImmediatePropagation();
}
}, false);
});
Using the mousepad or desktop IE11, everything is fine. All three events (mouse, pointer, MSPointer) are fired in the expected order: down, move, up.
But, when I use the tochscreen
at first a pointermove fires, then pointer down. On the screen a rectangle appears around my finger.
repeated move events are firing while not moving my finger
firing no further events when I move my finger
pointerend event when removing finger
What am I doing wrong? Calling preventDefault, stopPropagation or stopImmediatePropagation does not change this behavior. Setting the css pointer-events: none; disables all events.
Complete script on codepen
You need to use the touch-action CSS property to prevent the browser's pan and zoom behaviours when the user drags accross the screen with a finger or stylus.
For example:
#prevent, #stop, #stopimmediate {
touch-action: none;
}
Try my touch gesture abstraction library, DeepTissue. IE's touch model is extremely simply because the pointer events abstract all the input modalities into a common API. Chrome is making things complicated, but that is another story :).
You really do not want to hook into all the events. I get that it would be confusing. That is why I wrote Deeptissue. It keeps you from having to write all the plumbing code and it chooses the best option and hooks into that event set.
Related
I am currently making a game that requires the player to drag around an object on a touch screen device.
I've used the event listener mousemove, and it has worked on my Intel XDK emulator, but now that I move it to a touch screen device, I need an touch event that is mousemove and mousedown, and I am not sure how to do that.
Example of ideal code:
canvas.addEventListener("mousemove" && "mousedown", function(e){
pointerX = e.pageX;
pointerY = e.pageY;
}
So this ideal code spits out x and y when the mouse is down, and it has moved.
If anyone knows the legit syntax or a different method of doing this, it would be a great help.
I don't want to incorporate JQuery into this, just pure JS.
Thanks! :)
Edit: Let me rephrase this so it is all straight forward. While the user is dragging an object I need a function that spits out x and y of the pointer the entire drag.
Per MDN:
The EventTarget.addEventListener() method registers the specified listener on the EventTarget it's called on. The event target may be an Element in a document, the Document itself, a Window, or any other object that supports events (such as XMLHttpRequest).
Note the "eventTarget" above. The AddEventListener method takes only one string which represents EventType. You'll need to write a custom function in order to iterate multiple events:
const target = document.getElementById("myDiv");
['mousedown', 'mousemove'].forEach(eventType => {
target.addEventListener(eventType, (event) => {
target.innerText = `x: ${event.pageX} y: ${event.pageY}`;
});
});
#myDiv {
width: 100px;
height: 100px;
background-color: orange;
color: white;
}
<div id="myDiv"></div>
For touch devices, you should be looking into touchstart, touchend, touchcancel and touchmove.
Touch events are similar to mouse events except they support simultaneous touches and at different locations on the touch surface.
https://developer.mozilla.org/en-US/docs/Web/API/Touch_events`
MDN has a great post on touch events. The posts are not just full of quality information but also there are lots of javascript code shown which will provide you with a good resource for touch events.
Interfaces
TouchEvent
Represents an event that occurs when the state of touches on the surface changes.
Touch
Represents a single point of contact between the user and the touch surface.
TouchList
Represents a group of touches; this is used when the user has, for example, multiple fingers on the surface at the same time.
How does this solve my current problem?
The information above provides greater detail for all the types of events you may want to look into. However, for your specific problem, you should look into touchmove & touchend events.
Side note - check touchmove & touchend links for compatibility concerns.
I'm trying to prevent default scrolling behavior while still determining the number of pixels a user has attempted to scroll.
My objective is (at some vertical position on my page) to fix a navigation element to the top of the screen and hijack the scroll/swipe event to pull down a mobile menu when the user scrolls back up (so moving said element up and down by n pixels depending on how many pixels the user tries to scroll).
I am aware of the UX/accessibility concerns insofar as blocking native behavior, but the suits want what the suits want.
So far I have:
$('body').on({
'mousewheel' : function(e) {
e.preventDefault();
e.stopPropagation();
}
});
but am stumped as to how to access the number of pixels scrolled (since element/scroll offsets are no longer a guide).
Edit: Please note that this question is specifically asking for information regarding mouse/scroll actions while scrolling is blocked. Don't think this has been appropriately marked as duplicate.
This is browser-depended because of the mousewheel event you are using. This is because it is non-standard. Don't use it!
In Chrome (43.0) you get different properties with different values:
e.originalEvent.wheelDelta: -120
e.originalEvent.wheelDeltaY: -120
e.originalEvent.deltaY: 100
In IE (11.0), you can get only one property:
e.originalEvent.wheelDelta: -120
In Firefox (38.0.5), the capturing of the mousewheel event doesn't work at all.
Solution:
Use the wheel event (MDN reference). This event has the e.originalEvent.deltaY property in all browsers.
Before cancelling event propagation take the deltaY out of the original event like this
$('body').on({
'wheel' : function(e) {
console.log(e.originalEvent.deltaY);
e.preventDefault();
e.stopPropagation();
}
});
I am trying to implement horizontal scrolling using a two finger gesture on laptops. I am trying to find a solution that works in IE, chrome and safari. Currently I have tried to using the mouse wheel event to simply capture the scrolling Event. I thought I could use the deltaX and deltaY to determine if it is scrolling vertically and horizontally.
$('#ryan').on('mousewheel', function (event) {
if (event.originalEvent.deltaX > 0) {
console.log(event.originalEvent.deltaX);
console.log("horizontally");
console.log(event.deltaX);
}
Here is a fiddle which is not working. I am also not sure if there is another event I am missing.
I have never done it but jquery has a well documented element handler for scroll
I would try
$('#ryan').scroll(function(event) {
if (event.originalEvent.deltaX > 0) {
console.log(event.originalEvent.deltaX);
console.log("horizontally");
console.log(event.deltaX);
});
http://api.jquery.com/scroll/
I have a page with a section to sketch a drawing in. But the touchmove events, at least the vertical ones, are also scrolling the page (which degrades the sketching experience) when using it on a mobile browser. Is there a way to either a) disable & re-enable the scrolling of the page (so I can turn it off when each line is started, but turn it back on after each is done), or b) disable the default handling of touchmove events (and presumably the scrolling) that go to the canvas the sketch is drawn in (I can't just disable them completely, as the sketching uses them)?
I've used jquery-mobile vmouse handlers for the sketch, if that makes a difference.
Update: On an iPhone, if I select the canvas to be sketched in, or just hold my finger for a bit before drawing, the page doesn't scroll, and not because of anything I coded in the page.
Set the touch-action CSS property to none, which works even with passive event listeners:
touch-action: none;
Applying this property to an element will not trigger the default (scroll) behavior when the event is originating from that element.
Note: As pointed out in the comments by #nevf, this solution may no longer work (at least in Chrome) due to performance changes. The recommendation is to use touch-action which is also suggested by #JohnWeisz's answer.
Similar to the answer given by #Llepwryd, I used a combination of ontouchstart and ontouchmove to prevent scrolling when it is on a certain element.
Taken as-is from a project of mine:
window.blockMenuHeaderScroll = false;
$(window).on('touchstart', function(e)
{
if ($(e.target).closest('#mobileMenuHeader').length == 1)
{
blockMenuHeaderScroll = true;
}
});
$(window).on('touchend', function()
{
blockMenuHeaderScroll = false;
});
$(window).on('touchmove', function(e)
{
if (blockMenuHeaderScroll)
{
e.preventDefault();
}
});
Essentially, what I am doing is listening on the touch start to see whether it begins on an element that is a child of another using jQuery .closest and allowing that to turn on/off the touch movement doing scrolling. The e.target refers to the element that the touch start begins with.
You want to prevent the default on the touch move event however you also need to clear your flag for this at the end of the touch event otherwise no touch scroll events will work.
This can be accomplished without jQuery however for my usage, I already had jQuery and didn't need to code something up to find whether the element has a particular parent.
Tested in Chrome on Android and an iPod Touch as of 2013-06-18
There is a little "hack" on CSS that also allows you to disable scrolling:
.lock-screen {
height: 100%;
overflow: hidden;
width: 100%;
position: fixed;
}
Adding that class to the body will prevent scrolling.
document.addEventListener('touchstart', function(e) {e.preventDefault()}, false);
document.addEventListener('touchmove', function(e) {e.preventDefault()}, false);
This should prevent scrolling, but it will also break other touch events unless you define a custom way to handle them.
The ultimate solution would be setting overflow: hidden; on document.documentElement like so:
/* element is an HTML element You want catch the touch */
element.addEventListener('touchstart', function(e) {
document.documentElement.style.overflow = 'hidden';
});
document.addEventListener('touchend', function(e) {
document.documentElement.style.overflow = 'auto';
});
By setting overflow: hidden on start of touch it makes everything exceeding window hidden thus removing availability to scroll anything (no content to scroll).
After touchend the lock can be freed by setting overflow to auto (the default value).
It is better to append this to <html> because <body> may be used to do some styling, plus it can make children behave unexpectedly.
EDIT:
About touch-action: none; - Safari doesn't support it according to MDN.
try overflow hidden on the thing you don't want to scroll while touch event is happening. e.g set overflow hidden on Start and set it back to auto on end.
Did you try it ? I'd be interested to know if this would work.
document.addEventListener('ontouchstart', function(e) {
document.body.style.overflow = "hidden";
}, false);
document.addEventListener('ontouchmove', function(e) {
document.body.style.overflow = "auto";
}, false);
I found that ev.stopPropagation(); worked for me.
To my surprise, the "preventDefault()" method is working for me on latest Google Chrome (version 85) on iOS 13.7. It also works on Safari on the same device and also working on my Android 8.0 tablet.
I am currently implemented it for 2D view on my site here:
https://papercraft-maker.com
this worked for me on iphone
$(".owl-carousel").on('touchstart', function (e) {
e.preventDefault();
});
the modern way (2022) of doing this is using pointer events as outlined here in the mozilla docs: https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events
Pointer events build on touchstart and other touch events and actually stop scroll events by default along with other improvements.
I'm displaying some HTML content in my iPhone app using a UIWebView. I have an image link, and I want it to change when the user touches it - at the moment the user puts a finger on the screen, rather than waiting until they lift their finger back off.
What CSS or JavaScript concept could accomplish this? I've looked at the hover and active states in CSS, but they don't seem to be what I'm after: hover relates to touch-up rather than touch-down, while active seems to have no effect at all.
You could try this.
I think it should be what you are looking for!
http://articles.sitepoint.com/article/iphone-development-12-tips/2
8: Touch Events
Of course, you use your iPhone with a
finger instead of a mouse; rather than
clicking, you tap. What’s more, you
can use several fingers to touch and
tap. On the iPhone, mouse events are
replaced by touch events. They are:
touchstart
touchend
touchmove
touchcancel (when the system cancels the touch)
When you subscribe to any of those
events, your event listener will
receive an event object. The event
object has some important properties,
such as:
touches — a collection of touch objects, one for each finger that
touches the screen. The touch objects
have, for example, pageX and pageY
properties containing the coordinates
of the touch within the page.
targetTouches — works like touches, but only registers touches on
a target element as opposed to the
whole page.
The next example is a simple
implementation of drag and drop. Let’s
put a box on a blank page and drag it
around. All you need to do is
subscribe to the touchmove event and
update the position of the box as the
finger moves around, like so:
window.addEventListener('load', function() {
var b = document.getElementById('box'),
xbox = b.offsetWidth / 2, // half the box width
ybox = b.offsetHeight / 2, // half the box height
bstyle = b.style; // cached access to the style object
b.addEventListener('touchmove', function(event) {
event.preventDefault(); // the default behaviour is scrolling
bstyle.left = event.targetTouches[0].pageX - xbox + 'px';
bstyle.top = event.targetTouches[0].pageY - ybox + 'px';
}, false);
}, false);
The touchmove event listener first cancels the default behavior of the finger move—otherwise Safari will scroll the page. The collection event.targetTouches contains a list of data for each finger currently on the target div element.
We only care about one finger, so we use event.targetTouches[0]. Then pageX gives us the X coordinate of the finger. From this value we subtract half the width of the div so that the finger stays in the center of the box.
Hope it helps!
Try the Javascript "onMouseDown", hopefully the mobile Safari will fire the event.
Link