javascript slowly decrease volume of audio element - javascript

audio element is playing with volume:
audio.setVolume(.20)
At a certain point I want to fade out the volume, rather than have it cut abruptly, so in essence I want
audio.setVolume(.15)
audio.setVolume(.10)
audio.setVolume(.05)
audio.setVolume(.03)
audio.setVolume(.01)
but there needs to be some very brief delay in between these changes so they are audible and I get my fade out effect. What is the proper way to do this?
thanks!

You could use a setInterval():
// Initial volume of 0.20
// Make sure it's a multiple of 0.05
var vol = 0.20;
var interval = 200; // 200ms interval
var fadeout = setInterval(
function() {
// Reduce volume by 0.05 as long as it is above 0
// This works as long as you start with a multiple of 0.05!
if (vol > 0) {
vol -= 0.05;
audio.setVolume(vol);
}
else {
// Stop the setInterval when 0 is reached
clearInterval(fadeout);
}
}, interval);

I would wrap the setTimeout inside of the function, as well as the options. Regarding the factor, 0.01 will be a safe value to decrease without you having to know or adjust the initial value.
function fadeVolume(volume, callback)
{
var factor = 0.01,
speed = 50;
if (volume > factor)
{
setTimeout(function(){
fadeVolume((audio.volume -= factor), callback);
}, speed);
} else {
(typeof(callback) !== 'function') || callback();
}
}
fadeVolume(audio.volume, function(){
console.log('fade complete');
});
Once the fade is complete, it will fire a callback that you can use to play the next song.

You can use this mouse key event too.
audio.on('keydown', function() {
// and here keep increasing or decreasing the volume, untill keyUp
})
As being viewed, its jQuery! You can use it for your work. Also, the audio tag is for the div, that contains the audio tag!

Related

create a soundbar with Angularjs

I looked into different solutions, such as this one that I improved with a button : http://jsfiddle.net/3mhJJ/.
$(".button").click(function(){
$(".bar").each(function(i) {fluctuate($(this));});
});
I would like to be able to pause the recording, and also to stop the animation when the sound is over ( I didn't include it, but just imagine the sound lasts 10 seconds)
I have never worked with jQuery, but I am familiar with AngularJS, do you think there is any way for me to do this only with JQuery or by mixing JQuery and AngularJS together?
Otherwise, I'd like to recreate something like Soundcloud but I am not sure how hard it is.
Thanks for advices.
Not entirely sure that I understood what you're after but here's how to start/stop the animation:
http://jsfiddle.net/kyysdo4n/2/ (updated to include an auto-stop feature)
var stopAnimation = false;
var closeTimeoutHandle = null;
function fluctuate(bar) {
if(stopAnimation){
return;
}
var amplitude = Math.random() * 10;
console.log(amplitude);
var height = amplitude * 4;
//Animate the equalizer bar repeatedly
bar.animate({
height: height
}, function() {
fluctuate($(this));
});
}
$("#btnStart").click(function(i) {
stopAnimation = false;
fluctuate($('.bar'));
closeTimeoutHandle = setTimeout(function(){
stopAnimation = true;
}, 10 * 1000); //10 seconds
});
$("#btnStop").click(function(i) {
stopAnimation = true;
fluctuate($('.bar'));
// clear the timeout so that if the user starts the animation again
// it doesn't get stopped when the initial timeout gets called
if(closeTimeoutHandle){
clearTimeout(closeTimeoutHandle);
}
});
I'm not sure if this helps .. if it doesn't then please add more details, maybe more code ?

How to insert black space between two consecutive images

In my slideshow images are shown one for one at random, preferable in FULLSCREEN. Since the aspect-ratio of the [mostly abstract] images are different I want to insert [imageless] black space inbetween the images to let the eye adapt like insertingwhitespacebetweenwords makes the text more readable. I think the lenght of black space should be, say one tenth of a second, just a blink of an eye, so to speak. So far I have tried to do so with setTimeout to delay the concatenation of the images in the show, without succes. Ofcourse, inserting black space must be repeated between the current and next imnage. In the motionpicture camera this [analogue] technique is wel known as Maltese Cross Mechanism, which blocks incoming light when exposed filmnegative is transported to the next frame. Since I do not want to use fadein/fadeout I need total black space instead. I'm told that the browser [its graphic engine] has a delay of itself of a few millisecs, but that is too short. Appreciate any suggestion and help. Relevant piece of code in my javascript:
var currand=0
function rotateImage(){
var nextrand = Math.floor(Math.random()*(rimages.length));
// compare current image with next image0.
if (currand > rimages.length -12) {
if (nextrand > rimages.length -12) {
currand = nextrand - 12;
document.images[0].src = rimages[currand];
}
else {
currand = nextrand;
document.images[0].src = rimages[currand];
}
...etc.
var paused = false;
document.onkeydown = function(evt) {
evt = evt || window.event;
if (evt.ctrlKey && evt.keyCode == 32) {
paused = !paused;
}
};
(function loop() {
var rantime = Math.round(Math.random() * 7000) + 1000;
setTimeout(function() {
if (!paused) {
rotateImage();
}
loop();
}, rantime);
})();
I have experimented a little bit on this. Since the images are shown one for one in full screen they are not dived, except for the credits of the show (text). CSS:
#blackit { display: none; }
<body>
<script>
var timeoutID = setTimeout(function() { document.getElementById('blackit').style.display ='block'; }, 2000);
(function loop() {
timeoutID;
setTimeout(function() {
if (!paused) {
rotateImage(); }
...
Now, this works only once, at the very start of the loop, and NOT when the loop is repeated. Images remain still concatenated. Why? Thanks again!

setInterval running really slow

I made a website where I need to animate strings that are longer than the containing parent.
This is the website: Here
If you click on next, you can see multiple pages of breeders with long names, that need to animate from left to right, but this only happens after 10 or 15 seconds and it takes a long time for it to start.
Now I have checked my code and this is where I create my functions:
function newsTicker() {
console.log('newsTicker')
verifyLength();
$('.breeder').not('.short-breed-name').each(function() {
var breederNameWidth = $(this).find('.breeder_name').width();
var divBreederNameWidth = $(this).find('.breeder_name_div').width();
var diff = Math.max(parseInt(breederNameWidth - divBreederNameWidth),0);
// console.log('diff:',diff)
$(this).find('.breeder_name').animate({
marginLeft: -diff
}, 3000,
function(){
$(this).animate({
marginLeft : 0
},3000)
})
})
}
function verifyLength() {
// console.log('verifyLength')
$('.breeder.visible').each(function() {
// debugger
var breederNameWidth = $(this).find('.breeder_name').width() + 10;
var divBreederNameWidth = $(this).find('.breeder_name_div').innerWidth();
if(breederNameWidth < divBreederNameWidth) {
$(this).addClass('short-breed-name');
$(this).find('.breeder_name').css({'width':'100%','text-align':'center'})
}
})
}
And this is where I call newsTicker:
function breederAnimate(){
verifyLength();
newsTicker();
setInterval(newsTicker, 1000);
}
Why is it so slow when my times are between 1 and 3 seconds?
You should be calling setTimeout not setInterval because you only want your animation to run once. You're restarting your animations every second
Also, you should be cancelling existing setIntervals when you click next or previous

Javascript fade in doesn't visibly animate

So I've created the following function to fade elements in and passed in a div that I want to fade in which in this case is an image gallery popup that I want to show when a user clicks an image thumbnail on my site. I'm also passing in a speed value (iSpeed) which the timeout uses for it's time value. In this case I'm using 25 (25ms).
I've stepped through this function whilst doing so it appears to be functioning as expected. If the current opacity is less than 1, then it is incremented and it will recall itself after the timeout until the opacity reaches 1. When it reaches one it stops fading and returns.
So after stepping through it, I take off my breakpoints and try to see it in action but for some reason my gallery instantly appears without any sense of fading.
var Effects = new function () {
this.Fading = false;
this.FadeIn = function (oElement, iSpeed) {
//set opacity to zero if we haven't started fading yet.
if (this.Fading == false) {
oElement.style.opacity = 0;
}
//if we've reached or passed max opacity, stop fading
if (oElement.style.opacity >= 1) {
oElement.style.opacity = 1;
this.Fading = false;
return;
}
//otherwise, fade
else {
this.Fading = true;
var iCurrentOpacity = parseFloat(oElement.style.opacity);
oElement.style.opacity = iCurrentOpacity + 0.1;
setTimeout(Effects.FadeIn(oElement, iSpeed), iSpeed);
}
}
}
Here's where I'm setting up the gallery.
this.Show = function (sPage, iImagesToDisplay, oSelectedImage) {
//create and show overlay
var oOverlay = document.createElement('div');
oOverlay.id = 'divOverlay';
document.body.appendChild(oOverlay);
//create and show gallery box
var oGallery = document.createElement('div');
oGallery.id = 'divGallery';
oGallery.style.opacity = 0;
document.body.appendChild(oGallery);
//set position of gallery box
oGallery.style.top = (window.innerHeight / 2) - (oGallery.clientHeight / 2) + 'px';
oGallery.style.left = (window.innerWidth / 2) - (oGallery.clientWidth / 2) + 'px';
//call content function
ImageGallery.CreateContent(oGallery, sPage, iImagesToDisplay, oSelectedImage);
//fade in gallery
Effects.FadeIn(oGallery, 25);
}
Could anyone help me out?
Also, I'm using IE10 and I've also tried Chrome, same result.
Thanks,
Andy
This line:
setTimeout(Effects.FadeIn(oElement, iSpeed), iSpeed);
calls Effects.FadeIn with the given arguments, and feeds its return value into setTimeout. This is exactly like foo(bar()), which calls bar immediately, and then feeds its return value into foo.
Since your FadeIn function doesn't return a function, that would be the problem.
Perhaps you meant:
setTimeout(function() {
Effects.FadeIn(oElement, iSpeed);
}, iSpeed);
...although you'd be better off creating that function once and reusing it.
For instance, I think this does what you're looking for, but without recreating functions on each loop:
var Effects = new function () {
this.FadeIn = function (oElement, iSpeed) {
var fading = false;
var timer = setInterval(function() {
//set opacity to zero if we haven't started fading yet.
if (fading == false) { // Consider `if (!this.Fading)`
oElement.style.opacity = 0;
}
//if we've reached or passed max opacity, stop fading
if (oElement.style.opacity >= 1) {
oElement.style.opacity = 1;
clearInterval(timer);
}
//otherwise, fade
else {
fading = true;
var iCurrentOpacity = parseFloat(oElement.style.opacity);
oElement.style.opacity = iCurrentOpacity + 0.1;
}
}, iSpeed);
};
};
Your code has a lot of problems. The one culpable for the element appearing immediately is that you call setTimeout not with a function but with the result of a function, because Effects.FadeIn will be executed immediately.
setTimeout(function(){Effects.FadeIn(oElement, iSpeed)}, iSpeed);
will probably act as you intend.
But seriously, you probably should not re-invent this wheel. jQuery will allow you to fade elements in and out easily and CSS transitions allow you to achieve element fading with as much as adding or removing a CSS class.
T.J. and MoMolog are both right about the bug: you're invoking the Effects.FadeIn function immediately before passing the result to setTimeout—which means that Effects.FadeIn calls itself synchronously again and again until the condition oElement.style.opacity >= 1 is reached.
As you may or may not know, many UI updates that all take place within one turn of the event loop will be batched together on the next repaint (or something like that) so you won't see any sort of transition.
This jsFiddle includes the suggested JS solution, as well as an alternate approach that I think you may find to be better: simply adding a CSS class with the transition property. This will result in a smoother animation. Note that if you go this route, though, you may need to also include some vendor prefixes.

detecting collision between two images in jquery

i have this game :http://jsfiddle.net/Qfe6L/5/
i am trying to detect when a shuriken hit an enemy so when it hit it the enemy should disappear and the score should be increased by 1 what i searched for is that i should calculate the position of the two images to check whether their is a collision but i don't seem i can do that any help from you guys ?
$(window).keypress(function (e) {
if (e.which == 32) {
CreateChuriken();
$("#Shuriken" + Shurikengid).animate({ left: '+=300px' }, 'slow');
if ($(".Shuriken").css('left') == $(".Enemy").css('left'))
{ alert("Met"); }
}
});
You need to check for collision in each animation step. Fortunately jQuery .animate() has a progress option, which you can pass a function to be called every frame.
$("#Shuriken" + Shurikengid).animate(
{ left: '+=300px' },
{ duration : 'slow',
progress: function(){
/* collision detection here */
}
}
);
Keep in mind that
if ($(".Shuriken").css('left') == $(".Enemy").css('left'))
will only compare position of first projectile and first enemy, while there are more of them on the screen. You need to iterate over every projectile and compare its powition with every enemy to find a colliding pair, like:
$('.Shuriken').each( function(){
var sOffset = $(this).offset();
$('.Enemy').each( function(){
var eOffset = $(this).offset();
if( sOffset.left == eOffset.left ){
/* boom! */
}
});
});
The above is close, but still won't work. Animation doesn't progress by 1px each frame, so you may go from Shuriken at 100px left and Enemy at 101px left at one frame to Shuriken at 102px left and Enemy at 99px left in the next one. They'll pass each other, but won't meet at the same point. So you'd need to round these values to, say, nearest 10s which will give you a bigger tolerance. You sholud also compare the vertical positions.
Updated fiddle: http://jsfiddle.net/Qfe6L/8/
(Fixed vertical posiotion of Enemies for easier testing).
Edit:
as suggested by #Kasyx it would be better to move all of this out of animation function and create a Game Loop and Scene Graph. Scene graph would keep track of elements' positions, and within Game Loop you'd check for collisions, then call a rendering function which would draw elements on screen based on the scene graph.
At the moment you’re running your hit check function once, directly after you’ve started the animation. What you need to be doing is running it every frame to see the intersect. Luckily jQuery provides a callback handler for this: $.animate’s step option. If you pass a second object into $.animate you can specify both your duration and step function like so:
$(window).keypress(function (e) {
if (e.which == 32) {
CreateChuriken();
$("#Shuriken" + Shurikengid).animate({
left: '+=300px'
}, {
duration: 'slow',
step: function(){
if ($(".Shuriken").css('left') == $(".Enemy").css('left')) {
alert("Met");
}
}
});
}
});
As you’re calling your step function once every frame you’ll want to cache your selectors inside ($('.Shuriken'), $('.Enemy')) first:
$(window).keypress(function (e) {
if (e.which == 32) {
var shuriken, enemy;
CreateChuriken();
shuriken = $('.Shuriken');
enemy = $('.Enemy');
$("#Shuriken" + Shurikengid).animate({
left: '+=300px'
}, {
duration: 'slow',
step: function(){
if (shuriken.css('left') == enemy.css('left')) {
alert("Met");
}
}
});
}
});

Categories

Resources