call function (audio playing) in order - javascript

I hava a function that playing audios in order. But there may be a case where the function is called almost at the same time, and all audios playing is mixed. How can I call the same function where audios order of the second call is played after the audios order of the first call.
function playSound() {
$('#content').append('<audio id="ding" src="ding.wav" preload="auto"></audio>');
$('#ding')[0].play();
$('#ding')[0].onended = function() {
$('#content').append('<audio id="number" src="sound/voice/number.wav" preload="auto"></audio>');
$('#number')[0].play();
$('#number')[0].onended = function() {
$('#content').append('<audio id="goToCounter" src="sound/voice/goToCounter.wav" preload="auto"></audio>');
$('#goToCounter')[0].play();
}
}
}

One possible way is to have a counter that counts the number of times the playSound function is called. If it is still in the middle of playing sounds, increase the counter, but return from the function. Only after the playing of the three sounds is finished, you call playSound again if there are still calls in the queue.
var numberOfTimesAudioHasStarted = 0;
function playSound(buttonClicked) {
if(buttonClicked === true){
numberOfTimesAudioHasStarted++;
}
if(numberOfTimesAudioHasStarted > 1 && buttonClicked === true){
return;
}
$('#content').append(
'<audio id="ding" src="https://thumbs.dreamstime.com/audiothumb_22779/227796222.mp3" preload="auto"></audio>');
$('#ding')[0].play();
$('#ding')[0].onended = function() {
$('#content')
.append(
'<audio id="number" src="https://thumbs.dreamstime.com/audiothumb_22779/227796222.mp3" preload="auto"></audio>');
$('#number')[0].play();
$('#number')[0].onended = function() {
$('#content')
.append(
'<audio id="goToCounter" src="https://thumbs.dreamstime.com/audiothumb_11413/114136296.mp3" preload="auto"></audio>');
$('#goToCounter')[0].play();
$('#goToCounter')[0].onended = function() {
numberOfTimesAudioHasStarted--;
if(numberOfTimesAudioHasStarted > 0){
playSound(false);
}
}
}
}
}
$('button').click(function() {
playSound(true);
});
<div id="content"></div>
<button>play</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Note that this function keeps adding audio elements to the page every time the function runs. This is bad practice, since no two elements with the same id should be present on a page.

Related

Need simplified function for onclick button sounds

This is my first question here sorry if I make any mistake.
I want to know how to simplify an action (function), I have a drumkit with different buttons and sounds, I'm using this code: FIDDLE
JS
function play() {
var audio = document.getElementById('audio1');
if (audio.paused) {
audio.play();
} else {
audio.currentTime = 0
}
}
How can I write just one function and play different sounds for every button?
You could try firing multiple functions from one function. Something like:
<button onClick="play()">song1</button>
<button onClick="play()">song2</button>
<button onClick="play()">song3</button>
function someFunc() {
function audioOne() {
var audio = document.getElementById('audio1');
if (audio.paused) {
audio.play();
}
else{
audio.currentTime = 0
};
function audioTwo() {
var audio = document.getElementById('audio2');
if (audio.paused) {
audio.play();
}
else{
audio.currentTime = 0
};
function audioThree() {
var audio = document.getElementById('audio3');
if (audio.paused) {
audio.play();
}
else{
audio.currentTime = 0
};
}
Alternatively you could also try something like:
var audio = document.getElementById("id");
audio.addEventListener("click", function(){alert("audio1 triggered")}, false);
audio.addEventListener("click", function(){alert("audio2 triggered")}, false);
function play(id) {
var audio = document.getElementById(id);
if (audio.paused) {
audio.play();
}else{
audio.currentTime = 0
}
call it like this:
play('audio1');
play('audio2');
If i understand your question correctly this should work for your use-case. You basically just pass the elements id as parameter. Everytime you call the function the logic will apply to the element you specified as parameter in your function call.

JavaScript Timeout reset mechanism

What I want:
There are two pictures that are being switched/swapped every three seconds.
I want to make it so that when the button is clicked, the picture switches and the auto-swap resets. So if the button is clicked, the image swaps and three seconds later, it will auto-swap, until the button is clicked again in which the cycle will repeat.
What I have right now
Currently, the problem is that: when the button is clicked, it messes up the timing of the auto-switches.
Edit:
Please don't create a new code base. Just modify mines. The code doesn't have to be an expert super concise level. I'm only three weeks into JavaScript (and it's my first programming language). I have to explain to classmates and it wouldn't be nice the code had elements I don't understand. So sorry for the inconvenience.
Right now I just need the button to correctly stop and restart the time.
<html>
<head>
<script>
let reset = setTimeout(change, 3000);
function change() {
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
setTimeout(change, 3000);
}
function fastChange() {
clearTimeout(reset);
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
}
</script>
</head>
<body>
<input type="button" onclick="fastChange();">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350" id="picture">
</body>
</html>
The reason why your timer resets is because you are not clearing the timeout.
you need to make a reference to the timeout and then use clearTimeout() on it whne you make the fast change. I don't think it is possible or wise to do that inline the way you have it so you code needs to be refactored
let imgSrc1 = 'https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350'
let imgSrc2 = 'https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350'
let imgElement = document.getElementById('picture');
let timeout;
function change() {
if(imgElement.src === imgSrc1) {
imgElement.src = imgSrc2;
} else {
imgElement.src = imgSrc1;
  }
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(change, 3000);
}
You don't even need the second function fastChange. Now you can sent the onClick listener to change() like this
document.getElementById('whatever you want to click').onCLick = change;
Setting and clearing timeouts in multiple places will work, but I prefer using a "main loop" and a variable to count frames.
Here's an example that uses setInterval and resets a timer variable when the button was clicked:
const url1 = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
const url2 = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
function change() {
picture.src = picture.src == url1 ? url2 : url1;
}
var timer = 0;
setInterval(function() {
timer++;
time.textContent = timer;
if (timer === 30) fastChange();
}, 100);
function fastChange() {
change();
timer = 0;
}
picture.src = url1;
swap.onclick = fastChange;
#picture {
height: 70vh
}
<button id="swap">SWAP</button> <span id="time"></span><br>
<img id="picture">
You can do this by calling setTimeout and updating the index as necessary. Just be sure to store the most recent timeout id so that it can be cancelled on reset using clearTimeout.
// store the reference to the <img> that contains the picture
const pic = document.getElementById('picture')
// store a list (array) of the two picture urls
const sources = [
'https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350',
'https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350'
]
// used to store a reference to the interval timer you created.
var lastTimer
// a starting index of the list (i.e. which image we are up to right now)
var index = 1
// this functions swaps the image and sets a timer
function startRotation() {
// update the index to the next one (goes 0-1-0-1->etc)
index = 1 - index
// sets the .src of the image element
pic.src = sources[index]
// starts a 3 second timer to call this same function again
// but also stores a reference to the timer so that it can be cancelled
lastTimer = setTimeout(startRotation, 3000)
}
// this functions resets the timer and restarts the process
function reset() {
// stop the current timer if there is one
if(lastTimer){
clearTimeout(lastTimer)
}
// restart the process
startRotation()
}
// start the swapping process on start
startRotation()
<input type="button" onclick="reset();">
<img id="picture">
NOT HOW YOU CLEARTIMEOUT:
<html>
<head>
<script>
var i;
function change() {
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
i = setTimeout(change, 3000);
}
function fastChange() {
clearTimeout(i);
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
i = setTimeout(change, 3000);
}
</script>
</head>
<body onload="setTimeout(change, 3000)">
<input type="button" onclick="fastChange();">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350" id="picture">
</body>
</html>

JQuery transition animation

This program randomly selects two employees from a json-object Employees array, winnerPos is already defined.
For better user experience I programmed these functions to change pictures one by one. The animation stops when the randomly selected person is shown on the screen.
The slideThrough function will be triggered when the start button is pressed.
function slideThrough() {
counter = 0;
start = true;
clearInterval(picInterval);
picInterval = setInterval(function () {
changePicture();
}, 500);
}
function changePicture() {
if (start) {
if (counter > winnerPos) {
setWinner();
start = false;
killInterval();
} else {
var employee = Employees[counter];
winnerPic.fadeOut(200, function () {
this.src = 'img/' + employee.image;
winnerName.html(employee.name);
$(this).fadeIn(300);
});
counter++;
}
}
}
The problem is the animation doesn't work smoothly. At first it works, but not perfect. The second time the transition happens in an irregular way, i.e. different speed and fadeIn/fadeOut differs from picture to picture.
Could anyone help me to fine-tune the transition?
I would avoid using setInterval() and add a function to the call to .fadeIn() that starts the animation of the next picture.
It would look like this:
function changePicture(pos) {
pos = pos || 0;
if (pos <= winnerPos) {
var employee = Employees[pos];
winnerPic.fadeOut(200, function() {
this.src = 'img/' + employee.image;
winnerName.html(employee.name);
$(this).fadeIn(300, function() {
changePicture(pos + 1);
});
});
} else {
setWinner();
}
}
To start the animation, you call changePicture() without any arguments, like this.
changePicture();
jsfiddle

Wait until div is not visible to process next line

I need to write some code which is supposed to wait until a predefined div is no longer visible in order to process the next line. I plan on using jQuery( ":visible" ) for this, and was thinking I could have some type of while loop. Does anyone have a good suggestion on how to accomplish this task?
$( document ).ready(function() {
$(".scroller-right" ).mouseup(function( event ) {
alert('right');
pollVisibility();
});
});
function pollVisibility() {
if ($(".mstrWaitBox").attr("visibility")!== 'undefined') || $(".mstrWaitBox").attr("visibility") !== false) {
alert('inside else');
microstrategy.getViewerBone().commands.exec('refresh');
} else {
setTimeout(pollVisibility, 100);
}
}
$( document ).ready(function() {
$(".scroller-right" ).mouseup(function( event ) {
alert('right');
pollVisibility();
});
});
function pollVisibility() {
if (!$(".mstrWaitBox").is(":visible")) {
alert('inside if');
microstrategy.getViewerBone().commands.exec('refresh');
} else {
setTimeout(pollVisibility, 100);
}
}
div when not visible:
<div class=​"mstrWaitBox" id=​"divWaitBox" scriptclass=​"mstrDialogImpl" dg=​"1" ty=​"edt">​
</div>​
div when visible:
<div class=​"mstrWaitBox" id=​"divWaitBox" scriptclass=​"mstrDialogImpl" dg=​"1" ty=​"edt" visibility="visible">​
</div>​
You can use the setTimeout function to poll the display status of the div. This implementation checks to see if the div is invisible every 1/2 second, once the div is no longer visible, execute some code. In my example we show another div, but you could easily call a function or do whatever.
http://jsfiddle.net/vHmq6/1/
Script
$(function() {
setTimeout(function() {
$("#hideThis").hide();
}, 3000);
pollVisibility();
function pollVisibility() {
if (!$("#hideThis").is(":visible")) {
// call a function here, or do whatever now that the div is not visible
$("#thenShowThis").show();
} else {
setTimeout(pollVisibility, 500);
}
}
}
Html
<div id='hideThis' style="display:block">
The other thing happens when this is no longer visible in about 3s</div>
<div id='thenShowThis' style="display:none">Hi There</div>
If your code is running in a modern browser you could always use the MutationObserver object and fallback on polling with setInterval or setTimeout when it's not supported.
There seems to be a polyfill as well, however I have never tried it and it's the first time I have a look at the project.
FIDDLE
var div = document.getElementById('test'),
divDisplay = div.style.display,
observer = new MutationObserver(function () {
var currentDisplay = div.style.display;
if (divDisplay !== currentDisplay) {
console.log('new display is ' + (divDisplay = currentDisplay));
}
});
//observe changes
observer.observe(div, { attributes: true });
div.style.display = 'none';
setTimeout(function () {
div.style.display = 'block';
}, 500);
However an even better alternative in my opinion would be to add an interceptor to third-party function that's hiding the div, if possible.
E.g
var hideImportantElement = function () {
//hide logic
};
//intercept
hideImportantElement = (function (fn) {
return function () {
fn.apply(this, arguments);
console.log('element was hidden');
};
})(hideImportantElement);
I used this approach to wait for an element to disappear so I can execute the other functions after that.
Let's say doTheRestOfTheStuff(parameters) function should only be called after the element with ID the_Element_ID disappears, we can use,
var existCondition = setInterval(function() {
if ($('#the_Element_ID').length <= 0) {
console.log("Exists!");
clearInterval(existCondition);
doTheRestOfTheStuff(parameters);
}
}, 100); // check every 100ms

jQuery stop video script

This script work perfectly, but what it does is stops an instance of a playing video if a new video is started. How would I rewrite this to stop ALL instances of playing videos when the function stopAllButMe(); is called?
function stopAllButMe(playerState, player) {
if (playerState=='PLAYING') {
var myId = player.getId();
projekktor('*').each(function() {
if (this.getId()!==myId) {
this.setStop();
}
});
}
}
projekktor('*').each(function() {
this.addListener('state', stopAllButMe);
});
function stopAllButMe(playerState) {
if (playerState=='PLAYING') {
projekktor('*').each(function() {
this.setStop();
});
}
}
projekktor('*').each(function() {
this.addListener('state', stopAllButMe);
});
The 'if' statement was checking against the input.
function stopAllButMe (state, player) {
//iterate through each of the `<video>` elements
$.each($('video'), function () {
//check if the current iteration is the same element that got passed into this function
if (this.id != player.id) {
//stop any `<video>` element that isn't the one passed into this function
this.stop();
}
});
}
//find each `<video>` element and add an event handler for the `state` event
$('video').bind('state', stopAllButMe);
This assumes that each <video> tag has it's own unique ID.

Categories

Resources