JS counting numbers with thousands separator - javascript

For example, I want to display the number 90,000 while it is counting up.
I have already managed to count up with the following code, but without "." or ",":
<div class="fact">
<div class="number" num="90000">0</div>
</div>
const counters = document.querySelectorAll('.number');
const speed = 500;
counters.forEach( counter => {
const animate = () => {
const value = +counter.getAttribute('num');
const data = +counter.innerText;
const time = value / speed;
if(data < value) {
counter.innerText = Math.ceil(data + time);
setTimeout(animate, 1);
}else{
counter.innerText = value;
}
}
animate();
});
Have already found examples with thousands separator but I can't manage to convert it to my project.
while (/(\d+)(\d{3})/.test(val.toString())){
val = val.toString().replace(/(\d+)(\d{3})/, '$1'+','+'$2');
I have little experience with javascript.

Per my comment, Keep data separate from formatting
const counters = document.querySelectorAll('.number');
const speed = 500;
const formatter = new Intl.NumberFormat();
counters.forEach(counter => {
const animate = () => {
let value = +counter.dataset.num;
let data = +counter.dataset.state;
let time = value / speed;
if (data < value) {
counter.dataset.state = Math.ceil(data + time);
setTimeout(animate, 1);
}
counter.innerText = formatter.format(counter.dataset.state);
}
animate();
});
<div class="fact">
<div class="number" data-num="90000" data-state="0">0</div>
<div class="number" data-num="45000" data-state="0">0</div>
</div>

Related

HTML number input - how to increase step size w/ time held

For number inputs in HTML, is there any way to have it function such that the longer the user holds the stepper arrows, the larger the increment/step size becomes?
For example, we start out at step size=1, but after a few seconds of holding, it will ramp up to 5, 10, 20, ... etc.
Is this possible?
Thanks!
The step attribute controls the quantity added to the value of the input when the stepper is activated.
Using the setInterval method, we can change this value every X milliseconds.
Using a listener for the input's mousedown event, we can start/stop the interval and reset the current step when the mouse is released.
Here's a sample:
const input = document.getElementById('my-stepper');
const label = document.getElementById('my-label');
const defaultStep = 1;
const maxStep = 100000;
let interval;
input.addEventListener('mousedown', () => {
interval = setInterval(() => {
const currentStep = Number(input.step);
if (currentStep < maxStep) {
input.step = currentStep * 10;
label.innerText = `Current step is ${input.step}`;
}
}, 1000);
});
input.addEventListener('mouseup', () => {
clearInterval(interval);
input.step = defaultStep;
label.innerText = `Current step is ${input.step}`;
});
<input id="my-stepper" type="number" step="1" value="0">
<p id="my-label">Current step is 1</p>
Basic idea is below using mouse event listeners.
const elem = document.querySelector("#num");
let timer;
elem.addEventListener("mousedown", (evt) => {
const inp = evt.target;
inp.dataset.step = inp.step;
const initialValue = Number(inp.value);
timer = window.setInterval(()=>{
const dir = Number(inp.value) > initialValue ? 100 : -100;
console.log(Number(inp.step) + dir);
inp.step = Number(inp.step) + dir;
},2000);
});
elem.addEventListener("mouseup", (evt) => {
if (timer) window.clearTimeout(timer);
const inp = evt.target;
inp.setAttribute('step', inp.dataset.step);
});
<input type="number" step="1" id="num">

Large numbers in count-up show NaN in safari browser

I have created a count-up function in Vanilla JS. Everything works well. The counter starts when you scroll down to it. Unfortunately the big number 35 000 000 shows up as NaN in the iOS Safari browser. I have no idea why. Please help. It looks like large numbers don't work in iOS Safari browser.
var animationDuration = 3000;
var frameDuration = 1000 / 60;
var totalFrames = Math.round(animationDuration / frameDuration);
var easeOutQuad = t => t * (2 - t);
var animateCountUp = el => {
let frame = 0;
var countTo = parseInt(el.innerHTML.replace(/ /g, ''), 10);
var counter = setInterval(() => {
frame++;
var progress = easeOutQuad(frame / totalFrames);
var currentCount = Math.round(countTo * progress);
if (parseInt(el.innerHTML, 10) !== currentCount) {
el.textContent = currentCount.toLocaleString().replace(/,/g, ' ');
}
if (frame === totalFrames) {
clearInterval(counter);
}
}, frameDuration);
};
var count = document.querySelectorAll('.countup'),
once = 1;
document.addEventListener('scroll', function() {
if (once == 1 && count[0].getBoundingClientRect().top < window.innerHeight) {
once = 0;
count.forEach(animateCountUp);
}
});
<div style="position: fixed">
<span class="countup">12 500</span>
<span class="countup">35 000 000</span>
</div>
<div style="height: 5000px"></div>
Using innerHTML for this is slightly less than ideal, and in fact iOS Safari is adding markup to your large number which is tripping up your code. It's identifying it as a telephone number and changing the inner HTML of that element to: 35 000 000. That's very surprising, but you can see it here:
console.log(document.querySelector(".countup").innerHTML);
<span class="countup">35 000 000</span>
Note: Only on iOS Safari as far as I can tell.
Using textContent instead works, since the text is unchanged:
var animationDuration = 3000;
var frameDuration = 1000 / 60;
var totalFrames = Math.round(animationDuration / frameDuration);
var easeOutQuad = t => t * (2 - t);
var animateCountUp = el => {
let frame = 0;
var countTo = parseInt(el.textContent.replace(/ /g, ''), 10);
var counter = setInterval(() => {
frame++;
var progress = easeOutQuad(frame / totalFrames);
var currentCount = Math.round(countTo * progress);
if (parseInt(el.textContent, 10) !== currentCount) {
el.textContent = currentCount.toLocaleString().replace(/,/g, ' ');
}
if (frame === totalFrames) {
clearInterval(counter);
}
}, frameDuration);
};
var count = document.querySelectorAll('.countup'),
once = 1;
document.addEventListener('scroll', function() {
if (once == 1 && count[0].getBoundingClientRect().top < window.innerHeight) {
once = 0;
count.forEach(animateCountUp);
}
});
<div style="position: fixed">
<span class="countup">12 500</span>
<span class="countup">35 000 000</span>
</div>
<div style="height: 5000px"></div>
You can also tell iOS Safari not to do this by adding a meta tag as described in this question's answers:
<meta name="format-detection" content="telephone=no">
but as far as I can tell that disables it page-wide.
Why not use counto instead of using DOM as a storage for the number to counto?
And as TJ said, the issue was Safari's handling of your number when using innerHTML instead of textContent
if (currentCount<=countTo) {
el.textContent = currentCount.toLocaleString().replace(/,/g, ' ');
}
Tested on iOS 14.4
https://plungjan.name/SO/tl.html
var animationDuration = 3000;
var frameDuration = 1000 / 60;
var totalFrames = Math.round(animationDuration / frameDuration);
var easeOutQuad = t => t * (2 - t);
var animateCountUp = el => {
let frame = 0;
var countTo = parseInt(el.textContent.replace(/ /g, ''), 10); // do not use innerHTML here
var counter = setInterval(() => {
frame++;
var progress = easeOutQuad(frame / totalFrames);
var currentCount = Math.round(countTo * progress);
if (currentCount<=countTo) {
el.textContent = currentCount.toLocaleString().replace(/,/g, ' ');
}
if (frame === totalFrames) {
clearInterval(counter);
}
}, frameDuration);
};
var count = document.querySelectorAll('.countup'),
once = 1;
document.addEventListener('scroll', function() {
if (once == 1 && count[0].getBoundingClientRect().top < window.innerHeight) {
once = 0;
count.forEach(animateCountUp);
}
});
<div style="position: fixed">
<span class="countup">12 500</span>
<span class="countup">35 000 000</span>
</div>
<div style="height: 5000px"></div>

How can I fix the stop-start process within this Javascript stopwatch-clock?

I have a JavaScript stopwatch here, I require the start-stop button to keep the same time when continuing.
Currently, if I stop and continue the clock diff is something ridiculous such as '-19330839:-3:-53'
Can anyone explain how this is fixed?
I have various method stopwatches made; however I would rather use real date time instead of a counter, this is because (I have tested after being made aware of this) that counters are very inaccurate over a period of time.
Any help is much appreciated.
html:
Please ignore the reset button for now. I will configure this later.
<input id="startstopbutton" class="buttonZ" style="width: 120px;" type="button" name="btn" value="Start" onclick="startstop();">
<input id="resetbutton" class="buttonZ" style="width: 120px;" type="button" name="btnRst1" id='btnRst1' value="Reset" onclick="resetclock();"/>
<div id="outputt" class="timerClock" value="00:00:00">00:00:00</div>
JS:
const outputElement = document.getElementById("outputt");
var startTime = 0;
var running = false;
var splitcounter = 0;
function startstop() {
if (running == false) {
running = true;
startTime = new Date(sessionStorage.getItem("time"))
if (isNaN(startTime)) startTime = Date.now();
startstopbutton.value = 'Stop';
document.getElementById("outputt").style.backgroundColor = "#2DB37B";
updateTimer();
} else {
running = false;
logTime();
startstopbutton.value = 'Start';
document.getElementById("outputt").style.backgroundColor = "#B3321B";
}
}
function updateTimer() {
if (running == true) {
let differenceInMillis = Date.now() - startTime;
sessionStorage.setItem("time", differenceInMillis)
let {
hours,
minutes,
seconds
} = calculateTime(differenceInMillis);
let timeStr = `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
outputElement.innerText = timeStr;
requestAnimationFrame(updateTimer);
}
}
function calculateTime(milliS) {
const SECONDS = 1000; // should be 1000 - only 10 to speed up the timer
const MINUTES = 60;
const HOURS = 60;
const RESET = 60;
let hours = Math.floor(milliS / SECONDS / MINUTES / HOURS);
let minutes = Math.floor(milliS / SECONDS / MINUTES) % RESET;
let seconds = Math.floor(milliS / SECONDS) % RESET;
return {
hours,
minutes,
seconds
};
}
function pad(time) {
return time.toString().padStart(2, '0');
}
I just need the timer to continue on from where it was stopped at.
Issue with your code:
You start with initial value for sessionStorage as Date.now but then save difference on update.
You interact a lot with session storage. Any communication with external API is expensive. Instead use local variables and find an event to initialise values.
Time difference logic is a bit off.
Date.now - startTime does not considers the difference between stop action and start action.
You can use this logic: If startTime is defined, calculate difference and add it to start time. If not, initialise it to Date.now()
Suggestions:
Instead of adding styles, use classes. That will help you in reset functionality
Define small features and based on it, define small functions. That would make reusability easy
Try to make functions independent by passing arguments and only rely on them. That way you'll reduce side-effect
Note: as SO does not allow access to Session Storage, I have removed all the related code.
const outputElement = document.getElementById("outputt");
var running = false;
var splitcounter = 0;
var lastTime = 0;
var startTime = 0;
function logTime() {
console.log('Time: ', lastTime)
}
function resetclock() {
running = false;
startTime = 0;
printTime(Date.now())
applyStyles(true)
}
function applyStyles(isReset) {
startstopbutton.value = running ? 'Stop' : 'Start';
document.getElementById("outputt").classList.remove('red', 'green')
if (!isReset) {
document.getElementById("outputt").classList.add(running ? 'red' : 'green')
}
}
function startstop() {
running = !running;
applyStyles();
if (running) {
if (startTime) {
const diff = Date.now() - lastTime;
startTime = startTime + diff;
} else {
startTime = Date.now()
}
updateTimer(startTime);
} else {
lastTime = Date.now()
logTime();
}
}
function printTime(startTime) {
let differenceInMillis = Date.now() - startTime;
let {
hours,
minutes,
seconds
} = calculateTime(differenceInMillis);
let timeStr = `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
outputElement.innerText = timeStr;
}
function updateTimer(startTime) {
if (running == true) {
printTime(startTime)
requestAnimationFrame(() => updateTimer(startTime));
}
}
function calculateTime(milliS) {
const SECONDS = 1000; // should be 1000 - only 10 to speed up the timer
const MINUTES = 60;
const HOURS = 60;
const RESET = 60;
let hours = Math.floor(milliS / SECONDS / MINUTES / HOURS);
let minutes = Math.floor(milliS / SECONDS / MINUTES) % RESET;
let seconds = Math.floor(milliS / SECONDS) % RESET;
return {
hours,
minutes,
seconds
};
}
function pad(time) {
return time.toString().padStart(2, '0');
}
.red {
background-color: #2DB37B
}
.green {
background-color: #B3321B
}
<input id="startstopbutton" class="buttonZ" style="width: 120px;" type="button" name="btn" value="Start" onclick="startstop();">
<input id="resetbutton" class="buttonZ" style="width: 120px;" type="button" name="btnRst1" id='btnRst1' value="Reset" onclick="resetclock();" />
<div id="outputt" class="timerClock" value="00:00:00">00:00:00</div>
simple stopwatch example
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<input class="startstop" style="width: 120px;" type="button" value="Start" onclick="startstop();">
<input class="reset" style="width: 120px;" type="button" value="Reset" onclick="reset();"/>
<div class="timerClock" value="00:00:00">00:00:00</div>
<script type="text/javascript">
var second = 0
var minute = 0
var hour = 0
var interval
var status = false
var element = document.querySelector('.startstop')
var clock = document.querySelector('.timerClock')
var string = ''
function startstop()
{
if(status == 'false')
{
element.value = 'Stop'
clock.style.backgroundColor = "#2DB37B";
status = true
interval = setInterval(function()
{
string = ''
second += 1
if(second >= 60)
{
minute += 1
second = 0
}
if(minute >= 60)
{
hour += 1
minute = 0
}
if(hour < 10)
string += `0${hour}:`
else
string += `${hour}:`
if(minute < 10)
string += `0${minute}:`
else
string += `${minute}:`
if(second < 10)
string += `0${second}`
else
string += `${second}`
clock.innerHTML = string
},1000)
}
else
{
clock.style.backgroundColor = "#B3321B";
element.value = 'Start'
status = false
clearInterval(interval)
}
}
function reset()
{
second = 0
minute = 0
hour = 0
status = false
element.value = 'Start'
clearInterval(interval)
clock.innerHTML = `00:00:00`
clock.style.backgroundColor = "transparent";
}
</script>
</body>
</html>
One thing to know about requestAnimationFrame is that it returns an integer that is a reference to the next animation. You can use this to cancel the next waiting animation with cancelAnimationFrame.
As mentioned by #Rajesh, you shouldn't store the time each update, as it will stop the current process for a (very) short while. Better in that case to fire an event, preferably each second, that will wait until it can run. I haven't updated the code to take that into account, I only commented it away for now.
It's also better to use classes than updating element styles. I wrote sloppy code that overwrites all classes on the #outputt element (it's spelled "output"). That's bad programming, because it makes it impossible to add other classes, but it serves the purpose for now. #Rajesh code is better written for this purpose.
I added two variables - diffTime and animationId. The first one corrects startTime if the user pauses. The second one keeps track if there is an ongoing timer animation.
I refactored your style updates into a method of its own. You should check it out, because it defines standard values and then changes them with an if statement. It's less code than having to type document.getElementById("outputt").style... on different rows.
I also added a resetclock method.
const outputElement = document.getElementById("outputt");
var startTime = 0;
var diffTime = 0;
var animationId = 0;
function startstop() {
const PAUSED = 0;
let paused = animationId == PAUSED;
//diffTime = new Date(sessionStorage.getItem("time")) || 0;
startTime = Date.now() - diffTime;
if (paused) {
updateTimer();
} else {
cancelAnimationFrame(animationId);
animationId = PAUSED;
}
updateTimerClass(paused);
}
function updateTimerClass(paused) {
var outputClass = 'red';
var buttonText = 'Start';
if (paused) {
outputClass = 'green';
buttonText = 'Stop';
}
startstopbutton.value = buttonText;
outputElement.classList = outputClass;
}
function updateTimer() {
let differenceInMillis = Date.now() - startTime;
//sessionStorage.setItem("time", differenceInMillis)
let {
hours,
minutes,
seconds
} = calculateTime(differenceInMillis);
let timeStr = `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
outputElement.innerText = timeStr;
diffTime = differenceInMillis;
animationId = requestAnimationFrame(updateTimer);
}
function calculateTime(milliS) {
const SECONDS = 1000; // should be 1000 - only 10 to speed up the timer
const MINUTES = 60;
const HOURS = 60;
const RESET = 60;
let hours = Math.floor(milliS / SECONDS / MINUTES / HOURS);
let minutes = Math.floor(milliS / SECONDS / MINUTES) % RESET;
let seconds = Math.floor(milliS / SECONDS) % RESET;
return {
hours,
minutes,
seconds
};
}
function pad(time) {
return time.toString().padStart(2, '0');
}
function resetclock() {
let paused = animationId == 0;
startTime = Date.now();
diffTime = 0;
if (paused) {
const REMOVE_ALL_CLASSES = '';
outputElement.className = REMOVE_ALL_CLASSES;
outputElement.innerText = '00:00:00';
}
}
#outputt.green {
background-color: #2DB37B;
}
#outputt.red {
background-color: #B3321B;
}
<input id="startstopbutton" class="buttonZ" style="width: 120px;" type="button" name="btn" value="Start" onclick="startstop();">
<input id="resetbutton" class="buttonZ" style="width: 120px;" type="button" name="btnRst1" id='btnRst1' value="Reset" onclick="resetclock();"/>
<div id="outputt" class="timerClock" value="00:00:00">00:00:00</div>
class Stopwatch {
constructor(display, results) {
this.running = false;
this.display = display;
this.results = results;
this.laps = [];
this.reset();
this.print(this.times);
}
reset() {
this.times = [ 0, 0, 0 ];
}
click(){
var x=document.getElementById('ctrl');
if(x.value=="start"){
this.start();
x.value="stop";
document.getElementById("outputt").style.backgroundColor = "#2DB37B";
}
else{
x.value="start";
this.stop();
document.getElementById("outputt").style.backgroundColor = "#B3321B";
}
}
start() {
if (!this.time) this.time = performance.now();
if (!this.running) {
this.running = true;
requestAnimationFrame(this.step.bind(this));
}
}
stop() {
this.running = false;
this.time = null;
}
resets() {
document.getElementById("outputt").style.backgroundColor = "#2DB37B";
if (!this.time) this.time = performance.now();
if (!this.running) {
this.running = true;
requestAnimationFrame(this.step.bind(this));
}
this.reset();
}
step(timestamp) {
if (!this.running) return;
this.calculate(timestamp);
this.time = timestamp;
this.print();
requestAnimationFrame(this.step.bind(this));
}
calculate(timestamp) {
var diff = timestamp - this.time;
// Hundredths of a second are 100 ms
this.times[2] += diff / 1000;
// Seconds are 100 hundredths of a second
if (this.times[2] >= 100) {
this.times[1] += 1;
this.times[2] -= 100;
}
// Minutes are 60 seconds
if (this.times[1] >= 60) {
this.times[0] += 1;
this.times[1] -= 60;
}
}
print() {
this.display.innerText = this.format(this.times);
}
format(times) {
return `\
${pad0(times[0], 2)}:\
${pad0(times[1], 2)}:\
${pad0(Math.floor(times[2]), 2)}`;
}
}
function pad0(value, count) {
var result = value.toString();
for (; result.length < count; --count)
result = '0' + result;
return result;
}
function clearChildren(node) {
while (node.lastChild)
node.removeChild(node.lastChild);
}
let stopwatch = new Stopwatch(
document.querySelector('.stopwatch'),
document.querySelector('.results'));
<input type="button" id="ctrl" value="start" onClick="stopwatch.click();">
<input type="button" value="Reset" onClick="stopwatch.resets();">
<div id="outputt" class="stopwatch"></div>

Repeat an audioContext oscillator every 5 seconds

I am trying to write a morse code trainer that produces a random two letter pattern every 5 seconds with the audiocontext recreated each loop, but I cannot figure out how to add code which will call for a repeated loop. I've tried setTimeout() setInterval(), but they both eliminate the audio.
Also, after pressing the button five times on the following code.
I get the error
" TypeError: null is not an object (evaluating 'ctx.currentTime')"
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button onclick = "startIt()">Play</button>
<button onclick = "stopIt()">Stop</button>
<h2>Morse Code</h2>
<h1 id="demo"></h1>
<h1 id="demo2"></h1>
<script>
var codeStream = '';
var dot = 1.2 / 15;
var text = "";
var display = "";
var k = 0;
var alphabet = [["A",".-"],["B","-..."],["C","-.-."],["D","-.."],["E","."],["F","..-."],["G","--."],["H","...."],["I",".."],["J",".---"],
["K","-.-"],["L",".-.."],["M","--"],["N","-."],["O","---"],["P",".--."],["Q","--.-"],["R",".-."],["S","..."],["T","-"],["U","..-"],
["V","...-"],["W",".--"],["X","-..-"],["Y","-.--"],["Z","--.."],["1",".----"],["2","..---"],["3","...--"],["4","....-"],["5","....."],
["6","-...."],["7","--..."],["8","---.."],["9","----."],["0","-----"],[".",".-.-.-"],[",","--..--"],["?","..--.."],["'",".----."],["!","-.-.--"],
["/","-..-."],[":","---..."],[";","-.-.-."],["=","-...-"],["-","-....-"],["_","..--.-"],["\"",".-..-."],["#",".--.-."],["(","-.--.-"],[" ",""]];
stopIt = function(){
ctx.close();
location.reload();
}
function nextGroup() {
for (i = 0; i < 2; i++){
var randomLetter = Math.floor(Math.random() * 26);
var code = alphabet[randomLetter][1] + " ";
var character = alphabet[randomLetter][0];
display += code;
text += character;
}
codeStream = display;
}
function startIt(){
var AudioContext = window.AudioContext || window.webkitAudioContext;
var ctx = new AudioContext();
var t = ctx.currentTime;
var oscillator = ctx.createOscillator();
oscillator.type = "sine";
oscillator.frequency.value = 600;
oscillator.start();
var gainNode = ctx.createGain();
nextGroup();
console.log(codeStream);
document.getElementById("demo").innerHTML = text;
document.getElementById("demo2").innerHTML = codeStream;
display = "";
text = "";
gainNode.gain.setValueAtTime(0, t);
for (var i = 0; i < codeStream.length; i++) {
switch(codeStream.charAt(i)) {
case ".":
gainNode.gain.setValueAtTime(1, t);
t += dot;
gainNode.gain.setValueAtTime(0, t);
t += dot;
break;
case "-":
gainNode.gain.setValueAtTime(1, t);
t += 3 * dot;
gainNode.gain.setValueAtTime(0, t);
t += dot;
break;
case " ":
t += 7 * dot;
break;
}
}
gainNode.gain.setValueAtTime(0, t);
t += 50 * dot;
oscillator.connect(gainNode);
gainNode.connect(ctx.destination);
codeStream = '';
oscillator.stop(t);
}
</script>
</body>
</html>
It looks like some of the issues are to do with scoping and state management of the oscillator. I wasn't able to reproduce the error you were seeing but the stopIt function certainly doesn't have access to ctx created in startIt.
An alternative might be to, rather than recreate the context, oscillator and gain node on each run, create them once and reuse them instead. Demo here: http://jsfiddle.net/kts74g0x/
The code:
const ALPHABET = [
["A", ".-"],
...
[" ",""]
];
const DOT = 1;
const DASH = 3;
const NEXT = DOT;
const SPACE = 7;
const SPEED = 1.2 / 15;
const AudioContext = window.AudioContext || window.webkitAudioContext;
/**
* Create a single audio context, oscillator and gain node and repeatedly
* use them instead of creating a new one each time. The gain is just
* silent most of the time.
*/
const ctx = new AudioContext();
const oscillator = ctx.createOscillator();
const gainNode = ctx.createGain();
oscillator.type = "sine";
oscillator.frequency.value = 600;
oscillator.connect(gainNode);
oscillator.start();
gainNode.connect(ctx.destination);
gainNode.gain.value = 0;
function playCodeStream(stream) {
let t = ctx.currentTime;
gainNode.gain.setValueAtTime(0, t);
for (var i = 0; i < stream.length; i++) {
switch(stream.charAt(i)) {
case ".":
gainNode.gain.setValueAtTime(1, t);
t += DOT * SPEED;
gainNode.gain.setValueAtTime(0, t);
t += NEXT * SPEED;
break;
case "-":
gainNode.gain.setValueAtTime(1, t);
t += DASH * SPEED;
gainNode.gain.setValueAtTime(0, t);
t += NEXT * SPEED;
break;
case " ":
t += SPACE * SPEED;
break;
}
}
}
/**
* Set interval will wait initially for the period of
* time before first triggering the function.
*/
setInterval(() => { playCodeStream([
ALPHABET.filter(v => v[0] === "H"),
ALPHABET.filter(v => v[0] === "E"),
ALPHABET.filter(v => v[0] === "L"),
ALPHABET.filter(v => v[0] === "L"),
ALPHABET.filter(v => v[0] === "O")
].join(" ")); }, 10000);
Set interval returns an ID that can be passed to clearInterval to prevent future runs, the play button might start the interval and the stop button could clear it, for example.
For iOS there are restrictions so that an AudioContext cannot play sound unless it is in response to a user interaction (https://hackernoon.com/unlocking-web-audio-the-smarter-way-8858218c0e09). We can get around the problem by adding a button.
<button id="go">Go</button>
And checking the state of the audio context / starting the interval in response to clicking this button (demo: http://jsfiddle.net/7gfnrubc/). The updated code:
function next() {
playCodeStream([
ALPHABET.filter(v => v[0] === "H"),
ALPHABET.filter(v => v[0] === "E"),
ALPHABET.filter(v => v[0] === "L"),
ALPHABET.filter(v => v[0] === "L"),
ALPHABET.filter(v => v[0] === "O")
].join(" "));
}
function go() {
if (ctx.state === 'suspended') {
ctx.resume();
}
/**
* Set interval will wait initially for the period of
* time before first triggering the function. Can call
* the function initially to start off.
*/
next();
setInterval(next, 10000);
}
const button = document.getElementById("go");
button.addEventListener("click", go);

How to add a number to a var every second

As a beginner in Javascript, I'm trying to make a clicker game. I don't know how to add a number to a var every second
Below is the code at the moment. I'm not sure how to make one of my "dank miners" automatically add coins every second to the player. Let's say there are two auto miners, then the player earns 4 coins per second. Also how to display how much the player is automatically making.
Thanks!
let borkCoins = 0;
let dankMiner = 0;
const earnBork = () => {
borkCoins += 1;
displayScreen();
};
const buydankMiner1 = () => {
if (borkCoins >= 20) {
dankMiner += 1;
borkCoins -= 20;
displayScreen();
} else {
alert("Insufficient funds!")
}
};
const displayScreen = () => {
document.getElementById("bork-coins").innerText =
borkCoins;
document.getElementById("dankMiner").innerText =
dankMiner;
};
displayScreen();
<h3>Your BorkCoins: <span id="bork-coins"></h3>
<img src="https://i.pinimg.com/736x/ef/6a/cf/ef6acfc481b76637b71d4a71db7de82a--dog-birthday-animal-memes.jpg"
height="80" width="80" id="bork-coins" onclick="earnBork();">
<p>Click on Gabe the Doggo to earn a BorkCoin!</p>
<h3>Shop</h3>
<p>Dank Miner <i>(2 BorkCoins/sec)</i>
<br>Your Dank Miner(s): <span id="dankMiner"></span></p>
<button id="dank-miner" onclick="buydankMiner1();">Buy 1 (20 BorkCoins)</button>
You can use setInterval function and do something like this :
let borkCoins = 0;
let dankMiner = 0;
const earnBork = () => {
borkCoins += 1;
displayScreen();
};
/* Code Added */
setInterval(earnBork, 1000);
/*--*/
const buydankMiner1 = () => {
if (borkCoins >= 20) {
dankMiner += 1;
borkCoins -= 20;
displayScreen();
} else {
alert("Insufficient funds!")
}
};
const displayScreen = () => {
document.getElementById("bork-coins").innerText =
borkCoins;
document.getElementById("dankMiner").innerText =
dankMiner;
};
displayScreen();
<h3>Your BorkCoins: <span id="bork-coins"></span></h3>
<img src="https://i.pinimg.com/736x/ef/6a/cf/ef6acfc481b76637b71d4a71db7de82a--dog-birthday-animal-memes.jpg" height="80" width="80" id="bork-coins" onclick="earnBork();">
<p>Click on Gabe the Doggo to earn a BorkCoin!</p>
<h3>Shop</h3>
<p>Dank Miner <i>(2 BorkCoins/sec)</i>
<br>Your Dank Miner(s): <span id="dankMiner"></span></p>
<button id="dank-miner" onclick="buydankMiner1();">Buy 1 (20 BorkCoins)</button>
Add an interval that checks for the number of miners:
setInterval(() => {
if (dankMiner > 0) {
borkCoins += dankMiner;
displayScreen();
}
}, 1000);

Categories