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

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).

Related

Preventing iPad top page drag

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.

How to determine if event was fired from scrollbar

I have a div in which I have implemented iPad like swiping.
Check out what I mean on JSFiddle (Just click and drag your mouse in the div.)
I want to prevent the swiping from happening when someone is using the scroll bar (click on the scrollbar, then move from left to right, swiping still occurs).
In short, what I need is if(!event.wasTriggeredFromScrollbar) that I can use in any event trigger (in this case mousedown/move/up).
jQuery and regular 'ol Javascript answers welcomed.
Edited: To make a lot more sense.
Here's how I got around this, as it doesn't seem to actually be possible.
Step 1: Capture the MouseDown event. Store the current position of scrollLeft and scrollTop into variables.
Step 2: On the MouseMove event, check the current position of scrollLeft and scrollTop and compare them against your variables. If they're different, then cancel whatever operation you were going to perform. If they're the same, the MouseDown event wasn't triggered by a scrollbar (or anything else that would change scrollLeft and scrollTop such as another animation), and you're free to do what you wish!
Happy coding!

On a webpage can I hijack the vertical scrolling action and make it horizontal?

On a webpage can I hijack the vertical scrolling action and make it horizontal?
Please try and ignore the potential usability issues.
On a webpage can I hijack the vertical scrolling action and make it horizontal?
Not as far as I know (except maybe by rotating the element - but that is probably not what you want).
You would have to re-arrange the contents to make the vertical scroll bar go away, and force a horizontal one instead.
Whether that is possible will strongly depend on the nature of the HTML elements inside the page.
Here's a jQuery Plugin that does this, and you can specify it to only work when the mouse is over the target element:
http://flowplayer.org/tools/scrollable/index.html
Yes you can do this.
Vertical scrolling is set to element.scrollTop
You could simply add a loop that catches scrollTop when it changes, sets it back to zero and then sets the scrollLeft to be = to the changed position.
More so, an even better solution is to overwrite the onscroll event.
window.onscroll = function(event){
event.preventDefault() // Stops the page from scrolling vertically.
window.scrollLeft = event.scrollTop // This is not the correct event attribute, youll have to locate it yourself.
}
You could hook into the scroll event, check which plane is being scrolled, if it was the vertical then set the difference as the horizontal scroll and set the vertical scroll to it's previous value. Though I can imagine that would be incredibly expensive.

How to prevent mouse scrolling outside hovered element?

I have a div which is set to overflow:scroll;. I get scrollbars which is what I want. However when scrolling the div with the mousewheel it scrolls the rest of the page when it reaches the top or bottom of the div's content.
How can I scroll only the div or the entire page based on what's hovered ?
First I don't think you can override the scroll event. So here is what I would do. I don't know jquery but here is some straight javascript.
document.getElementById('scrollDiv').onmouseover=function(){
document.getElementByTagName('body')[0].style.overflow='hidden';
}
document.getElementById('scrollDiv').onmouseout=function(){
document.getElementByTagName('body')[0].style.overflow='';
}
Obviously you could tweak this a little, but this is the basic idea. Also, if you need to you could do other test cases. Like if the div has focus then do the same thing. Depends on your setup.
You could test the mouse position and cancel the scroll events for the document if the mouse is within the bounds of the div.
In this case, I think you'll have to override the default onscroll event for the body. In your handler, you'll need to manually scroll the div's contents.

Differentiate between a scroll caused by .scrollLeft and a user trying to scroll in an HTML page

I have a scrollbar that has to follow some timeline. It is being constantly scrolled with .scrollLeft using setInterval.
I still want the user to be able to naturally take control and just drag the scrollbar away. If I can detect the user did that, I would just turn off the setInterval timer and leave the control to the user until he explicitly turns the auto scroll back on.
Is there a way to differentiate the user scroll event, from the scroll created by .scrollLeft?
You can set a flag before changing scrollLeft and clear it afterwards, then check the flag in the scroll event.
Since Javascript is run on the UI thread, it is not possible for the user to scroll while your code is running.
One alternative is to give up using a scroll-bar at all and do it using CSS and a jQuery slider control. This also gives you the option of making it look more like a time-line. you can set the scroller elements to whatever CSS you want.
There are a few out there, but it's not too hard to roll-your-own using a jQuery draggable control and constraining one axis inside a long, narrow container DIV.

Categories

Resources