How to distinguish scrolling by mouse from scrolling programmatically in JavaScript? - javascript

I am scrolling an overflowing DIV's content by changing the scrollLeft property in Javascript:
setInterval(function(){
$('#scrollbox').scrollLeft($('#scrollbox').scrollLeft()+1);
}, 50);
However, I want to stop this as soon as the user scrolls the content themselves, using the mouse. I tried to detect this using the scroll event
$('#scrollbox').scroll(function(){...});
however, my automatic scrolling above also triggers that event. How can I distinguish this and only react to user-initiated scrolling? (or: how can I stop the above code from firing a scroll event? That would also do the trick)

You could use the .hover(): function to stop the scrolling when the mouse is over the scrollbox element:
http://jsfiddle.net/bGHAH/1/
setInterval(function(){
if(!mouseover)
{
$('#scrollbox').scrollLeft($('#scrollbox').scrollLeft()+1);
}
}, 50);
var mouseover = false;
$('#scrollbox').hover(function(){
mouseover = true;
},function(){
mouseover = false;
});
Edit
Based on your comments I managed to find a jquery plugin from the following site: special scroll events for jquery.
This plugin contains an event which attempts to determine whether scrolling has stopped based on the period of time that has elapsed between the last scroll step and the time the check was made.
To get this to work I needed to slow your interval to just over the latency used by the plugin which worked out to be 310 milliseconds. Doing this meant I had to increase the scroll step to keep it visibly moving.
Here is the link:
http://jsfiddle.net/EWACn/1/
and here is the code:
var stopAutoScroll = false;
$(document).ready(function(){
setInterval(function(){
if(!stopAutoScroll)
{
$('#status').html('scrolling');
$('#scrollbox').scrollLeft($('#scrollbox').scrollLeft()+10);
}else{
$('#status').html('not scrolling');
}
}, 310);
$('#scrollbox').bind('scrollstart', function(e){
stopAutoScroll = true;
});
$('#scrollbox').bind('scrollstop', function(e){
stopAutoScroll = false;
});
});
Hope this helps.

For FF (Mozilla):
document.addEventListener('DOMMouseScroll', handler, false);
For IE, Opera and Chrome:
document.onmousewheel = handler;

Another option is to have an external flag that you can set prior to the programmatic scrolling, and then reset afterwords. If the scroll event is fired and this flag isn't set you know that the user is responsible and can act accordingly.
Unfortunately while this is browser independent and easy to read it could lead you to believe that some user scrolls are programmatic ones. However I would think the occurrences of this is small and may be worth it depending on the app you are writing.

Try wheel event, for most modern browsers
The wheel event is fired when a wheel button of a pointing device (usually a mouse) is rotated.

Related

Javascript stop scrolling on touchmove after scrolling has already started

I have a simple example where a user starts to scroll on a touch screen, and then after one second, I want to disable scrolling. I thought event.preventDefault() would stop the scrolling but it doesn't seem to work after scrolling has already started
Here is an example: https://jsfiddle.net/7s5m8c6L/30/
let allowScroll=true;
function TS(e){//touchstart handler
setTimeout(function(){
allowScroll=false;
},1000)
}
function TM(e){//touchmove handler
if(!allowScroll){
e.preventDefault();
}
}
In this example, you can start scrolling, and after a second, I want the scrolling to stop, but it does not. I know there are ways that I can get this to work with CSS (adding overflow:hidden), but I would particularly like to know why preventDefault doesn't work.
If you are using chrome, there is a hint in the console:
[Intervention] Ignored attempt to cancel a touchmove event with cancelable=false, for example because scrolling is in progress and cannot be interrupted.
The problem is exactly that Event.cancelable. Unfortunately for you this property is read-only and it is not safe to call preventDefault for a not cancelable event. If you print e.cancelable in the TM function you can observe that throughout the scrolling e.cancelable is false.

Jquery Click need two tap on Mobile

I have a problem with Jquery hover and click on mobile.. Let me explain!
I have square div and, when the mouse is hover it, a new div appear and follow the mouse. You can even click the square div and if so, a new page is opened. The problem now is that, on mobile, I need two click for the new page to be opened, since the first click is read as "hover".
I tried the
$("#mydiv").on('click touchend', function(e)
Actually it works, but with this, if I want to scroll the page on mobile, and I start the swipe on the square div, the new page is opened, which it shouldn't since I didn't click on the square div, just "passed by".
Try using one of those events
https://github.com/benmajor/jQuery-Touch-Events#4-the-events
$('#mydiv').bind('tap', function(e) {
console.log('User tapped #myDiv');
});
As per documentation:
"The event's target is the same element that received the touchstart event corresponding to the touch point, even if the touch point has moved outside that element."
You can see the documentation of touchend also:
https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
If you start your scroll with the square div then square div touchend event will be fired after the release of that finger even after you move your finger to the other elements.
To solve this problem, you can use these events:
https://github.com/benmajor/jQuery-Touch-Events#4-the-events
If you want to stick with this touchend event then there is a workaround:
Declare a global variable i.e.
var isScroll = false, timer;
Apply touchmove eventhandler on document which will fired for touch devices only, this handler detect whether the document is getting scrolled if yes set the isScroll flag to true that will false after 500ms:
$(document).on("touchmove", function(e) {
isScroll = true;
if(timer) clearTimeout(timer);
timer = setTimeout(function() {
isScroll = false;
}, 800);
})
and insert if condition in your eventHandler:
$("#mydiv").on('click touchend', function(e) {
if(!isScroll) {
//insert your code here;
}
}

Javascript onscroll event not being called

I have an instant chat program I've created with HTML5/CSS, Asynch. Javascript and PHP. I have an interval that is constantly checking the user's chat box div is scrolled to the bottom for user convenience. This became a problem when a user wished to scroll up to view previous messages so I tried the onscroll event to stop the interval. I couldn't get this to work and so have gone the longer way around by using the onmouseover and onmouseout events to start and stop the interval.
This works perfectly fine for desktop computers as they have a visible mouse. For mobile devices however, such as my Windows phone - which the program is primarily designed for, there is an issue as you first have to tap the message box (presumably to first move the invisible mobile mouse over the chat box) and then scroll with the finger movement to scroll unaffected.
This isn't a major problem as I could inform mobile users to first tap then scroll, but I feel that successfully using the onscroll event would match the usability with desktop users.
Are there known issues with the onscroll event? I dare say I'm familiar with JS events and can use them appropriately, but this is the only event I haven't managed to get to work, in FF or IE.
Any thoughts or help would be appreciated,
Lee.
Here are the current events that manage the scrollcheck on/off, where ScrollCheck() is the function that checks the scroll position and moves it if not at the bottom and scrollInterval is the global var that holds the id of the interval.
document.getElementById('messages').onmouseover = function()
{
clearInterval(scrollInterval);
}
document.getElementById('messages').onmouseout = function()
{
scrollInterval = setInterval(ScrollCheck, 300);
}
I simply replaced the onmouseover event to onscroll without any luck.
When I make a chat page, I only check the scroll when new messages are added:
var currentScroll = elem.scrollTop, oldmaxScroll = elem.scrollHeight-elem.clientHeight;
// add new message(s) here
var newmaxScroll = elem.scrollHeight-elem.clientHeight;
if( currentScroll == oldmaxScroll) elem.scrollTop = newmaxScroll;

mobile Safari vertical scrolling - how to detect when the window has stopped moving in Javascript

Is there a js method to detect when a vertical flick on a long iOS safari page has stopped moving, such as an equivalent to the pseudo:
window.element.momentumScroll == false
This is to detect if the decelerating content is still moving or the scroll event has finished.
Any and all clues gratefully received.
ADDENDUM I have not implemented any external libraries in my code (no jQuery etc) and need to find a native js listener/method to tell me when the flick scroll has ended.
doc.addeventlistener("scroll", function(e){setvariable to 1}, false)
doc.addeventlistener("noscroll", function(e){setvariable to 0}, false)
Method:
startTop = window.pageYOffset on touchStart
currTop = window.pageYOffset on touchEnd
deltaTop = startTop - currTop
deltaTop == 0 means no momentum scrolling occurred during another event.
I'm not sure if I understood the question correctly. I believe u are trying to achieve something like loading new content when the page reaches its bottom? (forgive me for assuming)
I think you are looking for some javascript gesture library, if your event is based on touches.
There are Mootools library on this
Powertools: http://cpojer.net/PowerTools/#!
Drag.Flick: http://mootools.net/forge/p/drag_flick
There should be equal implementation in other framework as well. (jQuery: http://jgestures.codeplex.com/)
Possible solution is to look for an event that can return the current position of touches that exceeds document.body.clientHeight (read: not cross platform) .
Hope I manage to point to the right way.
just do a setTimeout in the touchend event. The timeout will fire once the touchend has stopped working. Timers get paused during touch event. On ios set timeout will fire once the page has stopped scrolling and there is no longer momentum.
body.addeventlistener("ontouchend", function(e){
setTimeout(function(){
alert("done moving")
},0);
}, false);
or
$('body').on('touchend.scroll', function () {
setTimeout(function(){
alert("done moving")
},0);
});
Note that Android will fire the event as soon as you let your finger go. Timers dont seem to be paused.

Detect if mouse is over an element when page loads with Javascript

I have an image that I want to have trigger certain behaviors when the mouse is over, I have a mouseover and mouseout method, but if you happen to have your mouse over the image when the page loads, the mouseover method never fires until you leave the image and come back over it.
Is there a way to detect if the mouse is over an element on the fly without the mouse having to be off of the element and then come over the element to trigger the JS mouseover event? Like is there a document.getElementById("blah").mouseIsOver() type function in Javascript?
I believe this is possible without any action from the user. When your page loads, bind the mouseover event to your image and hide your image (i.e. using CSS display:none). Use setTimeout() to show it again in a few milliseconds (10 should be enough). The even should be fired.
If you don't want to cause the 'flick' effect on your image, you may try using some temporary element instead, attaching event to it, and delegating the event onto your image.
I have no idea if this is cross-browser solution, but it worked from my Firefox 3.0 console ;)
You could use the mousemove event. That would trigger anytime the user moves a mouse; so the only instance of the trigger not firing would be if the user does not move the mouse at all, which should be rare.
The only problem with this is that the event would fire anytime the mouse would move over your image, so you would get a LOT of those events while over the component. What you would probably need to do is implement some sort of flag within your method when the event fires. You turn on the flag when the event first fires, and you turn it off when you leave the component.
This is less than ideal, but I think this will probably satisfy your problem scenario. The following is some quick pseudo code on what that solution might look like, I think it should work.
<img src="blah.png" onmousemove="JavaScript:triggerOn(event)" onmouseout="JavaScript:triggerOff(event)"/>
...
<script type='text/javascript'>
var TriggerActive = false;
function triggerOn(e){
e = e||window.e;
if( !TriggerActive){
TriggerActive = true;
// Do something
} else {
// Trigger already fired, ignore this event.
}
}
function triggerOff(e){
e = e||window.e;
if(TriggerActive)
TriggerActive = false;
}
</script>
You can find some great mouse event information including browser compatibility notes here.
Use document.querySelectpor and onload/onready events.
var a = document.querySelector('#a:hover');
if (a) {
// Mouse cursor is above a
}
else {
// Mouse cursor is outside a
}
There is no way to get the mouse coordinates aside from listening for mouse events, namely mousemove, mouseover etc. However, these events are very sensitive in the sense that moving the cursor by just one pixel is enough to trigger them, so having the cursor hover over your image while perfectly still should be somewhat unusual.

Categories

Resources