I would like, when navigating away from the page, to execute a fade of a musical cue instead of cutting if off abruptly. It is okay with me if the fade adds a half second to the time needed to execute the link.
I have the following code that will execute a fadeout of a playing music cue.
<audio id="myAudio"
<source src="./audio/pluto.mp3" type="audio/mp3">
Your browser does not support the audio element.
</audio>
and
<script>
function fadeAudio()
{
if (myAudio.volume > 0)
{
myAudio.volume = Math.max(0, myAudio.volume - 0.05);
setTimeout(fadeAudio, 20);
}
}
</script>
I tested this code with a button, and it works fine (sometimes there is a bit of zippering, but I prefer it to an abrupt cutoff).
<button onclick="fadeAudio()">Try it</button>
My problem is that I don't know how to call and execute this fade before navigating away. I was looking at html's onbeforeunload, but that seems to be geared entirely to printing a warning prompt, with no way to insert my intervening fadeAudio() function.
Simply doing the following accomplished nothing:
<body onbeforeunload="fadeAudio()">
And this didn't work with onunload either.
I am thinking another approach would be to rewrite the links on the page to run the fadeAudio() function first. (It's more important to me that transitions between my pages sound nice than if the user decides to close or go elsewhere.) Perhaps this can be done via making a button and calling the fadeAudio and a linking function in sequence. But it seems there might also be a neater way. Any suggestions?
Here is what I found that kind of works:
(1) in the link, one can call a function
(2) in the function, I first call the fadeAudio() function, then I call a setTimeout() function with 1000 ms time allotted to allow the fadeAudio() to complete
(3) then the setTimeout calls a window.open() method of the target link.
I'm going to be tweaking the various timings to see how far I can tighten this without adding too much zippering. It will definitely make things a little sluggish going from location to location on my site though.
Wouldn't it be nice if there was a way for the sound to just fade out in its own thread while the new page appears. If there is a way, I would love to know about it.
In the script tag:
function linkToHome()
{
fadeAudio();
setTimeout(openHome, 1000);
}
function openHome()
{
window.open('index.htm','_self');
}
The URL call in HTML:
Home
Will probably try to figure out a way to paramaterize the above to allow the method or tag to include the target URL.
Related
I have two Javascript files, both setup to generate an image from base64. The first script, called static.js looks like this.
var element = new Image();
element.src = "data:image/png;base64,..."
document.body.appendChild(element);
I can embed the script into my website using the following code and the image appears with no issues. (To see the full code, including the base64, go here)
<body>
<script src="./static.js"></script>
</body>
Similarly, I have a second script that I found on CodePen by takashi that converts a base64 image into an animated glitch. I was able to take that code and modify it using the same base64 image as the static code but with the glitch (apologies, but the code is really long even without my base64 image so I just included the link). The code for my image can be seen here. Note that while CodePen shows the HTML and Javascript on the same page, I broke mine out into separate files.
Again, if I embed the script into the webpage, it works with no issues.
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/p5.min.js"></script>
<script src="./glitch.js"></script>
</body>
The issue I have is that neither code has a dedicated javascript function() attribute, so the only way they work is if I embed the code as indicated above. Using the static image for brevity, if I add a dedicated function:
function isStatic() {
var element = new Image();
element.src = "data:image/png;base64,..."
document.body.appendChild(element);
}
and then try a callback,
<body>
<script src="./static.js">
isStatic();
</script>
</body>
the image does not appear on the webpage any longer. The same happens on the glitched image when I try to wrap the whole script into a function and then try a callback.
The main reason I was trying to turn each JS file into functions is so that I could combine the two into one file (which I did), and then using an embedded script like
<script>
setInterval(function(isStatic) {
// This will be executed every 9 seconds
}, 9000);
setInterval(function(isGlitch) {
// This will be executed every 2 seconds
}, 2000);
</script>
to create an image that switches from static to glitched, and then back again.
Since I was not able to successfully turn each JS file/script into it's own function, what I am trying to figure out is if there is a better way to combine my Static and Glitch JS scripts into one, or if there is a way that I can set the webpage to call each script file individually in such a way that creates a loop of the static and glitched images switching back and forth.
I have scoured the Google-webs looking for anything that describes what I am trying to do visually, but have absolutely nothing to show for it but a whole heap of scripts on various ways to make text and/or images glitch (just not how to make them start out static and then glitch randomly). Essentially what I would like to do with my two scripts is
- run static image (script or call) for *x* seconds (120-180 seconds)
- run glitched image (script or call) for *x* seconds (3-5 seconds)
- reset (loop) the sequence
in order to create the appearance of a single image that seems to randomly glitch for unknown reasons.
Edited answer after your clarifying comment:
Your code uses a library called p5, which is controlling your animation timing, so my previous answer is irrelevant. If you just want to change how often the glitch occurs, you already have almost everything you need. The glitch.js file already has a flag to turn the glitch on and off (this.throughFlag). And, it already has a slight random delay between glitches on line 226:
setTimeout(() => {
this.throughFlag = true;
}, floor(random(40, 400)));
The second parameter to setTimeout controls how long to wait beofre setting this.throughFlag to true (and thus starting to glitch again).
You just need to make this number longer. To do so, you want to make the time on the timeout longer, ie by multiplying it by some constant, which I'll call delayFactor.
const delayFactor = 10;
setTimeout(() => {
this.throughFlag = true;
}, delayFactor * floor(random(40, 400)));
See it in action here.
Based on what I understand you need 60fps on your animations to make the animations appear smooth. Basically what I'm trying to do is to do the heavy calculations at the start of the frame so by the time the rendering is actually going to happen there won't be much work left to do.
I understand you can use window.requestAnimationFrame to run a function right before the screen is redrawn. But that will cause a jerking effect if the function takes a long time. Is there a way to run a function right after the screen has done a repaint?
I tried something like this but its miss and hit:
window.requestAnimationFrame(do_before);
do_before(){
window.setTimeout(do_after, 1);
}
do_after(){
//code to execute after animation frame
}
As you can see in the picture below the do_after code is still executing in the same frame and because of this I sometimes get long frames:
Link to image
Is there a way to make do_after() run after the screen has finished drawing itself?
Thanks in advance
Actually, the code from you question is right. setTimeout(do_after) is enough in Chrome and Safari (I haven't tested in other browsers). It makes the browser execute the function when the browser is free of other tasks.
If you want to delay the execution from inside a requestAnimationFrame callback, just call setTimeout(do_after) and the callback will be executed right after the frame flush:
requestAnimationFrame(() => {
do_before();
setTimeout(do_after);
});
If you want to delay the execution from another place (e.g. a click handler or an AJAX response handler), call requestAnimationFrame first and then setTimeout:
document.addEventListener('click', () => {
do_before();
requestAnimationFrame(() => {
setTimeout(do_after);
});
});
Unfortunately I haven't found a universal way to execute a callback right at the start of the next frame because there is no straightforward way to know if a code is executed inside a requestAnimationFrame handler. You may use a trick to solve it
If you need to execute a callback right after any frame flush, use the second approach (requestAnimationFrame + setTimeout). It may lead to idling a whole animation frame before running the callback.
There is no API function to do what you want, but you can do the following:
window.requestAnimationFrame(function()
{
do_before();
window.requestAnimationFrame(do_after);
});
This makes sure your do_after is called after the first animation frame, and will trigger a second one after it's done executing.
I'm trying to call for a jQuery function when my Flash Canvas animation ends. I can't seem to figure out what code I need to add on that last keyframe in order to do that. I found something like this but it's not working:
this.stop();
ExternalInterface.call("javascript:start_website();");
Thanks in advance!
I managed to find a solution from browsing a few other websites. Basically at the end of my animation on the very last keyframe I added this bit of code:
this.animation_tracker = function() {
start_website();
return false; // prevent the function from being run over and over again
}
exportRoot.animation_tracker();
And within my website I created a jQuery function called start_website(); where I placed all the actions that I wanted to have happen once my animation was over.
in flash canvas you are already programming in javascript (and other js libraries flash uses), so you can't use and don't need the ExternalInterface.call and such.
You can and should call straight to the javascript function:
this.stop();
start_website();
Good luck!
Disclaimer: Don't worry about my code being "standards compliant"
Basically, the page I am making is supposed to play a short audio clip upon loading using the <object data="someAudio.wav"> tag. I then use Javascript and setTimeout() to play a couple of other audio files after a few seconds of delay. The setTimeout does this by using innerHTML and rewriting the correct div section with with a new object, where the object is just another audio. For example:
<script type="text/javascript">
setTimeout("update_audio()", 2500);
function update_audio(){
document.getElementById('slide_audio').innerHTML="<object classid='clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95' height='0' width='0'><param name='FileName' value='../../../Audio_general/good.wav'><param name='autoplay' value='true'><object type='audio/mpeg' height='0' width='0' data='../../../Audio_general/good.wav'><param name='controller' value='true'><param name='autoplay' value='false'></object></object>";
}
</script>
I have the image linked to a map so that it is divided up into the 4 sections. When I click on a section, it will call a function that will perform logic based on my selection and then should play 1 of 2 other audio files. Section of map code here:
<map id="testing_image" name="pictureMap">
<area id="image1" shape="rect" coords="0, 0, 449, 331" onclick="evaluate_status(1);" onmouseover="this.style.cursor='pointer'" alt="FB">
</map>
My problem is, the onclick="evaluate_status()" parts of the map will only work before I update the innerHTML. Meaning, if I can click on a section before 2.5 seconds (the first innerHTML update) it will play the correct audio. However, after it updates the div section using innerHTML, none of the onclicks of my map will work. I am confused as to why this is since only a small section is being changed.
Can anyone help me figure out why the onclicks don't work and how I can fix it? I am still pretty new to web design and really need the assistance. Thanks!
You're missing a closing </div> tag for slide_audio, therefore testing_image in fact is a child of slide_audio and is being replaced with the new object when the script runs.
If you look in Firebug with JavaScript disabled you'll be able to see that testing_image is inside slide_audio, not separate from it. Here's a screenshot of Chrome's Developer Tools on that site:
Can you show of evaluate_status() function?
Also for the first code
setTimeout("update_audio()", 2500);
function update_audio(){
document.getElementById('slide_audio').innerHTML="";
}
You should define the function before you use it in settimeout. This will not generate error in Chrome, but in other browsers, it will.
Is there a way for javascript/jQuery to know if the source file for an <audio> tag has been/is being loaded?
I am using mediaelement.js, however I'll accept an answer that works for just a regular <audio> tag. Currently I'm faking the loading indication:
$("#temp-loading").spin(minySpinner);
setTimeout(function() {
$('#temp-loading').spin(false);
}, 12000);
(spin() is a function from spin.js). Obviously the indicator is meaningless in this case, but people were getting confused when the page was loaded but the audio was taking about 15 seconds to start playing, so I had to implement this temporary solution. I'd like it to actually indicate if the file is still being loaded, though, so on slower connections the icon will remain until the file has actually started playing.
Also of note is that I have the element set to autoplay (it's okay, I promise!), so when the page is loaded it automatically starts "playing", even though no actual audio is happening yet. This makes it hard to use the play event to stop the spinner, since it just stops immediately. So I'll either have to stop the spinner when the audio actually starts, or not PLAY until the audio is actually ready to be played, if that makes sense.
I also noticed that while the audio file is loading, the time indicator says, "00:00". When it's loaded, it changes to "00:00:00". So it seems that the ability to do what I need is already built-in, I just need to know how to use it.
If it makes a difference, the file is a live stream (via Icecast). Thanks!
What about the canplay event?
EDIT
Since I got the points, I'd better paste brick's solution for posterity:
$("audio").mediaelementplayer({
audioWidth: 150,
features: ['playpause','current','volume'],
success: function(element) {
element.addEventListener('loadeddata', function(){
$("#temp-loading").spin(false);
}, false);
}
});
I've half-way solved it with the following:
$("#temp-loading").spin(minnerSpinner);
var audio = document.getElementsByTagName('audio')[0];
audio.addEventListener('loadeddata', function(){
$("#temp-loading").spin(false);
});
However this is not a cross-browser solution (works in Chrome and Safari, not Firefox).
edit I have it working with jQuery now, but still doesn't work for Firefox (which is using mediaelement's Flash fallback). At this point it's not an html5 question anymore, it's a mediaelement problem.
$('audio').bind('loadeddata', function(){
$("#temp-loading").spin(false);
});
edit 2 I ended up getting it work following Tetaxa's suggestion... not exactly what he/she suggested, but it gave me the idea to use the success callback:
$("audio").mediaelementplayer({
audioWidth: 150,
features: ['playpause','current','volume'],
success: function(element) {
element.addEventListener('loadeddata', function(){
$("#temp-loading").spin(false);
}, false);
}
});
Thanks!