Why won't this clearInterval work? - javascript

I'm making a race where two images move to the right a random number of px's but they won't stop with the clear interval, the alert "stop" works. I'm using a red and green picture with changing z-indexes like a stoplight for the user to start and stop the race.
<script type="text/javascript">
var ship = 0;
var ufo = 0;
function random()
{
var rand = Math.floor((Math.random() * 15) + 1);
var rand2 = Math.floor((Math.random() * 15) + 1);
ship = ship + rand;
ufo = ufo + rand2;
document.getElementById("ufo").style.left = ufo + 'px';
document.getElementById("spaceship").style.left = ship + 'px';
}
function start()
{
if(document.getElementById("red").style.zIndex == 1)
{
document.getElementById("red").style.zIndex = "0";
alert("go");
var timer = setInterval(function() {random()},1000);
}
else
{
document.getElementById("green").style.zIndex = "0";
document.getElementById("red").style.zIndex = "1";
clearInterval(timer);
alert("stop");
}
}
</script>

Because var timer only exists within the if statement. You need to move it outside of the start() function, like this:
var timer;
function start()
{
if(document.getElementById("red").style.zIndex == 1)
{
document.getElementById("red").style.zIndex = "0";
alert("go");
timer = setInterval(function() {random()},1000);
}
else
{
document.getElementById("green").style.zIndex = "0";
document.getElementById("red").style.zIndex = "1";
clearInterval(timer);
alert("stop");
}
}

Related

How can i create multiple audio players(each containing different song) without copying javascript functionality?

I dont know if my title is clear enough so ill try my best to sumerize.
I created audio player containing one song using audio tag. I made all functionality in javascript for player(progress bar, volume bar, play pause stop, time etc..) and now i want to repeat same plyer in column. I copied html and everything is ok but second player with different song is not triggering javascript even though all classes are the same.
My goal is to create something similar to soundcloud website where each audio has its own audio player but i dont want to copy javascript code for every audio. Is there a way to do this using same variables?
Code is huge btw :).
HTML:
<!-- AUDIO PLAYER -->
<div class="mainPlayerDiv">
<h1>Amelie Lens - Hypnotized</h1>
<div class="mainPlayer">
<div class="audioPlayerDiv">
<div class="playPauseBtn">
<div class="btnLine"></div>
<div class="btnLine"></div>
<div class="btnLine"></div>
</div>
<div class="stopBtnDiv">
<div class="stopBtn"></div>
</div>
<i class="fas fa-volume-down volumeDownIcon"></i>
<div class="mainVolumeDiv">
<div class="volumeBar" id="volumeBar">
<div id="volume"></div>
</div>
<span id="volPercentage"></span>
</div>
<div class="trackTime">
<span id="currTime"></span> /
<span id="duration"></span>
</div>
</div>
<a class="dlLink" href="/Track/Amelie Lens - Hypnotized.mp3" download="Amelie Lens - Hypnotized">
<button class="freeDownload">
<h5>mp3</h5>
<h3>Free Download</h3>
</button>
</a>
<button class="buyTrack">
<h3>Buy This Beat</h3>
</button>
</div>
<!--<canvas id="progress" width="500" height="10"></canvas>-->
<audio id="audio" class="track" src="/Track/Amelie Lens - Hypnotized.mp3" download></audio>
<div class="progressBarCont" id="progressBarCont">
<div class="progress" id="progress"></div>
</div>
</div>
Javascript:
// AUDIO PLAYER
var audioEl = document.querySelector('.track');
audioEl.addEventListener('loadedmetadata', function(){
var duration = audioEl.duration;
var currentTime = audioEl.currentTime;
document.getElementById("duration").innerHTML = convertElapsedTime(duration);
document.getElementById("currTime").innerHTML = convertElapsedTime(currentTime);
audioEl.volume = 0.31;
document.getElementById("volPercentage").innerHTML = 30 + " %";
});
// TIME UP
audioEl.addEventListener("timeupdate", function(){
var timeline = document.getElementById("currTime");
var s = parseInt(audioEl.currentTime % 60);
var m = parseInt((audioEl.currentTime / 60) % 60);
if (s < 10) {
timeline.innerHTML = m + ':0' +s;
} else {
timeline.innerHTML = m + ':' +s;
}
if (audioEl.ended) {
playPauseBtn.classList.remove('transform');
stopBtnDiv.classList.add('transform');
audioEl.currentTime = 0;
percent = 0;
progress.style.width = '0';
stopped = true;
clearInterval(interval);
clearInterval(interval2);
audioPlayerDiv.classList.remove('playAnimation');
audioPlayerDiv.classList.remove('playAnimation2');
}
}, false);
// OVERALL DURATION
function convertElapsedTime(inputSeconds) {
var seconds = Math.floor(inputSeconds % 60);
if (seconds < 10) {
seconds = "0" + seconds;
}
var minutes = Math.floor(inputSeconds / 60);
return minutes + ":" + seconds;
}
// PROGRESS BAR
var timer;
var percent = 0;
var audioEl = document.getElementById("audio");
audioEl.addEventListener("playing", function(_event) {
var duration = _event.target.duration;
advance(duration, audioEl);
});
audioEl.addEventListener("pause", function(_event) {
var progress = document.getElementById("progress");
clearTimeout(timer);
});
var advance = function(duration, element) {
var progress = document.getElementById("progress");
increment = 10/duration
percent = Math.min(increment * element.currentTime * 10, 100);
progress.style.width = percent+'%'
startTimer(duration, element);
}
var startTimer = function(duration, element){
if(percent < 100) {
timer = setTimeout(function (){advance(duration, element)}, 100);
}
}
// PROGRESS BAR SEEK
var progressBarCont = document.getElementById('progressBarCont');
var progress = document.getElementById("progress");
progressBarCont.addEventListener("mousedown", function(event){
var viewportset = progressBarCont.getBoundingClientRect();
var clickedPos = event.clientX - viewportset.left;
audioEl.currentTime = (clickedPos / event.target.offsetWidth) * audioEl.duration;
}, false);
// PROGRESS BAR END
/*
VOLUME SLIDER
*/
var volumeSlider = document.getElementById("volume");
var volumeBar = document.getElementById("volumeBar");
volumeBar.addEventListener('click', function(e){
var viewportOffset = volumeBar.getBoundingClientRect();
var cursorPosition;
cursorPosition = Math.floor(e.clientX - viewportOffset.left);
if(cursorPosition <= 9) {
audioEl.volume = '0.0' + cursorPosition;
document.getElementById("volPercentage").innerHTML = cursorPosition + " %";
volumeSlider.style.width = cursorPosition + "px";
} else if (cursorPosition === 100) {
audioEl.volume = 1;
document.getElementById("volPercentage").innerHTML = cursorPosition + " %";
volumeSlider.style.width = cursorPosition + "px";
} else {
audioEl.volume = '0.' + cursorPosition;
document.getElementById("volPercentage").innerHTML = cursorPosition + " %";
volumeSlider.style.width = cursorPosition + "px";
}
if(cursorPosition >= 50) {
volumeIconBtn.classList.remove('.fas');
volumeIconBtn.classList.remove('fa-volume-mute');
volumeIconBtn.classList.add('.fas');
volumeIconBtn.classList.add('fa-volume-up');
audioDownUp = 2;
} else {
volumeIconBtn.classList.remove('.fas');
volumeIconBtn.classList.remove('fa-volume-up');
}
if (cursorPosition <= 49) {
volumeIconBtn.classList.remove('.fas');
volumeIconBtn.classList.remove('fa-volume-mute');
volumeIconBtn.classList.add('.fas');
volumeIconBtn.classList.add('fa-volume-down');
audioDownUp = 1;
} else {
volumeIconBtn.classList.remove('.fas');
volumeIconBtn.classList.remove('fa-volume-down');
}
volPercentage.classList.add('showVolPercent');
setTimeout(function(){
volPercentage.classList.remove('showVolPercent');
}, 5000);
});
///////////////////// VOLUME SLIDER END
const playPauseBtn = document.querySelector('.playPauseBtn');
const stopBtnDiv = document.querySelector('.stopBtnDiv');
const stopBtn = document.querySelector('.stopBtn');
playPauseBtn.addEventListener('click', playPauseFunction);
stopBtnDiv.addEventListener('click', stopFunction);
let stopped = true;
var interval;
var interval2;
function playPauseFunction() {
if(audioEl.paused) {
playPauseBtn.classList.add('transform');
playPauseBtn.classList.add('transform2');
setTimeout(function(){
playPauseBtn.classList.remove('transform2');
}, 200);
audioEl.play();
audioEl2.play();
stopped = false;
let animation = 1;
interval = setInterval(function() {
if(animation === 1) {
audioPlayerDiv.classList.add('playAnimation');
animation = 0;
} else {
audioPlayerDiv.classList.remove('playAnimation');
animation = 1;
}
},16000);
let animation2 = 1;
interval2 = setInterval(function() {
if(animation2 === 1) {
audioPlayerDiv.classList.add('playAnimation2');
animation2 = 0;
} else {
audioPlayerDiv.classList.remove('playAnimation2');
animation2 = 1;
}
},32000);
} else {
playPauseBtn.classList.remove('transform');
playPauseBtn.classList.add('transform2');
setTimeout(function(){
playPauseBtn.classList.remove('transform2');
}, 200);
audioEl.pause();
stopped = false;
clearInterval(interval);
clearInterval(interval2);
audioPlayerDiv.classList.remove('playAnimation');
audioPlayerDiv.classList.remove('playAnimation2');
}
}
function stopFunction() {
if(!audioEl.paused) { // IF PLAYING
playPauseBtn.classList.remove('transform');
stopBtnDiv.classList.add('transform2');
stopBtnDiv.classList.add('transform');
setTimeout(function(){
stopBtnDiv.classList.remove('transform');
stopBtnDiv.classList.remove('transform2');
}, 200);
clearInterval(interval);
clearInterval(interval2);
audioPlayerDiv.classList.remove('playAnimation');
audioPlayerDiv.classList.remove('playAnimation2');
audioEl.currentTime = 0;
percent = 0;
progress.style.width = '0';
stopped = true;
audioEl.pause();
} else if (audioEl.paused && !stopped) {
stopBtnDiv.classList.add('transform');
stopBtnDiv.classList.add('transform2');
setTimeout(function(){
stopBtnDiv.classList.remove('transform');
stopBtnDiv.classList.remove('transform2');
}, 200);
clearInterval(interval);
clearInterval(interval2);
audioPlayerDiv.classList.remove('playAnimation');
audioPlayerDiv.classList.remove('playAnimation2');
audioEl.currentTime = 0;
percent = 0;
progress.style.width = '0';
stopped = true;
} else if (stopped){
audioEl.currentTime = 0;
percent = 0;
progress.style.width = '0';
stopped = true;
}
}
here's ss of players
Many thanks in advance.
You could use the Audio() constructor.
const player = (audiofile) => {
const newPlayer = new Audio(audiofile)
return newPlayer
}
https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement
Then create a new player by calling player('audio.wav')
ADDED:
Now that I can see your code, the other way to create many players dynamically is:
Create an array for your audio files:
const tracks = ['track1.wav', 'track2.wav']
Add a container for your players in your HTML
<div id="players"></div>
Add a function that creates a player and appends it to the container dynamically
const players = document.getElementById('players')
const player = (audiofile) => {
const newPlayer = document.createElement('audio')
audio.src = audiofile
// anything else you want to add
}
players.appendChild(newPlayer)
}
The audio() constructor and createElement(audio) both create new audio element, but audio() does not interact with the DOM.
Lastly, you would have to create a function that renders as many players as there are tracks.
Once you have rendered the players successfully, you should add an event listener for you controls so that the correct audio is played when user clicks on play etc.
https://developer.mozilla.org/en-US/docs/Web/API/Event/target

Javascript is timeout in loop valid

I am trying to build a visual sorting algorithm. I search through the data and whenever I find a new min I add the selected class. The algorithm works but it shows all the new mins at once and not one at a time. I tried to achieve one by one with setTimeout but this did not work. Is the usage of setTimeout invalid?
Thank you
var gBars = [];
function Bar(index, height){
this.index = index;
this.height = height;
this.getIndex = function(){
console.log(this.index);
};
this.getHeight = function(){
console.log(this.height);
};
this.getStats = function(){
console.log(this.index + ' ' + this.height);
}
this.setHeight = function(h){
this.height = h;
}
this.setIndex = function(i){
this.index = i;
}
}
function insertAfter(newNode, referenceNode){
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
function setHeight(i, h){
document.getElementById(i).style.height = h + 'em';
}
function addBar(i, h){
//base case i = 0
//first bar
if(i === 0){
var currentDiv = document.getElementById("root");
d = document.createElement('div');
d.setAttribute("id", 'block'+i);
d.setAttribute("class", 'block');
gBars[i] = new Bar(i, h);
currentDiv.appendChild(d);
setHeight('block'+i,h);
}
else {
let last = i-1;
var currentDiv = document.getElementById('block'+last);
d = document.createElement('div');
d.setAttribute("id", 'block'+i);
d.setAttribute("class", 'block');
gBars[i] = new Bar(i, h);
insertAfter(d, currentDiv);
setHeight('block'+i,h);
}
}
function findMin() {
let min = gBars[19].height;
//start at 18 because bars are rotated 180deg
//go backwards so it appears to go forwards
var delay = 500;
for(let i=18; i>=0; i--) {
setTimeout(function() {
if(min > gBars[i].height) {
min = gBars[i].height;
var selected = document.getElementById('block'+i);
selected.style.backgroundColor = "blue";
console.log('new min ' + min);
}
}, delay);
}
return min;
}
function init(){
for(let i=0; i<20; i++){
let ran = Math.floor(Math.random() * 50 + 1);
gBars[i] = new Bar(i,ran);
addBar(i,ran);
}
for(let i=0; i<20; i++){
gBars[i].getStats();
}
let min = findMin();
console.log('min '+ min);
}
init();
.selected{
background-color:blue;
}
.block{
border:1px solid rgba(0,0,0,.4);
width:20px;
background-color:grey;
}
#root{
display:flex;
transform:rotate(180deg);
position:absolute;
left:10%;
}
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<button>sort</button>
<div id="root"></div>
</body>
<script src="selectionsort.js"></script>
</html>
the best way to solve your problem is to create recursive function. It will fire itself after specified delay and once more after delay and once more until you will stop it.
Here, have some code:
function findMin() {
let min = gBars[19].height;
//start at 18 because bars are rotated 180deg
//go backwards so it appears to go forwards
var delay = 500;
let i = 18
min = setTimeout(timeout(i, min), delay);
return min;
}
function timeout(i, min) {
console.log("Next loop: " + i);
if(min > gBars[i].height) {
min = gBars[i].height;
var selected = document.getElementById('block'+i);
selected.style.backgroundColor = "blue";
console.log('new min ' + min);
}
i--;
if (i == 0) {
console.log("End");
return min;
} else {
setTimeout(function(){
return timeout(i, min);
},500)
}
}
You can see how it will run only after the previous function has been fired, so after the delay you have set.

Increase and decrease SVG shape - JS

I would like you to help me for a thing here, for a function to increase and then decrease SVG shape when it hits limit.
It should go from 3 to 6 and then 6 to 3 and so on... but instead it goes from 3 to 6 and then 6 to minus infinite. And I don't understand why.
Here is my code :
var size = 3;
var sizeManager = 1;
function increaseAnimation(el){
var elem = document.getElementById(el);
elem.style.transform = "scale("+size+")";
timer = setTimeout('increaseAnimation(\''+el+'\',3000)');
size=size+0.005*sizeManager;
if(size >= 6){
sizeManager=sizeManager*-1;
}
if (size <= 3){
sizeManager=sizeManager*+1;
}
}
Your weird setTimeout implementation, with bound was broken.
There's also the issue that your sizeManager is not properly reflecting:
function increaseAnimation(id, interval) {
var size = 1;
var velocity = 0.05;
var elem = document.getElementById(id);
function iterate() {
elem.style.transform = "scale(" + size + ")";
size += velocity;
if (size > 2 || size < 1) {
velocity *= -1; // velocity reflected
}
}
var timer = setInterval(iterate, interval);
return function stop() {
clearInterval(timer)
}
}
I also added a stop function which you can call at a later point.
var stopper = increaseAnimation("content", 16);
setTimeout(stopper, 5000);
The error is with the line sizeManager=sizeManager*+1; Multiplying a number by one doesn't change it. You basically want to toggle sizeManager between -1 and +1, and you can do so by multiplying by -1, regardless of whether it is currently negative or positive.
I've tested this code and it seems to work:
var size = 3;
var sizeManager = 1;
function increaseAnimation(el) {
var elem = document.getElementById(el);
elem.style.transform = "scale(" + size + ")";
timer = setTimeout("increaseAnimation('" + el + "', 3000)");
size += 0.005 * sizeManager;
if (size >= 6 || size <= 3) {
sizeManager *= -1;
}
}
Full HTML for a POC demo at: https://pastebin.com/GW0Ncr9A
Holler, if you have questions.
function Scaler(elementId, minScale, maxScale, deltaScale, direction, deltaMsecs) {
var scale = (1 == direction)?minScale:maxScale;
var timer = null;
function incrementScale() {
var s = scale + deltaScale*direction;
if (s < minScale || s > maxScale) direction *= -1;
return scale += deltaScale*direction;
};
function doScale(s) {
document.getElementById(elementId).style.transform = 'scale(' + s + ')';
};
this.getDeltaMsecs = function() {return deltaMsecs;};
this.setTimer = function(t) {timer = t;};
this.run = function() {doScale(incrementScale());};
this.stop = function() {
clearInterval(timer);
this.setTimer(null);
};
};
var scaler = new Scaler('avatar', 3, 6, .05, 1, 50);
function toggleScaler(ref) {
if ('run scaler' == ref.value) {
ref.value = 'stop scaler';
scaler.setTimer(setInterval('scaler.run()', scaler.getDeltaMsecs()));
}
else {
scaler.stop();
ref.value = 'run scaler';
}
};

Javascript. Button to stop code from running

I am making little reaction game for fun as I am new to this, It's quite a big challenge, so, I ran into the problem, how do I make script to stop from running when the button is pressed, I've managed to start everything when the start is clicked, but can't stop it from running.
Maybe anyone have any ideas how to make this happen? Here's my code so far:
Here's my HTML:
<button id="start">Start</button>
<button id="stop">Stop</button>
<button id="reset">Reset</button>
<p>Your reaction time: <u><span id="timeTaken"></span></u></p>
<p>Your average reaction time: <u><span id="average"></span></u></p>
<p>Your best reaction time: <u><span id="best"></span></u></p>
<div id="shape"></div>
And here's my javascript:
var start = new Date().getTime();
function getRandomColor() { //generates random color
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function makeShapeAppear() { //makes that shape appear on screen
var top = Math.random() * 400;
var left = Math.random() * 400;
var width = (Math.random() * 200) + 100;
if (Math.random() > 0.5) {
document.getElementById("shape").style.borderRadius = "50%"
} else {
document.getElementById("shape").style.borderRadius = "0";
}
document.getElementById("shape").style.backgroundColor = getRandomColor();
document.getElementById("shape").style.top = top + "px";
document.getElementById("shape").style.left = left + "px";
document.getElementById("shape").style.width = width + "px";
document.getElementById("shape").style.height = width + "px";
document.getElementById("shape").style.display = "block";
start = new Date().getTime();
}
function appearAfterDelay() { //makes that shape appear after some delay
setTimeout(makeShapeAppear, Math.random() * 3000);
}
document.getElementById("reset").onclick = function() { //reset button, so when you click it, everything resets
location.reload();
}
var totaltime = 0;
var totalgames = 0;
document.getElementById("start").onclick = function() { //start button, so when you click it, shapes start appearing and time's running
appearAfterDelay();
document.getElementById("shape").onclick = function() {
document.getElementById("shape").style.display = "none";
var end = new Date().getTime();
var timeTaken = (end - start) / 1000;
totaltime += timeTaken;
totalgames += 1;
var notroundaverage = (totaltime / totalgames);
var roundaverage = notroundaverage.toFixed(3);
document.getElementById("timeTaken").innerHTML = timeTaken + " s";
document.getElementById("average").innerHTML = roundaverage + " s";
appearAfterDelay();
}
}
JavaScript is event based, and you really shouldn't attempt to 'stop' it. From looking at your code I can see that what you really want to do is clear the timeout when your button is clicked. This can be achieved by placing this line:
var timeOutId;
at the top of your code, and changing
setTimeout(makeShapeAppear, Math.random() * 3000);
to
timeOutId = setTimeout(makeShapeAppear, Math.random() * 3000);
Then, simply add a button with a click event that clears the timeout, which can be achieved using this line: window.clearTimeout(timeOutId);

Check if all percentages in the array were shown

I'm using this Code to show the current progress in my progressbar:
var rotatingTextElement;
var rotatingText = new Array();
var ctr = 0;
function initRotateText() {
rotatingTextElement = document.getElementById("percent");
rotatingText[0] = rotatingTextElement.innerHTML;
rotatingText[1] = "5%";
rotatingText[2] = "10%";
rotatingText[3] = "15%";
rotatingText[4] = "20%";
rotatingText[5] = "25%";
rotatingText[6] = "30%";
rotatingText[7] = "35%";
rotatingText[8] = "40%";
rotatingText[9] = "45%";
rotatingText[10] = "50%";
rotatingText[11] = "55%";
rotatingText[12] = "60%";
rotatingText[13] = "65%";
rotatingText[14] = "70%";
rotatingText[15] = "75%";
rotatingText[16] = "80%";
rotatingText[17] = "85%";
rotatingText[18] = "90%";
rotatingText[19] = "95%";
rotatingText[20] = "100%";
setInterval(rotateText, 500);
}
function rotateText() {
ctr++;
if(ctr >= rotatingText.length) {
ctr = 0;
}
rotatingTextElement.innerHTML = rotatingText[ctr];
}
window.onload = initRotateText;
It basicly writs a new percentage in span#percent every 500 miliseconds.
The problem is that after the progressbar has reached 100% it starts again with 0%, 5% and so on.
How can I check if the percentages in the array rotatingText till [20] were all shown and then stop the rotation?
Do this instead:
var rotatingTextElement = document.getElementById("percent");
var ctr = 0;
function rotateText() {
rotatingTextElement.innerHTML = ctr + "%";
ctr += 5;
if (ctr <= 100) {
window.setTimeout(rotateText, 500);
}
}
rotateText();
There are a few ways you can tidy this up. To answer your question, start by assigning the interval to a variable:
var rotator = null;
...
rotator = setInterval(rotateText, 500);
...
function rotateText() {
ctr++;
if(ctr >= rotatingText.length -1) {
clearInterval(rotator);
}
rotatingTextElement.innerHTML = rotatingText[ctr];
}
...
Then instead of resetting the iterator to 0 when it goes out of bounds, clear the interval so it stops changing the value. You'll need to add the -1 so that it stops on rotatingText[length-1] (the last element)

Categories

Resources