Play a random song on button press using Javascript - javascript

I made some HTML code a function so that when a button is clicked it runs randomSong() which is supposed to run a random song right now it runs this:
function randomSong() {
var n = (1 + Math.random() * 2);
if (n == 0){
var song = document.getElementById('1')
console.log("0")
}else if(n == 1){
var song = document.getElementById('2');
console.log('1')}
let y = song
}
var x = y
function playAudio() {
x.play();
}
function pauseAudio() {
x.pause();
}
but it doesn't work it says x is not defined anyone now why?
Link to the website I am using this for

I tried your demo it says y is not defined because when you try to access to the outer scope of y.
you can try like so:
var x;
function randomSong() {
var n = (1 + Math.random() * 2);
var song;
if (n === 0){
song = document.getElementById('1')
console.log("0")
}
else if(n === 1){
song = document.getElementById('2');
console.log('1')
}
x = song;
}
function playAudio() {
if(x){
x.play();
}
}
function pauseAudio() {
if(x){
x.pause();
}
}

Yuu need to provide more code if this didn't work. All I did was fix some obviose mistakes. Specifically, n ==enter code here 0 changed to n==0 and var x = y; where y was not a global variable y is now global. If this didn't help add more code and I will see if I can solve it.
var y;
function randomSong() {
var n = (1 + Math.random() * 2);
if (n == 0) {
var song = document.getElementById('1')
console.log("0")
} else if (n == 1) {
var song = document.getElementById('2');
console.log('1')
}
y = song;
}
var x = y;
function playAudio() {
x.play();
}
function pauseAudio() {
x.pause();
}

let, const and class introduced identifiers are block scoped. Hence in
else if(n == 1){
var song = document.getElementById('2');
console.log('1')}
let y = song
}
var x = y
the y variable created by let y = song is not in scope when assigned to x by
var x = y
If the assignment to x proceeds without generating an error it probably means a previous definition of y, possibly with undefined value is in scope. This is a trap that automatically typing can produce:
Don't automatically precede assignments to outer scoped variables with let or const or the assignment won't take place.

let x;
function randomSong() {
const n = (1 + Math.random() * 2);
let song;
if (n === 0) {
song = '0'
console.log("0");
}else if (n === 1) {
song = '1';
console.log('1');
} else {
song = '999';
console.log('999');
}
x = song;
}
function playAudio() {
console.log(`${x} play`);
}
function pauseAudio() {
console.log(`${x} pause`);
}
randomSong();
playAudio();
pauseAudio();
Don't recommend to use var if using of var is unnecessary

i take a look at your site and i noticed when you click on Click Here For Suggesed Song it call function num(), so this show an alert with track suggested. So to turn this to what you want. when we click on button we have to call function randomSong and code with commented explain:
var song = null;
function randomSong() {
//to get audio's number dynamically.
let n = document.querySelectorAll('p audio').length;
//grab all audios from HTML Node List to an array.
let audios = [...document.querySelectorAll('p audio')];
//if there is another song singing ! we should stop it
if(song!==null) song.pause();
//we pick randomly a song inside the array of audios.
song = audios[ Math.floor ( Math.random() * n) ];
//and then we play the song, Enjoy listening!
song.play();
}

Thank you all for you answers but I found a better/eaiser way to do it the javascript is
var songList = [
'mp3_url',
'mp3_url',
'mp3_url',
'mp3_url',
'mp3_url',
];
//this gets a random url from the list
function randomChoice(choices) {
var index = Math.floor(Math.random() * choices.length);
return choices[index];
}
//this is just a place holder you can change this function to anything
function age(){
let current = new Date().getTime();
var myAge = current - 1151560800000;
var myAge = myAge/1000
return myAge;
}
/*this trys to pause x and then play a new song but if x is not defined then you
get an error so you have to do try catch finally*/
function playAudio() {
try{x.pause();}catch(err){
var old = age();
var years = old / 31536000;
console.log('Hello I was ' + old + ' seconds (' + years + ' years) old when you clicked that button!');}finally{
x = randomChoice(songList);
x = new Audio(x);
x.play();
}};
function pauseAudio() {
x.pause();
}
and the HTML is some thing like this
<button onclick="playAudio()">play a song</button>
<button onclick="pauseAudio()">pause the current song</button>

Related

Executing two functions in the same onclick event but running one only once

I'm trying to get an image to run two javascript functions at the same time, the problem is that I want the changeImg() function to run continually with each click but only execute the clock() function once. (So that it starts the timer).
<img id="emotion" src="Target.jfif" width="50" onclick="changeImg();clock(); this.onclick=null;"/>
This is my changeImg() script:
{
var x = Math.floor(Math.random()*900);
var y = Math.floor(Math.random()*900);
var obj = document.getElementById("emotion");
obj.style.top = x + "px";
obj.style.left = y + "px";
}
And this is my clock() script:
function clock() {
myTimer = setInterval(myClock, 1000);
var c = 30;
function myClock() {
document.getElementById("demo").innerHTML = --c;
if (c == 0) {
clearInterval(myTimer);
alert("Reached zero");
}
}
}
Have clock() check if the timer is already set, and return.
function clock() {
if (myTimer) { // clock already started
return;
}
myTimer = setInterval(myClock, 1000);
var c = 30;
function myClock() {
document.getElementById("demo").innerHTML = --c;
if (c == 0) {
clearInterval(myTimer);
alert("Reached zero");
}
}
}
instead of passing null to onclick pass the function changeImg
onclick="changeImg();clock();this.onclick=changeImg;"
I don't know about good practices but it works without changing your code too much

Progressively add image (arrays)

So I am creating a game where a spaceship moves and it must avoid a fireball image in order to win. My issue is that I have only one fireball looping over and over. Instead, I would like to have many fireballs, which are multiplied as time passes. I think I should need to incorporate an array and use push() method but I tried and it didn't worked. If anyone could help me, it would be very appreciated. Thanks
//Fireball script
function fireballScript(offset) {
return Math.floor(Math.random() * (window.innerWidth - offset))
}
let fireballMovement = {
x: fireballScript(fireball.offsetWidth),
y: 0
}
const fireLoop = function () {
fireballMovement.y += 1
fireball.style.top = fireballMovement.y + 'px'
if (fireballMovement.y > window.innerHeight) {
fireballMovement.x = fireballScript(fireball.offsetWidth)
fireball.style.left = fireballMovement.x + 'px'
fireballMovement.y = 0
fireball.setAttribute('hit', false)
}
}
fireball.style.left = fireballMovement.x + 'px'
let fireballSpeed = setInterval(fireLoop, 1000 / 250)
let fireball = document.querySelector("#fireball")
<img src = "Photo/fireball.png" id = "fireball" >
//Stop game on collision
function checkCollision() {
if (detectOverlap(spaceship, fireball) && fireball.getAttribute('hit') == 'false') {
hits++
fireball.setAttribute('hit', true)
alert("lost")
}
setTimeout(checkCollision, 1)
}
var detectOverlap = (function () {
function getPositions(spaceship) {
var pos = spaceship.getBoundingClientRect()
return [[pos.left, pos.right], [pos.top, pos.bottom]]
}
function comparePositions(p1, p2) {
let r1 = p1[0] < p2[0] ? p1 : p2
let r2 = p1[0] < p2[0] ? p2 : p1
return r1[1] > r2[0] || r1[0] === r2[0]
}
return function (a, b) {
var pos1 = getPositions(a),
pos2 = getPositions(b)
return comparePositions(pos1[0], pos2[0]) && comparePositions(pos1[1], pos2[1])
}
})()
let spaceship = document.querySelector("#icon")
<img src = "Photo/Spaceship1.png" id="icon">
Ps: I asked this question a dozen of times but I could never get an answer which is incorporate into my code. It would be very helpful if someone could fix this... thanks again
You need to have an array of fireballs
var fireballs = [];
Make a constructor for fireballs instead of putting them directly in the html
function fireball(x, y) {
movementX = x;
movementY = y;
}
Then push new ones into the array with dynamic position values. To add them to the document, you need to append them to a parent element. If the <body> is that parent, you'd do this:
let f = new fireball(10, 20)
fireballs.push(f)
document.body.appendChild(f)
In your update, iterate through the fireballs and update their movement.
fireballs.forEach((fireball) => {
// update position for each fireball
});

Button to randomize pictures won't work the second time

var fnr = function (a,b) {
// random integer on closed interval
var y = a + Math.floor((b - a + 1) * Math.random());
return y
}
var foo;
var myTimer;
function toRandom() {
var x = fnr(0, PICTURES.length - 1);
var y = SERVER + FOLDER + PICTURES[x] + SUFFIX;
document.getElementById("img").src = y;
document.getElementById("filename").value = PICTURES[x].toUpperCase();
}
function toRandomize() {
if(!foo) {
foo = true;
document.getElementById("random").value = "stop shuffle";
myTimer = setInterval("toRandom()", 600);
} else {
foo = false;
document.getElementById("random").value = "start shuffle";
clearInterval(myTimer);
}
}
window.onload = function () {
document.getElementById("random").onclick = toRandomize;
}
// button in the body of the HTML portion of my code
<input id="random" type="button" value="start shuffle">
I have a button to randomize photos, but it won't work the second time. Do you guys have any insight in reading the code? I know fnr stands for first-non-repeating, but I'm not too familiar with how to "reset it," or if it requires a reset to get it to work again. I have the same setup for other functions and they work fine.
It's cut so it will only show the parts relevant to the question. I apologize if it's confusing.

javascript countdown with showing milliseconds

I want to do a count down and want to show like format as Minutes:Seconds:Milliseconds. I made a count down with jquery plug-in countdown but it shows just Minutes:Seconds format.
Is there any way to make it right?
Many Thanks!
Hi guys I have developed a code for my self use the following code
counter for 20 seconds
var _STOP =0;
var value=1999;
function settimer()
{
var svalue = value.toString();
if(svalue.length == 3)
svalue = '0'+svalue;
else if(svalue.length == 2)
svalue = '00'+svalue;
else if(svalue.length == 1)
svalue = '000'+svalue;
else if(value == 0)
svalue = '0000';
document.getElementById('cn1').innerHTML = svalue[0];
document.getElementById('cn2').innerHTML = svalue[1];
document.getElementById('cn3').innerHTML = svalue[2];
document.getElementById('cn4').innerHTML = svalue[3];
value--;
if (_STOP==0 && value>=0) setTimeout("settimer();", 10);
}
setTimeout("settimer()", 10);
Try this: http://jsfiddle.net/aamir/TaHtz/76/
HTML:
<div id="timer"></div>
​
JS:
var el = document.getElementById('timer');
var milliSecondsTime = 10000;
var timer;
el.innerHTML = milliSecondsTime/1000;
timer = setInterval(function(){
milliSecondsTime = milliSecondsTime - 1000;
if(milliSecondsTime/1000 == 0) {
clearTimeout(timer);
el.innerHTML = 'BOOOOM';
}
else {
el.innerHTML = milliSecondsTime/1000;
}
},1000);
​
If you want to make your own timer.
read this earlier question
How to create a JQuery Clock / Timer
Try setting the format parameter - http://keith-wood.name/countdownRef.html#format
On further reading, this plugin doesn't do milliseconds. At this point, you either have to edit the actual plugin code or find a new plugin.
I completely agree with #Matt Ball's comment.It may also cause the browser to crash.
Why don't you try this solution instead
jQuery 1 minute countdown with milliseconds and callback
I did it like this (generic counter from N to X (X > N)):
var dynamicCounterAddNewValue = 20;
var currentDynamicUpdater;
function dynamicCounterForValueForControlUpdater(_updaterData) {
_updaterData.from += dynamicCounterAddNewValue;
if (_updaterData.from > _updaterData.to) {
_updaterData.from = _updaterData.to;
}
_updaterData.c.html(_updaterData.from.toString());
if (_updaterData.from < _updaterData.to) {
currentDynamicUpdater = setTimeout(
dynamicCounterForValueForControlUpdater,
10,
{
c: _updaterData.c,
from: _updaterData.from,
to: _updaterData.to
}
);
}
else {
clearTimeout(currentDynamicUpdater);
}
return;
}
// _c -> jQuery object (div,span)
// _from -> starting number
// _to -> ending number
function dynamicCounterForValueForControl(_c, _from, _to) {
clearTimeout(currentDynamicUpdater);
dynamicCounterForValueForControlUpdater(
{
c: _c,
from: _from,
to: _to
}
);
return;
}
EDIT: Updated version (more flexible - for N elements one after another):
(input element is Array of elements for making them dynamic-counts)
var dynamicCounterTimeout = 10;
var currentDynamicUpdater;
function odcArray(_odca) {
this.odca = _odca;
return;
}
function odc(_c, _from, _to) {
this.c = _c; // $('#control_id')
this.from = _from; // e.g. N
this.to = _to; // e.g. M => (M >= N)
var di = parseInt(_to / 45, 10);
if (di < 1) {
di = 1;
}
this.dynamicInc = di;
return;
}
function dynamicCounterForValueForControlUpdater(_odca) {
if (
_odca.odca === null
||
!_odca.odca.length
) {
clearTimeout(currentDynamicUpdater);
return;
}
var o = _odca.odca[0];
o.from += o.dynamicInc;
if (o.from > o.to) {
o.from = o.to;
_odca.odca.shift(); // Remove first element
}
o.c.html(o.from.toString());
currentDynamicUpdater = setTimeout(
dynamicCounterForValueForControlUpdater,
dynamicCounterTimeout,
_odca
);
return;
}
function dynamicCounterForValueForControl(_odca) {
clearTimeout(currentDynamicUpdater);
// SETUP all counters to default
for (var i = 0; i < _odca.odca.length; i++) {
_odca.odca[i].c.html(_odca.odca[i].from.toString());
}
dynamicCounterForValueForControlUpdater(
_odca
);
return;
}

Trouble with onclick attribute for img when used in combination with setInterval

I am trying to make images that move around the screen that do something when they are clicked. I am using setInterval to call a function to move the images. Each image has the onclick attribute set. The problem is that the clicks are not registering.
If I take out the setInterval and just keep the images still, then the clicks do register.
My code is here (html, css, JavaScript): https://jsfiddle.net/contini/nLc404x7/4/
The JavaScript is copied here:
var smiley_screen_params = {
smiley_size : 100, // needs to agree with width/height from css file
num_smilies: 20
}
var smiley = {
top_position : 0,
left_position : 0,
jump_speed : 2,
h_direction : 1,
v_direction : 1,
intvl_speed : 10, // advance smiley every x milliseconds
id : "smiley"
}
function randomise_direction(s) {
var hd = parseInt(Math.random()*2);
var vd = parseInt(Math.random()*2);
if (hd === 0)
s.h_direction = -1;
if (vd === 0)
s.v_direction = -1;
}
function plotSmiley(sp /* sp = smiley params */) {
var existing_smiley = document.getElementById(sp.id);
if (existing_smiley !== null)
// delete existing smiley so we can move it
document.getElementById("smileybox").removeChild(existing_smiley);
var smiley_to_plot = document.createElement('img');
smiley_to_plot.setAttribute('src', "http://i.imgur.com/C0BiXJx.png");
smiley_to_plot.setAttribute('id', sp.id);
smiley_to_plot.setAttribute('onclick', "my_click_count()");
smiley_to_plot.style.position = 'absolute';
smiley_to_plot.style.top = sp.top_position + "px";
smiley_to_plot.style.left = sp.left_position + "px";
document.getElementById("smileybox").appendChild(smiley_to_plot);
}
function random_direction_change() {
var r = parseInt(Math.random()*200);
if (r===0)
return true;
else
return false;
}
function moveFace(sp_array /* sp_array = smiley params array */) {
var i;
var sp;
for (i=0; i < sp_array.length; ++i) {
// move ith element
sp = sp_array[i];
if (
(sp.h_direction > 0 && sp.left_position >= smiley_screen_params.width - smiley_screen_params.smiley_size) ||
(sp.h_direction < 0 && sp.left_position <= 0) ||
(random_direction_change())
) {
sp.h_direction = -sp.h_direction; // hit left/right, bounce off (or random direction change)
}
if (
(sp.v_direction > 0 && sp.top_position >= smiley_screen_params.height - smiley_screen_params.smiley_size) ||
(sp.v_direction < 0 && sp.top_position <= 0) ||
(random_direction_change())
) {
sp.v_direction = -sp.v_direction; // hit top/bottom, bounce off (or random direction change)
}
sp.top_position += sp.v_direction * sp.jump_speed;
sp.left_position += sp.h_direction * sp.jump_speed;
plotSmiley(sp);
}
}
if (typeof Object.create !== 'function') {
Object.create = function(o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
function generateFaces() {
var smilies = new Array();
var s;
var i;
var css_smileybox=document.getElementById("smileybox");
var sb_style = getComputedStyle(css_smileybox, null);
// add info to the screen params
smiley_screen_params.width = parseInt(sb_style.width);
smiley_screen_params.height = parseInt(sb_style.height);
// create the smileys
for (i=0; i < smiley_screen_params.num_smilies; ++i) {
s = Object.create(smiley);
s.id = "smiley" + i;
s.top_position = parseInt(Math.random() * (smiley_screen_params.height - smiley_screen_params.smiley_size)),
s.left_position = parseInt(Math.random() * (smiley_screen_params.width - smiley_screen_params.smiley_size)),
randomise_direction(s);
smilies.push(s);
}
setInterval( function(){ moveFace(smilies) }, smiley.intvl_speed );
}
var click_count=0;
function my_click_count() {
++click_count;
document.getElementById("mg").innerHTML = "Number of clicks: " + click_count;
}
generateFaces();
The generateFaces() will generate parameters (for example, coordinates of where they are placed) for a bunch of smiley face images. The setInterval is within this function, and calls the moveFace function to make the smiley faces move at a fixed interval of time. moveFace computes the new coordinates of each smiley face image and then calls plotSmiley to plot each one on the screen in its new location (removing it from the old location). The plotSmiley sets the onclick attribute of each image to call a dummy function just to see if the clicks are registering.
Thanks in advance.
This is not a complete answer but it could give you some perspective to improve your code.
First of all, your idea of deleting the existing img so wrong. If it does exist, all you need is to just change its position so instead of this
if (existing_smiley !== null)
// delete existing smiley so we can move it
document.getElementById("smileybox").removeChild(existing_smiley);
you should do something like this:
if (existing_smiley !== null)
var smiley_to_plot = existing_smiley;
else {
var smiley_to_plot = document.createElement('img');
smiley_to_plot.setAttribute('src', "http://i.imgur.com/C0BiXJx.png");
smiley_to_plot.setAttribute('id', sp.id);
smiley_to_plot.style.position = 'absolute';
document.getElementById("smileybox").appendChild(smiley_to_plot);
smiley_to_plot.addEventListener('click', my_click_count);
}
smiley_to_plot.style.top = sp.top_position + "px";
smiley_to_plot.style.left = sp.left_position + "px";
As you can see new image is only being added if it's not already there. Also notice that adding events by using .setAttribute('onclick', "my_click_count()"); is not a good way to do. You should use .addEventListener('click', my_click_count); like I did.
Like I said this is not a complete answer but at least this way they response to the click events now.
FIDDLE UPDATE
Good luck!

Categories