Preventing iPad top page drag - javascript

I'm trying for numerous days to solve the following issue.
I have a menu located on the top of the page which needed to be open using swipedown event (I'm using Hammer.js jQuery version).
Problem is, every time I try to interact using swipes I either scroll the page (swipeup) or pulling the page down same as described in the following question.
Here is what I've tried so far:
overflow: hidden; on the body element with an inner container with overflow: auto, swipe on top element still triggered document scroll.
Setting preventDefault on the document also disabled lower elements events in the DOM hierarchy and by that I had no swipe events working in the page.
Also tried using stopPropagation on the actual element when the event occurs, to prevent the bubbling up the chain for the event, the result cause the object to not respond to the events (swipes) and document scroll worked with no problems.
Any ideas how can I still keep page scroll but also when using common gestures, such as swipedown/swipeup, on specific elements that the element only will be affected?
Here is an example using JSFiddle, to better demonstrate the issue.
Would appreciate ideas/thoughts

I don't know if this will help, but I've always liked to use drag more than swipe. Using Hammer on my projects, swipes were a bit finicky. And from a UX standpoint, drag feels instantaneous vs a swipe. Much like, mousedown vs mouseup/click. So in instances where it's appropriate, and I believe in the case of showing swipey menu it is, I'd opt for drag.
Replacing your example with drag rather than swipe, and also using CSS transition, -webkit-transition, rather than jQuery's animate (drag will trigger like a mousemove, vs a click or a mouseup) seemed to make it work.
Hammer('.nav').on('dragdown', function(e){
e.gesture.preventDefault()
$(".blue").html("down")
$('.nav').css({"top":"0px"});
})
.on('dragup', function(e){
e.gesture.preventDefault()
$(".blue").html("dragup")
$('.nav').css({"top":"-150px"});
});
//Added in CSS, for .nav
.nav {-webkit-transition:0.5s top;}
Example
This does still have the page overscroll. A preventDefault() on document.ontouchstart would could fix that but that breaks scrolling. You might be able to do a selective preventDefault() by checking the scrollOffset perhaps. But I guess in the long run, I'd recommend something like iScroll.
Example
Also maybe tweak the hitbox for the drag to be a bit larger. Which I did in the last example. I attached the dragdown event on the document instead of the "menu" so the menu doesn't have to be visibly bigger.
Hammer(document).on("dragdown",function(e){
//calculate ratio of first touch from top
var pos=e.gesture.startEvent.center.pageY/window.innerHeight
if(pos<0.2){ //drag occurs in the first 20% of the screen
menu.style.marginTop="0px" //or animate here
e.gesture.preventDefault()
e.gesture.stopPropagation();
}
})

You should use the preventDefault function of the orginal gesture, to stop the browsers default behaviour, see here: https://github.com/EightMedia/hammer.js/wiki/Event-delegation-and-how-to-stopPropagation---preventDefaults
When you have a div element, on which you want to register swipe events, you would do the following:
$('#swipeDiv').hammer().on("swipe", function(ev) { ev.gesture.preventDefault(); });
That should prevent the scrolling of the page, but only if the swipe happens on the div element.

Related

Nondeterministic jQuery .toggle() How to prevent this fluky behaviour?

Using jQ the .toggle() behaviour seems to depend on the location of the client mouse pointer at the time of page load events. And that, in terms of reliable (Turin like) behaviour, is totally useless!!
For example hovering over an iframe video while the page loads inverts the toggle state. Each subsequent hover event has the reverse effect, hiding instead of
$("iframe").hover(function () {
$('#sliderContainer').fadeToggle();
});
Initially I searched to find some mitigation. Am I correct to conclude that at some timepoint there will always be a risk of hover-toggle becoming inverted?
Also I've read in SO that .toggle has been deprecated, but don't see any indication of that on jQ's website. What's going on there?
I still found .toggle to be non-deterministic with mouseenter and mouseleave.
Those mouse events do work with display:none and display: block, with the provision that when the mouse is over the 'toggle' area for the time during page load, then the mouse has to leave the area and trigger the mouseenter event.
At least that is expected and dependable behaviour! Then animation has to be added.

how do I recreate the sencha style gesture scroll for lists and content?

So... I am working on an interaction design project and I want to create a sencha-style gesture scroll for content areas. The way I've done it so far, is to attach touchmove/start/end events to the content area, and it translateY's the contents. It works in on desktop with mousemove/up/down events, but it jumps around like crazy with touch. I'm not sure whats wrong.. here is a link to a prototype.
**requires webkit.
http://apps.omorphos.com/gesture-scroll
I think it is an issue with the event response, but I tried and haven't been able to nail it down. Any help is greatly appreciated!
So, I figured this out.
What I was doing was attaching the touch event to the list tag itself.. and, that works fine on desktop with mouse events; however, with touch, the target changes and touchend doesn't fire properly.
So, what I did, and what I believe sencha does, ... and I had originally implemented but went in a different direction... is have an absolutely positioned element with a transparent background color floating above the element that will be manipulated. All of the touch events will be captured by that DIV and then the elements below can be manipulated without losing the event data.
In the new version I used HammerJs ... more info: http://eightmedia.github.io/hammer.js/
but i'm pretty sure you could just use standard events; but the good thing about hammer js, is that it will translate touch events to mouse events for testing in the browser, this also means making the coordinates for touch the same as mouse, so you can access mouse event coords via
e.gesture.touches[0].pageX
e.gesture.touches[0].pageY
which let's you write less code.
Part 2:
Additionally... part of the issue is... how do you click on the content/components(e.g. links) below the screen.
How you do this... is you take the coords from the event handler and pass them through this native Javascript function...
var a = document.elementFromPoint(x, y);
this will return the dom element. and all you have to do is trigger the click/tap event.
Which would be great, except it will pick the element with the highest z-index.. so that is your screen obj(the one that is capturing all of the touch events). So, what you need to do, is hide the screen after a tap is registered, and then execute this function 200ms later, and then bring back the screen to capture whatever events.
You can do this with this function...
$(theScreen).on('tap', function(e){
screen.hide();
var hit = document.elementFromPoint(e.gesture.touches[0].pageX, e.gesture.touches[0].pageY);
$(hit)[0].tagName !=="A" || $(hit).trigger('click');
setTimeout(function(){screen.show()},300);
});
And, that is how I solved it!
My code is not super annotated, but you can find it at the link below:
Updated example:
http://apps.omorphos.com/gesture-scroll/v2/

Have html element follow finger on jQuery mobile swipe

I have a div on which I listen for swipe events using jQuery mobile.
I was wondering how I could get the div to follow and move with the finger from the time that the swipe starts until the time that the swipe ends?
Almost like draggable only while the swipe is happening.
Although I would prefer to not use jQuery UI.
How can I do this properly and in the best way possible?
My method of doing this was on mouse down, set the offset of the div to the x location of the mouse. But that fires every pixel and seem inefficient. Also it happens on mouse-down, not on swipe.
Here is my code that listens for the swipe, in this case swipe right:
$('#main').on('swiperight', '.dataCard', function(event){
event.preventDefault();
// what happens on swipe here
});
Now, how can I get .dataCard to follow the finger as it swipes until the finger is picked up?
Well, you can inspect the event in a breaking in a debugger. Also, you cannot change positions of a "relative" element, it will always be in document flow position (hence why I asked if you had made the element absolute).

onscroll for div

Does a div element not have an onscroll event handler?
The behaviour on my page doesn't seem to indicate the div onscroll event handler is recognized.
<div id='bd' onscroll='alert("Scroll Called");'></div>
Also,
Do div scroll events roll up to window scroll events, as per DOM event bubbling ?
Depending on which version of HTML you're using, you could use the onwheel event, instead.
The onscroll event works only if all the following are true:
The div has overflow: auto, overflow: scroll, overflow-y: scroll, etc.
The div currently has a visible scrollbar that can scroll.
The mouse movement actually causes the scrollbar to scroll.
So the onscroll event is not really suited for detecting general mouse wheel movement.
Please note that the onwheel event is new in HTML 5. According to w3schools, it is pretty widely supported, though.
I scratched my head on this one too, until I started learning more about DOCTYPE directives. The onscroll attribute is not supported in most recent version of the HTML spec. It'll show as invalid syntax in Visual Studio. It might work in many browsers, but it's still invalid code.
Instead, you canan event using Javascript or jQuery. I use an approach like this to synchronize scrolling on two separate div's:
$("#gridTableContainer").scroll(function() {
HandlingScrollingStuff();
});
Yes but the element needs to have a scrollbar. You can give it one with either overflow: auto (which gives you a scrollbar when the content is tall enough) or overflow: scroll. (These can be set specifically for x & y as well overflow-y: scroll...)
Although they don't bubble once the div has been scrolled to the bottom the window will start scrolling. (Basically if the div can scroll it will intercept the scroll event, but if it can't then it will go to the page)
I know it may not be exactly what you're looking for, but a lot of javascript frameworks can help you with this. It is not necessary for the div to have a scrollbar for you to hook to the scroll events.
Eg. Mootools has the mousewheel event. Demo here. (It has scrollbars, but you can use Firebug to remove the scrollbars and try -- it still works).
I have used this myself on a site I made a while back. If you scroll while holding your mouse over the images it prevents the default page scrolling and instead slides the image-bar.
JQUERY scroll() can help you.
$("#gridTableContainer").scroll(function() {
HandlingScrollingStuff();
});

Html scroll: how to avoid it to "cut" my inner elements

this question is for an autocomplete drop down list I have to do that will fire while you're writing in an html textbox.
It basically consists of a div containing the suggestion elements, each of them being a div as well.
I got to the point where it's begining to work properly but now I added a vertical scroll to the containing div so you can limit the height of the drop down list, and I got the following behaviour:
If you use the scroll, it scrolls up or down in "pixels", so it cuts my elements making it all look anything but sleek.
I'd like to override the behaviour to go up and down one whole div element when you use the scroll. I don't even know how to google for this...
Anybody knows any useful resource about this or can give any tip as to where to start, if it's possible to override the scroll movement events or I should look into another direction?
Thanks a lot in advance
Note: I cannot use jquery autocomplete plugin.
You could implement your own scrollbar, using mouse events and updating positions manually.
Could you not tap into a 'scroll' event for that element (DOM 3 Events provides a scroll event for an element, not sure how supported it is), such that whenever the scroll position is changed, it calls a little routine of your own that adjusts the scroll position by rounding it to the nearest 'notch'?
Or, you could regularly poll for the scroll position and adjust it when it has moved. This scroll position seems fairly cross-browser.
First:
Using your own scroll bar, make a scroll event handler. Here you could use an animation by delta ( it is found in evt ) on which you can set the scrollTop of the element yourself by the offsetHeight of your top or bottom visible element. Also if the div height does cut off an element just make the previous or next element a bit "higher" aka set it's height to push the cut off element up or down.
Second:
You could "patch" the div so only a few elements would be visible. and while you scroll you hide the top one and display the bottom one in a animation, without using scrollTop or scrollHeight.
Watch out for scroll event in Firefox. It has another name, but you can test it like this:
eventName = eventName === 'mousewheel' ? ((/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : eventName) : eventName;
Good Luck. If you need any help in about 2 days i will have it implemented, because i need one too.
This simply cannot be done, there is no solution, period. One must live with this limitation.
Why is there no solution?
Because even if you implement your own scroll bar, you would still have to rely on scroll events, and these can be neither canceled nor prevented from bubbling to the body element. Really, they can't, you can call preventDefault() and stopPropagation() on them till the cows come home and they still bubble. This is a deliberate decision on the part of the standardizing body and browser implementors.
If scroll events were cancellable, EхpеrtEхchangе could prevent you from scrolling to the bottom of the page to see the answer ;) (don't worry, I used some Cyrillic letters in "EхpеrtEхchangе" so they don't get an indexable mention).

Categories

Resources