Adobe Edge Mobile Image Gallery - javascript

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!

Related

How can I make an entire row clickable? [duplicate]

is there a touch equivalent of the mouseenter.
I would like to detect if user slide on my DIV.
I prefer a solution depending directly on the target element not on a parent element with recounting positions etc.
The site: http://dizzyn.github.io/piano-game/ - works fine with mouse (mouse down and slide; not working with touch slide)
Thank you
2019: Yes-ish: Using pointerenter.
BUT, by default, a touch (or mouse down) causes the element to 'capture' the pointer, preventing further pointerleave/enter events unless you explicitly release the capture.
Moreover, you'll want to set touch-action:none on relevant elements to avoid the browser intercepting touches for default pan/zoom etc.
Example:
CSS:
*{ touch-action: none; }
JS:
let div = document.querySelector("div")
div.addEventListener("pointerdown",(e)=>{
console.log("down")
console.log("attempt release implicit capture")
div.releasePointerCapture(e.pointerId) // <- Important!
})
div.addEventListener("pointerenter",(e)=>{
console.log("enter")
})
div.addEventListener("pointerleave",(e)=>{
console.log("leave")
})
Works in Chrome at least. Not so much in Mobile Safari 13 beta though... According to the w3c specs, I'm fairly certain it should work this way. Maybe when iOS 13 is officially released we'll be in the clear. [I've filed a bug and looks like it's being attended to.]
[Update: iOS 13 issue fixed. Should work in Chrome/FF/Safari]
Look into these events:
touchstart Triggers when the user makes contact with the touch surface and creates a touch point inside the element the event is bound to.
touchmove Triggers when the user moves the touch point across the touch surface.
touchend Triggers when the user removes a touch point from the surface. It fires regardless of whether the touch point is removed while inside the bound-to element, or outside, such as if the user's finger slides out of the element first or even off the edge of the screen.
touchenter Triggers when the touch point enters the bound-to element. This event does not bubble.
touchleave Triggers when the touch point leaves the bound-to element. This event does not bubble.
touchcancel Triggers when the touch point no longer registers on the touch surface. This can occur if the user has moved the touch point outside the browser UI or into a plugin, for example, or if an alert modal pops up.
Specifically touchenter and touchleave.
Source: http://www.javascriptkit.com/javatutors/touchevents.shtml
For anyone who is trying to handle touch events in a web app here is helpful documentation W3C - Touch Events which explains the events in detail and how they are handled.
WC3 states:
If a Web application can process touch events, it can intercept them, and no corresponding mouse events would need to be dispatched by the user agent. If the Web application is not specifically written for touch input devices, it can react to the subsequent mouse events instead.
In short:
You can merely handle mouse events relative to touch events instead of handling both touch and mouse events.
I just wanted to say thank you to the previous poster. His suggestion worked perfectly. And I've been struggling to find a solution to this for weeks. If you're using Svelte within your pointerdown handler function I would suggest using:
const pointerDownHandler = (event) => {
// whatever logic you need
event.target.releasePointerCapture(event.pointerId);
}
He's accurate in saying this part is key. It will not work without it.
Answered this at Touchenter/Touchleave question.
Check please.
https://stackoverflow.com/a/61179966/835753
I will make a shot clarifying for Ian's answer:
Equivalent for mouseenter event is pointerenter event. But it will not work out of the box. To make it work you should:
Add to parent element pointerdown event listener with releasePointerCapture method
div.addEventListener("pointerdown",(e) => e.target.releasePointerCapture(e.pointerId))
Add to parent and to your element touch-action: none CSS property.
Enjoy :)

Is disabling all click events at first touchstart event a good idea?

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.

Capture horizontal touch movement while allowing native vertical scroll

I'm trying to explore how feasible it is to create an HTML5 interaction where a touch can be conditionally captured by the initial direction of the motion.
The goal is to capture and track the motion of the touch only if it initially moves in a horizontal direction. Combined with a responsive page layout which only scrolls vertically, we should be able to use horizontal swipe motion to do something cool by tracking it.
The problem is in the seeming impossibility (especially on iOS) of performing touch sequence capture conditionally.
In order to track a touch (and by this I mean specifically obtaining the stream of x,y coordinates which represent the position of the finger over time), touchstart has to be preventDefaulted in order to prevent the page from engaging native momentum-scroll. Native momentum-scroll, while in operation, suspends all JS execution (setTimeout, rAF, jQuery animate et al...) and even CSS keyframe/animation/transition execution.
I would really like to know if there's a way to somehow condition the preventDefault() of the original touchstart event. It's completely possible for JS to store that event object, and then not call it until some later time (when it is determined that we are indeed interested in preventing the native scroll from starting).
But this is certain to fail because the default behavior of not running preventDefault() on that event is to engage native-scroll, which then will block JS execution for the entire remaining duration of the scroll. Failing to return the event listener function attached to touchstart does not appear to be an option. It would freeze everything.
The tentative answer, then, without any additional insight, is that all swipes must be captured if we want to be able to capture it at all, and scrolling has to be "faked" via external means à la (iScroll)[http://cubiq.org/iscroll-5-ready-for-beta-test] (personally I would want to explore some sort kind of combination of rAF and window.scrollTo and would be surprised if iScroll 5 does not employ these APIs)
Incidentally the description for the 4th demo there got me really excited, but it turns out that all it does is create a page section that iScrolls horizontally while the rest of the page behaves regularly, which is entirely mundane.

trying to get CSS3 spotlight effect working with touch events

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.

How do I prevent the default behavior of the touchmove event in iOS 5?

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.

Categories

Resources