This question already has answers here:
Changing the interval of SetInterval while it's running
(17 answers)
Closed 5 years ago.
I can't seem to figure out why the farmerTime is not updating when you level up. There is a button that just adds a level to farmingLevel.
window.setInterval(function() {
farmerTime = 2500;
farmerLevel = 3;
x = farmerTime;
y = farmerLevel;
z = x / y;
farmerTime = z;
if (farmers >= 1) {
a = farmers;
b = potatoes;
c = a * 1;
d = b + c;
potatoes = d;
}
}, farmerTime);`
You need to define farmerTime before you use it. In your case, before the setInterval function. Also, if you want to change the farmerLevel you need to change it somewhere else, not in the setinterval function.
Changing level example:
<button type="button" onclick="setFarmerLevel(farmerLevel + 1);">Change level </button>
And the code for the interval thing:
var farmerTime = 2500;
var farmerLevel = 1;
var setFarmerLevel = function (level) {
farmerLevel = !level ? 1 : level;
farmerTime = farmerTime / farmerLevel;
clearInterval(farmerInterval);
farmerInterval = window.setInterval(run, farmerTime);
};
var run = function () {
if (farmers >= 1) {
a = farmers;
b = potatoes;
c = a * 1;
d = b + c;
potatoes = d;
}
};
var farmerInterval = window.setInterval(run, farmerTime);
UPDATE
I forgot setInterval's function time cannot be change in runtime, so the code is updated now.
Related
I am working on a specific calculator and I need to sum up variables in my jQuery.each for a range from 0 to 4 (= 5 years).
I have found many pages where the solution is described, but only with references to an element, not to the range.
My code:
jQuery.each(new Array(duration),
function(n){
var investment = 1000; // 1000$
var duration = 5; // 5 years
var revenueRatio = 10; // 10% revenue / year
var reinvest = 50; // 50% reinvestment
if(n == 0){
var revenueReinvest = 0;
var newInvestment = investment;
}else{
console.log(revenueReinvest); // undefined
console.log(newInvestment); // undefined
var interest = ( ( newInvestment - investment ) * ( revenueRatio / 100 ) );
var removeInterest = interest * reinvest / 100;
var restIntereset = interest - removeInterest;
revenueReinvest += restIntereset;
newInvestment = newInvestment + revenueReinvest;
}
}
);
Any help or idea would be great! Thank you!
The issue with the code is that you have declared revenueReinvest and newInvestment inside the if block and using it inside the else block. This wont be possible. Declare revenueReinvest and newInvestment outside each loop and assign the values to them inside if statement. Now you can access the assigned values inside else statement.
You have to declare the variable outside the loop to prevent redeclaring of the variable inside the loop. Each time the variable gets redeclared inside the loop, old value will be lost.
The below code will work
$(document).ready(function () {
const duration = 4;
// Declare here
var revenueReinvest;
var newInvestment;
jQuery.each(new Array(duration),
function (n) {
var investment = 1000; // 1000$
var duration = 5; // 5 years
var revenueRatio = 10; // 10% revenue / year
var reinvest = 50; // 50% reinvestment
if (n == 0) {
// assign value here
revenueReinvest = 0;
newInvestment = investment;
} else {
var interest = ((newInvestment - investment) * (revenueRatio / 100));
var removeInterest = interest * reinvest / 100;
var restIntereset = interest - removeInterest;
revenueReinvest += restIntereset;
newInvestment = newInvestment + revenueReinvest;
}
}
);
console.log(revenueReinvest); // will be defined
console.log(newInvestment); // will be defined
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
So right now, I'm trying to implement a search bar function into my d3.js plot. Right now it doesn't do anything, but that's not the issue at the moment. The problem is that when I type/delete something from the bar, there's visible lag/choppiness in the characters appearing/disappearing. I believe the issue is stemming from my plot. I have 140+ dots moving around the screen, and their position is being interpolated. So from the beginning to the end of the transition, my code has to compute 140 positions thousands of times over.
I've looked into trying to reduce the cardinality of the d3.interpolateNumber function, but it appears that there isn't a third argument to change the number of terms like in a linspace command. Right now I have an array of 1000 numbers for my function to run through, but I don't know how to pass the array to my other functions.
Below are the pertinent functions for this issue. The commented line in tweenPatch is the original code I had that made my code run, but gave my plot computational issues. Variables arr, curr, and step were my attempt to fix the situation, but I haven't been able to figure out how to pass the array into displayPatch().
function tweenPatch() {
var patch = d3.interpolateNumber(1, 26);
var arr = [];
var curr = 1;
var step = (26 - 1) / (1000 - 1);
for (var i = 0; i < 1000; i++) {
arr.push(curr + (step * i));
}
return arr.forEach(function(d) {
console.log(arr[d]);
displayPatch(arr[d]);
});
//return function(t) { displayPatch(t); };
}
function displayPatch(patch) {
dots.data(interpolateData(patch), function(d) { return d.name; }).call(position).sort(order);
var inter = Math.floor(patch);
var seas = 8;
var patc = 1;
if (inter > 24) {
seas = 9;
patc = inter - 24;
} else {
patc = inter;
}
label.text("Patch " + seas + "." + patc);
}
function interpolateValues(values, number) {
old = Math.floor(number);
upd = Math.ceil(number);
var old_data = values.filter(function(d) {return d.internal == old;});
var new_data = values.filter(function(d) {return d.internal == upd;});
var oobj = old_data[0];
var nobj = new_data[0];
var onum = oobj[Object.keys(oobj)[4]];
var nnum = nobj[Object.keys(nobj)[4]];
var difint = number - old;
var difdis = 0;
var newnum = nnum;
if (nnum > onum) {
difdis = nnum - onum;
newnum = ((difint) * difdis) + onum;
} else if (onum > nnum) {
difdis = onum - nnum;
newnum = onum - ((difint) * difdis);
}
return newnum;
}
I believe switching my SVG to a canvas may help things, but since I have no knowledge of canvas I'd rather leave that as a last resort.
I have this earning calculator function
EarningsCalculator.prototype.computeEarning = function (rate, investedValue) {
var earnings = {};
var currentState = investedValue;
for (var i = 0; i <= 5; i++) {
earning=currentState*rate;
currentState = currentState + earning;
earnings[i] = currentState;
}
return earnings;
}
It takes an "invested value" and based on a give rate, it calculates earning, which in this case is limited to 5 years with a for loop. What I need is to calculate earnings[0] at 1 year interval and earnings[1] through earnings[4] at a 5 year interval.
So with Invested value of 1000 and interest rate of 10%, it returns the following output for 5 years
Year1 = 1100
Year2 = 1210
Year3 = 1331
Year4 = 1464.1
Year5 = 1610.51
What I want is this
Year1 = 1100
Year5 = 1610.51
Year10 = 2593.74246
Year15 = 4177.248169
Year20 = 6727.499949
You could use the formular for calculation the earnings.
function getPeriodicCompounding(p, r, t) {
return Math.pow(r + 1, t) * p;
}
var originalPrincipalSum = 1000,
interestRate = 0.1,
times = [1, 5, 10, 15, 20]
times.forEach(function (time) {
console.log(time, getPeriodicCompounding(originalPrincipalSum, interestRate, time));
});
You could use a modulus on the years in your for loop to add only those years that are divisible by 5. Then add another or condition for the first year:
function EarningsCalculator (rate, investedValue) {
var earnings = {};
var currentState = investedValue;
var YEAR_INTERVAL = 5;
var YEARS_COMPOUNDING = 20;
for (var i = 1; i <= YEARS_COMPOUNDING; i++) {
earning=currentState*rate;
currentState = currentState + earning;
if (i % YEAR_INTERVAL == 0 || i == 1) {
earnings[i] = currentState;
}
}
return earnings;
}
var earnings = [];
earnings = EarningsCalculator(.10,1000);
console.log(earnings);
That should log the correct values to your object in the console.
One advantage of this is being able to change your yearly interval as a variable rather than hardcoding those values in an array for different periods of time.
JSFiddle: https://jsfiddle.net/kgill/zgmrtmhg/1/
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);
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
I'm trying to make a hover for every tile, but when I use tileArray[i].x it uses the last tiles position. And I'm trying to get the position of the tile I'm hovering.
Here is the code I've made.
for (x = 0; x < mapxtiles; x++) {
for (y = 0; y < mapytiles; y++) {
if(map[x][y].height != 'x') {
i++;
var topPos = (x * 16) + (y * 16) - 24;
var leftPos = (y * 32) - (x * 32) + (mapxtiles * 32) - 32;
var normalTileTexture = PIXI.Texture.fromImage("./assets/map/normal.png");
var tileHoverTexture = PIXI.Texture.fromImage("./assets/map/hoverTexture.png");
tileArray[i] = new PIXI.Sprite(normalTileTexture);
tileArray[i].setInteractive(true);
var tileHover = new PIXI.Sprite(tileHoverTexture);
tileArray[i].mouseover = function(mouseData) {
tileHover.position = new PIXI.Point(tileArray[i].x - 2, tileArray[i].y + 22);
floorMap.addChild(tileHover);
};
tileArray[i].position = new PIXI.Point(leftPos, topPos);
floorMap.addChild(tileArray[i]);
}
}
}
i is a counter which has reached a certain value at the end of your loop. if you hover your tile, it will always have the last value. a workaround for that, is to wrap your code in a closure:
(function (a) {
tileArray[a].mouseover = function(mouseData) {
tileHover.position = new PIXI.Point(tileArray[a].x - 2, tileArray[a].y + 22);
floorMap.addChild(tileHover);
};
})(i);
what i do here:
i wrap your event-handler in an iife with i as parameter and recieve it as a inside the closure. this is for illustration purposes, you could of course leave the inner var by the name of i
it is also a little bit more readable, to just move it into a function which is declared outside of your loop:
function helperfunction (tileArrayElement, tileHover, floorMap) {
tileArrayElement.mouseover = function(mouseData) {
tileHover.position = new PIXI.Point(tileArrayElement.x - 2, tileArrayElement.y + 22);
floorMap.addChild(tileHover);
};
}
and call it in your loop:
for (x = 0; x < mapxtiles; x++) {
for (y = 0; y < mapytiles; y++) {
if(map[x][y].height != 'x') {
// your other code...
helperfunction(tileArray[i], tileHover, floorMap);
// your other code...
}
}
}