extracting an anonymous function - javascript

CodePen
On line 19, the event listener calls an anonymous function, I'd like to break this out into its own function, but I also think I need to be passing a 3rd argument in. possibly the padz class, or maybe the audio tags.. maybe a combination of both, but not sure of the syntax to do that.
JavaScript
var clickCounter = 0;
var currentLevel = 0;
var simon_sSequence = [];
var player_sInput = [];
const audioTapper = document.querySelector("#audioT");
const audioError = document.querySelector("#audioE");
const levelDisplay = document.getElementById("level_Display");
const simonzSequence = document.getElementById("simon_sSequence");
const playerInput = document.getElementById("player_sInput");
const start_Tapper = document.querySelector(".startTapper");
const pads = document.querySelectorAll(".padz");
// Convert the padz list to an array that we can iterate over using .forEach()
Array.from(pads).forEach((pad, index) => {
// Get the associated audio element nested in the padz-div
const audio = pad.querySelector("audio");
// Add a click listener to each pad which
// will play the audio, push the index to
// the user input array, and update the span
pad.addEventListener("click", () => {
player_sInput.push(index);
if (player_sInput[clickCounter] !== simon_sSequence[clickCounter]) {
audioError.play();
$("body").animate({ backgroundColor: "red" }, 100);
$("#container").effect( "shake", {times:100}, 1000, 'linear' );
$("body").animate({ backgroundColor: "gray" }, 5000);
//console.log("wrong");
} else { //end of if
audio.play();
playerInput.textContent = "Player's reply " + player_sInput;
clickCounter++;
//console.log(clickCounter);
} //end of else
}); //end of EventListener
}); //end of Array.from(pads).forEach((pad, index)
start_Tapper.addEventListener("click", (resetStart)); //end of EventListener
function resetStart() {
//generate a random number & push it to simon_sSequence
simon_sSequence.push(Math.floor(Math.random() * 4));
simonzSequence.textContent = "Simon says " + simon_sSequence;
playerInput.textContent = "Player's reply " + player_sInput;
//for each in the array set time interval(300ms);
//dipslay hover effect
//play pad sound
audioTapper.play();
player_sInput = []; //clear player's input for this turn
clickCounter = 0;
currentLevel++;
levelDisplay.textContent = "Level: " + currentLevel + " " + simon_sSequence.length + " " + player_sInput.length;
}

Related

How to use 'timeupdate' event listener to highlight text from audio?

I'm using the 'timeupdate' event listener to sync a subtitle file with audio.
It is working currently, but I'd like to adjust it to where it is just highlighting the corresponding sentence in a large paragraph instead of deleting the entire span and replacing it with just the current sentence. This is the sort of functionality I am trying to replicate: https://j.hn/lab/html5karaoke/dream.html (see how it only highlights the section that it is currently on).
This is made complicated due to timeupdate constantly checking multiple times a second.
Here is the code:
var audioSync = function (options) {
var audioPlayer = document.getElementById(options.audioPlayer);
var subtitles = document.getElementById(options.subtitlesContainer);
var syncData = [];
var init = (function () {
return fetch(new Request(options.subtitlesFile))
.then((response) => response.text())
.then(createSubtitle);
})();
function createSubtitle(text) {
var rawSubTitle = text;
convertVttToJson(text).then((result) => {
var x = 0;
for (var i = 0; i < result.length; i++) {
if (result[i].part && result[i].part.trim() != '') {
syncData[x] = result[i];
x++;
}
}
});
}
audioPlayer.addEventListener('timeupdate', function (e) {
syncData.forEach(function (element, index, array) {
if (
audioPlayer.currentTime * 1000 >= element.start &&
audioPlayer.currentTime * 1000 <= element.end
) {
while (subtitles.hasChildNodes()) {
subtitles.removeChild(subtitles.firstChild);
}
var el = document.createElement('span');
el.setAttribute('id', 'c_' + index);
el.innerText = syncData[index].part + '\n';
el.style.background = 'yellow';
subtitles.appendChild(el);
}
});
});
};
new audioSync({
audioPlayer: 'audiofile', // the id of the audio tag
subtitlesContainer: 'subtitles', // the id where subtitles should show
subtitlesFile: './sample.vtt', // the path to the vtt file
});

Clar Ajax data after each OnClick and then append new data

I'm doing a project for school. A memory game that uses the pokéAPI to get images.
I have three buttons depending on the game level (easy, medium, hard) and it generates the amount of cards.
When I click a button it generates the pictures but when I click it again it append the new data into the same selector.
I have tried with: $('#output').html(''), $('#output').append(''), $('#output').remove(), $('#output').empty()
// Settings for game level. Each integer represents number of cards * 2.
let easy = 4;
let medium = 6;
let hard = 8;
// Arrays for PokemonImgUrl.
let originalPokemonImgUrl = [];
let duplicateAllPokemonImgUrl = [];
let allPokemonImgUrl = [];
// PokéAPI URL.
const pokemonDataUrl = 'https://pokeapi.co/api/v2/pokemon/';
// This function creates a random number depending on the settings below.
function randomNumber() {
// Settings for max randomnumbers starting from index 1.
let randomNumberMax = 500;
let fromIndex = 1;
// Math random function with values from randomnumbers.
return Math.floor(Math.random() * randomNumberMax) + fromIndex;
}
// Function for getting data from PokéAPI.
function getData() {
$.ajax ({
type: 'GET',
url: pokemonDataUrl + randomNumber(), // Calling randomnnumber to get a random pokémon.
success: function(pokemonData) {
var pokemonImgUrl = pokemonData.sprites.front_default; // Store and extract pokemon images.
originalPokemonImgUrl.push(pokemonImgUrl); // store ImagesURL to a global array called allPokemonImgUrl.
}
})
}
// Shuffle code from css-tricks.com.
function Shuffle(cards) {
for(var j, x, i = cards.length; i; j = parseInt(Math.random() * i), x = cards[--i], cards[i] = cards[j], cards[j] = x);
return cards;
};
// function iterates through allPokemonImgUrl array and outputs it into the DOM.
function output() {
allPokemonImgUrl.forEach(function (i) {
$('#output').append('<img src="'+ [i] +'">');
}
)}
/* This function copies the array so that we always have two of the same cards.
Then concat into a new array and shuffles it. After that it outputs the result.*/
function startGame(){
setTimeout( function(){
duplicateAllPokemonImgUrl = originalPokemonImgUrl.slice();
}, 1000 );
setTimeout( function(){
allPokemonImgUrl = originalPokemonImgUrl.concat(duplicateAllPokemonImgUrl);
}, 1500 );
setTimeout( function(){
Shuffle(allPokemonImgUrl)
}, 2000 );
setTimeout( function(){
output();
}, 2500 );
}
/* Events for clicking on game levels. It iterates to check how many cards it needs
and calls the function getData accordingly. */
$(document).on('click', '#easy', function() {
for (var cards = 0; cards < easy; cards++) {
getData();
}
startGame();
})
$(document).on('click', '#medium', function() {
for (var cards = 0; cards < medium; cards++) {
getData();
}
startGame();
})
$(document).on('click', '#hard', function() {
for (var cards = 0; cards < hard; cards++) {
getData();
}
startGame();
})
When I click a button I get the images as expected.
But when I click it again it appends the new data after the old data. I want to remove the old ajax data first and then append the new data.
I found the solution:
Adding a clear function:
function clear() {
originalPokemonImgUrl = [];
duplicateAllPokemonImgUrl = [];
allPokemonImgUrl = [];
$('#output').empty();
}
Then just call it:
$(document).on('click', '#easy', function() {
for (var cards = 0; cards < easy; cards++) {
getData();
}
clear();
startGame();
})

Javascript loop logic error with Tone.js Tone.Transport.scheduleRepeat

Just playing around with Tone.js and not quite understanding the finer points of Tone.Transport.scheduleRepeat
When using a function more than once the sounds start to distort and timing changes.
I'm following this tutorial, and trying to duplicate within Codepen.
My "playScore" function changes every time I run it despite the index counter being reset to zero.
<!-- HTML -- >
<button onclick="playScore()">
TEST SCORE
</button>
//js
function playScore() {
console.clear();
console.log("TEST SCORE");
const synthScore = new Tone.Synth
synthScore.oscillator.type = 'sine';
synthScore.toMaster();
//synth.triggerAttackRelease ('E4', '8n' );
const notes = [
'C4', 'E4', 'G4',
'C5', 'E5', 'G5'
];
let index = 0;
Tone.Transport.scheduleRepeat(time => {
repeat(time);
}, "8n");
function repeat(time) {
console.log("index: " + index + " notes.length: " + notes.length);
let note = notes[index % notes.length];
synthScore.triggerAttackRelease(note, '8n', time);
console.log("note:" + note + " time: " + time);
index++;
}
Tone.Transport.start();
setTimeout(() => {
Tone.Transport.stop();
}, 5000)
// Tone.Transport.bpm.value = 120
I expect the same notes to be played the same way in the same order.
Instead, I'm seeing it change on each iteration.
I found that it's because apparently, I have 2 index variable and logic with local instance within the function and global outside that function.
Found a simple solution.
The button function "playScore" simply starts and stops the Tone.Transport
The notes pick up right where they let off rather than starting at the top of the array.
console.clear();
const synthScore = new Tone.Synth
synthScore.oscillator.type = 'sine';
synthScore.toMaster();
//synth.triggerAttackRelease ('E4', '8n' );
const notes = [
'C4', 'E4', 'G4',
'C5', 'E5', 'G5'
];
let speed = '8n'
let index = 0;
Tone.Transport.scheduleRepeat(time => {
repeat(time);
}, "8n");
let repeat = ( time ) => {
console.log("index: " + index + " notes.length: " + notes.length);
let note = notes[index % notes.length];
//console.log(note)
synthScore.triggerAttackRelease(note, '8n', time);
addOutput(note, '8n')
index++;
}
function playScore() {
console.log("TEST SCORE");
Tone.Transport.start();
setTimeout(() => {
Tone.Transport.stop();
}, 5000);
// Tone.Transport.bpm.value = 120
}

Make chosen player stand out from other players on scoreboard

I have a little game I play around with to learn Javascript better.
The player gets to choose
So i'm doing a little dice game in javascript/jquery. I get some users (In this case players) from a REST API that i get with AJAX Like this:
var APICaller = (function () {
let endpoint = "https://jsonplaceholder.typicode.com/";
function api_call(method, url, data, callback) {
$.ajax({
url: url,
method: method,
data: data,
success: callback
});
}
function get_users(callback) {
let method = "GET";
let url = endpoint + "users";
let data = {};
api_call(method, url, data, callback);
}
return {
get_users: get_users,
};
})();
The person playing the game can choose a player from the user list and then press the play button.
When the play button is pressed the dice should roll 3 numbers for each player and display all the numbers at the side of each player. And then the dice value list should change after a time and only the total amount of the three dice values should be in that list, and also the user list should be in points order with the highest total points on the top.
I have manage to solve all of those problems but I just need guidance of how to make the player I choose to have a green background color in the final score board.
This is how my code looks like:
var players = [];
var currentPlayer;
function add_scoreboard() {
$("#my-list").css({
display: 'none'
});
$("#my-list2").css({
display: 'block'
});
// currentPlayer.style.background("green");
let elements = []
let container = document.querySelector('#main_gameDiv')
//Add each row to the array
container.querySelectorAll('.list-li2').forEach(el => elements.push(el))
//Clear the container
container.innerHTML = ''
//Sort the array from highest to lowest
elements.sort((a, b) => b.querySelector('.score').textContent - a.querySelector('.score').textContent)
//Put the elements back into the container
elements.forEach(e => container.appendChild(e))
if(elements.firstchild.data == currentPlayer.firstchild.data){
$(this).css({background: 'green'});
}
console.log(elements);
}
var EventHandlers = (function () {
function init() {
APICaller.get_users(on_get_users_success);
function on_get_users_success(response) {
//For each user in the API
$.each(response, function (i, user) {
$("#my-list").append('<li class="list-li"><a class="list-a">' + user.name + '</a><span class="score"></span></li>');
$("#my-list2").append('<li class="list-li2">' + user.name + '<span class="score"></span></li>');
var playerObject = {
id: user.id,
name: user.name,
score: 0
};
//Add all objects to the array
players.push(playerObject);
});
$("#my-list2").css({
display: 'none'
});
//change information
$("#info-txt").text("Välj en spelare!");
}
// On klick on a user make klicked user your own player.
$("#my-list").on('click', '.list-a', function () {
currentPlayer = this;
$("#info-txt").text("Tryck på spela knappen för att börja spelet!");
$("#currentPlayer-div").animate({
height: '300px',
opacity: '1'
});
$("#currentPlayer-h3").text(this.text);
});
// On klick of the play button
$("#startGame-button").click(function () {
$("#info-txt").text("Vänta 5 sekunder tills scoreboarden visas :)");
setTimeout(function () {
add_scoreboard();
}, 5000);
$("#my-list2").css({
display: 'none'
});
console.log(players);//Show players in console just for extra info
$(".score").animate({
opacity: '1'
});
$("#currentPlayer-div").animate({
height: '150px'
});
$("#startGame-button").animate({
opacity: '0'
});
$("#dice_value").animate({
opacity: '1'
});
$("#my-list li").each(function (index) {
var numbers = [];
var v1 = Math.floor(Math.random() * 6) + 1;
var v2 = Math.floor(Math.random() * 6) + 1;
var v3 = Math.floor(Math.random() * 6) + 1;
//Add the numbers to the array
numbers.push(v1, v2, v3);
var totalScore = numbers.reduce(function (a, b) {
return a + b;
}, 0); //Count the sum of the array
//Set the players points to the sum of the array
players[index].score = totalScore;
//Find every list item of type span and set HTML to the content of the array
$(this).find(".score").html(numbers.toString());
});
$("#my-list2 li").each(function (index) {
var numbers = [];
var v1 = Math.floor(Math.random() * 6) + 1;
var v2 = Math.floor(Math.random() * 6) + 1;
var v3 = Math.floor(Math.random() * 6) + 1;
//Add the numbers to the array
numbers.push(v1, v2, v3);
var totalScore = numbers.reduce(function (a, b) {
return a + b;
}, 0); //Count the sum of the array
//Set the players points to the sum of the array
players[index].score = totalScore;
//Find every list item of type span and set HTML to the content of the array
$(this).find(".score").html(totalScore.toString());
});
});
}
return {
init: init,
}
})();
$(document).ready(function () {
EventHandlers.init();
});
This is where i choose the player:
// On klick on a user make klicked user your own player.
$("#my-list").on('click', '.list-a', function () {
currentPlayer = this;
$("#info-txt").text("Tryck på spela knappen för att börja spelet!");
$("#currentPlayer-div").animate({
height: '300px',
opacity: '1'
});
$("#currentPlayer-h3").text(this.text);
});
And this is where I try to set the color on that:
function add_scoreboard() {
$("#my-list").css({
display: 'none'
});
$("#my-list2").css({
display: 'block'
});
// currentPlayer.style.background("green");
let elements = []
let container = document.querySelector('#main_gameDiv')
//Add each row to the array
container.querySelectorAll('.list-li2').forEach(el => elements.push(el))
//Clear the container
container.innerHTML = ''
//Sort the array from highest to lowest
elements.sort((a, b) => b.querySelector('.score').textContent - a.querySelector('.score').textContent)
//Put the elements back into the container
elements.forEach(e => container.appendChild(e))
if(elements.firstchild.data == currentPlayer.firstchild.data){
$(this).css({background: 'green'});
}
console.log(elements);
}
I think it is if(elements.firstchild.data == currentPlayer.firstchild.data){ $(this).css({background: 'green'}); } and i know there is a problem because it is not changing background color.
Hope that describes it enough.
Thanks in advance!
Since elements is an array it doesn't have a property firstchild so that is why you get Uncaught TypeError: Cannot read property 'data' of undefined. It seems like what you want is to include that code in your elements.forEach function.
For example:
//Put the elements back into the container
elements.forEach(e => {
container.appendChild(e);
if (e.firstchild.data == currentPlayer.firstchild.data) {
$(e).css({
background: 'green'
});
}
});

objects in an array alerted randomly

I have built this code using javascript that makes a few objects called monster. I then put those monsters in an array and finally am trying to call one of thous monsters to the console randomly. Unfortunately it displays in my console log as undefined. Any advice on how to get a random monster in the console log every time I refresh the page?
function Monster(type, level, mAttack, mAgility, mHP) {
this.type = type;
this.level = level;
this.mAttack = mAttack;
this.mAgility = mAgility;
this.mHP = mHP;
}
Monster.prototype.logInfo = function() {
console.log("I am a : ", this.type);
console.log("I am level : ", this.level);
console.log("I have the attack of : ", this.mAttack);
console.log("I have the agility : ", this.mAgility);
console.log("I have the health : ", this.mHP);
}
var troll = new Monster("troll", 1, 10, 10, 10);
var skeleton = new Monster("skeleton", 1, 10, 10, 10);
var slime = new Monster("slime", 1, 10, 10);
var boar = new Monster("boat", 1, 10, 10);
var monsterList = new Array();
monsterList[0] = troll;
monsterList[1] = skeleton;
monsterList[3] = slime;
monsterList[4] = boar;
var summonRandomMonster = function (){
monsterSummoner = monsterList[Math.floor(Math.random() * monsterList.length)];
}
console.log(monsterSummoner);
You create a function but never call it. Therefor monsterSummoner is never set.
// THIS IS NEVER CALLED
var summonRandomMonster = function (){
monsterSummoner = monsterList[Math.floor(Math.random() * monsterList.length)];
}
console.log(monsterSummoner);
Try this instead. Notice that now that the function is called the value is set.
var monsterSummoner;
var summonRandomMonster = function (){
monsterSummoner = monsterList[Math.floor(Math.random() * monsterList.length)];
}
summonRandomMonster();
console.log(monsterSummoner);
You're close... Change your last four lines as follows -
var monsterList = [troll,skeleton,slime,boar];
var summonRandomMonster = function (){
monsterSummoner = monsterList[Math.floor(Math.random() * monsterList.length)];
console.log(monsterSummoner);
}
for (var i = 0; i < 100; i++) {
summonRandomMonster();
}
There are atleast two problems in this code. The variable "monsterSummoner" is not defined, and the function "summonRandomMonster" is not called.

Categories

Resources