Problem with Animating Number Counter on Javascript - javascript

I was hoping to create a counter which would increment to the eventual number of followers. I have other code, but I just included the part that would affect the incrementation. Currently, when I run the program the HTML file only displays the final number of followers, and the word "Followers" showing it is able to get the proper number, but it isn't able to have an incrementation animation as I would like. How would I go about fixing this?
var text_field = document.getElementById('followers');
fetch(api)
.then((response) => {
return response.json();
})
.then((data) => {
var number = data['Count'][0][0];
const updateCount = () => {
const target = number;
const count = text_field.innerText;
const increment = target / speed;
if (count < target) {
text_field.innerText = count + increment;
setTimeout(updateCount, 5);
} else {
text_field.innerText = target + ' Followers';
}
};
updateCount();
});

The innerText property returns a string value. Use the parseInt function before any calculations.
var text_field = document.getElementById("followers");
function counter(){
var number = 100;
const updateCount = () => {
const target = number;
const count = parseInt(text_field.innerText); //parsing
const speed=number;
const increment = target / speed;
if (count < target) {
text_field.innerText = count + increment;
setTimeout(updateCount, 5);
} else {
text_field.innerText = target;
}
};
updateCount();
}
counter();
<div id="followers">1</div> Followers!!!

Related

How do I switch the running codes using the IF?

Bear with me, I just started learning JS yesterday trying to make a HTML clock by putting multiple tutorials' results together.
I made two looping animations using 2 arrays, with the intent of switching between arrays depending on if it's earlier or later than 8pm. I would like for my code to constantly check if it's 8pm every X amount of seconds, and only re-run the script if the IF result or output is different than what it currently is.
const now = new Date();
if (now.getHours() > 20) { // Time checker!!!!!
var hat = ['A','B','C','D'],
a = -1;
(function f(){
a = (a + 1) % hat.length;
const hatformatted = `${(hat[ a ])}`;
document.querySelector(".main").textContent = hatformatted;
setTimeout(f, 1000);
})();
} else {
var hat = ['1','2','3','4'],
a = -1;
(function f(){
a = (a + 1) % hat.length;
const hatformatted = `${(hat[ a ])}`;
document.querySelector(".main").textContent = hatformatted;
setTimeout(f, 1000);
})();
}
I have tried setInterval however it re-runs the script even if the IF result has not changed, and messes up the animation.
I.E - if it's 6pm, it tries to play the animation from the start every 1 second and the frames get messed up.
Any advice or help would be great, thanks!
I tried to save your code.
const checkTimeDelay = 1000;
let isAbove8PM = null;
let curTimeHandler = null;
let intervalId = null;
// checking if is above 8 pm
const checkTime = () => {
const now = new Date();
if (now.getHours() > 20) {
return true;
}
return false;
};
const above8PMHandler = () => {
var hat = ['A','B','C','D'],
a = -1;
return () => {
a = (a + 1) % hat.length;
const hatformatted = `${(hat[ a ])}`;
document.querySelector(".main").textContent = hatformatted;
// setTimeout(f, 1000);
};
};
const before8PMHandler = () => {
var hat = ['1','2','3','4'],
a = -1;
return () => {
a = (a + 1) % hat.length;
const hatformatted = `${(hat[ a ])}`;
document.querySelector(".main").textContent = hatformatted;
// setTimeout(f, 1000);
};
};
// restart clock interval on based on new handler (above8PMHandler|before8PMHandler)
const rebaseClockInterval = () => {
clearInterval(intervalId);
intervalId = setInterval(curTimeHandler, 1000);
};
// main func, checks if we should change clocks handler (above8PMHandler|before8PMHandler)
const clockTick = () => {
const curTimeChecked = checkTime();
if (curTimeChecked === isAbove8PM) { return; }
isAbove8PM = curTimeChecked;
if (isAbove8PM) {
curTimeHandler = above8PMHandler();
} else {
curTimeHandler = before8PMHandler();
}
curTimeHandler();
rebaseClockInterval();
};
// start main func
setInterval(clockTick, checkTimeDelay);
I also provide some ideas here.
function setClockInterval() {
const hat1 = ['A', 'B', 'C', 'D'];
const hat2 = ['1', '2', '3', '4'];
let prevCheck = null;
let count = 0;
const checker = () => {
return new Date().getSeconds() > 20;
};
const next = () => {
count++;
};
const reset = () => {
count = 0;
};
const render = (content) => {
// console.log(`clockInterval ${content}`); // debug output
document.querySelector(".main").textContent = content;
};
const fn = () => {
const check = checker();
const arr = check ? hat1 : hat2;
// empty arr skip
if (arr.length <= 0)
return;
// restart count to 0
if (prevCheck !== null && prevCheck !== check)
reset();
render(arr[count % arr.length]);
prevCheck = check;
next();
};
return setInterval(fn, 1000);
}
// start interval
const clock = setClockInterval();
// stop
clearInterval(clock);
You can greatly simplify your code by removing everything from inside the if block that is repeated and running it afterward. You also need to get a new Date on each iteration, otherwise the array won't change when it gets to the designated time.
I have changed the condition check to be odd/even seconds to show how it swaps between arrays without losing the index.
// Global, could be kept inside closure
let a = -1;
// Function to run each iteration
(function f() {
// OP code
// let hat = new Date().getHours() > 18? ['A','B','C','D'] : ['1','2','3','4'];
// faster iteration as example
let hat = new Date().getSeconds() % 2? ['A','B','C','D'] :['1','2','3','4'];
a = (a + 1) % hat.length;
document.querySelector(".main").textContent = hat[a];
setTimeout(f, 1000);
})();
<div class="main"></div>

Store value in a variable

I am new in Javascript. I develop a program that store the score of humun and computer guess number. I want the human score and computer score will update when I call the updateScore() functions. However, it works but the score unable to increase by last score.
Here is the code:
let humanScore = 0;
let computerScore = 0;
let currentRoundNumber = 1;
// Write your code below:
const generateTarget = () => {
return Math.floor(Math.random()*10);
};
const compareGuesses = () => {
// Humun & Computer guess a number
const humunGuess = 1;
const computerGuess = 2;
// Call the generateTarget functions
const secretTargetNumber = generateTarget();
// Compare the difference between Target number and humun guess number
const humunTarget = Math.abs(humunGuess - secretTargetNumber);
// Compare the difference between Target number and computer guess number
const computerTarget = Math.abs(computerGuess - secretTargetNumber);
// Return true if humun won, false if computer won
if (humunTarget < computerTarget || humunTarget == computerTarget) {
return true;
}
else {
return false;
}
};
let updateScore = () => {
switch (compareGuesses()) {
case true:
return humanScore+=1;
case false:
computerScore+=1;
}
};
updateScore()
console.log(humanScore)
console.log(computerScore)
It is a programming language based on javascript event/trigger features. all variables are reset when you call the file again.
The variables seem to be reset every time you call the javascript file
let humanScore = 0,
computerScore = 0,
currentRoundNumber = 1;
// Write your code below:
const generateTarget = () => {
return Math.floor(Math.random() * 10);
};
const compareGuesses = () => {
// Humun & Computer guess a number
const humanGuess = 1;
const computerGuess = 2;
// Call the generateTarget functions
const secretTargetNumber = generateTarget();
// Compare the difference between Target number and humun guess number
const humanTarget = Math.abs(humanGuess - secretTargetNumber);
// Compare the difference between Target number and computer guess number
const computerTarget = Math.abs(computerGuess - secretTargetNumber);
// Return true if humun won, false if computer won
if (humanTarget < computerTarget) {
return true;
} else {
return false;
}
};
let updateScore = () => {
switch (compareGuesses()) {
case true:
return humanScore += 1;
case false:
computerScore += 1;
}
};
let showScore = () => {
updateScore();
console.log(humanScore)
console.log(computerScore)
}
<button onclick="showScore()">Click</button>
Woking Demo : https://jsfiddle.net/6v25y9qd/
Push click and show console
Because you're new, and I think #Onur Özkır is on to something, I will give some guidelines instead.
I understand that you mostly trying out to see if things works, and will refactor afterwards, but I recommend that you create methods that does only one thing. You already done that with generateTarget(), but if I look at compareGuesses(), that method doesn't just compare guesses. It also reads and generates numbers. I would instead read the values in updateScore() and then add them as parameters in compareGuesses.
By restricting your methods to only do one thing will make your code more readable, your methods will be smaller so they are easier to grasp, and the code is easier to debug.
I would also like to suggest that you only return a value at the end of the method, and always return (unless you can fit everything on one row) using a variable.
I also don't like switches in javascript, because the forced use of return. Would rather use ifs statement or a shorthand if statements, using conditional/ternary operator.
Use method names and variables to explain the code (ex. the constant HUMAN_WON in the code below). Try to avoid comments as far as possible. Comments should, IMHO, only be used if you generate a documentation. I suggest that you get your hands on Clean Code, which was a revelation for me to read, even as an experienced programmer.
I will refactor your code as a suggestion of how it can look like:
let humanScore = 0;
let computerScore = 0;
let currentRoundNumber = 1;
const HUMAN_WON = 1, COMPUTER_WON = -1, EQUAL = 0;
const generateTarget = () => {
return Math.floor(Math.random() * 10);
};
const readHumanGuess = () => {
return 1; // replace with appropriate code
}
const generateComputerGuess = () => {
return 2; // replace with generateTarget();
}
const compareGuesses = (humanGuess, computerGuess, secretTargetNumber) => {
let result = EQUAL;
const humanTarget = Math.abs(humanGuess - secretTargetNumber);
const computerTarget = Math.abs(computerGuess - secretTargetNumber);
if (humanTarget < computerTarget) {
result = HUMAN_WON;
} else if (computerTarget < humanTarget) {
result = COMPUTER_WON;
}
return result;
};
let updateScore = () => {
let humanGuess = readHumanGuess();
let computerGuess = generateComputerGuess();
let secretTargetNumber = generateTarget();
let whoWon = compareGuesses(humanGuess, computerGuess, secretTargetNumber);
if (whoWon == HUMAN_WON) {
humanScore++;
} else if (whoWon == COMPUTER_WON) {
computerScore++;
}
};
let displayCurrentScore = () => {
updateScore();
console.log(`${humanScore} vs ${computerScore}`);
}
<input type="button" onclick="displayCurrentScore()" value="Display Score">
You can even go one step further refactoring readGuesses() from updateScore() and separate updating UI—displayCurrentScore()—from handling logic in updateScore().
let humanScore = 0;
let computerScore = 0;
let currentRoundNumber = 1;
const HUMAN_WON = 1, COMPUTER_WON = -1, EQUAL = 0;
const generateTarget = () => {
return Math.floor(Math.random() * 10);
};
const readHumanGuess = () => {
return 1; // replace with appropriate code
}
const generateComputerGuess = () => {
return 2; // replace with generateTarget();
}
const readGuesses = () => {
let humanGuess = readHumanGuess();
let computerGuess = generateComputerGuess();
let secretTargetNumber = generateTarget();
return [humanGuess, computerGuess, secretTargetNumber]; // returning array
}
const compareGuesses = (humanGuess, computerGuess, secretTargetNumber) => {
let result = EQUAL;
const humanTarget = Math.abs(humanGuess - secretTargetNumber);
const computerTarget = Math.abs(computerGuess - secretTargetNumber);
if (humanTarget < computerTarget) {
result = HUMAN_WON;
} else if (computerTarget < humanTarget) {
result = COMPUTER_WON;
}
return result;
};
let updateScore = (humanGuess, computerGuess, secretTargetNumber) => {
let whoWon = compareGuesses(humanGuess, computerGuess, secretTargetNumber);
if (whoWon == HUMAN_WON) {
humanScore++;
} else if (whoWon == COMPUTER_WON) {
computerScore++;
}
return {'human': humanScore, 'computer': computerScore};
};
let displayCurrentScore = () => {
let [humanGuess, computerGuess, secretTargetNumber] = readGuesses();
let score = updateScore(humanGuess, computerGuess, secretTargetNumber);
console.log(`${score.human} vs ${score.computer}`);
}
<input type="button" onclick="displayCurrentScore()" value="Display Score">

Javascript Count Up Timer - How can I keep it from starting over on refresh?

I built a count up timer with JS to gradually count up to a number, but every time I refresh it resets. How can I make it so it doesn't reset every time?
const speed = 200; // The lower the slower
counters.forEach(counter => {
const updateCount = () => {
const target = +counter.getAttribute('data-target');
const count = +counter.innerText;
// Lower inc to slow and higher to slow
const inc = 1;
// console.log(inc);
// console.log(count);
// Check if target is reached
if (count < target) {
// Add inc to count and output in counter
counter.innerText = count + inc;
// Call function every ms
setTimeout(updateCount, 10000);
} else {
counter.innerText = target;
}
};
updateCount();
});

How do I implement a random number for my guessing game that doesn't keep changing until the user guesses it?

Every time I click "Confirm," it generates a new random number, so you can't actually guess it. And how do I display the number of tries the user has attempted guessing the number? Please help as I have been stuck on this for hours. Thanks!
const Home = () => {
const [enteredValue, setEnteredValue] = useState("");
const [confirmed, setConfirmed] = useState(false);
const [selectedNumber, setSelectedNumber] = useState();
const input = inputText => {
setEnteredValue(inputText.replace(/[^0-9]/g, ""));
};
const reset = () => {
setEnteredValue("");
setConfirmed(false);
};
const confirm = () => {
const chosenNum = parseInt(enteredValue);
setConfirmed(true);
setSelectedNumber(chosenNum);
setEnteredValue("");
let x = Math.floor(Math.random() * 100) + 1;
let count = 0;
if (!enteredValue) {
Alert.alert("Please Enter a Number");
} else if (chosenNum > x) {
Alert.alert("Guess Lower");
count+=1
} else if (chosenNum < x) {
Alert.alert("Guess Higher");
count+=1
} else if (chosenNum == x) {
Alert.alert("You Guessed Correctly");
}
};
let confirmedOutput;
if (confirmed) {
confirmedOutput = (
<View>
<Text style={styles.output}>Chosen Number: {selectedNumber}</Text>
<Text>Tries: </Text>
</View>
);
}
You're generating the x number inside the confirm function. So each time user guess (correct or not) x will be changed.
You should bring this:
let x = Math.floor(Math.random() * 100) + 1;
let count = 0;
out the function, somewhere when the game start, it'll be called.
And re-gen new x and reset count, when user guesses correct:
// ...
} else if (chosenNum == x) {
Alert.alert("You Guessed Correctly");
x = Math.floor(Math.random() * 100) + 1;
count = 0;
}
count is the user tries atempt, show it in view.

Get duration of a collection of audios

I am creating an audio player from an audio collection on an HTML page:
...
<div class="tr track" id="01">
<div class="td">
<button class="play" onclick="Play(this)">▶</button>
<button class="play" onclick="Pause(this)">❚❚</button>
<span class="title">A Corda da Liberdade</span>
</div>
<div class="td">
<audio preload="metadata" src="discografia/le-gauche-gnosis/01-a-corda-da-liberdade.ogg"></audio>
</div>
<div class="td">
<span class="duracao"></span>
</div>
</div>
...
I want the <span class="duracao"></span> element to show the duration of the audio it is related to:
// This function format the audio duration number in the way I want to present
function secToStr(sec_num) {
sec_num = Math.floor( sec_num );
var horas = Math.floor(sec_num / 3600);
var minutos = Math.floor((sec_num - (horas * 3600)) / 60);
var segundos = sec_num - (horas * 3600) - (minutos * 60);
if (horas < 10) {horas = "0"+horas;}
if (minutos < 10) {minutos = "0"+minutos;}
if (segundos < 10) {segundos = "0"+segundos;}
var tempo = minutos+':'+segundos;
return tempo;
}
var i;
var audios = document.getElementsByTagName('audio'); // get all audios elements of the player
for (i = 0; i < audios.length; i++) { // looping through audios
var audio = audios[i]; // get actual audio
var duracao = audio.parentNode.nextElementSibling.getElementsByClassName('duracao')[0] // get actual audio 'duration <span>'
audio.onloadedmetadata = function() {
duracao.innerHTML = secToStr(audio.duration);
}
}
The for loop is supposed to do the job but is just adding the duration of the last audio element to the last <span class="duracao"></span> element:
Any help?
The general approach with asynchronous loops would be to promisify the async action and then wait for a Promise.all(all_promises).
However, in this particular case, it might not be that easy:
Some browsers (Chrome to not tell their name) have a limit on the maximum number of parallel network requests a page can make for Media.
From there, you won't be able to get the duration of more than six different media at the same time...
So we need to load them one after the other.
The async/await syntax introduced in ES6 can help here:
const urls = [
'1cdwpm3gca9mlo0/kick.mp3',
'h8pvqqol3ovyle8/tom.mp3',
'agepbh2agnduknz/camera.mp3',
'should-break.mp3',
'/hjx4xlxyx39uzv7/18660_1464810669.mp3',
'kbgd2jm7ezk3u3x/hihat.mp3',
'h2j6vm17r07jf03/snare.mp3'
]
.map(url => 'https://dl.dropboxusercontent.com/s/' + url);
getAllDurations(urls)
.then(console.log)
.catch(console.error);
async function getAllDurations(urls) {
const loader = generateMediaLoader();
let total = 0;
for(let i = 0; i < urls.length; i++) {
total += await loader.getDuration(urls[i]);
}
return total;
}
// use a single MediaElement to load our media
// this is a bit verbose but can be reused for other purposes where you need a preloaded MediaElement
function generateMediaLoader() {
const elem = new Audio();
let active = false; // so we wait for previous requests
return {
getDuration,
load
};
// returns the duration of the media at url or 0
function getDuration(url) {
return load(url)
.then((res) => res && res.duration || 0)
.catch((_) => 0);
}
// return the MediaElement when the metadata has loaded
function load(url) {
if(active) {
return active.then((_) => load(url));
}
return (active = new Promise((res, rej) => {
elem.onloadedmetadata = e => {
active = false;
res(elem);
};
elem.onerror = e => {
active = false;
rej();
};
elem.src = url;
}));
}
}
But it's also very possible to make it ES5 style.
var urls = [
'1cdwpm3gca9mlo0/kick.mp3',
'h8pvqqol3ovyle8/tom.mp3',
'agepbh2agnduknz/camera.mp3',
'should-break.mp3',
'/hjx4xlxyx39uzv7/18660_1464810669.mp3',
'kbgd2jm7ezk3u3x/hihat.mp3',
'h2j6vm17r07jf03/snare.mp3'
]
.map(function(url) {
return 'https://dl.dropboxusercontent.com/s/' + url;
});
getAllDurations(urls, console.log);
function getAllDurations(urls, callback) {
var loader = new Audio();
var loaded = 0;
var total = 0;
loader.onloadedmetadata = function(e) {
total += loader.duration;
loadNext();
};
loader.onerror = loadNext;
loadNext();
function loadNext() {
if(loaded >= urls.length) {
return callback(total);
}
loader.src = urls[loaded++];
}
}
This is an excellent place to learn about, and then use Array.reduce() instead of a for-loop.
The concept of reduce is that you start with some starting value (which can be anything, not just a number), and you then walk through the array in a way that, at ever step, lets you run some code to update that value. So:
const total = [1,2,3,4,5].reduce( (sofar, value) => sofar + value, 0)
will run through the array, with start value 0, and at every step it runs (sofar, value) => sofar + value, where the first argument is always "whatever the original start value is at this point". This function assumes that value is a number (or a string) and adds (or concatenates) it to the start value. So at each step we get:
start = 0
first element: add 1 to this value: 0 + 1 = 1
second element: add 2 to this value: 1 + 2 = 3
third element: add 3 to this value: 3 + 3 = 6
fourth element: add 4 to this value: 6 + 4 = 10
fifth element: add 5 to this value: 10 + 5 = 15
We can apply the same to your audio elements: once they're all done loading in, you can tally their total duration with a single reduce call:
const total = audios.reduce((sofar, audioElement) => {
sofar += audioElement.duration;
}, 0); // this "0" is the starting value for the reduce-function's first argument
console.log(`Total number of seconds of play: ${total}`);
And then you can convert total into whatever format you need.
Alternatively, you can keep a global tally, but making each audo element update the total length themselves, simply by finishing loading:
let total = 0;
function updateTotal(increment) {
total += increment;
// and then update whatever HTML element shows that value on the page,
// in whatever format you need.
}
document.querySelectorAll('audio').forEach(element => {
element.onload = (evt) => {
updateTotal(element.duration);
})
});

Categories

Resources