I am trying to make a function that will only retain its variable count from the past minute.
For example, if I call function count 100 times, if 60 of those calls were from the past minute, it will only return 60, and not 100.
This is what I have tried so far, making the variable an array and adding numbers to it everytime its called, but I do not know how to remove a count when a minute has passed.
var count = 1;
var countArray = [];
UPDATE:
I have updated my code with this, but the array elements are not removing as they should,
function Count() {
var jNow = new Date();
jCountArray.push(jNow);
for (var i = 0; i <= jCountArray.length; i++) {
var secondsDiff = (new Date(jNow).getTime() - new Date(jCountArray[i]).getTime()) / 1000;
if (secondsDiff >= 10) { jCountArray.shift(); }
}
console.log(jCountArray);
return jCountArray.length;
}
If I understand your requirements correctly, and the only thing you need Count to do is return how many times it was called in the last minute, I think we could do something relatively easily leveraging setTimeout:
function getCounter() {
let count = 0;
let duration = 60000;
return function () {
count = count + 1;
setTimeout(function () {
count = count - 1;
}, duration);
return count;
}
}
let counter = getCounter();
function count() {
console.log(counter());
}
<button onclick="count()">Count</button>
The only trick here is, to keep the actual count private, we need a factory function to wrap it in a closure. If that's unimportant you can write it as a simple function and keep the count in the parent scope. Also, for testing purposes you can change the duration to a lower millisecond count to see it in action.
Related
I am attempting to write a dealer function for a card game, I want the function to keep its i value each time its called, so that that the card pile( player1Deck and player2Deck) gets smaller and smaller till empty. currently the i value looks like it will reset each time the function is called how can I stop this.
I am very new to all of this.
function dealOut(){
for (let i = 0; i < player1DeckHandcells.length; i++) {
const cell = player1DeckHandcells[i];
cell.appendChild(player1Deck.cards[i].getHTML)
}
for (let i = 0; i < player2DeckHandcells.length; i++) {
const cell = player2DeckHandcells[i];
cell.appendChild(player2Deck.cards[i].getHTML)
}
}
More information
Each dealout call should make i increase by 7. this means we are on the 8th "card"(player1Deck.cards[i].getHTML and player2Deck.cards[i].getHTML) in the "deck"( player1Deck and player2Deck)and there should be a total of 28 cards with 21 left to go. I want the i value to count through these "cards", so it doesn't just repeat the first 7 every time dealout is called.
You can use a closure (a function that keeps a copy of the outer variables). We can use that function for dealOut. Note: arrays are zero-indexed so i starts at 0 not 1.
function loop() {
// Maintain a count
let count = 0;
// Return a function that we actually use
// when we call dealOut. This carries a copy
// of count with it when it's returned that we
// can update
return function () {
const arr = [];
// Set i to count, and increase until
// i ia count + 7
for (let i = count; i < count + 7; i++) {
arr.push(i);
}
console.log(arr.join(' '));
// Finally increase count by 7
count += 7;
}
}
const dealOut = loop();
dealOut();
dealOut();
dealOut();
dealOut();
I have four different button effects where each effect are declared in a variable.
Therefore, I bring all of these four variables and place them within an array called arr in which is used in the clickByItself() function using Math.floor(Math.random()) methods.
Without the for loop, the code clicks by itself randomly in one of the four buttons every time I reload the page.
function clickByItself() {
let random = Math.floor(Math.random() * arr.length);
$(arr[random]).click();
}
However, using the for loop I am not being able to make these clicks one-by-one within the maximum of 10 times.
var blueButtonEffect = code effect here;
var redButtonEffect = code effect here;
var greenButtonEffect = code effect here;
var yellowButtonEffect = code effect here;
var arr = [blueButtonEffect, redButtonEffect, greenButtonEffect, yellowButtonEffect];
//will click on buttons randomly
function clickByItself() {
let random = Math.floor(Math.random() * arr.length)
var i;
for (i = 0; i < 10; i++) {
$(arr[random]).click();
setTimeout(clickByItself(), 1000);
}
}
The final output with the current code above is the four buttons being clicked at the same time, not one-by-one.
So, how can I have this function to press a random button by 10 times one-by-one with one second of interval from each click?
To fix your code you need:
A base case for your recursion
Pass a function reference to setTimeout. Currently, you are executing clickByItself and passing its return value (which is undefined) to setTimeout.
Do not use setTimeout in a loop without increasing the time by a factor of i, as the for loop will queue all the function calls at the same time
Alternatively, you can use a "times" argument to avoid looping
You could try something like
function clickByItself(times = 0) {
let random = Math.floor(Math.random() * arr.length)
$(arr[random]).click();
if (++times < 10) {
setTimeout(function(){clickByItself(times);}, 1000);
}
}
An example with console logs
https://jsfiddle.net/pfsrLwh3/
The problem is that the for loop calls the setTimeout 10 times very quickly. If you want to wait until the previous function call finishes prior to calling the next, then you should use recursion or just use a setInterval.
Recursion:
function clickByItself(numIterations) {
let random = Math.floor(Math.random() * arr.length)
let i;
$(arr[random]).click();
if( numIterations < 10 ){
setTimeout(() => {
clickByItself(numIterations += 1)
}, 1000)
}
}
clickByItself(0);
With setInterval
let numIterations = 0;
function clickByItself() {
let random = Math.floor(Math.random() * arr.length);
let i;
$(arr[random]).click();
numIterations += 1;
if( numIterations > 10) {
clearInterval(loop)
}
}
let loop = setInterval(test2, 1000);
Are you saying this is working for only 4 times but I think your above code will run in an infinite loop as you are calling clickByItself() again in the for loop.
If you want press a random button by 10 times one-by-one with one second of interval from each click then replace the for loop with
for (i = 0; i < 10; i++) {
setTimeout($(arr[random]).click(), 1000);
}
So I've got this counter and it needs to increment a number by 75 every 60 seconds. The code I have below does this fine but due to rounding some numbers stay up longer than others, and some numbers are skipped.
I'd rather have this to smoothly/evenly count to get the same end result. I know I would need to somehow calculate the setInterval timer number, but I'm not sure what to get that.
(function(){
//Numbers
var num = 0;
var perMinute = 75;
var perSecond = perMinute / 60;
//Element selection
var count = document.getElementById("count");
function update(){
//Add the per-second value to the total
num += perSecond;
//Display the count rounded without a decimal
count.innerHTML = Math.round(num);
}
//Run the update function once every second
setInterval(update, 1000);
})();
Working example: http://jsfiddle.net/ChrisMBarr/9atym/1/
Never rely on Timeout or Interval to be accurate. Instead, save the "start time" and compare it to the current time.
(function() {
var start = new Date().getTime(),
perMinute = 75,
perMS = perMinute/60000,
count = document.getElementById('count');
function update() {
var elapsed = new Date().getTime()-start;
count.innerHTML = Math.round(elapsed*perMS);
}
setInterval(update,1000);
})();
Note that you can adjust the 1000 to vary "smooth" the counter is (more important for bigger values of perMinute) and it will always work perfectly, to within the resolution's overshoot.
Moving your rounding seemed to fix this (Edit: No it doesn't. See the jsfiddle example of a better fix I put below).
(function(){
//Numbers
var num = 0;
var perMinute = 75;
var perSecond = perMinute / 60;
//Element selection
var count = document.getElementById("count");
function update(){
//Add the per-second value to the total
num += Math.round(perSecond);
//Display the count rounded without a decimal
count.innerHTML = num;
}
//Run the update function once every second
setInterval(update, 1000/perSecond);
})();
Edit: a proper fix - http://jsfiddle.net/4y2y9/1/
Trying to make a simple count up timer in jQuery... this sort of works but is adding the numbers to the end of '0000' and I want it to go '0001' '0002' '0003' etc...
This is all happening in the jQuery onReady scope.
var i = '0000'
var timer = function doSomething ( )
{
i = i+= 1
$('.counter').text(i);
console.log(i);
}
setInterval (timer, 1000 );
Your "i" variable needs to be an integer. You can format it how you like when you want to print it somewhere.
$(document).ready(function() {
var i = 0;
var target = $('.counter');
var timer = function doSomething ( )
{
i++;
var output = pad(i,4);
target.text(output);
console.log(output);
}
setInterval (timer, 1000 );
});
function pad(number, length) {
var str = '' + number;
while (str.length < length) {
str = '0' + str;
}
return str;
}
Your current code is appending to a string, not addition to a number. It essentially looks like
i = '0000' + 1, i = '00001' + 1, i = '000011' + 1 ...
and so on. You'll need to keep it integer based to continue adding to the number. Here's an example with the formatting it looks like you wanted.
var pad = function(n) { return (''+n).length<4?pad('0'+n):n; };
jQuery.fn.timer = function() {
var t = this, i = 0;
setInterval(function() {
t.text(pad(i++));
}, 1000);
};
$('#timer').timer();
http://jsfiddle.net/jDaTK/
I would do something more like this:
// Make sure Date.now exists in your environment
Date.now = Date.now || function () { return Number(new Date()); };
var time = 0,
start = Date.now(),
intervalId;
intervalId = setInterval(function () {
var seconds, display;
// get the exact time since the timer was started
time = Date.now() - start;
// get the number or seconds, rounded down
seconds = Math.floor(time / 1000);
display = '' + seconds;
// pad the beginning of your display string with zeros
while (display.length < 4) {
display = "0" + display;
}
console.log(display);
}, 100);
setInterval is not exact. This code ensures that while the display could be up to nearly a second off (in theory), the actual time you are tracking is always the exact amount of time that has elapsed since you started the timer. But this code would update the display about once every tenth of a second, so it's not likely to ever be off more than a few milliseconds.
From here you can figure out smarter ways to update the display to ensure you have the level of accuracy you need. If this needs to be pretty accurate, then you could make sure you are displaying to the tenth of the second.
I really recommend the jQuery CountUp plugin. I tried a number of Javascript counters and this was one of the easiest to implement and came with lots of goodies:
<script type="text/javascript">
$(document).ready(function(){
$('#counter').countUp({
'lang':'en', 'format':'full', 'sinceDate': '22/07/2008-00::00';
});
});
</script>
<div id="counter"></div>
for (var i=list.length; i>=0; i--){
//do something....
}
I want to use a setInterval to make this process take 1 whole min no matter how many items are in the list. So if there are 10 items it would trigger every 6sec, 30items, every two seconds, etc.
Thanks for any help!
Something like this could be done:
var list = [1,2,3,4,5,6,7,8,9,10];
var timeFrame = 60000;
var interval = timeFrame / (list.length-1);
var i = 0;
(function iterate () {
if (list.length > i) {
console.log(list[i]);
i++;
}
setTimeout(iterate, interval);
})();
JsFiddle Demo
I am not sure if this is what you're looking for, but this will "iterate" through all items in the list, without using for loop, in the given timeframe. The function will always "call itself" using setTimeout. The timeout is calculated in the beginning based on the number of items.
This solution is much more "trustable" than setInterval. The next timeout will be set when the previous action is already done, so it won't stack up.
var totalItem = list.length;
setInterval(function(){ alert('');}, 60000/totalItem);
You'd do
function code(i) {
return function() { alert(i); };
}
var period = 60 * 1000 / (list.length - 1);
for (var i=list.length; i>=1; i--){
setTimeout(code(list[i - 1]), period * (i - 1));
}
Try something like the following:
var interval = 2;
for (var i=list.length; i>=0; i--){
setTimeout(your_code_here(), i*interval);
}