Alright so my question today is bit of a weird one. Basically what I'm trying to do is take this image code
<img src="3d.php?a=-25&w=35&wt=-45&abg=0&abd=-30&ajg=-25&ajd=30&ratio=13&format=png&displayHairs=true&headOnly=false&login=">
and have it update only the w=35 part of it and have it add +1 to that number, either forever or until it hits 360 then resets it to 0, every x amount of seconds.
The point of this is to create what looks like a spinning image, instead of spawning each possible wt= from 0 to 360 by hand.
Try this:
<img id="threedee">
In your script, further down the page:
var w = 35;
var x = 5; // every 5 seconds
var threedee = document.getElementById("threedee");
setInterval(function () {
w = (w + 1) % 360;
var src = "3d.php?a=-25&w=" + w + "&wt=-45&abg=0&abd=-30&ajg=-25&";
src += "ajd=30&ratio=13&format=png&displayHairs=true&headOnly=false&login=";
threedee.src = src;
}, x * 1000);
You can try something like
var counter = 35;
var x = 5;
var url = '3d.php?a=-25&w={{counter}}&wt=-45&abg=0&abd=-30&ajg=-25&ajd=30&ratio=13&format=png&displayHairs=true&headOnly=false&login='
setInterval(function(){
img.src = url.replace('{{counter}}',counter);
counter = counter + 1 > 360 ? 0 : counter + 1;
},x * 1000);
Related
This script should scroll through each container on a website with a randomly generated delay.
I want to replace the "pause" of 2000ms with a randomly generated number between min and max seconds for each iteration in the loop.
var min = 3,
max = 9;
var y = document.querySelectorAll('.chunk-container').length;
for (let x=0; x<y; x++) {
task(x);
}
function task(x) {
// var z = randomGen() * 1000;
setTimeout(function() {
console.log('X = ' + x + ' Y = ' + y);
document.getElementsByClassName('chunk chunk-container')[x].scrollIntoView({behavior: 'smooth'});
console.log('Scrolled to next Container');
}, /* z */ 2000 * x);
}
})
Random number generator:
function randomGen() {
var rand = Math.floor(Math.random() * (max - min + 1) + min);
console.log('Random Number generated: ' + rand + ' seconds');
return rand;
}
Like this it works fine. After each iteration, there is a 2 second pause. However when I remove the comments to add the lines var z = randomGen() * 1000; to randomize the time between each iteration, the x value (at which container it should scroll to) starts off fine, but then turns out random as well.
The console output:
Random Number generated: 6 seconds
Random Number generated: 5 seconds
Random Number generated: 4 seconds
Random Number generated: 8 seconds
Random Number generated: 4 seconds
Random Number generated: 8 seconds
X = 0 Y = 7
Scrolled to next Container
X = 1 Y = 7
Scrolled to next Container
X = 2 Y = 7
Scrolled to next Container
X = 4 Y = 7
Scrolled to next Container
X = 3 Y = 7
Scrolled to next Container
X = 5 Y = 7
Scrolled to next Container
X = 6 Y = 7
Scrolled to next Container
How can I fix this?
I rewrote you code.
I think the main problem was that setTimeout is non blocking.
I used promise together with await to solve it
function sleep(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
function randomGen(max, min) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
async function randomWaitAndScroll(elements, timeMin, timeMax) {
for (element of elements) {
let random = randomGen(timeMin, timeMax)
await sleep(random);
element.scrollIntoView({behavior: 'smooth'});
}
}
const containerElements = document.querySelectorAll('.chunk-container');
randomWaitAndScroll(containerElements, 3000, 9000);
The problem is that 2000 * x works because the delay between each scroll is constant, so your timeouts trigger at:
x = 0 -> 0ms
x = 1 -> 2000ms
x = 2 -> 4000ms
So you launch all of the timeouts at once at the start and they end up triggering every 2 seconds, but each timeout's value is different. Each implicitly depends on the fact that all timeouts before have been triggering every 2 seconds.
One approach would be to use an asynchronous function that returns a promise and await for it before scrolling to the next element as Josh points out
An alternative would be to keep track of the previous timeouts values and add them up, to compute the next timeout's value. Like this:
var min = 3,
max = 9;
var y = document.querySelectorAll('.chunk-container').length;
for (let x=0, accumulatedDelay = 0; x<y; x++) {
accumulatedDelay += task(x, accumulatedDelay);
}
function task(x, accumulatedDelay) {
const z = randomGen() * 1000;
setTimeout(function() {
console.log('X = ' + x + ' Y = ' + y);
document.getElementsByClassName('chunk chunk-container')[x].scrollIntoView({behavior: 'smooth'});
console.log('Scrolled to next Container');
}, z + accumulatedDelay);
return accumulatedDelay;
}
It's kind of math problem. I want to fire specific number of setTimeout (the number is based on an array length) in a specific period of time (say, 5 seconds).
The first setTimeout should start at 0 sec. and the last at 5 sec.. All timeouts between should start with an ease-in effect, so that each timeout starts faster.
There's an example which ilustrates what I want to achieve exactly.
I'm struggling around this line:
next += timePeriod/3.52/(i+1);
which works almost perfect in demo example (for any timePeriod), but obviously it doesn't work for a different letters.length as I have used static number 3.52.
How do I calculate next?
var letters = [
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T'
];
var div = $('#container');
var timePeriod = 5000; // 5 seconds;
var perLetter = timePeriod/(letters.length-1); // it gives equal time between letters
var next = 0;
for(var i=0; i<letters.length; i++){
setTimeout(function(letter){
//div.append('<span class="letter">' + letter + '</span>');
// Used "|" instead of letter, For better redability:
div.append('<span class="letter">|</span>');
}, next, letters[i]);
// Can't find the logic here:
next += timePeriod/3.52/(i+1);
};
///////////////// FOR DEMO: ///////////////
var sec = timePeriod/1000;
var secondsInterval = setInterval(seconds, 1000);
var demoInterval = setInterval(function(){
sec >= 0 || clearInterval(demoInterval);
div.append('\'');
}, 30);
function seconds(){
sec || clearInterval(secondsInterval);
$('#sec').text(sec-- || 'DONE');
}
seconds();
.letter{
color : red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id=container></span>
<span id=sec class=letter></span>
var steps = letters.length;
var target = timePeriod;
function easeOutQuad(t, b, c, d) {
t /= d;
return -c * t*(t-2) + b;
};
var arrayOfTimeouts = new Array(steps);
var n;
var prev = 0;
for(var i = 1; i <= steps; i++){
n = easeOutQuad(i, 0.0, target, steps);
arrayOfTimeouts[i-1] = n-prev;
prev = n;
}
This one should work with any input value.
fiddle
Note that the graph appears to be slightly too fast but I believe that discrepancy to be a product of timing imperfections, as the sum of my array equals the timePeriod exactly.
more on easing equations
Here's a solution based on a geometric series. It's a bit goofy but it works. It generates an array with your timeout values.
Steps = size of your array.
Target = the total time.
var steps = 50;
var target = 5000;
var fraction = 1.5 + steps / 7;
var ratio = (fraction-1) / fraction;
var n = target / fraction;
var sum = 0;
var arrayOfTimeouts = new Array(steps);
for(var i = 0; i < steps; i++){
sum += n;
arrayOfTimeouts[i] = n;
n *= ratio;
}
console.log(arrayOfTimeouts, sum);
I am trying to increment from 0 to a number (can be any number from 2000 to 12345600000) within a certain duration (1000 ms, 5000 ms, etc). I have created the following:
http://jsfiddle.net/fmpeyton/c9u2sky8/
var counterElement = $(".lg-number");
var counterTotal = parseInt(counterElement.text()/*.replace(/,/g, "")*/);
var duration = 1000;
var animationInterval = duration/counterTotal;
counterElement.text("0");
var numberIncrementer = setInterval(function(){
var currentCounterNumber = parseInt(counterElement.text()/*.replace(/,/g, "")*/);
if (currentCounterNumber < counterTotal){
currentCounterNumber += Math.ceil(counterTotal/duration);
// convert number back to comma format
// currentCounterNumber = addCommas(currentCounterNumber);
counterElement.text(currentCounterNumber);
} else {
counterElement.text(counterTotal);
clearInterval(numberIncrementer);
}
console.log("run incrementer");
}, animationInterval);
function addCommas(number){
for (var i = number.length - 3; i > 0; i -= 3)
number = number.slice(0, i) + ',' + number.slice(i);
return number;
}
And this somewhat works, but it does not respect the duration. I.e. if you increase the number from 1000 to 1000000000, they both take different amounts of time to reach the destination number.
How can I increment from zero to a number in a specific time frame?
As #Mouser pointed out, the issue is that the animationInterval can't be too small (the actual minimum threshold will vary based on the browser and platform). Instead of varying the interval, vary the increment to the counter:
var counterElement = $(".lg-number");
var counterTotal = parseInt(counterElement.text()/*.replace(/,/g, "")*/);
var duration = 1000;
var animationInterval = 10;
var startTime = Date.now();
counterElement.text("0");
var numberIncrementer = setInterval(function(){
var elapsed = Date.now() - startTime;
var currentCounterNumber = Math.ceil(elapsed / duration * counterTotal);
if (currentCounterNumber < counterTotal){
counterElement.text(currentCounterNumber);
} else {
counterElement.text(counterTotal);
clearInterval(numberIncrementer);
}
console.log("run incrementer");
}, animationInterval);
I played around with your fiddle and found that the delay needs to be higher. At 8ms or 16ms, it is accurate enough to handle a second, but not accurate enough to handle half a second. From experimenting, it seems like a delay of 64ms is small enough to seem like it's incrementing smoothly, but big enough to have an accurate effect.
The difference is that the current number is calculated based on the process rather than directly manipulated.
var counterElement = $(".lg-number");
var counterTotal = parseInt(counterElement.data('total'));
var interval = 0;
var duration = parseInt(counterElement.data('duration'));;
var delay = 64
var numberIncrementer = setInterval(function(){
var currentCounterNumber = 0;
interval += delay;
if (interval <= duration){
var progress = interval / duration;
currentCounterNumber = Math.round(progress * counterTotal);
} else {
currentCounterNumber = counterTotal
clearInterval(numberIncrementer);
}
counterElement.text(currentCounterNumber);
}, delay);
http://jsfiddle.net/c9u2sky8/5/
Also: Javascript timers are not perfectly accurate. But this should be accurate enough for UI use cases.
I'm looking for a way to move a div from an array of position with javascript/jquery.
I have trying to do it with jquery.animate but he moved the div with a pause at each iteration of my array.
That could be something like move the div from 0,0 to 120px,230px passing by the 23px,35px;45px,50px etc...
That is for moving an game character on a Tile map
So as requested, some bit of code
First you have a global timer that call a function at short interval to see if it have any action to execute.
In this loop a routine look if some mobile tiles are waiting of any mouvement.
Mobiles are declared as Object class and have a sub function that do the deplacement like that
setPos:function(coord){
var pos = jQuery("#"+this.id).position();
var x = (coord[0] - 32 + this.screenOffX + this.xOffset) - pos.left;
var y =(coord[1] + this.yOffset) - pos.top;
//this.stopAnimation();
//this.startAnimation(this.walkingAnimation);
jQuery("#"+this.id).animate({
left: '+='+ x,
top: '+='+ y
}, 33, function() {
// Animation complete.
});
},
That is a bit messy cause i trying a lot of thing to do the smooth movement that i'm looking for.
so setPos is calling in another place like that
stepMobile:function(mobile){
var wp;/*TEST*/
mobile.changeState("idle");
var ind = mobile.getWayPointIndex();
while(ind < (mobile.getWayPoints()).length - 1){
if (ind < (mobile.getWayPoints()).length - 1) {
wp = (mobile.getWayPoints())[ind + 1];
if (getTime() > wp.time) {
mobile.setWayPointIndex(ind + 1);
ind = ind +1;
}
}
wp = (mobile.getWayPoints())[ind];
var x;
var y = 0;
var z;
x = this.tileWidth * (wp.getTile()).getCol();
z = this.tileHeight * (wp.getTile()).getRow();
var elapsed = getTime() - wp.getTime();
console.log(elapsed);
if (ind == (mobile.getWayPoints()).length - 1) {
console.log('checkForOnStopEvent()');
} else {
//x += 1 * mobile.getWalkSpeed() * mobile.getCosAngle();
//z += 1 * mobile.getWalkSpeed() * mobile.getSinAngle();
}
var coord = this.mapToScreen(x, y, -z);
mobile.setPos(coord);
ind = mobile.getWayPointIndex();
}
},
Again lot of junk code here cause i literally burned my brain but i didn't get any good result.
And you have that global function that run this function over all mobiles waiting for deplacement.
My aim is to create identify a piece of code that increments a number by 1, every 1 second:
We shall call our base number indexVariable, I then want to: indexVariable = indexVariable + 1 every 1 second; until my indexVariable has reached 360 - then I wish it to reset to 1 and carry out the loop again.
How would this be possible in Javascript? - if it makes a difference I am using the Raphael framework.
I have carried out research of JavaScript timing events and the Raphael delay function - but these do not seem to be the answer - can anyone assist?
You can use setInterval() for that reason.
var i = 1;
var interval = setInterval( increment, 1000);
function increment(){
i = i % 360 + 1;
}
edit: the code for your your followup-question:
var interval = setInterval( rotate, 1000);
function rotate(){
percentArrow.rotate(1,150,150);
}
I'm not entirely sure, how your rotate works, but you may have to store the degrees in a var and increment those var too like in the example above.
var indexVariable = 0;
setInterval(function () {
indexVariable = ++indexVariable % 360 + 1; // SET { 1-360 }
}, 1000);
Try:
var indexVariable = 0;
setInterval(
function () {
indexVariable = (indexVariable + 1) % 361;
}, 1000}