I'm trying to get this effect to work with touch events on an ipad, here is what it should look like with mouse events on jsfiddle http://jsfiddle.net/FwsV4/1/
This is what I've tried http://jsfiddle.net/FwsV4/3/ which isn't working for me.
To be honest I'm a little lost with touch events and how to translate mouse clicks/moves to them. I'm actually not sure how to best utilise this effect, but I want to keep the elements underneath interactive using touch start/end events.
Can anyone point me in the right direction?
Your first problem is that you will need to bind to touchstart to prevent the page from scrolling. You could just do:
$('myElement').htmlElement.bind("touchstart", function(event) {
event.preventDefault();
}
);
It's probably better to get the co-ords from this as well though.
Here is a good tutorial on touch events:
http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
Your second problem is setting the element to 5000px height and width, as by default iOS will zoom to include the entire page. You should adjust this OR use the viewport tag to change zoom behaviour (see viewport apple docs).
The following code is also incorrect and returns a Boolean value, not one of the objects.
var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
This should be:
var touch = e.originalEvent.touches[0] ? e.originalEvent.touches[0] : e.originalEvent.changedTouches[0];
BUT with touchmove you're interested in e.originalEvent.touches[0] (assuming only single finger touch events are of interest).
You should also avoid using inline js and separate file js in this manner (there are reasons to do so in some circumstances perhaps). It makes it harder to follow.
I'm not sure using touch events with jfiddle is a great plan either (I might be wrong), i'd just use a normal webserver/local files to develop on.
Related
Since I´m working on a project where I need to be able to drag objects around my canvas but also to scroll the entire page by dragging the actual canvas 'background' behind my PIXI Sprites, i followed the findings of this guy here:
https://github.com/pixijs/pixi.js/issues/2483 :
By default, the Pixi canvas/display-area cannot be used to scroll the
webpage that contains it. Which is important on touch screens. (eg. If
you use the rest of the web-page to pinch-zoom into the Pixi canvas,
you can become trapped and unable to zoom back out (or pan away),
because there's no non-Pixi-canvas area of the page to "grab" with
your pinch gesture).
To enable this functionality, I use autoPreventDefault. But this comes
with some undesirable side-effects, like scroll/pinch-zoom actions
over the canvas registering "taps" or clicks in a way that doesn't
make sense. (ie. I'm attempting to zoom or scroll the outer page at
that point, not interact with the Pixi canvas)
To work around that, I modify and compile my own custom version of
Pixi where I can apply preventDefault in a more granular way...
To get page-scrolling functionality it seems I only need to
preventDefault in the InteractionManager.prototype.onTouchEnd
function. Whereas autoPreventDefault will also preventDefault on 3
other events. (onMouseDown, onTouchMove, onTouchStart).
Leaving autoPreventDefault = false and applying preventDefault only to
onTouchEnd, gives me the functionality I need. But it'd be nice to not
have to customize and rebuild Pixi in this way every release. (Sorry
if there's something else I'm missing here; I don't completely
understand the event system in Pixi, or what else to do about this
scroll-touch problem)
So i disabled e.preventDefault() on 'onTouchStart' and on 'onMouseMove' but left it as is on 'onTouchEnd'
This works perfect on IOS devices but not on Android, the only exception being a Samsung A7 using Adblock browser (fails on Chrome).
Would really appreciate some help on this.
TLDR:
Disabling PIXI´s e.preventDefault on onTouchStart and onMouseMove works on IOS devices and lets me scroll the page by draggin my canvas around but not on Android devices.
My solution for that was to use
renderer.plugins.interaction.autoPreventDefault = false
This should work on iOS and Android.
Docs for autoPreventDefault reads:
Should the manager automatically prevent default browser actions.
Using PIXI 4.5.6.
Take a look at the docs:
http://pixijs.download/dev/docs/PIXI.CanvasRenderer.html#plugins
http://pixijs.download/dev/docs/PIXI.interaction.InteractionManager.html
Using renderer.plugins.interaction.autoPreventDefault=true should do the trick.
Making a nice quick-responding website is relatively difficult because of the conflicts between touchstart, tap and the 300ms delayed click.
Ofcourse vclick should fix these issues, but also they seem to have problems fixing it completely. From the documentation:
Warning: Use vclick with caution
Use vclick with caution on touch devices. Webkit based browsers
synthesize mousedown, mouseup, and click events roughly 300ms after
the touchend event is dispatched. The target of the synthesized mouse
events are calculated at the time they are dispatched and are based on
the location of the touch events and, in some cases, the
implementation specific heuristics which leads to different target
calculations on different devices and even different OS versions for
the same device. This means the target element within the original
touch events could be different from the target element within the
synthesized mouse events.
We recommend using click instead of vclick anytime the action being
triggered has the possibility of changing the content underneath the
point that was touched on screen. This includes page transitions and
other behaviors such as collapse/expand that could result in the
screen shifting or content being completely replaced.
Now I'm thinking about doing something simpler. Whenever a touchstart event is being triggered I know this is a touch device for sure. I just disable all click events, and start listening to touchstart (or tap) events only. Ignoring the 300ms delayed click events.
Of course there are devices with a mouse and touch, but people using these at the same time seem like a minority to me.
Is this a good idea, or am I missing something in my thinking?
First of… what makes you say that people that use both touch and mouse input are a minority?
The 300ms click delay has been gone a while now on Android when using <meta name="viewport" content="width=device-width">. Unfortunately it can't be removed on iOS because it's a scroll gesture on unzoomable pages that almost nobody seems to be aware of.
I'd say that the best approach is still to support both mouse as well as touch input, despite the 300ms delay on iOS devices. It's dangerous to assume a user will exclusively use touch input when they use it once.
Imagine a user happily using a mouse to navigate. They see something interesting that they want to look at a bit closer so they use a touch gesture to zoom in and all of a sudden mouse clicks don't work anymore. That sounds broken to me.
I just remembered an interesting discussion about detecting a mouse user. Maybe it'll help you see things a bit differently.
Yes, in my honest opinion it is smart way to go. This has proven to be quite a hard problem and when you still combine it to the compatibility problems caused by some really crappy mobile devices which don't follow standards even that bit, it quickly becomes a battle that you can't win. We have adopted a solution close to this, with realization of fact that there might arise problems with poor devices. But after all, you can't satisfy the needs of everybody and the distribution of usage tends to favor those devices (nowadays) that follow the standards.
Also note that you don't need to wait for first touchstart to happen. Instead you can do this trick after DOM is ready and bind the events accordingly.
var isTouchDevice = 'ontouchstart' in document.documentElement;
which is copied from KevBurnsJr's answer.
Also as you most probably already know, you can bind to all kind of events and then check when entering the callback of which type the event actually is with
event.type
Good luck!
It would be a bad idea to disable all click events on the basis of a single touchstart as you suggest. While using both pointers or touch at the same time isn't a common use case. Preventing dual use of mouse/pens and touch isn't a forward compatible approach.
And when you say: "Ignoring the 300ms delayed click events."
I think you make a false assumption on click. You'd still have to synthesize clicks one way or another. touchstart alone isn't a click action. An assumed click happens on touchend, not touchstart. Here is the principle behind detecting clicks early on mobile: https://developers.google.com/mobile/articles/fast_buttons
If you are looking for fastclicks you may want to look into the fastclick script or other fastclick ones on github instead of vclicks.
To avoid issues with people using both touchscreen and mouse with pleasant reactivity I suggest this in JQuery, it works good enough for me:
$elem.on('click touchstart', function(e){
var $self = $(this);
if(e.type == 'touchstart'){
$self.mouseenter(); //fire events you still need
e.preventDefault();
}
/* your code */
});
From my experience it's better than keep the delay on click event and some hazardous comportment through devices, but there's inconvenient too.
On the iPad I tested, it avoids the situation where hover event is triggered on first tap then click event on second tap, but also it seems that the click event fire when you tap near the border of your element and not the touchstart, have to keep it in mind.
Also, it seems not working well with 'tap' event, certainly because it's not well treated yet by JQuery.
I am using Adobe Edge Animate to create a large portion of my website, but I want to make a mobile version as well, and so obviously instead of onClick events, I want to use onTouch events. I just can't seem to find any good information on how to use touch events as I have never used them before.
I want to make a simple image gallery that plays forward when you swipe to the left, and plays reverse when you swipe to the right.
The big problem here is, how do I tell a touch event to do different things based on the direction of the swipe?
first of all, you're right, you want to use three event handlers: touchstart, touchmove, touchend
one approach you might take is to compare the starting position of the user's finger(s) to the ending position. although the code will vary based on how many fingers you want to detect, i'll outline a basic method you can adapt. in order to detect one finger, enter the following in a "touchstart" event handler:
var xStart = e.originalEvent.touches[0].pageX;
sym.setVariable('xStart', xStart);
that will store the starting x-position of the first finger in a variable and then make it globally accessible by other event handlers.
then maybe do the same thing in a "touchend" event handler. use some logic to compare the two values.
xStart = sym.getVariable('xStart');
var xEnd = e.originalEvent.touches[0].pageX;
if (xEnd > xStart)
{
sym.playReverse();
}
else if (xEnd < xStart)
{
sym.play();
}
then you'll have some stop frames to hold at those images.
that's just an example, but hopefully it'll help you get going.
good luck!
I'd assume this question has been asked to death, but I'm not finding anything good.
What I'd like is a unified set of events that span devices. I know the mapping isn't always 1 to 1, but just something that covers the basics like:
ignores/disables hover events/styles on a touch device
maps a touchstart to a mousedown
similarly, touchend to mouseup
tap to click
etc...
maybe even touch, hold 1s, touchmove to dragstart...
I haven't thought through all the specifics. And of course device specific events like hover on a desktop, or swipe on a tablet, can't be translated and should just be ignored if not supported.
Anybody know of a library that will do this. Preferably an invisible jQuery patch.
Thanks.
jQuery Mobile does exactly this, amongst many other things.
See their documentation on virtual mouse events, which:
... provide a set of "virtual" mouse events that attempt to abstract away mouse and touch events
I have a web-based application that includes a component that the user can scroll up and down with their finger. I use the event's preventDefault method to prevent the default behavior where the touch move shifts the whole screen around on iOS devices.
Unfortunately this does not seem to work anymore in iOS 5 which I just upgraded to this morning. I have to assume that this is just done differently in iOS 5, but I have yet to be able to find a resource that provides instructions.
Update #1: I haven't been able to find an answer to my specific question, but I was able adjust my code a bit to use the -webkit-overflow-scrolling style (set to a value of "touch") and implement the snazzy inertial scrolling capability (where the content scrolls faster depending on the velocity of your swipe and will "rubber band bounce" back if it hits the boundaries. Pretty cool looking...
Update #2: I have another strange problem now. For some odd reason that overflow scrolling behavior gets mixed up sometimes whereby you have to drag your finger left and right across the containing element in order to make its contents move up and down. I have yet to be able to figure out why this happens - does anyone have any ideas?
I found a very simple solution. When the event hits your element that is allowed to scroll, just flag the event. On the event listener on the document just check if the flag is set and only stop the event if the flag isn't set:
this.$scrollableEl.on('touchmove', function(event){
event.comesFromScrollable = true;
// when you have containers that are srollable but
// doesn't have enough content to scroll sometimes:
// event.comesFromScrollable = el.offsetHeight < el.scrollHeight;
});
$(document).on('touchmove', function(event){
if (!event.comesFromScrollable){
event.preventDefault();
}
});
You could also use event.stopImmediatePropagation instead, so you dont need the eventListener on the document element, but this breaks zepto.js tap in my case:
this.$scrollableEl.on('touchmove', function(event){
event.stopImmediatePropagation();
});
First, I can verify that e.preventDefault() disables all scrolling in iOS 5 using the following code:
document.ontouchmove = function(e){ e.preventDefault(); }
Unfortunately, however, this disables the scrolling on overflow:scroll divs. (If anyone has a solution that leaves the inner element scrolling enabled, please share.)
Regarding update#2, I have noticed strange behavior when there is a scrollable element nested in another scrollable element (including the page itself). Sometimes the device hesitates on which element the user intends to scroll. In particular I've noticed this problem using position:fixed. My solution was to make sure the body has 100% height and that the scrollable elements use position:absolute where possible.