How to add audio to a 10 second countdown in javascript - javascript

First time posting on here so go easy.
I am having some problems with a recent project. I am trying to create a countdown as the landing page with audio sounds for each number (street fighter 2 sound effects if anyone is familiar). I have managed to get the countdown to work and it will work but only at the click of a button as this is the only way I could get it to work.
Like I said this is not the desired effect as once the countdown finishes I want it to load the main page. Also in regards to adding the sound to each individual number, I have absolutely no idea where to start!
This is my current JS for it
document.addEventListener('DOMContentLoaded', () => {
const timeLeftDisplay = document.querySelector('#time-left')
const startBtn = document.querySelector('#start-button')
let timeLeft = 10
function countDown (){
setInterval(function(){
if(timeLeft <= 0){
clearInterval(timeLeft = 0)
}
timeLeftDisplay.innerHTML = timeLeft
timeLeft -= 1
}, 1000)
}
startBtn.addEventListener('click', countDown)
} )
This is the current HTML
<script type= "text/javascript" src="assets/javascript/script.js"></script>
<title>Bro-nament</title>
</head>
<body>
<div class="container text-center">
<h1 class="bro-title"> TIME TILL BRO - DOWN</h1>
<h2 id="time-left"> 10 </h2>
<button id="start-button"> <i class="fas fa-fist-raised"> Continue? </i> <i class="fas fa-fist-raised"></i></button>
Current page view
Thanks

In your server, you need to name your audio files with a number for all of them and use the value of time variable to increment and get the url of the file for each every seconde.
Like :
9.mp3
8.mp3
7.mp3
6.mp3
....
Once the counter is to 0, you redirect where the url you want.
let time = 10;
countdown();
function countdown() {
// we upadate number text
document.querySelector('#time-left').textContent = --time;
// if count is equal to 0 (end of counter)
if (time === 0) {
time = 10;
// we redirect to this url
window.location.href = "http://www.google.com";
// we stop the loop
return false;
}
//console.log(time);
// we set the url of audio file for each seconde
const audio = new Audio("https://srv-store5.gofile.io/download/RFgvcw/" + time + ".mp3");
// if you only want one, u dont need the const time
//const audio = new Audio("https://srv-store5.gofile.io/download/RFgvcw/1.mp3");
audio.play();
setTimeout(countdown, 1000);
}
#time-left {
font-size: 150px;
font-weight: bold;
margin: auto 0;
text-align: center;
}
<div id="time-left"></div>

Related

Alternative to setInterval() - Keep time while computer is locked/doing other stuff in Chrome

I have a timer to keep track of the time the user spends doing something. There's a button that, among other things, resets the timer to zero. That works fine.
However, when the user is away (i.e. taking their 15 or 30 minute breaks), the computer must be locked. I've noticed that the time is inconsistent upon return. Some times it appears the timer doesn't move until the user returns. Sometimes it's a few seconds, or a few minutes, but is never the time the user was way - always LESS.
For instance, if I lock the PC now, and the timer is on 5 minutes and 38 seconds, and I take a 15 minute break, I'll typically return to a timer that's roughly where it was when I left, or perhaps it'll be like 6 minutes and 5 seconds.
How can I fix this? Is there any way to ensure setInterval() continues to behave consistently, or am I better doing something else (such as comparing time stamps instead of an independent counter like I have now)?
For what it's worth, it seems even MORE inconsistent now that we are using VDI workstations, though I don't know if that makes a difference (the issue happened on normal workstations as well).
EDIT: I noticed in another question this appears to also be a thing with Chrome (maybe)? And how it throttles when not the active window or tab. Are there workarounds for --app-mode windows?
If you set the start time as a variable, then you can calculate the the current time of the counter in the interval by subtracting the timestamp that you stored as a variable from the current time. So, then even if the interval pauses while the computer is locked, then when you unlock it and the interval resumes, it will calculate the correct time.
You could also use window.sessionStorage to store the start time. I have a timer I created in CodePen that uses session storage to store the values. You can see that here: https://codepen.io/steebn/pen/eYWrPeM
In the snippet below, I modified the code from that codepen to use a global variable instead of session storage since apparently you cannot use session storage in a snippet.
Hopefully this helps.
const qs = (selector) => document.querySelector(selector);
const qsa = (selector) => document.querySelectorAll(selector);
//variable to store the timestamps
const tLog = {
startTime: null,
stopTime: null,
duration: null
};
//variable to store the interval
let timerInterval;
//Add event listeners to each button
qsa(".timer").forEach((btn) => {
btn.addEventListener("click", (event) => {
qsa(`button.timer`).forEach((btn) => (btn.disabled = true));
qs("#time").classList.remove(`paused`);
switch (event.target.id) {
case `start`:
setMessage(`Timer Counting`);
qsa(`button.started`).forEach((btn) => (btn.disabled = false));
tLog.startTime = tLog.duration ?
new Date().getTime() - tLog.duration :
new Date().getTime();
//Start the timer interval
timerInterval = window.setInterval(() => {
const currentTime = new Date().getTime();
//Calculate duration using the starting timestamp in the tLog variable
qs("#time").innerText = getDuration(currentTime - tLog.startTime);
}, 1000);
break;
case `stop`:
setMessage(`Timer Complete`);
qsa(`button.stopped`).forEach((btn) => (btn.disabled = false));
window.clearInterval(timerInterval); //Clear the interval
tLog.stopTime = new Date().getTime();
tLog.duration = tLog.stopTime - tLog.startTime;
break;
case `pause`:
qs(`#time`).classList.add(`paused`);
setMessage(`Timer Paused`);
qsa(`button.paused`).forEach((btn) => (btn.disabled = false));
window.clearInterval(timerInterval);
tLog.stopTime = new Date().getTime();
tLog.duration = tLog.stopTime - tLog.startTime;
break;
case `reset`:
qsa(`button.cleared`).forEach((btn) => (btn.disabled = false));
qs("#time").innerText = `00:00:00`;
qs("#time").classList.remove(`paused`);
Object.keys(tLog).map((key) => (tLog.key = null));
setMessage(`Timer is ready to begin`);
break;
}
});
});
const setMessage = (msg) => (qs(".status").innerText = msg);
const getDuration = (timeStamp) => {
const d = new Date(timeStamp);
const H = d.getUTCHours().toString().padStart(2, 0);
const M = d.getUTCMinutes().toString().padStart(2, 0);
const S = d.getUTCSeconds().toString().padStart(2, 0);
const s = d.getUTCSeconds().toString().padStart(3, 0);
return `${H}:${M}:${S}`;
};
.btn {
font-size: 3rem !important;
}
#time {
position: relative;
font-size: 4rem;
}
#time.paused {
animation: animate 1.25s linear infinite;
}
#keyframes animate {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/css/bootstrap.min.css' integrity='sha512-usVBAd66/NpVNfBge19gws2j6JZinnca12rAe2l+d+QkLU9fiG02O1X8Q6hepIpr/EYKZvKx/I9WsnujJuOmBA==' crossorigin='anonymous' />
<body class="bg-dark text-white">
<header class="container d-flex my-0">
<div class="btn-group btn-group-lg mx-auto" role="group" aria-label="Basic example">
<button id="start" class="btn p-0 timer cleared paused">▶️</button>
<button id="pause" class="btn p-0 timer started" disabled>⏸️</button>
<button id="stop" class="btn p-0 timer started paused" disabled>⏹️</button>
<button id="reset" class="btn p-0 timer stopped" disabled>🔃</button>
</div>
</header>
<main class="container d-flex my-0 flex-column">
<div id="time" class="mx-auto">00:00:00</div>
<div class="mx-auto status">Timer is ready to begin</div>
</main>
</body>

Custom html 5 player multiple tracks does not work

I am trying to create multiple custom javascript audio players on my website but once I copy the code in html the second player does not work, how should I adjust the javascript code for it to work? Here is my code: https://github.com/streamofstream/streamofstream.github.io
and here is relevant part of the code that I am talking about:
index.html relevant part here, I tried to just duplicate this part and change the audio source but once I do this the second player appears but it wont trigger javascript
<script>
function durationchange() {
var duration = $('audio')[0].duration;
if(!isNaN(duration)) {
$('#duration').html(Math.ceil(duration));
}
}
</script>
<div id="audioWrapper">
<audio id="audioPlayer" preload="metadata">
<source src="assets/millriver.wav" type="audio/wav" />
Your browser does not support the audio element.
</audio>
<div id="playPause" class="play"></div>
<div id="trackArtwork"><img src="assets/smiths.jpg" /></div>
<div id="trackArtist">04/28/2021, 8PM Eastern Time, Mill River</div>
<div id="trackTitle">41°20'09.3"N 72°54'37.7"W</div>
<div id="trackProgress">
<div id="elapsedTime"></div>
<input type="range" id="scrubBar" value="0" max="100" />
<div id="remainingTime"></div>
</div>
</div>
<script type="text/javascript" src="js/audioplayer.js"></script>
and java script here (Code by https://github.com/jon-dean/html5-audio-player)
var audioPlayer = document.getElementById('audioPlayer');
var scrubBar = document.getElementById('scrubBar');
var elapsedTime = document.getElementById('elapsedTime');
var remainingTime = document.getElementById('remainingTime');
var playPause = document.getElementById('playPause');
var trackLength;
// Set up a listener so we can get the track data once it's loaded
audioPlayer.addEventListener('loadedmetadata', function() {
// Get the length for the current track
trackLength = Math.round(audioPlayer.duration);
// Set the initial elapsed and remaining times for the track
elapsedTime.innerHTML = formatTrackTime(audioPlayer.currentTime);
remainingTime.innerHTML = '-' + formatTrackTime(trackLength - audioPlayer.currentTime);
});
function runWhenLoaded() { /* read duration etc, this = audio element */ }
// Set up a listener to watch for play / pause and display the correct image
playPause.addEventListener('click', function() {
// Let's check to see if we're already playing
if (audioPlayer.paused) {
// Start playing and switch the class to show the pause button
audioPlayer.play();
playPause.className = 'pause';
} else {
// Pause playing and switch the class to show the play button
audioPlayer.pause();
playPause.className = 'play';
}
});
// Track the elapsed time for the playing audio
audioPlayer.ontimeupdate = function() {
// Update the scrub bar with the elapsed time
scrubBar.value = Math.floor((100 / trackLength) * audioPlayer.currentTime);
// Update the elapsed and remaining time elements
elapsedTime.innerHTML = formatTrackTime(audioPlayer.currentTime);
remainingTime.innerHTML = '-' + formatTrackTime(trackLength - audioPlayer.currentTime + 1);
};
// Set up some listeners for when the user changes the scrub bar time
// by dragging the slider or clicking in the scrub bar progress area
scrubBar.addEventListener('input', function() {
changeTrackCurrentTime();
scrubBar.addEventListener('change', changeTrackCurrentTime);
});
scrubBar.addEventListener('change', function() {
changeTrackCurrentTime();
scrubBar.removeEventListener('input', changeTrackCurrentTime);
});
// Change the track's current time to match the user's selected time
var changeTrackCurrentTime = function() {
audioPlayer.currentTime = Math.floor((scrubBar.value / 100) * trackLength);
};
// Format the time so it shows nicely to the user
function formatTrackTime(timeToFormat) {
var minutes = Math.floor((timeToFormat) / 60);
var seconds = Math.floor(timeToFormat % 60);
seconds = (seconds >= 10) ? seconds : '0' + seconds;
return minutes + ':' + seconds;
}
// Let's reset everything once the track has ended
audioPlayer.addEventListener('ended', function() {
audioPlayer.currentTime = 0;
elapsedTime.innerHTML = formatTrackTime(audioPlayer.currentTime);
remainingTime.innerHTML = '-' + formatTrackTime(trackLength - audioPlayer.currentTime);
playPause.className = 'play';
});
Thank you

javascript setTimeout function doesn't work inside a loop

I'm making a Simon Game and I'm trying to make the button presses have 1 second interval. But It seems that my setTimeout function is not doing its job and all clicks are performed at once without the 1s interval. I tried alerting something outside the loop and it works just fine. Can anyone help me with this?
This is my JavaScript code:
for (var count = 1; count <= 20; count++) {
$("#count").html(count);
seq.push(Math.floor(Math.random() * 4));
seq.forEach(function(press) {
setTimeout(function() {
eval('$("#button' + press + '").click();');
}, 1000);
});
}
and the corresponding html:
<p>count: <span id="count">0</span></p>
<button id="button0" onclick="sound1.play()"></button>
<button id="button1" onclick="sound2.play()"></button>
<button id="button2" onclick="sound3.play()"></button>
<button id="button3" onclick="sound4.play()"></button>
Thank you!
The problem is the way you do setTimeout.
The for loop iterates within a few milliseconds and you basically request all the clicks to run one second later, so they all happen one second later but at the same time.
If you request the first click after one, the second click after two seconds and so forth, you'll get what you want:
seq.forEach(function(press, i) {
setTimeout(function() {
$("#button" + press).click();
}, 1000 * i);
});
Also note that you probably want to restructure your code to not do this twenty times over:
for (var count = 1; count <= 20; count++) {
$("#count").html(count);
seq.push(Math.floor(Math.random() * 4));
}
seq.forEach(function(press, i) {
setTimeout(function() {
$("#button" + press).click();
}, 1000 * i);
});
Your eval function is running after 1 second but all of them are.
What happens:
loop from 1 to 20
add an item to the seq array
loop through the seq array
define the setTimeout to happen in 1 second.
Your code does not sleep while wating for the setTimeout to execute. So all of them are defined on the loop and happen as near as possible to the 1 second requested.
You could make an asynchronous loop, by calling a function repeatedly from within a setTimeout: that way the sequencing and delay will be as desired.
Here is a working snippet with some other ideas:
// First generate the array (only 8 to not annoy SO public):
var seq = Array.from(Array(8), _ => Math.floor(Math.random() * 4));
function replay() {
// Iterate seq asynchronously
(function loop(i) {
if (i >= seq.length) return; // all done
$("#count").text(i+1);
$("#buttons>button").eq(seq[i]).click();
setTimeout(loop.bind(null, i+1), 1000);
})(0);
}
$("#buttons>button").click(function () {
// Play sound here...
playNote([523, 659, 784, 880][$(this).index()], 800);
// Some visual effect:
$(this).addClass("clicked");
setTimeout($(this).removeClass.bind($(this), "clicked"), 800);
});
// Sound support
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
function playNote(frequency, duration) {
// create Oscillator node
var oscillator = audioCtx.createOscillator();
oscillator.type = 'square';
oscillator.frequency.value = frequency; // value in hertz
oscillator.connect(audioCtx.destination);
oscillator.start();
setTimeout(oscillator.stop.bind(oscillator), duration);
}
// Play the sequence on page load
replay();
button {
border: 2px solid silver;
}
button.clicked {
border: 2px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>count (up to 8): <span id="count">0</span></p>
<div id="buttons">
<button>A</button>
<button>B</button>
<button>C</button>
<button>D</button>
</div>

How to approach a setInterval triggering a setInterval within the same function

I a rewards site. Users earn points when they watch videos. Users want to skip to the end of the video to quickly earn their points. Therefore, the mechanism of the video being marked as completed is managed by a JS timer.
The Problem: When a user pauses the video, the timer needs to pause. When the user clicks play again, a setInterval is used to reopen the function, where a setInterval within the existing function does the same thing, creating a huge problem...
This is the code that is set every second to update the timer...
var video_percent_count = 0;
function video_percent() {
var prize_video = document.getElementById("prize_video");
total_duration = Math.floor(prize_video.duration) + 1;
video_percent_count++;
percent = video_percent_count / total_duration;
convert_percent = (percent * 100).toFixed(2);
if(convert_percent == 100) {
clearInterval(video_percent_interval);
}
if(prize_video.paused) {
clearInterval(video_percent_interval);
}
if(prize_video.play) {
setInterval("video_percent()", 1000);
}
$(".percent_container").text(convert_percent);
}
function prize_video(count_prize) {
var back_count_prize = count_prize - 1;
$("#prize_video").get(back_count_prize).play();
video_percent_interval = setInterval("video_percent()", 1000);
}
How can I properly manage play and pause and still keep setInterval clean?

Combine ASP.net AJAX timer with javascript countdown

I am currently working on porting a vb.net winforms program over to a web based version, and one of the functions in the original program has be stumped.
In the original program, every 5 minutes, a form pops up for user input. There is also a label control on the main form which counts down to the next popup. This is accomplished with a single timer control with a 1 second duration. every tick, it decrements the countdown, and when the countdown reaches 0, it pops up the form and then resets. Simple enough, but in my web app, I can't afford to be doing a postback every second, so what I am attempting is to combine a javascript countdown widget with an AJAX timer. Essentially, what should happen is that when the page loads, the countdown begins decrementing from 300 seconds, and the AJAX timer begins with a duration of 300 seconds. My idea is that when the timer ticks, it will run my function, as well as reset the countdown to 300 seconds again.
My problem, is that I am not able to reset the countdown with the code that I have, and I know that I am doing something (likely very simple) wrong, but I don't know enough Java to know what.
If I hardcode the Timer var to 300, the countdown works, and the timer ticks (fires the additional functons), but the countdown just keeps counting down (into negative numbers). How do I reset the countdown variable from code behind?
Here is the countdown function
var Timer = <%= CountDown %>;
function updateClock() {
// Update Countdown
Timer -= 1;
var TimerMin = Math.floor(Timer / 60);
var TimerSec = Timer - (TimerMin * 60);
TimerSec = (TimerSec < 10 ? "0" : "") + TimerSec;
var TimerFormat = TimerMin + ":" + TimerSec;
// Update the countdown display
document.getElementById("javaCountdown").firstChild.nodeValue = TimerFormat
}
Here is the body code
<body onload="updateClock(); setInterval('updateClock()', 1000 )">
And the Code Behind
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Countdown = 300
End Sub
PProtected Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
Countdown = 300
'Additional Functions
End Sub
This solution uses jQuery.
<script>
var intervalSecond = null;
var interval5minutes = null;
$(document).ready(function() {
// enable both intervals
enableIntervals();
// onsubmit event for your form
$("#popupForm").submit(function() {
// hide the form again
$("#popupForm").css("display", "none");
// enable intervals again.
enableIntervals();
});
});
function enableIntervals() {
// every second interval
intervalSecond = setInterval(function() {
$("#updateMeEverySecond").html(new Date());
}, 1000);
// every 5 minutes interval
interval5minutes = setInterval(function() {
// display form and shut off the interval timers
$("#popupForm").css("display", "block");
clearInterval(intervalSecond);
clearInterval(interval5minutes);
}, 5 * 60 * 1000);
}
</script>
<div id="popupForm" style="display:none;">
<form>
<input type="text" />
</form>
</div>
<label id="updateMeEverySecond">Test</label>

Categories

Resources