How to decrease audio volume while looping in javascript and jquery - javascript

I want to control audio volume by decreasing it while function loop, but my below code doesn't seems to work.
var count = 0;
var rotate= 5;
var saudio = $("#saudio").get(0);
function tryitnow(){
count++;
saudio.volume = parseInt(saudio.volume)- parseInt(0.1);
if (count != rotate) {
setTimeout(function() {
tryitnow()
}, 1000);
}
}

parseInt(0.1); will return 0 because it will round the float 0.1 so each time you are reducing the volume by 0
You don't need to parseInt(saudio.volume) since it's already a number too.
So this should work
var count = 0;
var rotate = 5;
var saudio = $("#saudio").get(0);
function tryitnow() {
count++;
saudio.volume = saudio.volume - 0.1;
if (count != rotate) {
setTimeout(function() {
tryitnow()
}, 1000);
}
}

Related

Playing animation during x seconds using setInterval

I want to display an animated number from 0 to max value y during x seconds. I have tried this following code but it take too much to complete and clear the interval.
jQuery('.numbers').each(function(item, index) {
const $obj = jQuery(this);
let objValue = parseInt($obj.text()),
currentValue = 0,
speed = 1,
time = 4000,
step = Math.floor(objValue / time);
$obj.text(currentValue);
let interVal = setInterval(() => {
if (currentValue >= objValue) {
clearInterval(interVal);
$obj.text(objValue);
}
$obj.text(currentValue);
currentValue += step
}, speed);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class='numbers'>7586</span>
<span class='numbers'>147520</span>
How do I play this animation during exactly time seconds?
It is better not to depend on the timing of setInterval(), but the real problem in your script is that you use the floored value to decide the new value to print out.
It is better to use Window.requestAnimationFrame() and create a update() function that prints the current number based on the real time elapsed.
let start, previousTimeStamp;
let numbers = document.querySelectorAll('.numbers');
requestAnimationFrame(update);
function update(timestamp) {
if (start === undefined) {
start = timestamp;
}
const elapsed = timestamp - start;
[...numbers].forEach(elm => {
if(!elm.dataset.start){
elm.dataset.start = elm.textContent;
}
let start = parseInt(elm.dataset.start);
elm.textContent = Math.floor(start / 4000 * elapsed);
});
if (elapsed < 4000) {
previousTimeStamp = timestamp;
requestAnimationFrame(update);
}else {
start = undefined;
[...numbers].forEach(elm => {
elm.textContent = elm.dataset.start;
});
}
}
<span class='numbers'>7586</span>
<span class='numbers'>147520</span>

How to correctly move objects at different speeds in the direction of the `Y` axis

Tried to make a script like this:
let intervals = [],
isClick = [],
isGameOver = false,
countElement = 3,
count = 0,
gameOver = function () {
if (isGameOver) {
return;
}
isGameOver = true;
if (countElement <= count) {
for (var i = 0; i < intervals.legth; ++i) {
clearInterval(intervals[i]);
}
intervals = [];
countElement = 0;
}
},
elm = function (index) {
return function () {
if (isGameOver || isClick[index]) {
return null;
}
isClick[index] = true;
clearInterval(intervals[index]);
intervals[index] = null;
if (!intervals.filter(a => a).length) {
count = countElement;
gameOver();
return;
}
};
};
for (let i = 0; i < 17; ++i) {
setTimeout(() => {
element.on('pointerup', elm(i));
intervals[i] = setInterval(() => {
if (countElement <= count) {
clearInterval(intervals[i]);
gameOver();
return;
}
if (-64 > element.position.y) {
clearInterval(intervals[i]);
intervals[i] = null;
++count;
} else {
element.position.y -= 30;
}
}, pos.speed);
}, pos.startTime * i);
}
It actually works, but for some reason it doesn't always work as it should.
Perhaps I'll tell you right away what is required ..
It is necessary to generate the required number of elements and move along the axis Y.
They must have different speeds.
I tried to solve it like this:
let rnd = function (min, max) {
return Math.floor(Math.random() * (max - min) + min);
}, pos = {
speed: Math.floor(rnd(100, rnd(370, 470))),
startTime: Math.floor(rnd(rnd(370, 470), rnd(700, 1000)))
}
In general, I would like to see the elements start flying with different departure and flight speeds, there were attempts that can be missed if the element flew away, when you click on the element, it stops.
Well, in fact, if all the elements flew out - it doesn't matter if they flew away or stopped, the main thing is that all intervals should stop and there would be a kind of exit ...
Connoisseurs help out how this can be done without third-party libraries?
How to do it correctly, please show.
Problem solved...
There was no need to zero out countElement and intervals in gameOver.
Because of this, subsequent intervals were looped, as the indices were violated.

How would you throttle a recursive function?

Let's suppose I want to run a recursive function that will take weeks, months or even years to complete. It returns all possible permutations of a string based on the specified parameters. While it's running, I want to be able to see how far along it is progressing - e.g. how many permutations it has generated so far. In a nutshell, I want a very long-running recursive function to execute without locking up my UI.
Also, I would like to do this with vanilla ES5, not in strict mode, and without WebWorkers. It should be able to run in IE9.
What I have works fine as-is, but when I raise numspaces to 10, for example, the browser locks up. So I am assuming that I am just working the browser too hard, and "throttling" the amount of work it has to do would help solve this problem. I did try increasing the setTimeout delays from 1 to 250 and even 1000, but the browser still locked up.
I am interested in this simply because I tried to do it, and couldn't. Also, I know for a fact that this code is terribly inefficient and there are much, much better ways to do what I am looking to achieve. So recommend them!
var inputString = "abcdefghijklmnopqrstuvwxyz";
function allPossibleCombinations(input, length, curstr, callback) {
if (curstr.length === length) return callback(curstr);
(function(n) {
setTimeout(allPossibleCombinations.bind(n, input, length, curstr + input[n], callback), 1);
n++;
if (n < input.length) setTimeout(arguments.callee.bind(n,n), 1);
})(0);
}
var totalResults = 0,
numDigits = inputString.length,
numSpaces = 2,
maxResults = Math.pow(numDigits, numSpaces),
consoleElement = document.getElementById('console'),
startTime = +new Date();
console.log("Starting.. expecting", maxResults, "total results...");
allPossibleCombinations(inputString.split(""), numSpaces, "", function(result) {
totalResults++;
if (totalResults === maxResults) {
var elapsed = +new Date() - startTime;
consoleElement.innerText = "Done.";
console.log("Completed in", elapsed, "ms!");
} else {
// Do something with this permutation...
//...
// Show progress...
var progress = ((totalResults / maxResults) * 100).toFixed(2) * 1;
consoleElement.innerText = progress + "%";
}
});
<div id="console"></div>
You’re getting close with the setTimeout, but the current implementation queues up all the timers for a given prefix at once, resulting in an exponential number of timers and quick memory exhaustion. One small change would be to create another callback to indicate completion and use it to wait on recursive calls, never holding more than one timer at once:
var inputString = "abcdefghijklmnopqrstuvwxyz";
function allPossibleCombinations(input, length, curstr, resultCallback, doneCallback) {
if (curstr.length === length) {
resultCallback(curstr);
doneCallback();
return;
}
var n = 0;
(function next() {
if (n === input.length) {
doneCallback();
return;
}
allPossibleCombinations(
input, length, curstr + input[n],
resultCallback,
function () {
n++;
setTimeout(next, 0);
});
})();
}
var totalResults = 0,
numDigits = inputString.length,
numSpaces = 4,
maxResults = Math.pow(numDigits, numSpaces),
consoleElement = document.getElementById('console'),
startTime = +new Date();
console.log("Starting.. expecting", maxResults, "total results...");
allPossibleCombinations(
inputString.split(""), numSpaces, "",
function (result) {
totalResults++;
// Do something with this permutation...
//...
// Show progress...
var progress = ((totalResults / maxResults) * 100).toFixed(2) * 1;
consoleElement.innerText = progress + "%";
},
function () {
var elapsed = +new Date() - startTime;
consoleElement.innerText = "Done.";
console.log("Completed in", elapsed, "ms!");
});
<div id="console"></div>
That’s really slow, though. Thinking of how you could write this as a generator:
function* strings(input, length, current) {
if (current.length === length) {
yield current;
return;
}
for (let i = 0; i < input.length; i++) {
yield* strings(input, length, current + input[i]);
}
}
and translating that to a system where the callback is responsible for resuming generation:
function strings(input, length, current, yield_, continue_) {
if (current.length === length) {
yield_(current, continue_);
return;
}
var i = 0;
(function next() {
if (i === input.length) {
continue_();
return;
}
strings(input, length, current + input[i++], yield_, next);
})();
}
you can have the flexibility of setting a timer as infrequently as you’d like for performance.
"use strict";
function countSequences(n, k) {
var result = 1;
for (var i = 0; i < k; i++) {
result *= n--;
}
return result;
}
function strings(input, length, current, yield_, continue_) {
if (current.length === length) {
yield_(current, continue_);
return;
}
var i = 0;
(function next() {
if (i === input.length) {
continue_();
return;
}
var c = input[i++];
strings(input.replace(c, ''), length, current + c, yield_, next);
})();
}
var inputString = "abcdefghijklmnopqrstuvwxyz";
var totalResults = 0;
var numDigits = inputString.length;
var numSpaces = 5;
var maxResults = countSequences(numDigits, numSpaces);
var consoleElement = document.getElementById('console');
var startTime = +new Date();
console.log("Starting… expecting", maxResults, "total results.");
strings(
inputString, numSpaces, "",
function (result, continue_) {
if (totalResults++ % 1000 === 0) {
var progress = (totalResults / maxResults * 100).toFixed(2);
consoleElement.innerText = progress + "% (" + result + ")";
setTimeout(continue_, 0);
} else {
continue_();
}
},
function () {
var elapsed = +new Date() - startTime;
consoleElement.innerText = "Done.";
console.log("Completed in", elapsed, "ms!");
});
<div id="console"></div>
(This style is still non-optimal, but it’ll never finish for 2610 no matter how quick individual operations are.)

Replacing previous number in JS/JQuery

I would like to add an effect that some websites now have i.e. coffees drank: and then number of coffees drank, gradually growing from 0 to N-1. This is my attempt, if I print i in the console in the first if statement , each number prints out. But, when in HTML it goes from 0-950 instantly with no numbers in between.
To sum make it up: I would like the number to increment on the page, each new number replacing its previous number.
for (i = 0; i < 950; i++) {
if ($("#counter").length) {
setTimeout(function() {
// body...
$("#counter").append('<p id = "counter">' + i + '</p>');
}, 2000);
console.log(i);
} else {
$(".coffee-drank").append('<p id = "counter">' + i + '</p>');
}
}
If I got your idea correctly, it can be done generally like this:
var start = -1, end = 950;
var countUp = function func() {
if(start >= end) return;
var elem = document.getElementById("counter");
elem.innerText = ++start;
setTimeout(func, 25);
}
countUp();
count up to 950:
<span id="counter">0</span>
UPDATE
In your case it might look like this (no need for a cycle at all):
var start = -1, end = 950;
var countUp = function func() {
if(start >= end) {
// the end is reached; start is equal to 950 now; do something useful and quit
$(".coffee-drank").append('<p id = "counter">' + start +'</p>');
return;
}
$("#counter").text(++start);
setTimeout(func, 25);
}
countUp();
Replace your for loop with this:
var speed = 16; // Lower is faster
increase(0, 950);
function increase(i, max){
if(i <= max){
if ($("#counter").length) {
$("#counter").html(i);
} else {
$(".coffee-drank").append('<p id = "counter">' + i + '</p>');
}
setTimeout(function(){
increase(++i, max);
}, speed);
}
}

Make number grow with jQuery using same amount of time for every number

My goal is to perform a jQuery script that'll make any number visually grow from zero until its value with setInterval().
Here's what I came up with:
$('.grow').each(function() {
var $el = $(this);
var max = parseInt($el.text().replace(/\s/g, ''));
var refresh = 5;
var start = 0;
var step = 1;
var interval = window.setInterval(function() {
start += step;
$el.text(start);
if(start >= max)
clearInterval(interval);
}, refresh);
});
My problem is I have numbers ranging from a few hundreds to several hundreds thousands. With this script, bigger number take more time to reach their value.
My goal is to make any number, regardless of its goal value, take the same amount of time to reach it. I sense that I should divide the number by the number of seconds I want the animation to run and then, set the result as the interval step?
I'm inquiring but still seeking for help :)
Thanks.
$('.grow').each(function() {
var $el = $(this);
var max = parseInt($el.text().replace(/\s/g, ''));
var duration = 1000; // shared duration of all elements' animation
var refresh = 5;
var frames = duration / refresh; // number of frames (steps)
var start = 0;
var step = Math.max(Math.round(max / frames), 1); // step should be >= 1
var interval = window.setInterval(function() {
if(start + step < max) {
start += step;
}
else {
start = max;
clearInterval(interval);
}
$el.text(start);
}, refresh);
});
This should work I suppose,
$('.grow').each(function() {
var $el = $(this);
var max = parseInt($el.text().replace(/\s/g, ''));
var start = 0;
var refresh = 5;
var totalSteps = 10;
var step = max/totalSteps;
function calculate(){
start += step;
$el.text(Math.round(start));
if(start < max){
setTimeout(function() {
calculate();
}, refresh);
}
}
calculate();
});
This will always finish in 100 steps. I.e. 100*refresh = 100*5 = 500 seconds.

Categories