I'm using Wavesurfer.js to visualize waveforms from . Is there a way to use jQuery or Javascript to dynamically change the loaded audio file when I click on an HTML element?
I'm able to visualize a single file, but don't know how to change the loaded file dynamically.
Here's the Wavesurfer.js instance in my footer
<script>
var wavesurfer = WaveSurfer.create({
backend: 'MediaElement',
container: '#waveform',
barWidth: 1,
barGap: 3,
cursorColor: '#e15a13',
cursorWidth: 3,
mediaControls: true,
hideScrollbar: true,
waveColor: "#000000",
fillParent: true,
responsive: true,
});
wavesurfer.setHeight(40);
wavesurfer.load('http://dev.chrislamdesign.com/shortwave/wp-content/uploads/2019/10/Pharrell-Williams-Happy-Official-Music-Video-1.mp3');
wavesurfer.on('ready', updateTimer)
wavesurfer.on('audioprocess', updateTimer)
// Need to watch for seek in addition to audioprocess as audioprocess doesn't fire
// if the audio is paused.
wavesurfer.on('seek', updateTimer)
function updateTimer() {
var formattedTime = secondsToTimestamp(wavesurfer.getCurrentTime());
$('.waveform-time-indicator .time').text(formattedTime);
}
function secondsToTimestamp(seconds) {
seconds = Math.floor(seconds);
var h = Math.floor(seconds / 3600);
var m = Math.floor((seconds - (h * 3600)) / 60);
var s = seconds - (h * 3600) - (m * 60);
h = h < 10 ? '0' + h : h;
m = m < 10 ? '0' + m : m;
s = s < 10 ? '0' + s : s;
return h + ':' + m + ':' + s;
}
</script>
I want to replace the loaded file (wavesurfer.load) with an HTML string on click. I'm using Wordpress to loop song results, each have a URL printed in a paragraph tag with the class "move_to_wavesurfer". So, when I click on the song, i want to replace the wavesurfer.load value with the paragraph tag value.
Here's the HTML to inject
<div class="col-md-3">
<a class="song-link" data-target="#song-8">
<img width="606" height="610" src="http://dev.chrislamdesign.com/shortwave/wp-content/uploads/2019/07/cover.png" class="attachment-full size-full wp-post-image" alt="" srcset="http://dev.chrislamdesign.com/shortwave/wp-content/uploads/2019/07/cover.png 606w, http://dev.chrislamdesign.com/shortwave/wp-content/uploads/2019/07/cover-150x150.png 150w, http://dev.chrislamdesign.com/shortwave/wp-content/uploads/2019/07/cover-298x300.png 298w" sizes="(max-width: 606px) 100vw, 606px"></a>
<p class="move_to_wavesurfer>http://dev.chrislamdesign.com/shortwave/wp-content/uploads/2019/10/other_song.mp3</p>
</div>
</div>
<p>In your PHP loop... maybe you can put the urls in a data attribute</p>
<button rel='song-switch' data-song-url='song-url-a'>
play
</button>
<button rel='song-switch' data-song-url='other-song-url'>
play
</button>
...
console.clear();
// I'd normally write this in plain JavaScript - but since you are using WordPress - it has jQuery already
function switchTrack(url) {
// your code...
alert('play the song ' + url);
}
// get references to the HTML(DOM) elements
var $switches = $('[rel="song-switch"]');
// add event listeners to each switch
$switches.each( function() {
// $(this) refers to each switch
$(this).on('click', function() {
var url = $(this).data('song-url'); // get the value of that attr
//
switchTrack(url); // pass it into your function - to load a new track
// and this is where you'd work with the player's api...
// consider wrapping your current code in a function - or breaking it into some reusable functions
});
});
// yes... you should use event delegation... but you can look that up in the future.
From what I can see of your code - you probably don't have a script file / or aren't using it - so, remember to put this JS in a script tag / or generally - just make sure it's in the right place for you.
Here's where you can learn more about jQuery and all of it's functions: https://jquery.com/
https://jsfiddle.net/sheriffderek/teLm7drn
and also... keep in mind that with WordPress... you'll need to wrap your jQuery code with something like this:
(function($) {
// $ Works! You can test it with next line if you like
// console.log($);
})( jQuery );
Related
This is the function. I am including Jquery library from Google CDN and it is before this script.
{
$(document).ready( function() {
function displayTime() {
var currentTime = new Date();
var hours = currentTime.getHours();
var minutes = currentTime.getMinutes();
var seconds = currentTime.getSeconds();
// This gets a "handle" to the clock div in our HTML
//This does not work???
var clockDiv = $(document).getElementById('clock');
//This works though
var clockDiv = document.getElementById('clock');
// Then we set the text inside the clock div
// to the hours, minutes, and seconds of the current time
clockDiv.innerText = hours + ":" + minutes + ":" + seconds;
}
// This runs the displayTime function the first time
displayTime();
});
}
As others have mentioned, to achieve the same functionality as you would using just the Web API for Document with jQuery, you would use a selector instead. As Arun P states, you would do
var clockDiv = $('#clock'); // select the div with an ID of clock
clockDiv.text( /* your text */ ); // set the text of the selected element to the passed argument
jQuery is a library the abstracts the Web APIs to help with cross-browser compatibility issues and to generally make navigating and manipulating the DOM a bit easier.
to set text in a div
$('#clock').text('some text');
Because jQuery returns the document information differently. If I remember correctly it would have to be:
$(document)[0].getElementById('clock');
I have a range input in a HTML page, which actually stands for a music timeline. I got a script that moves the handle along the slider as the music progresses.
Now, I want to be able to move the handle so the music will play where I set the handle with the mouse.
The problem is that when I begin dragging the handle along the slider, as soon as its position is updated by the script, it is set to its actual position and I lose control over it.
How can I fix that so I can move my handle freely ?
To play the music I am using a plugin, soundmanager2, and I am using the provided whileplaying callback function to set the position of the slider as the music progresses.
Here is the HTML bit :
<div id="timeCtl">
<span id="timeRange">
<input id="time" type="range" value="0" min="0" max="1000"/>
</span>
<p id="timeCpt">00:00 / 00:00</p>
</div>
And the JS that goes with it :
//This is the callback function contained within an object being created
whileplaying : function() {
//This whole block processes the "position / duration" display
var dur = parseInt(this.duration/1000, 10);
var durMin = parseInt(dur/60, 10);
var durSec = dur%60;
var pos = parseInt(this.position/1000, 10);
var posMin = parseInt(pos/60, 10);
var posSec = pos%60;
if (posMin < 10)
{
posMin = "" + "0" + posMin.toString();
}
if (posSec < 10)
{
posSec = "" + "0" + posSec.toString();
}
if (durMin < 10)
{
durMin = "" + "0" + durMin.toString();
}
if (durSec < 10)
{
durSec = "" + "0" + durSec.toString();
}
var displayDur = durMin.toString() + ":" + durSec.toString();
var displayPos = posMin.toString() + ":" + posSec.toString();
g("timeCpt").innerHTML = displayPos + " / " + displayDur;
//And here is the part that take care of moving the handle
var curPos = parseInt(pos / dur * 1000, 10);
g("timeRange").innerHTML = "<input id=\"time\" type=\"range\" value=\"" + curPos.toString() + "\" min=\"0\" max=\"1000\">";
//The problem is that it moves the handle while I'm dragging it and then I lose control and have to grab it again
//How to avoid that ?
}
Thank you for your time reading this, and thank you in advance for your answers.
Actually I may have found a way to solve the problem.
I could make things so that when the onclick event is fired, the script moving the range is disabled, until the onrelease event is fired (totally not sure about the events names but I guess find out what they really are).
I'm gonna try this out and keep the thread up to date.
EDIT: This works.
Create a boolean variable.
Surround the updating part of your script with a condition controlled by the boolean variable.
Set the boolean variable to false when the slider's onmousedown event is fired, and it will prevent the script from updating it.
Set it back to true when onmouseup is fired, with some additionnal processing if needed.
I am implementing a Stopwatch in JavaScript.
I want to delete additional div elements when pushing a clear button. I added function cc();, but function cc() doesn't work. What's wrong with my code?
Javascript:
a = 0;
myButton = 0;
function myWatch(flug) {
if(myButton == 0) {
Start = new Date();
myButton = 1;
document.myForm.myFormButton.value = "Stop!";
myInterval = setInterval("myWatch(1)", 1);
} else {
if(flug == 0) {
myButton = 0;
document.myForm.myFormButton.value = "Start";
clearInterval(myInterval);
}
Stop = new Date();
T = Stop.getTime() - Start.getTime();
H = Math.floor(T / (60 * 60 * 1000));
T = T - (H * 60 * 60 * 1000);
M = Math.floor(T / (60 * 1000));
T = T - (M * 60 * 1000);
S = Math.floor(T / 1000);
Ms = T % 1000;
document.myForm.myClick.value = H + ":" + M + ":" + S + ":" + Ms;
}
}
b = 0;
function stop() {
b++;
stopa();
}
function stopa() {
var element = document.createElement('div');
element.id = pos;
var objBody = document.getElementsByTagName("body")
.item(0);
objBody.appendChild(element);
rap = "";
rap = "rap" + b + "=" + H + ":" + M + ":" + S + ":" + Ms;
element.innerHTML = rap;
}
function cc() {
document.body.removeChild(element);
}
HTML:
<form name="myForm" action="#">
<input type="text" size="20" name="myClick">
<input type="button" value="Start" name="myFormButton" onclick="myWatch(0)" />
<input type="button" value="Rap" name="Rap" onclick="stop()">
<input type="button" value="clear" name="clear" onclick="cc()">
</form>
<h3>
<div id="pos">
</div>
</h3>
Try to pass the context explicitly as parameter on the cc() function.
js
function cc(el) {
el.parentNode.removeChild(el);
}
html
<input type="button" value="clear" name="clear" onclick="cc(this)">
Open up your Console. It's found in most major browsers and will help you loads with JS development.
For example, if you look at your code exactly as is, you get an error:
Uncaught ReferenceError: element is not defined
As several have said, it's a variable scope issue. There's a few easy fixes, the easiest being simply making element have a larger scope - that is, define it outside of your functions first.
var element = null;
and then in stopa, don't use var because it'll make a new, local variable instead of using the global one.
element = document.createElement('div');
The next problem you'll notice is that element in cc still doesn't refer to the correct element - this is because in the following line, pos is not defined.
element.id = pos;
Again, take a look at the Console (now more specifically at the HTML section than the JS, but it's in the same developer options). You'll notice the created element's ID is [object HTMLDivElement] - not "pos". I'd recommend not even worrying about giving them ids, you have a div with id pos already in your HTML, simply append your results to that instead of the body.
objBody = document.getElementById("pos");
Then when you clear, clear all children from pos (you'll also want to clear the text box I'm sure, so here ya go)
while (objBody.hasChildNodes()) {
objBody.removeChild(objBody.lastChild);
}
document.myForm.myClick.value = "";
Notice now we no longer need element to be global, because it's only referenced in one function - it can be local to that function. However, objBody is now referenced in stopa and cc, so we'll make it global as we did with element and simply ensure all future references to it don't include var.
var element = null;
Add some error checking (clearing before you click Start causes errors, for example) and you're good to go!
http://jsfiddle.net/daCrosby/MMywX/1/
The function cc has no idea what 'element' is. The easiest way to fix this is to use jquery. When you delete the div, do something like
$('#pos').remove()
This finds the div with id 'pos' and removes it. You may need to pass the id of the div to cc if it's not just 'pos'.
Modern browsers supports remove() method on the element. You don't need to use external libraries as jQuery or long code. It's simple as :
var x = document.getElementById("myElement");
x.remove();
Working exemple here -> https://jsfiddle.net/tmj3p7t5/
I am using a jQuery Based Memory Game on my site. You can restart the game at anytime you like. Works great. Now I finish a game then I hit Play Again. If I hit restart it no longer works. Why and How do I fix it?
Here is a fiddle.
JS:
// this script shows how you can get info about the game
var game = jQuery('div.slashc-memory-game'); // get the game
var info = jQuery('p#info').find('span'); // get the info box
var restart = jQuery('a#restart').css('visibility', 'visible'); // get the play again link
var playAgain = jQuery('a#play-again').css('visibility', 'hidden'); // get the play again link
// format time like hh:mm:ss
var formatTime = function(s)
{
var h = parseInt(s / 3600), m = parseInt((s - h * 3600) / 60); s = s % 60;
return (h < 10 ? '0' + h : h) + ':' + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
}
// listen for game 'done' event
game.bind('done', function(e)
{
// show basic stats
var stats = game.slashcMemoryGame('getStats');
info.html('Success ! Number of clicks : ' + stats.numClicks + ', elapsed time : ' + formatTime(parseInt(stats.time / 1000)) + '.');
playAgain.css('visibility', 'visible'); // show link
restart.css('visibility', 'hidden'); // show link
});
// Restart action
restart.click(function(e)
{
game.slashcMemoryGame('restart'); // restart game
});
// play again action
playAgain.click(function(e)
{
playAgain.css('visibility', 'hidden'); // hide link
info.html('Memory Game, click to reveal images. <a id="restart" href="#">Restart</a>'); // reset text
game.slashcMemoryGame('restart'); // restart game
e.preventDefault();
});
HTML:
<p id="info"><span>Memory Game, click to reveal images. <a id="restart" href="#">Restart</a></span> <a id="play-again" href="#">Play Again</a></p>
You're replacing the #restart element whenever you click #play-again at this line:
info.html('Memory Game, click to reveal images. <a id="restart" href="#">Restart</a>');
This means the click handler for the #restart element is no longer attached to the new element.
You should attach the handler to an ancestor element which is always present in the DOM using a delegated event handler .on():
info.on('click', '#restart', function(e)
{
game.slashcMemoryGame('restart'); // restart game
});
Fiddle
I replaced the #restart element's directly-bound event handler with a delegated event handler. Here's the reference for an extra read: Direct and delegated events. Basically, you can only bind event handlers to elements currently in the DOM, and:
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time.
Hi Masters Of Web Development,
first I want to say that I did not believe in my eyes - I've got a piece of javascript that works just fine in IE7, and don't in Firefox!!! :)))) That was little joke. :)
So I already told you the problem (it wasn't joke), now I'm pasting the javascript:
<script type="text/javascript">
<!-- This script and many more are available free online at -->
<!-- The JavaScript Source!! http://javascript.internet.com -->
<!-- Begin
var ms;
ms = %%CONTENT_REFRESH%% - 5;
var stop;
stop = 0;
var myvalue;
function display() {
if (!stop) {
setTimeout("display();", 1000);
}
thetime.value = myvalue;
}
function recalc() {
var hours;
var minutes;
var seconds;
ms = ms - 1;
hours = Math.floor(ms / 3600);
minutes = Math.floor(ms / 60);
if (minutes < 10) {
minutes = "0"+minutes;
}
seconds = ms - (minutes*60) - (hours*3600);
if (seconds < 10) {
seconds = "0"+seconds;
}
myvalue = hours+":"+minutes+":"+seconds;
thetime.value = myvalue;
if (myvalue == "0:00:00") {
stop = 1;
}
if (!stop) {
setTimeout("recalc();", 1000);
}
}
// End -->
</SCRIPT>
This is very old script I know that. It takes my current remaining song time, from my winamp and countdowns in site. But as I said, it does not work in Firefox.
Body and code that calls countdown timer looks like this:
<body class="playlist_body" onLoad="recalc();display();">
Time Left In Song: <INPUT align="center" TYPE="text" Name="thetime" size=5 />
</body>
//Edit: I look at FireBug, and I saw the following error:
thetime is not defined
recalc()playlist.cgi (line 87)
function onload(event) { recalc(); display(); }(load )1 (line 2)
error source line: [Break on this error] thetime.value = myvalue;\n
The problem is that it's accessing DOM elements by name.
Add the following code to the top to declare a variable for the thetime element, add id="thetime" to the INPUT, and add a call to init(); in onload in the body element.
var thetime;
function init() {
thetime = document.getElementById('thetime');
}
By the way, you can replace the textbox with a regular DIV element by setting the div's ID to thetime, and replacing thetime.value with thetime.innerHTML.
Also, it's better to call setTimeout with a function instead of a string; you should replace "display();" and "recalc();" with display and recalc respectively.
IE has a "feature" where an element with a name attribute is placed in the window object, eg.
<div name=foo></div>
Will give you a variable "foo" -- this is non-standard, you should do
document.getElementByName("foo")
To get the timer output element.
var thetime = document.getElementById("thetime");
and add id="thetime" instead of just name="thetime" to the input