I have a wheel event setup but if you are using OS X, the event continues to fire because of the native elastic effect.
How do I prevent this elastic effect?
Here is some code...
window.addEventListener('wheel',function(){
pxCount++;
var starContainer =
document.getElementById('starContainer').style.left = '-'+50*pxCount+'px';
});
Here is the entire project http://codepen.io/www139/pen/wKbOJz
You could wrap your listener in a debounce function, the purpose of which being that a certain action is only performed once in a given time limit.
I'm a fan of this one: https://davidwalsh.name/javascript-debounce-function
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
You'd probably use it like this:
var wheelAction = debounce(function() {
pxCount++;
var starContainer =
document.getElementById('starContainer').style.left = '-'+50*pxCount+'px';
}, 250);
window.addEventListener('wheel', wheelAction);
Related
This question already has answers here:
How to detect when mouse has stopped
(2 answers)
Closed 1 year ago.
I would like to call a function when mousemove ends.
I have an onmousemove event listener like below which fires too many times:
window.onmousemove = (e) => { console.log(e) }
I would like to reduce calling the function too often to prevent high load.
For example, call the function once when the cursor stops.
If the are any other solutions I will be glad to try them as well.
You can wrap your event callback in a debounce function. This wrapping function will only get called if you stop for 1/4 of a second after you start moving the mouse. If you start moving within 250 milliseconds after stopping, the timeout will reset and wait till you stop again.
const debounce = function(func, wait, immediate) {
let timeout;
return function() {
const
context = this,
args = arguments,
later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
},
callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
const onMouseMove = (e) => {
console.log(`Stopped position: (${e.clientX}, ${e.clientY})`);
};
const debounceMouseMove = debounce(onMouseMove, 250); // 1/4 of a second
document.addEventListener('mousemove', debounceMouseMove);
There is no way of directly doing it. But you could try this:
var timeout;
element.onmousemove = function (e) {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(function() {
// do your stuff here
}, 200);
}
It will fire if there is no event detected for 200 milliseconds.
I have debounce funtion
function debounce(func, wait, immediate) {
// 'private' variable for instance
// The returned function will be able to reference this due to closure.
// Each call to the returned function will share this common timer.
var timeout;
// Calling debounce returns a new anonymous function
return function() {
// reference the context and args for the setTimeout function
var context = this,
args = arguments;
// Should the function be called now? If immediate is true
// and not already in a timeout then the answer is: Yes
var callNow = immediate && !timeout;
// This is the basic debounce behaviour where you can call this
// function several times, but it will only execute once
// [before or after imposing a delay].
// Each time the returned function is called, the timer starts over.
clearTimeout(timeout);
// Set the new timeout
timeout = setTimeout(function() {
// Inside the timeout function, clear the timeout variable
// which will let the next execution run when in 'immediate' mode
timeout = null;
// Check if the function already ran with the immediate flag
if (!immediate) {
// Call the original function with apply
// apply lets you define the 'this' object as well as the arguments
// (both captured before setTimeout)
func.apply(context, args);
}
}, wait);
// Immediate mode and no wait timer? Execute the function..
if (callNow) func.apply(context, args);
}
}
and some function for example :
const storageEventCb = () => console.error(1);
// Define the debounced function
var debouncedCb = debounce(storageEventCb, 1500);
debouncedCb(); // run
debouncedCb(); // ignore
debouncedCb(); // ignore
feel good but when I lisnener event storage
window.addEventListener('storage', storageEventCb );
I get many call function . How to fix ?
Well just set the debounced function as event listener?
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
const storageEventCb = () => console.error(1);
// Define the debounced function
const debouncedCb = debounce(storageEventCb, 1500);
window.addEventListener('storage', debouncedCb);
I'm trying to debounce keystrokes in a form input on IE Mobile 6 (from what I gather, about on par with IE 3-4 in terms of support).
Due to the lack of support, I can't add event listeners after declaration (i.e., document.getElementById('elementId').addEventListener(...) doesn't work), I can only do them inline, like onkeydown="doSomething()".
Here is a jsBin.
So, with this debounce function (taken from David Walsh):
function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this, args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
The recommended way to set up your event function would be like:
var doSomething = debounce(function() { ... }, 250);
However, I can't use this doSomething style function in the inline event listeners on IE Mobile 6.
So, in the markup, I've tried:
<input type="text" onkeydown="doSomething()" />
And
<input type="text" onkeydown="doSomething()()" />
And in javascript:
// return the result of debounce()
function doSomething() {
return debounce(function() { ... }, 250);
}
// just debounce()
function doSomething() {
debounce(function() { ... }, 250);
}
// return the result of the returned function of debounce, aka debounce()()
function doSomething() {
return debounce(function() { ... }, 250)();
}
I've also just tried putting the whole contents of the debounce function inside of this function, like:
function doSomething() {
var timeout, func, wait, immediate;
func = function() {
console.log('test');
};
wait = 250;
return function () {
var context = this, args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
So, long question short:
How can I write this exact statement:
var doSomething = debounce(...);
Like this:
function doSomething() {
}
You seem to have a pretty unique situation. Given that your target browser (IE Mobile 6) implements pretty old technologies (ECMAScript 3 and elements from IE 8), you won't be able to use the standard addEventListener method. Part of your problem is likely due to a mixture of the context limitations of using inline javascript along with the fact that you're programming against an old, old (1999) version of JS. Let's see how this works.
EDIT
Also make sure you're wrapping your code in some kind of document ready. I'll use jQuery to do that. That could be why your JS isn't executing.
HTML
<input type='text' id='theInput' />
<script src='yourDebounceScript.js'></script>
JS
// by the time this is executed,
// DOM elements above this script will be ready
(function() {
function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this, args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
var input = document.getElementById('theInput');
input.attachEvent('keydown' function() {
// wrap your debounce function in an anonymous function
// so that you can pass arguments to the debounce as needed
debounce(function() { /* ... */ }, 250, true);
});
})();
If you can use jQuery:
// make sure the document is ready before trying to access the DOM
$(function() {
// your debounce function here...
// jQuery will handle the version compatibility for you
$('#theInput').keydown(debounce);
});
I want to write a scroll callback function that gets called after every one second when user scrolls. I tried
window.on('scroll', function(e) {
//scroll function body
});
But the problem is it gets called everytime user scrolls even one pixel. Can someone please suggest a solution.
You can write a function like this
scrollCb = function(func, later) {
var timeout;
return function() {
var context = this, args = arguments;
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
and call it like
scrollCb(function() {
//Your scroll callback handler
}, 1000);
I am creating the app for the samsung smart tv. In that i want the volume bar to appear for 5 seconds after that it has to hide. If the user continuously presses the volume, it has to hide after 5 secs the user stops pressing the button. I tried like this:
var vt;
if($("#volume").css('display')=='none'){
$("#volume").show();
vt=setInterval(function(){$("#volume").hide();},5000);
}
else{
clearInterval(vt);
vt=setInterval(function(){$("#volume").hide();},5000);
}
when the user presses the button it is not clearing the interval instead it is creating the instance for every click
Try this:
if($("#volume").css('display')=='none'){
$("#volume").show();
vt = setTimeout(function(){$("#volume").hide();},5000);
}
else{
clearTimeout(vt);
vt = setTimeout(function(){$("#volume").hide();},5000);
}
This is bit sophisticated solution, picked from underscore library.
var debounce = function(func, wait, immediate) {
var timeout, result;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) {
result = func.apply(context, args);
}
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
}
return result;
};
};
var clickHandler = function(){
$("#volume").hide();
}
var debouncedClickHandler = debounce(clickHandler, 5000);
$('body').on('click', debouncedClickHandler) //change this line to your click handler
Now you don't have to do any thing, clickHandler will get called only after 5 seconds delay from last call to debouncedClickHandler