How do I toggle play/pause with SoundJS? - javascript

Im using SoundJS to build a psuedo MPC. I have the sound kit buttons programmed the way I want, but I cannot get the loops to work the way I want.
I would like the user to click on "loop1" and it plays.
If the user clicks "loop1" again, it should stop and resets.
If the user clicks "loop2" while "loop1" is playing, then "loop1" stops and resets while "loop2" starts to play.
How could I master this problem. Warning, I'm a UI/UX designer at heart and still learning Javascript, so if you could give me a bit more detail when explaining, that would be great. Thanks!
Here's some of my code below, but to see it in action, check here: http://nowthatsgenius.com/clients/beatbox/
<body onload="init();">
<section class="player-container">
<article class="player-controls">
<ul class="player-controls">
<li class="player-controls-button" id="loop1" onclick="playSound(this)">Loop 1</li>
<li class="player-controls-button" id="loop2" onclick="playSound(this)">Loop 2</li>
</ul>
</article>
</section>
<section class="mpc-container">
<article class="mpc-title mpc-col">
<span class="text">V1</span>
</article>
<article class="mpc-controls mpc-col">
<ul class="mpc-controls-wrap">
<li class="mpc-controls-row">
<ul>
<li class="mpc-controls-button" id="a1" onclick="playSound(this)"></li>
<li class="mpc-controls-button" id="a2" onclick="playSound(this)"></li>
<li class="mpc-controls-button" id="a3" onclick="playSound(this)"></li>
<li class="mpc-controls-button" id="a4" onclick="playSound(this)"></li>
<li class="mpc-controls-button" id="a5" onclick="playSound(this)"></li>
</ul>
<ul>
<li class="mpc-controls-button" id="a6" onclick="playSound(this)"></li>
<li class="mpc-controls-button" id="a7" onclick="playSound(this)"></li>
<li class="mpc-controls-button" id="a8" onclick="playSound(this)"></li>
<li class="mpc-controls-button" id="a9" onclick="playSound(this)"></li>
<li class="mpc-controls-button" id="a10" onclick="playSound(this)"></li>
</ul>
</li>
</ul>
</article>
</section>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<script src="http://code.createjs.com/soundjs-0.6.0.min.js"></script>
<script>
var preload;
function init() {
if (!createjs.Sound.initializeDefaultPlugins()) {
document.getElementById("error").style.display = "block";
document.getElementById("content").style.display = "none";
return;
}
var assetsPath = "assets/";
var sounds = [
{id:"loop1", src:"loop1.mp3"},
{id:"loop2", src:"loop2.mp3"},
{id:"a1", src:"snare.wav"},
{id:"a2", src:"kick1.wav"},
{id:"a3", src:"clap1.wav"},
{id:"a4", src:"closedhat.wav"},
{id:"a5", src:"cymbal.wav"},
{id:"a6", src:"kick2.wav"},
{id:"a7", src:"clap2.wav"},
{id:"a8", src:"openhat.wav"},
{id:"a9", src:"voice1.wav"},
{id:"a10", src:"voice2.wav"},
];
$('.player-controls-button').attr("disabled",true);
createjs.Sound.alternateExtensions = ["mp3"];
createjs.Sound.addEventListener("fileload", createjs.proxy(handleLoadComplete, this));
createjs.Sound.registerSounds(sounds, assetsPath);
}
function playSound(target) {
var instance = createjs.Sound.play(target.id, createjs.Sound.INTERRUPT_NONE);
$(".player-controls-button").click(function(event) {
if (instance.playState == createjs.Sound.PLAY_SUCCEEDED) {
instance.stop();
}
else {
instance.play(target.id, createjs.Sound.INTERRUPT_NONE);
}
});
console.log(instance.playState);
}
</script>
</body>

You can modify sounds after you've started playing them by assigning them to a variable. In this case, I've created variables loop1 and loop2.
// Creating variables outside playSound() so they exist in the global scope.
var loop1 = null;
var loop2 = null;
function playSound(target) {
if(loop1){ // If loop1 exists, stop it.
loop1.stop();
}
if(loop2){ // If loop2 exists, stop it.
loop2.stop();
}
if(target.id == "loop1"){
// Assign value to var loop1
loop1 = createjs.Sound.play(target.id, createjs.Sound.INTERRUPT_NONE);
}
else if(target.id == "loop2"){
// Assign value to var loop2
loop2 = createjs.Sound.play(target.id, createjs.Sound.INTERRUPT_NONE);
}
else{
// Otherwise, create generic sound
var instance = createjs.Sound.play(target.id, createjs.Sound.INTERRUPT_NONE);
}
$(".player-controls-button").click(function(event) {
if (instance.playState == createjs.Sound.PLAY_SUCCEEDED) {
instance.stop();
}else {
instance.play(target.id, createjs.Sound.INTERRUPT_NONE);
}
});
console.log(instance.playState);
}
I recommend you separate your playSound(target) function for sound effects, and create a new one named playLoop(target) for your music loops, just to make it easier to read. But that's up to you.
Version 2
var loop1 = null;
var loop2 = null;
function playLoop(target){
// If loop1 exists, stop it and delete it
if(loop1){
loop1.stop();
loop1 = null;
}else if(target.id == "loop1"){
loop1 = createjs.Sound.play(target.id, createjs.Sound.INTERRUPT_NONE);
}
// If loop2 exists, stop it and delete it
if(loop2){
loop2.stop();
loop2 = null;
}else if(target.id == "loop2"){
loop2 = createjs.Sound.play(target.id, createjs.Sound.INTERRUPT_NONE);
}
}
When you assign createjs.Sound.play() to a variable, the variable becomes an AbstractSoundInstance object. You can modify it in many cool ways, here's the documentation if you want to learn what more you can do with these variables.

Related

Continuously change text in an element

Hi all I have the following code :
var names = Array('John', 'Craig', 'Jim', 'Nick', 'Stuart');
$("#pickName").on('click', function () {
//pickName();
var name = names[Math.floor(Math.random() * names.length)];
alert(name);
names.splice($.inArray(name, names), 1);
$('#' + name).remove();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li id="John">John</li>
<li id="Craig">Craig</li>
<li id="Stuart">Stuart</li>
<li id="Nick">Nick</li>
<li id="Jim">Jim</li>
</ul>
<a id="pickName">Click Me</a>
<h1 id="randomName"></h1>
Which when I click on the #pickName selects a name from the array and displays it in a alert box then removes it from the array and from the <ul> list. Which is all fine but what I'd like to do is have the H1 tag (#randomName) looping through and 'flashing' all of the remaining names (constantly until I click #pickName).
I've tried doing an internet search for this but I can't think of how to word what it is that I'm trying to do!
Could anyone help?
You can do it using setInterval and by keeping a global counter, also take care to take the modulo of this counter with your array length to avoid out-of-bounds indexing.
Here is the doc for setInterval. You should also assign the return value so you can later clear your interval timer.
const names = Array('John', 'Craig', 'Jim', 'Nick', 'Stuart');
const h1$ = $('#randomName');
let idx = 0;
setInterval(() => {
h1$.text(names[idx++ % names.length]);
}, 200);
$("#pickName").on('click', function () {
const name = names[Math.floor(Math.random() * names.length)];
names.splice($.inArray(name, names), 1);
$('#' + name).remove();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li id="John">John</li>
<li id="Craig">Craig</li>
<li id="Stuart">Stuart</li>
<li id="Nick">Nick</li>
<li id="Jim">Jim</li>
</ul>
<a id="pickName">Click Me</a>
<h1 id="randomName"></h1>
Just like jo_va but having names going through randomly:
var names = Array('John', 'Craig', 'Jim', 'Nick', 'Stuart');
function pickName()
{
return names[Math.floor(Math.random() * names.length)]
}
$("#pickName").on('click', function () {
//pickName();
var name = pickName();
alert(name);
names.splice($.inArray(name, names), 1);
$('#' + name).remove();
});
setInterval(function(){
$("#randomName").text(pickName());
}, 200);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li id="John">John</li>
<li id="Craig">Craig</li>
<li id="Stuart">Stuart</li>
<li id="Nick">Nick</li>
<li id="Jim">Jim</li>
</ul>
<a id="pickName">Click Me</a>
<h1 id="randomName"></h1>
Though, I recommend you find a more sustainable way to manage your elements rather than giving the <li> ids that match their content. Unless it's really meant for static use :)

Using an active 'li' element to determine a video's source file

I tried creating a small video library where one div is split into two parts: 1) a menu on the left with the titles of the movies and 2) the rest of the div on the right being a video window that changes it's video source according to the selected title on the menu. I gave the li elements that housed the titles id's and used jQuery/JavaScript to retrieve the title and to assign a new video source based on that title, but it isn't working and I also can't claim to completely understand what I've done. The code is as follows:
HTML
<div class="miyazaki">
<div class="menu">
<ul>
<li><a id="Gulliver">Gulliver's Travels</a></li>
<li><a id="Howl">Howl's Moving Castle</a></li>
<li><a id="Kiki">Kiki's Delivery Service</a></li>
<li><a id="Castle">Castle of Cagoliostro</a></li>
<li><a id="Totoro">"My Neighbor Totoro</a></li>
<li><a id="Ponyo">Ponyo</a></li>
<li><a id="Mononoke">"Princess Mononoke</a></li>
<li><a id="Spirited">Spirited Away</a></li>
<li><a id="Sky">The Sky's Castle Laputa</a></li>
<li><a id="Nausicaa">Nausicaa Valley of the Wind</a></li>
<li><a id="Cat">"The Cat Returns</a></li>
</ul>
</div>
</div>
JavaScript
function Hayato() {
var movie = $("ul.menu li a.active");
if (movie.id == Gulliver || movie.id == null || movie.id == "") {
document.getElementsByClassName('window').video.source.src = Gulliver.mkv
}
else if (movie.id == Howl) {
document.getElementsByClassName('window').video.source.src = Howl.mkv
}
else if (movie.id == Kiki) {
document.getElementsByClassName('window').video.source.src = Kiki.mkv
}
else if (movie.id == Castle) {
document.getElementsByClassName('window').video.source.src = Castle.mkv
}
else if (movie.id == Totoro) {
document.getElementsByClassName('window').video.source.src = Totoro.mkv
}
else if (movie.id == Ponyo) {
document.getElementsByClassName('window').video.source.src = Ponyo.mkv
}
else if (movie.id == Mononoke) {
document.getElementsByClassName('window').video.source.src = Mononoke.mkv
}
else if (movie.id == Spirited) {
document.getElementsByClassName('window').video.source.src = Spirited.mkv
}
else if (movie.id == Sky) {
document.getElementsByClassName('window').video.source.src = Sky.mkv
}
else if (movie.id == Nausicaa) {
document.getElementsByClassName('window').video.source.src = Nausicaa.mkv
}
else (movie.id == Cat) {
document.getElementsByClassName('window').video.source.src = Cat.mkv
}
}
I'm not entirely sure this code is the best way to go about solving my problem, but it's the most logical progression I can think of.
This can all be condensed down considerably since most of the code stays the same in all cases. Also, your closing <ul> isn't a close tag and you are missing a closing <div>.
// Get all the <a> elements
var anchors = document.querySelectorAll(".menu a");
// Get a reference to the video element
var v = document.querySelector("video");
// Set up click event handlers for each
Array.prototype.slice.call(anchors).forEach(function(anchor){
anchor.addEventListener("click", function(evt){
// default video when no id is present
var d = "Gulliver.mkv";
// Use the default or the id
v.source = (!anchor.id) ? d : anchor.id + ".mkv";
console.log("video source is: " + v.source);
});
});
<div class="miyazaki">
<div class="menu">
<ul>
<li><a id="Gulliver">Gulliver's Travels</a></li>
<li><a id="Howl">Howl's Moving Castle</a></li>
<li><a id="Kiki">Kiki's Delivery Service</a></li>
<li><a id="Castle">Castle of Cagoliostro</a></li>
<li><a id="Totoro">"My Neighbor Totoro</a></li>
<li><a id="Ponyo">Ponyo</a></li>
<li><a>Porco Rosso</a></li>
<li><a id="Mononoke">"Princess Mononoke</a></li>
<li><a id="Spirited">Spirited Away</a></li>
<li><a id="Sky">The Sky's Castle Laputa</a></li>
<li><a id="Nausicaa">Nausicaa Valley of the Wind</a></li>
<li><a id="Cat">"The Cat Returns</a></li>
</ul>
</div>
</div>
<video></video>
As you also tagged jQuery here a working example for that:
$('.menu li a').on('click', function() {
var id = $(this).attr('id');
$('.window video source').attr('src', id + '.mkv');
});
Example
Note: Your html is invalid too. The ul is never closed
There's no need to use all these if blocks, you can do it in a one line statement.
You could just do it this way:
function Hayato() {
var movie = $("ul.menu li a.active").attr("id");
if(movie && movie !== "#")
document.getElementsByClassName('window')[0].video.source.src = movie + ".mkv";
}
Note:
In the code you used all the Strings are inavlid Strings, you should wrap them between two " or '.

Making a HTML link to a JavaScript Array for a JS Slider

So I want to create links in my website to link to an array in script.js file which is where I contain my JavaScript for the content slider I've created.
The idea is to click a link from this html:
<div id="slider">
<h2 id="sliderHeader">Social Determinants of Health</h2>
<p>______________________</p>
<p id="sliderPara">In terms of health - good quality health care is a determinant of health, and access, affordability, and acceptability of health are all socially determined. But most social determinants of health lie outside the health care system.</p>
<input class="readmore_button" type="submit" value="Read more" />
</div>
<div class="slider_menu">
<ul>
<li>Social Determinants of Health</li>
<li><span style="color:#fff;">|</span></li>
<li>Monitoring Progress</li>
<li><span style="color:#fff;">|</span></li>
<li>What Works</li>
<li><span style="color:#fff;">|</span></li>
<li>Making it Happen</li>
</ul>
</div>
To link to one of my arrays which is a separate slider. As seen below:
var headArray= ['Social Determinants of Health',
'Monitoring Progress',
'What Works',
'Making it Happen'];
Is this even possible? If not is there a workaround?
p.s. this is the website I'm working on http://hghazni.com/ihe/
Cheers!
I figured it out. I just made a function for each value in the array variable which reset the slider count and slider interval time. Then grabbed the relevant element id's.
function slider_link_1() {
cnt = 0;
timer = setInterval(slider, 5000);
var slider = document.getElementById('slider');
slider.style.backgroundImage = "url(\'" + imgadr[cnt] + "\')";
document.getElementById('sliderHeader').innerHTML = headArray[0];
document.getElementById('sliderPara').innerHTML = paraArray[0];
}
function slider_link_2() {
cnt = 1;
timer = setInterval(slider, 5000);
var slider = document.getElementById('slider');
slider.style.backgroundImage = "url(\'" + imgadr[cnt] + "\')";
document.getElementById('sliderHeader').innerHTML = headArray[1];
document.getElementById('sliderPara').innerHTML = paraArray[1];
}
function slider_link_3() {
cnt = 2;
timer = setInterval(slider, 5000);
var slider = document.getElementById('slider');
slider.style.backgroundImage = "url(\'" + imgadr[cnt] + "\')";
document.getElementById('sliderHeader').innerHTML = headArray[2];
document.getElementById('sliderPara').innerHTML = paraArray[2];
}
function slider_link_4() {
cnt = 3;
timer = setInterval(slider, 5000);
var slider = document.getElementById('slider');
slider.style.backgroundImage = "url(\'" + imgadr[cnt] + "\')";
document.getElementById('sliderHeader').innerHTML = headArray[3];
document.getElementById('sliderPara').innerHTML = paraArray[3];
}
Then I ended up linking them on my index.html like this:
<div class="slider_menu">
<ul>
<li>Social Determinants of Health
</li>
<li><span style="color:#fff;">|</span>
</li>
<li>Monitoring Progress
</li>
<li><span style="color:#fff;">|</span>
</li>
<li>What Works
</li>
<li><span style="color:#fff;">|</span>
</li>
<li>Making it Happen
</li>
</ul>
</div>
And now it works! That was hard, but I learnt a lot! Thanks to the people who pointed me in the right direction for me to figure it out myself.
Live version here: http://hghazni.com/ihe

radomize ul tag not working

this is probably an easy question for you guys but I'm very new to coding and can't figure out this. I have a code that I want to randomize the given choices in the questions, and I've found a script online that does that but it's not working. I don't know what the
// shuffle only elements that don't have "group" class
$ul.find("li[class!='single_question', 'question', 'title', 'text']").each(function() {
means so I tried to put all id that I don't need to randomize in it but it's still not working.
Can someone help me this please? Also is there anyway I can add choice "A", choice "B", choice "C", and choice "D" in front of each given options so even after the options(answers) are randomized, the A,B,C,D options will still be in order? Thank you. Here's the code:
HTML:
<!DOCTYPE html>
<html>
<body>
<script src="JQ.js"></script>
<script src="function.js"></script>
<link href="style.css" rel="stylesheet" />
<div id="quiz_container">
<ul class="quiz_container">
<li class="single_question" data-question-id="1" data-correct-answer="1">
<div class="question">
<h1 class="title">P.1 Grammar Review</h1>
<p class="text">1. "What is your name__"</p>
</div>
<ul class="options">
<li value="1">?</li>
<li value="2">.</li>
<li value="3">,</li>
</ul>
<div class="result"></div>
</li>
<li class="single_question" data-question-id="2" data-correct-answer="b">
<div class="question">
<p class="text">2. "Do you like the banana__"</p>
</div>
<ul class="options">
<li value="a">.</li>
<li value="b">?</li>
<li value="c">,</li>
</ul>
<div class="result"></div>
</li>
</div>
</body>
</html>
JS:
$(document).ready(function () {
/*
* shuffles the array
* #param {Array} myArray array to shuffle
*/
function shuffleArray(myArray) {
for (var i = myArray.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = myArray[i];
myArray[i] = myArray[j];
myArray[j] = temp;
}
return myArray;
}
var $ul, $li, li_content, li_list;
// find all lists to shuffle
$("#quiz_container > ul").each(function () {
$ul = $(this);
li_list = [];
// shuffle only elements that don't have "group" class
$ul.find("li[class!='single_question', 'question', 'title', 'text']").each(function () {
// add content to the array and remove item from the DOM
li_list.push($(this).html());
$(this).remove();
});
// shuffle the list
li_list = shuffleArray(li_list);
while (li_content = li_list.pop()) {
// create <li> element and put it back to the DOM
$li = $("<li />").html(li_content);
$ul.append($li);
}
});
$("#contact_div").show();
});
$(document).on('click', '.single_question .options li', function () {
// Save the question of the clicked option
question = $(this).parents('.single_question');
// Remove If Anyother option is already selected
question.find('.selected').removeClass('selected');
// Add selected class to the clicked li
$(this).addClass('selected');
// selected option value
selected_answer_value = $(this).attr("value");
// Value of correct answer from '.single-question' attribute
correct_answer_value = question.attr("data-correct-answer");
correct_answer_text = question.find('.options').find("li[value='" + correct_answer_value + "']").text();
if (correct_answer_value == selected_answer_value)
result = "<div class='correct'> Correct ! </div>";
else
result = "<div class='wrong'> Correct answer is -> " + correct_answer_text + "</div>";
// Write the result of the question
$(this).parents('.single_question').find('.result').html(result);
// Calculate the score
score_calculator();
});
/**
* It loops through every question and increments the value when "data-correct-answer" value and "option's value" are same
*/
function score_calculator() {
score = 0;
$('.single_question').each(function () {
question = $(this);
if (question.attr('data-correct-answer') == question.find('.selected').attr("value")) {
score++;
}
});
$('.correct_answers').html(score);
}
It looks like you're using jQuery, even though the question isn't tagged as such. If that's the case, you can use a code snippet written by Chris Coyier of CSS-Tricks called shuffle children.
Here's an example of the code in action.
$.fn.shuffleChildren = function() {
$.each(this.get(), function(index, el) {
var $el = $(el);
var $find = $el.children();
$find.sort(function() {
return 0.5 - Math.random();
});
$el.empty();
$find.appendTo($el);
});
};
$("ul.randomized").shuffleChildren();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h4>Static List:</h4>
<ul>
<li>First element</li>
<li>Second element</li>
<li>Third element</li>
<li>Fourth element</li>
</ul>
<h4>Randomized List:</h4>
<ul class="randomized">
<li>First element</li>
<li>Second element</li>
<li>Third element</li>
<li>Fourth element</li>
</ul>
In order to apply it to your own code, all you'd need to do is modify the CSS selector at the bottom of the jQuery snippet. In your case, ul.options might be a good choice.
Here are a couple of examples using your markup:
jsFiddle
Self-Contained HTML Doc

jQuery: How to specify element in this case?

I have a function that adds game results to a schedule.
I want to have the score of a winning team in yellow - add ".winner" class to (<%=score1%> or <%=score2%>).
I wonder what is the correct way to specify needed element, using jQuery.
My current code isn't working. All elements get ".winner" class, regardless of whether a team won or not.
addGame: function(gameInfo) {
var sHtml = window.JST["schedule/gamelist/inner_row"](gameInfo);
var tableRow = $("<tr>").append(sHtml);
tableRow.data("id", gameInfo.id);
return tableRow;
}
addNewTable: function(date, gameInfos, number) {
...
...
for (var ind = 0; ind < gameInfos.length; ++ind) {
gameInfo = gameInfos[ind].attributes;
var element = this.addGame(gameInfo);
$("#schedule_mytable_tbody" + number).append(element);
if (gameInfo.score1 > gameInfo.score2)
$("li:nth-child(5)").find("p:first-child").addClass("winner");
else
$("li:nth-child(5)").find("p:last-child").addClass("winner");
}
My template looks like this.
window.JST["schedule/gamelist/inner_row"] = _.template(
'<td width="668px">\
<ul>\
<li class="schedule_..."></li>\
<li class="schedule_..."></li>\
<li class="schedule_...."></li>\
<li class="schedule_..."></li>\
<li class="schedule_boxscore">\
<p><%=score1%></p>\
<p><%=score2%></p>\
</li>\
...
Rendered HTML part:
<li style="font-size:16px" class="schedule_boxscore">
<p class="winner">2</p>
<p class="winner">10</p>
</li>
So, because of the "for" loop, all paragraphs get the ".winner" class, not just <p class="winner">10</p>...

Categories