prevent mousewheel 1s after mousewheel - javascript

I have a problem, i want like this:
$(window).on('mousewheel', function(event) {
//prevent mousewheel in 1s
//do something, after 1s, enable mousewheel
}
or like this:
you rolled wheel many times in 1s, function in event mousewheel run 1 times.
Someone help me!

You could do something like this:
var mouseWheelEnabled = true;
function doSomethingWithMousewheel(event){
if(mouseWheelEnabled){
//... your code here
// set enabled = false;
mouseWheelEnabled = false;
setTimeout(function(){
mouseWheelEnabled = true;
}, 1000);
}
}
$(window).on('mousewheel', doSomethingWithMousewheel);

var scrollstop = false;
$(window).on('mousewheel', function(event) {
if(!scrollstop) {
scrollstop = true;
setTimeout(() => { scrollstop = false; }, 1000);
}
}
Something like this?

var pauseWheel = false;
$(window).on('mousewheel', function(event) {
if(pauseWheel) {
event.preventDefault();
}
else {
pauseWheel = true;
setTimeout(function(){ pauseWheel = false; }, 1000);
}
}
pauseWheel is a variable true if the mousewheel event fired in the last 1000ms.

Related

how to stop executting eventlisteners

Hi I've got some issues with my small project. I want to stop executting the mousedown and mousemove event after the mouseup event invokes. But after that the mousedown event must be active again. It should work like a reset. Here is the code
function quotesMouseDown(event) {
var isMouseDown = true;
document.getElementById("quotes").addEventListener("mouseup",
function() {
isMouseDown = false;
});
if (isMouseDown == false) {
return false;
}
else {
var mDownX = event.pageX;
document.getElementById("quotes").addEventListener("mousemove", quotoesMouseMove);
function quotoesMouseMove(event) {
var mMoveX = event.pageX;
console.log(mMoveX);
console.log(mDownX + "cos")
}
}
console.log(isMouseDown);
}
document.getElementById("quotes").addEventListener("mousedown", quotesMouseDown);
Just detach the mousedown callback at the end of the mouseup callback:
document.getElementById("quotes").addEventListener("mouseup", function() {
isMouseDown = false;
document.getElementById("quotes").removeEventListener("mousedown", quotesMouseDown);
});

Run function once then disallow further calls for 5 seconds

I want to stop a function being fired again for 5 seconds after the last.
This is what I had:
return {
buildUI: function() {
el.nav.on({
mouseenter: function() {
el.logo.addClass('spin');
},
mouseleave: function() {
el.logo.removeClass('spin');
}
});
}
}
On mouseenter, add class to spin the logo. On mouseleave, remove the class. But to stop the logo spinning every mouseenter, I want to add a 5 second ban since the last.
This is what I tried, amongst other attempts:
var flipLogoTimer;
return {
el.nav.on({
mouseenter: function() {
if (!flipLogoTimer) {
el.logo.removeClass('spin').addClass('spin');
}
},
mouseleave: function() {
el.logo.removeClass('spin');
flipLogoTimer = setTimeout(function() {
//
}, 5000);
}
});
}
I tried to add a 5 second timer to the mouseleave event, so the next mouseenter can check if the timer is still running to determine whether or not to run the animation again.
Where am I going wrong and is there a better way? It's a difficult one to search for, as there are so many questions about running a function on a timer.
You can use the flag like
return {
buildUI: function () {
var flag = false;
el.nav.on({
mouseenter: function () {
if (flag) {
return;
}
el.logo.addClass('spin');
},
mouseleave: function () {
if (flag) {
return;
}
flag = true;
el.logo.removeClass('spin');
setTimeout(function () {
flag = false;
}, 5000)
}
});
}
}
You can try something like this by toggling value of flipLogoTimer
var flipLogoTimer=false;
return {
el.nav.on({
mouseenter: function() {
if (!flipLogoTimer) {
el.logo.removeClass('spin').addClass('spin');
}
},
mouseleave: function() {
el.logo.removeClass('spin');
flipLogoTimer=true;
setTimeout(function() {
flipLogoTimer=false;
}, 5000);
}
});
}
You can use timestamp. Idea: you fix last time when you added/removed class, and compare it with current date.
// 5000 - equal to 5 seconds
function checkTimestamp(a, b){
return Math.abs(a - b) < 5000;
}
return {
buildUI: function () {
var lastTimeStamp = null;
el.nav.on({
mouseenter: function () {
if(lastTimeStamp && checkTimestamp(lastTimeStamp, Date.now())
return false;
el.logo.addClass('spin');
lastTimeStamp = Date.now();
},
mouseleave: function () {
if(lastTimeStamp && checkTimestamp(lastTimeStamp, Date.now())
return false;
el.logo.removeClass('spin');
lastTimeStamp = Date.now();
}
});
}
}

Setinterval with exponential time decrease

I've got a mousedown event with a setinterval. I want the time of intervals to be variable. So the first one is 500, the second one 500/2 = 250, etc. Any tips?
$plus.mousedown(function(e) {
increment(20)
timeout = setInterval(function(){
increment(20)
}, 500);
});
$(document).mouseup(function(){
clearInterval(timeout);
return false;
});
Cheers!
EDIT: sorry for the ambiguity. I want the time of interval to change during the mousedown. So while the mousedown is being performed the intervaltime should change. So not by every single mouse click but with every continuous click, and then reset it again.
You can't really do this with setInterval() unless you keep clearing for a delay change, so you might as well write a wrapper around setTimeout() to accomplish something similar:
function easingTimeout(delay, fn)
{
var id,
invoker = function() {
fn();
delay = Math.floor(delay / 2);
if (delay) {
id = setTimeout(invoker, delay);
} else {
id = null;
}
}
// start it off
id = setTimeout(invoker, delay);
return {
clear: function() {
if (id) {
clearTimeout(id);
id = null;
}
}
}
To use:
var timeout;
$plus.mousedown(function(e) {
increment(20);
timeout = easingTimeout(500, function() {
increment(20);
});
});
$(document).mouseup(function(){
timeout.clear();
return false;
});
This solution does not depend on jQuery:
var timeoutInterval = 500;
var mousedown = false;
function incrementAndWait() {
if (!mousedown) return;
increment(20);
timeout = setTimeout(incrementAndWait, timeoutInterval);
timeoutInterval /= 2;
}
document.onmousedown = function() {
timeoutInterval = 500; // Reset to 500 to allow multiple mousedown/mouseup
mousedown = true;
incrementAndWait();
};
document.onmouseup = function() {
mousedown = false;
}
You can add console.log((new Date).getTime(), 20); to the incrementAndWait method to see the numbers going on the console. Something fun to play with :)

How would I toggle the state of a setInterval function in jQuery?

I want to be able to click a an element with an id of pause to start a count of the elements in a time object and if I re click the pause it will stop it and reclick start it exactly like the toggle feature in JQuery but with a setInteval function how would I go about doing this?
$("#pause").click(function(ffe) {
if(on == true) {
on = false
alert("on");
}
else {
on = true;
alert("off");
}
if(on == false) {
setInterval(function() {
$("#timet ul").append("<li>" + $("#time ul")
.children('li').length +"</li>");
}, 100);
}
else {
alert("Error");
}
});
A classic technique is to use a single master setInterval loop and simply use if..else logic to determine what needs to run. This is how a lot of javascript games work:
var on = true;
// Our master scheduler:
setInterval(function() {
if (on) {
$("#timet ul").append("<li>" + $("#time ul")
.children('li').length +"</li>");
}
}, 100);
// Code to handle the pause button
$("#pause").click(function(ffe) {
on = !on;
}
You can use the setTimeout function, if you want to run the function once, setInterval runs continuously, try the following:
var on = false;
$("#pause").click(function(ffe) {
if (on) {
on = false;
setTimeout(function() {
$("#timet ul").append("<li>" + $("#time ul")
.children('li').length +"</li>");
}, 100);
} else {
on = true;
}
});
You need to use .clearInterval() to stop the execution.
Here is the code: (THE WORKING DEMO)
$("#pause").click((function () {
var interId = null;
var $ul = $("#timet ul");
return function (e) {
if (interId) {
$(this).text("start");
clearInterval(interId);
interId = null;
} else {
$(this).text("pause");
interId = setInterval(function () {
$ul.append($('<li>').text($('li', $ul).length));
}, 100);
}
};
}()));​

How do I know when I've stopped scrolling?

How do I know when I've stopped scrolling using Javascript?
You can add an event handler for the scroll event and start a timeout. Something like:
var timer = null;
window.addEventListener('scroll', function() {
if(timer !== null) {
clearTimeout(timer);
}
timer = setTimeout(function() {
// do something
}, 150);
}, false);
This will start a timeout and wait 150ms. If a new scroll event occurred in the meantime, the timer is aborted and a new one is created. If not, the function will be executed. You probably have to adjust the timing.
Also note that IE uses a different way to attach event listeners, this should give a good introduction: quirksmode - Advanced event registration models
There isn't a "Stopped Scrolling" event. If you want to do something after the user has finished scrolling, you can set a timer in the "OnScroll" event. If you get another "OnScroll" event fired then reset the timer. When the timer finally does fire, then you can assume the scrolling has stopped. I would think 500 milliseconds would be a good duration to start with.
Here's some sample code that works in IE and Chrome:
<html>
<body onscroll="bodyScroll();">
<script language="javascript">
var scrollTimer = -1;
function bodyScroll() {
document.body.style.backgroundColor = "white";
if (scrollTimer != -1)
clearTimeout(scrollTimer);
scrollTimer = window.setTimeout("scrollFinished()", 500);
}
function scrollFinished() {
document.body.style.backgroundColor = "red";
}
</script>
<div style="height:2000px;">
Scroll the page down. The page will turn red when the scrolling has finished.
</div>
</body>
</html>
Here's a more modern, Promise-based solution I found on a repo called scroll-into-view-if-needed
Instead of using addEventListener on the scroll event it uses requestAnimationFrame to watch for frames with no movement and resolves when there have been 20 frames without movement.
function waitForScrollEnd () {
let last_changed_frame = 0
let last_x = window.scrollX
let last_y = window.scrollY
return new Promise( resolve => {
function tick(frames) {
// We requestAnimationFrame either for 500 frames or until 20 frames with
// no change have been observed.
if (frames >= 500 || frames - last_changed_frame > 20) {
resolve()
} else {
if (window.scrollX != last_x || window.scrollY != last_y) {
last_changed_frame = frames
last_x = window.scrollX
last_y = window.scrollY
}
requestAnimationFrame(tick.bind(null, frames + 1))
}
}
tick(0)
})
}
With async/await and then
await waitForScrollEnd()
waitForScrollEnd().then(() => { /* Do things */ })
(function( $ ) {
$(function() {
var $output = $( "#output" ),
scrolling = "<span id='scrolling'>Scrolling</span>",
stopped = "<span id='stopped'>Stopped</span>";
$( window ).scroll(function() {
$output.html( scrolling );
clearTimeout( $.data( this, "scrollCheck" ) );
$.data( this, "scrollCheck", setTimeout(function() {
$output.html( stopped );
}, 250) );
});
});
})( jQuery );
=======>>>>
Working Example here
I did something like this:
var scrollEvents = (function(document, $){
var d = {
scrolling: false,
scrollDirection : 'none',
scrollTop: 0,
eventRegister: {
scroll: [],
scrollToTop: [],
scrollToBottom: [],
scrollStarted: [],
scrollStopped: [],
scrollToTopStarted: [],
scrollToBottomStarted: []
},
getScrollTop: function(){
return d.scrollTop;
},
setScrollTop: function(y){
d.scrollTop = y;
},
isScrolling: function(){
return d.scrolling;
},
setScrolling: function(bool){
var oldVal = d.isScrolling();
d.scrolling = bool;
if(bool){
d.executeCallbacks('scroll');
if(oldVal !== bool){
d.executeCallbacks('scrollStarted');
}
}else{
d.executeCallbacks('scrollStopped');
}
},
getScrollDirection : function(){
return d.scrollDirection;
},
setScrollDirection : function(direction){
var oldDirection = d.getScrollDirection();
d.scrollDirection = direction;
if(direction === 'UP'){
d.executeCallbacks('scrollToTop');
if(direction !== oldDirection){
d.executeCallbacks('scrollToTopStarted');
}
}else if(direction === 'DOWN'){
d.executeCallbacks('scrollToBottom');
if(direction !== oldDirection){
d.executeCallbacks('scrollToBottomStarted');
}
}
},
init : function(){
d.setScrollTop($(document).scrollTop());
var timer = null;
$(window).scroll(function(){
d.setScrolling(true);
var x = d.getScrollTop();
setTimeout(function(){
var y = $(document).scrollTop();
d.setScrollTop(y);
if(x > y){
d.setScrollDirection('UP');
}else{
d.setScrollDirection('DOWN');
}
}, 100);
if(timer !== 'undefined' && timer !== null){
clearTimeout(timer);
}
timer = setTimeout(function(){
d.setScrolling(false);
d.setScrollDirection('NONE');
}, 200);
});
},
registerEvents : function(eventName, callback){
if(typeof eventName !== 'undefined' && typeof callback === 'function' && typeof d.eventRegister[eventName] !== 'undefined'){
d.eventRegister[eventName].push(callback);
}
},
executeCallbacks: function(eventName){
var callabacks = d.eventRegister[eventName];
for(var k in callabacks){
if(callabacks.hasOwnProperty(k)){
callabacks[k](d.getScrollTop());
}
}
}
};
return d;
})(document, $);
the code is available here: documentScrollEvents
Minor update in your answer. Use mouseover and out function.
$(document).ready(function() {
function ticker() {
$('#ticker li:first').slideUp(function() {
$(this).appendTo($('#ticker')).slideDown();
});
}
var ticke= setInterval(function(){
ticker();
}, 3000);
$('#ticker li').mouseover(function() {
clearInterval(ticke);
}).mouseout(function() {
ticke= setInterval(function(){ ticker(); }, 3000);
});
});
DEMO
I was trying too add a display:block property for social icons that was previously hidden on scroll event and then again hide after 2seconds. But
I too had a same problem as my code for timeout after first scroll would start automatically and did not had reset timeout idea. As it didn't had proper reset function.But after I saw David's idea on this question I was able to reset timeout even if someone again scrolled before actually completing previous timeout.
problem code shown below before solving
$(window).scroll(function(){
setTimeout(function(){
$('.fixed-class').slideUp('slow');
},2000);
});
edited and working code with reset timer if next scroll occurs before 2s
var timer=null;
$(window).scroll(function(){
$('.fixed-class').css("display", "block");
if(timer !== null) {
clearTimeout(timer);
}
timer=setTimeout(function(){
$('.fixed-class').slideUp('slow');
},2000);
});
My working code will trigger a hidden division of class named 'fixed-class' to show in block on every scroll. From start of latest scroll the timer will count 2 sec and then again change the display from block to hidden.
For more precision you can also check the scroll position:
function onScrollEndOnce(callback, target = null) {
let timeout
let targetTop
const startPosition = Math.ceil(document.documentElement.scrollTop)
if (target) {
targetTop = Math.ceil(target.getBoundingClientRect().top + document.documentElement.scrollTop)
}
function finish(removeEventListener = true) {
if (removeEventListener) {
window.removeEventListener('scroll', onScroll)
}
callback()
}
function isScrollReached() {
const currentPosition = Math.ceil(document.documentElement.scrollTop)
if (targetTop == null) {
return false
} else if (targetTop >= startPosition) {
return currentPosition >= targetTop
} else {
return currentPosition <= targetTop
}
}
function onScroll() {
if (timeout) {
clearTimeout(timeout)
}
if (isScrollReached()) {
finish()
} else {
timeout = setTimeout(finish, 500)
}
}
if (isScrollReached()) {
finish(false)
} else {
window.addEventListener('scroll', onScroll)
}
}
Usage example:
const target = document.querySelector('#some-element')
onScrollEndOnce(() => console.log('scroll end'), target)
window.scrollTo({
top: Math.ceil(target.getBoundingClientRect().top + document.documentElement.scrollTop),
behavior: 'smooth',
})
Here's an answer that doesn't use any sort of timer, thus in my case predicted when the scrolling actually ended, and is not just paused for a bit.
function detectScrollEnd(element, onEndHandler) {
let scrolling = false;
element.addEventListener('mouseup', detect);
element.addEventListener('scroll', detect);
function detect(e) {
if (e.type === 'scroll') {
scrolling = true;
} else {
if (scrolling) {
scrolling = false;
onEndHandler?.();
}
}
}
}

Categories

Resources