I know there is a bunch of other people who have posted questions about throttling functions and I have scrolled through them but most if not all are way above my level or include stuff like jquery and really weird logic to function.
I'm just trying to limit the number of changes a user can make per second, to stop them from spamming stuff.
I wrote my code with the help of this youtube video and I can understand it, for the most part. However it doesn't seem to work, I can't see any issues or blocks.
This is my first attempt at implementing throttling:
const throttle = (bad_func, limit) =>{
var flag = true;
document.getElementById('key').innerHTML = flag;
return function(){
let context = this;
let args = arguments;
if(flag){
bad_func.apply(context,args);
bad_func();
flag = false;
setTimeout(()=>{
flag = true;
},limit);
}
}
}
ThrottledFunc = throttle(logKey, 4000);
window.addEventListener('keydown', ThrottledFunc);
function logKey(e){
// document.getElementById('EKey').innerHTML = e.which;
if (e.which == 87){
document.getElementById('demo').innerHTML = 'forwards';
}
else if (e.which == 83){
document.getElementById('demo').innerHTML = 'backwards';
}
else{
document.getElementById('demo').innerHTML = 'empty';
}
}
But it doesn't work, I can still spam w and s. The "demo" changes but there is no delay.
For my second attempt I just said screw it and tried to implement the timeout thing into the function, still no luck:
window.addEventListener('keydown', logKey);
function logKey(e){
var flag = true;
var limit = 10000;
document.getElementById('key').innerHTML = flag;
if(flag){
if (e.which == 87){
flag = false;
document.getElementById('demo').innerHTML = 'forwards';
setTimeout(()=>{
flag =true;
}, limit);
}
else if (e.which == 83){
document.getElementById('demo').innerHTML = 'backwards';
flag = false;
setTimeout(()=>{
flag =true;
}, limit);
}
}
else{
document.getElementById('demo').innerHTML = 'empty';
}
}
What am I doing wrong?
I went thru a similar exercise a couple years ago.
I ended up coming up with a really tiny implementation:
throttled-event-listener.js
Here's a live demo that uses it.
And here's some docs on what the calling code looks like.
Hope this helps!
You need to build a closure, that means the variable flag must preserve its value between each logKey() invocation. The solution is to store it global (as below) or in a parent scope where logKey can access it.
window.addEventListener("keydown", logKey);
var flag = true;
var limit = 10000;
function logKey(e) {
document.getElementById("key").innerHTML = flag;
if (flag) {
if (e.which == 87) {
flag = false;
document.getElementById("demo").innerHTML = "forwards";
setTimeout(() => {
flag = true;
}, limit);
} else if (e.which == 83) {
document.getElementById("demo").innerHTML = "backwards";
flag = false;
setTimeout(() => {
flag = true;
}, limit);
}
} else {
document.getElementById("demo").innerHTML = "empty";
}
}
<div id="demo"></div>
<div id="key"></div>
I would suggest using a library like lodash that provides a throttle function.
Related
I created a stopwatch using JavaScript, and I'm trying to start/stop the timer by space key, but it doesn't stop but always became more faster.
'''
var timer_start = "S";
var time;
document.body.onkeyup = function (e) {
if (e.keyCode == 32) {
time = setInterval(timer, 10);
if (timer_start == "S") {
timer_start = "F";
} else if (timer_start == "F") {
clearInterval(time);
timer_start = "S";
}
}
};
,,,
Once the spacebar is pressed, you are starting the timer again regardless of the current value of timer_start. You need to move this to be inside the if statement. I'd also recommend using a Boolean instead of the string "S" and "F".
Here is my proposed rewrite of your code:
var timer_start = true;
var time;
document.body.onkeyup = function (e) {
if (e.keyCode == 32) {
if (timer_start) {
time = setInterval(timer, 10);
timer_start = false;
} else {
clearInterval(time);
timer_start = true;
}
}
};
You could also shorten it a bit by doing this if you wanted
var timer_start = true;
var time;
document.body.onkeyup = function (e) {
if (e.keyCode == 32) {
if (timer_start) {
time = setInterval(timer, 10);
} else {
clearInterval(time);
}
timer_start = !timer_start
}
};
You set the interval regardless of the timer_start state, so you keep piling up new intervals and remove only half of them. You should set the interval only in the timer_start == "S" branch.
I know that there are many similar questions, but I can't understand what is the mistake in my if statement.
So basically I want to stop clicking nextBtn once I hover over timeoutArea,
but this: timeoutArea.mouseover != true doesn't seems to work.
const timeoutArea = document.getElementById("slider");
var time = 1;
let interval = setInterval(function() {
if (time <= 20 && window.pageYOffset < 393) {
if (timeoutArea.mouseover != true) {
nextBtn.click();
};
time++;
}
else {
time = 1;
}
}, 2000);
if u are using jquery u can use $('#slider').is(':hover') in if statement.
if u use only pure javascript u can use with one function
example fiddle https://jsfiddle.net/9x5hjpk3/
function isHover(e) {
return (e.parentElement.querySelector(':hover') === e);
}
so change
if (timeoutArea.mouseover != true) {
nextBtn.click();
};
to
if (!isHover(timeoutArea)) {
nextBtn.click();
};
im trying to get the value of a variable that i have to increase by 5 each time that the up key is pressed.
Currently i have the variable increasing upon keypress etc but the main problem i have is that from one keypress, the value will continue rise. For example, value would start at 5, upon one keypress would continue to rise by 5 each time and would stop just after 600. Whereas i want it to start at 5 then upon each keypress go to 10,15,20....
Here's the code i have, i'd be grateful for the help on where im going wrong etc
var projectoryHeight = 5;
function setHeight()
{
projectoryHeight = projectoryHeight + 5;
};
if (keyCode == 38)
{
setHeight();
console.log(projectoryHeight);
};
The code that relates to keycode for the up key being placed, is inside a rendering function, for use with requestAnimationFrame(). I feel like this may be what is causing the issue of it continuing to count however I have tried moving it outside of this function and nothing happens.
Javascript being used alongside THREE.js & Physi.js
More code to help with problem:
var render = function() {
requestAnimationFrame(render);
scene.simulate();
let keyFlag = false;
// Update the title page shape rotations
sphere.rotation.y += 0.06;
sphere.rotation.x += 0.10;
sphere.rotation.z += 0.06;
document.addEventListener("keydown", (e) => {
if(e.code == 'KeyW'){
$(title).hide();
$(keyTitle).hide();
scene.remove(sphere);
sphere.geometry.dispose();
sphere.material.dispose();
//add all the game functions here
scene.add(cube);
scene.add(firingBall);
scene.add(struct1);
scene.add(struct2);
scene.add(struct3);
scene.add(struct4);
scene.add(struct5);
scene.add(struct6);
scene.simulate();
}
});
document.addEventListener("keydown", (e) => {
if(e.code == 'Space'){
firingBall.setLinearVelocity(new THREE.Vector3(speedOfBall, projectoryHeight, 0));
}
});
document.addEventListener("keydown", (e) => {
if(e.code == 'ArrowUp'){
if (!keyFlag) {
keyFlag = true;
projectoryHeight = projectoryHeight + 5;
console.log(projectoryHeight);
}
}
});
document.addEventListener("keydown", (e) => {
if(e.code == 'ArrowDown'){
if (!keyFlag) {
keyFlag = true;
projectoryHeight = projectoryHeight - 5;
console.log(projectoryHeight);
}
}
});
document.addEventListener("keyup", (e) => {
if(e.code == 'ArrowUp'){
if (keyFlag){
console.log("stopped");
keyFlag = false;
}
}
});
document.addEventListener("keyup", (e) => {
if(e.code == 'ArrowDown'){
if (keyFlag){
console.log("stopped");
keyFlag = false;
}
}
});
renderer.autoClear = false;
renderer.clear();
renderer.render(backgroundScene, backgroundCamera);
renderer.render(scene, camera);
};
This is the function where keypresses etc are used, inside the render function. Also starts the animation frames and game physics.
This function is then called directly after it is declared
Thanks
You need to set a flag that tells you whether or not a key is being held down. To do this in simple form, you can use the keydown event in conjunction with the keyup event. In the following code the key can be held down but it only performs an action once based on the flag.
i.addEventListener("keydown", (e) => {
if (!keyflag) console.log(e.key);
keyflag = true;
});
i.addEventListener("keyup", (e) => {
if (keyflag) console.log("released!");
keyflag = false;
});
let i = document.querySelector("input"),
keyflag = false;
i.addEventListener("keydown", (e) => {
if (!keyflag) console.log(e.key);
else e.preventDefault();
keyflag = true;
});
i.addEventListener("keyup", (e) => {
if (keyflag) console.log("released!");
else e.preventDefault();
keyflag = false;
});
<input>
Note inside the snippet I use e.preventDefault() to stop letters appearing in the input box. My intention was only that this would make it easier to see.
I'm trying to hide a video when the page loads and keep the video shown after any link is pressed
this is my current code
var videoplayer = document.getElementById("videoplayerlayer");
var links = document.getElementsByTagName("a");
if(localStorage !== 'undefined')
{
console.log("localStorage exists")
if(localStorage["vv"] == false)
{
videoplayer.style.display = "none";
localStorage["vv"] = false;
}
else
{
for( i=0; i<links.length; i++ )
{
links[i].onclick = function()
{
localStorage["vv"] = true;
videoplayer.style.display = "block";
console.log(localStorage["vv"]);
}
}
}
}
else
{
localStorage["vv"] == false;
}
localStorage only holds strings. localStorage["vv"] = false; stores the string "false", which is not falsy.
Normally I store JSON and parse it. That's probably overkill here, though, just store "Y" or "N" as the flag and check that:
var videoplayer = document.getElementById("videoplayerlayer");
var links = document.getElementsByTagName("a");
if (typeof localStorage !== 'undefined')
// ^^^^^^ Note 2
{
console.log("localStorage exists")
if(localStorage["vv"] == "N")
{
videoplayer.style.display = "none";
// No need, it's already stored - localStorage["vv"] = false;
}
else
{
for( var i=0; i<links.length; i++ )
// ^^^^---- Note 1
{
links[i].onclick = function()
{
localStorage["vv"] = "Y";
videoplayer.style.display = "block";
}
}
}
}
/* You don't want this, it'll throw an error, since we know `localStorage` is falsy
else
{
localStorage["vv"] == false;
}
*/
However, nothing in the logic reasonably sets localStorage["vv"] to "N" (the one assignment that was there was in a branch where it's already there). You'll need to add something to set it, unless you want to default to hiding the video player and only show it when localStorage["vv"] is "Y" (or if local storage isn't accessible).
For instance, this hides the player and only shows it if the flag is "Y" on load or one of those links is clicked:
var videoplayer = document.getElementById("videoplayerlayer");
var links = document.getElementsByTagName("a");
if (typeof localStorage !== "undefined") {
if (localStorage.vv !== "Y") {
videoplayer.style.display = "none";
}
for (var i = 0; i < links.length; i++)
{
links[i].onclick = function()
{
localStorage["vv"] = "Y";
videoplayer.style.display = "block";
};
}
}
Note 1: Your code was falling prey to The Horror of Implicit Globals (that's a post on my anemic little blog). Be sure to declare your variables. See the "Note" comment above.
Note 2: Your check for whether you can use local storage was incorrect. I've updated it to what you probably meant above, but see see here for more thorough checks you'll want to use.
Note 3: I would recommend using modern event handling rather than setting onclick.
Below code can help you
$get('<%= AnchorId.ClientID %>').click(function(){
if(localStorage !== 'undefined'){
if(localStorage == false)
{
$get('<%= videoplayerlayer.ClientID %>').hide();
localStorage["vv"] = false;
}
else
{
$get('<%= videoplayerlayer.ClientID %>').show()
localStorage["vv"] = true;
}
}
});
I have a javascript page which checks an email and username, this works fine in every browser but Internet Explorer. The div box where errors are shown should be hidden unless an error is given e.g. username taken or invalid email.
If the email gets an error this is shown in the div tag, but doesnt work for username (in all browsers)
below is my code:
<script type="text/javascript">
var usernameok;
var emailok;
function checksubmit()
{
if (usernameok && emailok) {
document.getElementById("button").disabled = false;
} else {
document.getElementById("button").disabled = true;
}
}
function username(username)
{
make_request();
function stateck()
{
if (httpxml.readyState == 4) {
if (httpxml.responseText.indexOf("Username Ok") >= 0) {
usernameok = true;
} else {
usernameok = false;
}
checkCanSubmit();
}
}
httpxml.onreadystatechange = stateck;
user_url = "check_username.php?username=" + username.value;
httpxml.open("GET", user_url, true);
httpxml.send(null);
}
function email(email)
{
make_request();
function stateck()
{
if (httpxml.readyState == 4) {
if (httpxml.responseText.indexOf("Email Ok") >= 0) {
emailok = true;
} else {
emailok = false;
}
checkCanSubmit();
}
}
httpxml.onreadystatechange = stateck;
email_url = "check_email.php?email=" + email.value;
httpxml.open("GET", email_url, true);
httpxml.send(null);
}
</script>
I see your function stateck() is the return function from the HTTP request. However, you are defining it within another function. Not as an anonymous function, but just as a function within another function.
I see what you're doing now...ok, try this instead:
httpxml.onreadystatechange = function()
{
if (httpxml.readyState == 4) {
if (httpxml.responseText.indexOf("Email Ok") >= 0) {
document.getElementById("email").style.backgroundColor = "green";
document.getElementById("email").style.color = "white";
document.getElementById("email_div").style.display = 'none';
emailok = true;
} else {
document.getElementById("email").style.backgroundColor = "red";
document.getElementById("email_div").innerHTML=httpxml.responseText;
emailok = false;
}
checkCanSubmit();
}
};
Do you need to set your initial state to display: none? I think IE may initialize the divs with a non-0 height whereas the divs may be technically visible in other browsers but too short to see.
Edit:
Okay I think I misunderstood your question. Your problem is not with hiding the divs but with displaying errors for the username.
Nothing obvious jumps out at me. Try stepping through the code using VS or VWDE:
http://www.berniecode.com/blog/2007/03/08/how-to-debug-javascript-with-visual-web-developer-express/