I am currently working on a project that is showing and displaying DOM elements based on a countdown timer. There is another function calling this one every second.
Here is a code sample:
function eventsOnTimer() {
let x = 1;
const interval = setInterval(() => {
if (x >= 0.0 && x < 30.0) {
document.getElementById('thing1').style.display = 'block';
document.getElementById('thing2').style.display = 'none';
}
else if (x >= 30.0 && x < 60.0) {
document.getElementById('thing1').style.display = 'none';
document.getElementById('thing2').style.display = 'block';
}
x++;
}, 1000);
}
I'm trying to increase performance, and I'm doing this by trying to reduce the number of DOM requests and looking at alternative ways to fire code based on the countdown timer.
Something like
function eventsOnTimer(id1, id2, ms) {
let toggle = false, thing1 = document.getElementById(id1), thing2 = document.getElementById(id2);
const interval = setInterval(() => {
if(toggle){
thing1.style.display = 'block';
thing2.style.display = 'none';
} else{
thing1.style.display = 'none';
thing2.style.display = 'block';
}
toggle = !toggle;
}, ms);
}
eventsOnTimer('thing1', 'thing2', 30000);
You can store all of nodes references before run your timer to dicrease DOM access time (getElementById).
After that, using className instead of style property will be faster. You juste need declared an specific CSS rule per state.
I propose to you an generic function to set automatically all of your nodes with the same CSS class name.
JS
var nodeArray = [];
var max_node = 2;
function storeNodeRef() {
for(var i =1; i <= max_node; i++) {
nodeArray.push( document.getElementById("thing"+i)); // Your nodes are declared with ID thing"X". "X" is a numeric value, set "max_node" with the latest "X" value.
}
eventsOnTimer();
}
function setNodeClass(nodeClassName) {
var i = 0;
while(i < max_node) {
nodeArray[i++].className = nodeClassName;
}
}
function eventsOnTimer() {
let x = 1;
const interval = setInterval(() => {
if (x==30 || x == 60) { // declare here your different state, you can use multiple if/elseif or multiple switch case.
setNodeClass('hide myClass'+x); // Param : new className
}
x++;
}, 1000);
}
storeNodeRef();
CSS
.process > div, .hide {display:none;}
#thing2.myClass30, #thing1.myClass60, .process > div.show {display:block; }
HTML EXAMPLE
<div class="process">
<div id="thing1" class="show" >Hello World 1</div>
<div id="thing2">Hello World 2</div>
</div>
Related
i have a following function:
const catchingEggs = () => {
let eggIndex;
document.querySelector('html').style.backgroundColor = 'transparent';
leftArrow.style.display = 'none';
rightArrow.style.display = 'none';
player.removeEventListener('click', catchingEggs);
leftArrow.removeEventListener('click', choosePlayerLeft);
rightArrow.removeEventListener('click', choosePlayerRight);
document.querySelector('html').requestFullscreen();
myInterval = setInterval(function(){
if(score % 10 === 0) {
speed -= 10;
intervalScore += 5
}
if(heartIndex < 0) {
clearInterval(myInterval);
return;
}
eggIndex = Math.floor(Math.random()*4);
fallingEggs(allEggs[eggIndex], speed);
}, intervalLength);
}
which works fine, but if i want to keep reusing this function after clearInterval happened, by adding another catchingEggs() to the main function:
const playGame = () => {
screen.orientation.lock('landscape');
document.querySelector('html').style.backgroundColor = 'rgb(31, 28, 28)';
playerImages[0].style.display = 'block';
player.addEventListener('click', catchingEggs);
rightArrow.addEventListener('click', choosePlayerRight);
leftArrow.addEventListener('click', choosePlayerLeft);
}
to execute after a conditional, it doesn't do anything. Ideally i'd like to be able to change intervalLength while inside the interval, but that doesn't seem to be possible, so at least i want to be able to go around it by initiating the whole thing again, for example when score >= 20, so i added a new variable when true, as a condition of clearInterval (so far so good), and then inside playGame(): if new variable true catchingEggs(), but nothing happened.
thanks in advance.
What I am looking for would essentially be a "++" to a "++" command using native java script. The program simply runs an animation for a given number in which the idea of the animatio is that it adds 1 after one second, two after two seconds and keeps going in the same fashion until the animation is stopped.
var counter = 10;
var animationOn = false;
var counterAnimation;
var plusOne;
function updateCounter() {
//update the counter value
var plusOne = counter++;
for (var i = 1; i = < 100000000;) {
}
//show the counter
var counterSpan = document.getElementById("counterHolder");
counterSpan.innerHTML = plusOne;
}
function startCounterAnimation() {
if (animationOn == false) {
animationOn == true;
counterAnimation = setInterval(updateCounter, 1000);
}
}
function stopCounterAnimation() {
if (animationOn == true) {
animationOn == false;
}
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<button onclick="startCounterAnimation();">
Start counter animation
</button>
<button onclick="stopCounterAnimation();">
Stop counter animation
</button>
<span id="counterHolder">6931418</span>
</body>
</html>
You don't need the for loop.
You should assign to the global plusOne variable, not declare a local variable in the function.
You should add counter++ to it, not assign that directly.
Initialize plusOne from the number already in the output span.
Since your time intervals change between each update, you can't use setInterval(). Use setTimeout() to make a different timeout each time.
Use =, not ==, to assign to the animationOn variable.
var counter;
var animationOn = false;
var counterAnimation;
var plusOne = parseInt(document.getElementById("counterHolder").innerHTML);
function updateCounter() {
//update the counter value
plusOne += counter++;
//show the counter
var counterSpan = document.getElementById("counterHolder");
counterSpan.innerHTML = plusOne;
counterAnimation = setTimeout(updateCounter, counter * 1000);
}
function startCounterAnimation() {
if (!animationOn) {
animationOn = true;
counter = 1;
counterAnimation = setTimeout(updateCounter, 1000 * counter);
}
}
function stopCounterAnimation() {
if (animationOn) {
animationOn = false;
clearTimeout(counterAnimation);
}
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<button onclick="startCounterAnimation();">
Start counter animation
</button>
<button onclick="stopCounterAnimation();">
Stop counter animation
</button>
<span id="counterHolder">6931418</span>
</body>
</html>
You canĀ“t define var onePlus in two places, instead define it once and assign a value, var is wide scoped
Also add whatever logic you need in the for loop and put the onePlus ++ and counter as parts of the for loop
As it is now you are expecting to use the counter both outside the for loop and as the for loop middle part, which seems reduntant
Try something like(leaving the variable names as are):
var counter = 1000
for (var plusOne = 1; plusOne < counter; plusOne++) {
//Your logic in here
await sleep(1000);
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
This is my code and it runs, but I have to change the background color to red when the counter reaches zero.
<script>
window.onload = function () {
const tag = document.getElementById("tag1");
var time = 100;
const getTime = ()=>{
time = time - 1;
tag.innerHTML = "Goodbye Aliens: ship leaves in " + time + " secs ";
}
setInterval(getTime, 500);
}
</script>
<body>
<div>
<h1 id="tag1">Hello Earthling</h1>
</div>
</body>
<script>
const tag = document.getElementById("tag1");
tag.innerHTML = "Goodbye Aliens";
</script>
</html>
I thought of something like this in order to do it:
function changeColor() {
if (time == 0) {
document.change.bgColor = "red";
}
}
but it does not work and I do not understand where to put the code in the first place.
Please explain if someone has time. Thanks
My approach would be to check the time variable inside the GetTime method and calling changeColor when its 0.
Then you need to clear the interval using clearInterval to stop the loop.
function changeColor() {
document.querySelector("body").style.backgroundColor = "red";
}
window.onload = function () {
const tag = document.getElementById("tag1");
var time = 10;
const getTime = () =>{
time = time - 1;
tag.innerHTML = "Goodbye Aliens: ship leaves in " + time + " secs ";
if(time === 0){
changeColor();
window.clearInterval(interval);
}
}
var interval = setInterval(getTime, 500);
}
const tag = document.getElementById("tag1");
tag.innerHTML = "Goodbye Aliens";
<div>
<h1 id="tag1">Hello Earthling</h1>
</div>
I tend to favour setTimeout over setInterval. It seems more managable.
Note: I've used a class here instead of directly setting the style on the element.
const tag = document.getElementById('tag1');
// `getTime` accepts a time argument which
// we initialise as 100
function getTime(time = 100) {
// Print the message using `textContent` rather than `innerHTML`
tag.textContent = `Goodbye Aliens: ship leaves in ${time} secs`;
// If time reaches 0 set the background to red using a class
if (time === 0) {
tag.classList.add('red');
// Otherwise call `getTime` again passing in a decremented
// `time` value as the argument
} else {
setTimeout(getTime, 50, --time);
}
}
// Call `getTime` after showing the initial message
setTimeout(getTime, 2000);
.red { background-color: red; }
<div>
<h3 id="tag1">Hello Earthling</h3>
</div>
I have a problem. I created the following code! when you click on a button, a timer that lasts 3 seconds starts, the problem is that if I double click the button, the seconds go crazy, I would like to make sure that the click is reset as soon as the timer reaches 0! so that clicking again the timer always starts from 3 seconds!
document.getElementById("titolo").style.display="block"
count = 3 ;
setInterval(function(){
count--;
if(count>=0){
id = document.getElementById("titolo");
id.innerHTML = count;
}
if(count === 0){
document.getElementById("titolo").style.display="none" ;
}
},1000);
setInterval returns an ID that you can pass to clearInterval to cancel it. When the user clicks, cancel the existing ID and call setInterval again to reset it.
Capture the return value of setInterval so that later you can use it to call clearInterval.
You should disable (or hide) the button (or other element) that the user can click to start the count down.
Make sure to always declare your variables with var, let or const.
Don't use innerHTML when you only want to assign text (not HTML entities). For text (like the string representation of a counter) use textContent.
Here is how it could work:
let start = document.getElementById("start");
let id = document.getElementById("titolo");
start.addEventListener("click", function () {
start.disabled = true;
id.style.display = "block";
id.textContent = "3";
let count = 3;
let timer = setInterval(function(){
count--;
id.textContent = count;
if (count === 0) {
id.style.display = "none" ;
clearInterval(timer);
start.disabled = false;
}
}, 1000);
});
<button id="start">Start</button>
<div id="titolo"></div>
The function setInterval returns the unique id representing the interval. You can call the function clearInterval to delete that interval.
Example:
var intervalID = setInterval(function () { }, 0);
clearInterval(intervalID);
Example combined with your code:
var intervalID, count, dom = document.querySelector("#titolo");
document.querySelector("#button").addEventListener("click", onClick);
function onClick() {
clearInterval(intervalID);
dom.style.display = "block";
dom.textContent = 3;
count = 3;
intervalID = setInterval(function() {
count -= 1;
if (count >= 0) dom.textContent = count;
else {
dom.style.display = "none";
clearInterval(intervalID);
}
}, 1000);
}
<div id="titolo"></div>
<button id="button">Button</button>
I try to set a timeout on an element, fired with a jQuery plugin. This timeout is set again in the function depending on conditions. But, I want to clear this element's timeout before set another (if I relaunch the plug-in), or clear this manually.
<div id="aaa" style="top: 0; width: 100px; height: 100px; background-color: #ff0000;"></div>
Here's my code (now on http://jsfiddle.net/Ppvf9/)
$(function() {
$('#aaa').myPlugin(0);
});
(function($) {
$.fn.myPlugin = function(loops) {
loops = loops === undefined ? 0 : loops;
this.each(function() {
var el = $(this),
loop = loops,
i = 0;
if (loops === false) {
clearTimeout(el.timer);
return;
}
var animate = function() {
var hPos = 0;
hPos = (i * 10) + 'px';
el.css('margin-top', hPos);
if (i < 25) {
i++;
} else {
if (loops === 0) {
i = 0;
} else {
loop--;
if (loop === 0) {
return;
} else {
i = 0;
}
}
}
el.timer = window.setTimeout(function () {
animate();
}, 1000/25);
};
clearTimeout(el.timer);
//$('<img/>').load(function() {
// there's more here but it's not very important
animate();
//});
});
return this;
};
})(jQuery);
If I make $('#element').myPlugin();, it's launched. If I make it a second time, there's two timeout on it (see it by doing $('#aaa').myPlugin(0);
in console). And I want to be able to clear this with $('#element').myPlugin(false);.
What am I doing wrong?
EDIT :
SOLVED by setting two var to access this and $(this) here : http://jsfiddle.net/Ppvf9/2/
try saving the timeout handle as a property of the element. Or maintain a static lookup table that maps elements to their timeout handles.
Something like this:
el.timer = window.setTimeout(...);
I assume you need one timer per element. Not a single timer for all elements.