Spin counter to a number containing two digits - javascript

I've used the jQuery animate function to help with a spin to number counter. The following codepen demos this.
Here is the function:
function statsSpin(IDofObject, stat, duration) {
$({countNum: $(IDofObject).text()}).animate({countNum: stat}, {
duration: duration,
easing:'linear',
step: function() {
$(IDofObject).text(Math.floor(this.countNum));
},
complete: function() {
$(IDofObject).text(this.countNum);
}
});
};
As it stands it spins from a single decimal place e.g. 0 to 14 on day, month and year. How can I modify so that is spins from 00-00-00 to 08-09-14?

All you need to do is pad your numbers with a 0 if the value is less than 10. Since you need to do this twice I just created a simple utiltity function for it
function statsSpin(IDofObject, stat, duration) {
$({countNum: $(IDofObject).text()}).animate({countNum: stat}, {
duration: duration,
easing:'linear',
step: function() {
var num = padNumber(Math.floor(this.countNum));
$(IDofObject).text(num);
},
complete: function() {
$(IDofObject).text(padNumber(this.countNum));
}
});
};
function padNumber( num){
return num < 10 ? '0'+num : num;
}
DEMO

You can make use of the slice() function to add leading 0's to digits. If you change your step and complete functions to the following it should work:
function statsSpin(IDofObject, stat, duration) {
$({
countNum: $(IDofObject).text()
}).animate({
countNum: stat
}, {
duration: duration,
easing: 'linear',
step: function () {
var num = ("0" + Math.floor(this.countNum)).slice(-2);
$(IDofObject).text(num);
},
complete: function () {
var num = ("0" + this.countNum).slice(-2);
$(IDofObject).text(num);
}
});
};
See this FIDDLE for an example. We add a leading 0 to the number and take the last two characters of the resulting string.

Related

Recursive Function Uncaught RangeError: Maximum call stack size exceeded

This function which will execute when you enter on input field then it will calculate how much money do you have to return with x type to customer.
But getting stack size error sometime for 6 digit and everytime for 7 digit.
Reproduce: put 1234567 in input box and check the console.
Function:
let returnList = [];
let predictorList = [
100, 50, 20, 10, 5, 1, 0.5, 0.25, 0.1, 0.05, 0.01,
];
let total = 11.23
function isRemainingMoney(value) {
let remainingValue = value;
// when remaning value becomes zero then return the returnlist
if (remainingValue == 0) {
return returnList;
}
for (let pRed of predictorList) {
/* remainingValue is greater than predictor value then push it
eg: 41.33 > 20
21.33 > 20
1.33 > 1
0.33 > 0.25
0.08 > 0.05
0.03 > 0.01 * 3 times
*/
if (remainingValue >= pRed) {
const isPredExist = returnList.find(
(pItem) => +pItem.money == +pRed
);
if (!!isPredExist) {
isPredExist.count += 1;
isPredExist.total = isPredExist.total + +pRed;
} else {
returnList.push({
type: pRed,
money: pRed,
count: 1,
total: pRed,
});
}
remainingValue = +remainingValue.toFixed(2) - pRed;
break;
}
}
// recursive call the same method untill remainivalue becomes zero.
return isRemainingMoney(+remainingValue.toFixed(2));
}
document.querySelector('input').addEventListener('change', (event) => {
if(!!event.target.value) {
returnList.length = 0;
returnList = isRemainingMoney(+event.target.value - total);
console.log(returnList, 'returnList');
}
})
Playground: https://jsbin.com/kuwomalare/edit?html,js,console,output
Current Output From real application:
You end up having way too many recursive calls when the input value is large. It should be fairly straight forward to convert from recursive to iterative using a while loop. The only issue I ran into was floating point not getting down to 0 (like mentioned in the comment by #Keith). When doing money calculations, it is usually best to use integers. Use the smallest denomination in the currency. For example, in US currency, that would be cents. Only convert to decimal (or dollars in this case) when displaying the values.
I have also simplified your calculations a bit. Because of these changes, you could actually use recursion now, if you want since the maximum level of recursion now is predictorList.length.
let predictorList = [
10000, 5000, 2000, 1000, 500, 100, 50, 25, 10, 5, 1
];
let total = 709;
function isRemainingMoney(value) {
let returnList = [];
// when remaning value becomes zero then return the returnlist
while (value != 0) {
for (let pRed of predictorList) {
if (value >= pRed) {
returnList.push({
money: pRed / 100,
count: Math.floor(value / pRed),
});
value %= pRed;
}
}
}
return returnList;
}
document.querySelector('input').addEventListener('change', (event) => {
if (!!event.target.value) {
let returnList = isRemainingMoney(+event.target.value * 100 - total);
console.log(returnList, 'returnList');
}
})
<input type="number">

jQuery count to number with duration between digits

What I am looking to do is have a number start counting either up or down, lets say from 1 to a 100 or a 100 to 1. I have found many many plugins that do this but they all have a duration variable. The problem is that duration variable applies to how long it takes to get from start to finish. I am looking for a way to set how long it takes to get to the next digit. IE counting from X to Y and updating the number every .25 seconds. This way a larger number would take longer to get to than a smaller number.
This plugin looks great but I can't get it to do what I want.
https://github.com/mhuggins/jquery-countTo
Any help would be great.
Please try this and let me know if that's what you want:
function countTo(min, max, interval, callback) {
var counter = min;
var i = setInterval(function() {
callback(counter);
counter++;
if(counter> max) return clearInterval(i);
}, interval*1000);
};
countTo(0, 100, 0.25, function(counter) {
$("#counter").text(counter);
});
countTo(0, 100, 0.01, function(counter) {
$("#counter2").text(counter);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="counter"> </div>
<div id="counter2"> </div>
You can try something like this
function count(target, start, end, step, timeInterval) {
var timer = setInterval(function() {
if (start == end) {
clearInterval(timer);
return false;
}
start += step;
target.html(start);
}, timeInterval);
}
count($('#timer1'), 1, 100, 1, 50);
count($('#timer2'), 100, 1, -1, 50);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="timer1"></div>
<div id="timer2"></div>

Counter with thousands separator

So I have used this counter to count to a specific number :
(function($) {
$.fn.countTo = function(options) {
// merge the default plugin settings with the custom options
options = $.extend({}, $.fn.countTo.defaults, options || {});
// how many times to update the value, and how much to increment the value on each update
var loops = Math.ceil(options.speed / options.refreshInterval),
increment = (options.to - options.from) / loops;
return $(this).each(function() {
var _this = this,
loopCount = 0,
value = options.from,
interval = setInterval(updateTimer, options.refreshInterval);
function updateTimer() {
value += increment;
loopCount++;
$(_this).html(value.toFixed(options.decimals));
if (typeof(options.onUpdate) == 'function') {
options.onUpdate.call(_this, value);
}
if (loopCount >= loops) {
clearInterval(interval);
value = options.to;
if (typeof(options.onComplete) == 'function') {
options.onComplete.call(_this, value);
}
}
}
});
};
$.fn.countTo.defaults = {
from: 0, // the number the element should start at
to: 100, // the number the element should end at
speed: 1000, // how long it should take to count between the target numbers
refreshInterval: 100, // how often the element should be updated
decimals: 0, // the number of decimal places to show
onUpdate: null, // callback method for every time the element is updated,
onComplete: null, // callback method for when the element finishes updating
};
})(jQuery);
jQuery(function($) {
$('.timer').countTo({
from: 50,
to: 2500,
speed: 5000,
refreshInterval: 50,
onComplete: function(value) {
console.debug(this);
}
});
});
http://jsfiddle.net/YWn9t/
But unfortunately there are no separators (dots) between every third numbers.
To sum up: How to make the output of the script from e.g. 1000000 to 1.000.000?
I recommend using numberFormatter.
console.log(new Intl.NumberFormat().format(123456));

How to set a duration per slide in a jquery slideshow?

I am making a slideshow. This slides are all div's with content inside of them. Right now i have a function which adds a class to the next item in a container. I call that function with: setInterval("slideSwitch()", 10000) It works but all the slides have the same duration. What i want is that for example one slides shows 10 seconds and the following shows 15 seconds. Is there any way to set a duration per slide? Or should i use a javascript/jquery plugin?
The best approach to accomplishing a sliding timer is to use a recursive function call that sets a timeout and calls the same action. I have created a fiddle, but I will post the code here for clarity. You can go in and play with the code to see how it works. Here's the link to the fiddle.
function slideshow(action, time, index, max) {
setTimeout(function() {
action.call(this, index, max);
if (index === 0) {
slideshow(action, slideshow.duration.min, index + 1, max);
} else if (index < max) {
slideshow(action, slideshow.duration.max, index + 1, max);
} else {
slideshow(action, slideshow.duration.max, 0, max);
}
}, time);
}
slideshow.duration = {
min: 1000,
max: 2000
};
slideshow.slideSpeed = 'fast';
$(function() {
var slides = $('.slides .square');
slideshow(function(idx, max) {
switch (idx) {
case 0:
slides.eq(max).fadeOut(slideshow.slideSpeed, function() {
slides.eq(idx).fadeIn(slideshow.slideSpeed);
});
break;
case 1:
slides.eq(idx - 1).fadeOut(slideshow.slideSpeed, function() {
slides.eq(idx).fadeIn(slideshow.slideSpeed);
});
break;
case 2:
slides.eq(idx - 1).fadeOut(slideshow.slideSpeed, function() {
slides.eq(idx).fadeIn(slideshow.slideSpeed);
});
break;
case 3:
slides.eq(idx - 1).fadeOut(slideshow.slideSpeed, function() {
slides.eq(idx).fadeIn(slideshow.slideSpeed);
});
break;
}
}, slideshow.duration.min, 0, 3);
});
Let me know if you need further assistance with this.

Implementing jQuery's shake effect with animate

I've been given a cut down subset of the jQuery lib one of the key features I'm missing is the .effect functions. I do however have .animate. I was wondering if anyone would have any ideas how I could go about reproducing the animation functions.
I am particularly consious of making this only a few lines as I need to keep the code size down. Which is why the jquery lib is as small as it is and doesnt have the effects functions.
TLDR - I'm trying to replace
$("#"+id_string).effect( "shake", {}, "fast" );
With something using .animate within jQuery.
So far I have something like this ..
jQuery.fn.shake = function(intShakes, intDistance, intDuration) {
this.each(function() {
$(this).css("position","relative");
for (var x=1; x<=intShakes; x++) {
$(this).animate({left:(intDistance*-1)}, (((intDuration/intShakes)/4)))
.animate({left:intDistance}, ((intDuration/intShakes)/2))
.animate({left:0}, (((intDuration/intShakes)/4)));
}
});
return this;
};
I like #phpslightly solution so much, I keep using it. So here it is updated to basic jquery plugin form which will return your element
jQuery.fn.shake = function(interval,distance,times){
interval = typeof interval == "undefined" ? 100 : interval;
distance = typeof distance == "undefined" ? 10 : distance;
times = typeof times == "undefined" ? 3 : times;
var jTarget = $(this);
jTarget.css('position','relative');
for(var iter=0;iter<(times+1);iter++){
jTarget.animate({ left: ((iter%2==0 ? distance : distance*-1))}, interval);
}
return jTarget.animate({ left: 0},interval);
}
You would then use it like a regular plugin:
$("#your-element").shake(100,10,3);
Or use the default values (100, 10, 3):
$("#your-element").shake();
It's actually already implemented this way under the covers, you can see exactly how in jquery.effects.shake.js, if you wanted to copy only that functionality you can.
Another approach to think about: if you're using multiple effects, I'd recommend downloading jQuery UI with only the effects you want. For this effect, without copying the functionality yourself, you would just need jquery.effects.core.js and jquery.effects.shake.js.
This is probably irrelevant now but I've ported jQ UI's shake effect as a standalone jQuery plugin. All you need is jQuery and it will work exactly like the one provided in jQ UI.
For those who want to use the effect without actually bloating their project with unnecessary jQ UI core files.
$('#element').shake({...});
It can be found here with instruction: https://github.com/ninty9notout/jquery-shake
Thought I'd leave this here for future reference.
This is a more clean and smooth way to do the animation.
jQuery.fn.shake = function(shakes, distance, duration) {
if(shakes > 0) {
this.each(function() {
var $el = $(this);
var left = $el.css('left');
$el.animate({left: "-=" + distance}, duration, function(){
$el.animate({left: "+=" + distance * 2}, duration, function() {
$el.animate({left: left}, duration, function() {
$el.shake(shakes-1, distance, duration); });});
});
});
}
return this;
};
I don't understand all the complexity being thrown into reproducing the shake effect with solely animate. Here's my solution in just a couple lines.
function shake(div,interval=100,distance=10,times=4){
$(div).css('position','relative');
for(var iter=0;iter<(times+1);iter++){
$(div).animate({ left: ((iter%2==0 ? distance : distance*-1))}, interval);
}//for
$(div).animate({ left: 0},interval);
}//shake
EDIT: Updated code to return element to original position. Still believe this is the lightest and best solution to the problem.
I wrote some time ago a few simple jquery animations:
https://github.com/yckart/jquery-custom-animations
/**
* #param {number} times - The number of shakes
* #param {number} duration - The speed amount
* #param {string} easing - The easing method
* #param {function} complete - A callback function
*/
jQuery.fn.shake =
jQuery.fn.wiggle = function (times, duration, easing, complete) {
var self = this;
if (times > 0) {
this.animate({
marginLeft: times-- % 2 === 0 ? -15 : 15
}, duration, easing, function () {
self.wiggle(times, duration, easing, complete);
});
} else {
this.animate({
marginLeft: 0
}, duration, easing, function () {
if (jQuery.isFunction(complete)) {
complete();
}
});
}
return this;
};
This is not perfect, but functional
// Example: $('#<% =ButtonTest.ClientID %>').myshake(3, 120, 3, false);
jQuery.fn.myshake = function (steps, duration, amount, vertical) {
var s = steps || 3;
var d = duration || 120;
var a = amount || 3;
var v = vertical || false;
this.css('position', 'relative');
var cur = parseInt(this.css(v ? "top" : "left"), 10);
if (isNaN(cur))
cur = 0;
var ds = d / s;
if (v) {
for (i = 0; i < s; i++)
this.animate({ "top": cur + a + "px" }, ds).animate({ "top": cur - a + "px" }, ds);
this.animate({ "top": cur }, 20);
}
else {
for (i = 0; i < s; i++)
this.animate({ "left": cur + a }, ds).animate({ "left": cur - a + "px" }, ds);
this.animate({ "left": cur }, 20);
}
return this;
}
Based on #el producer solution, I added some multiply logic and make it look like a random shake.
jQuery.fn.shake = function (interval, distance, times) {
interval = typeof interval == "undefined" ? 100 : interval;
distance = typeof distance == "undefined" ? 10 : distance;
times = typeof times == "undefined" ? 3 : times;
var jTarget = $(this);
jTarget.css('position', 'relative');
for (var iter = 0; iter < (times + 1) ; iter++) {
jTarget.animate({ top: ((iter % 2 == 0 ? distance * Math.random() : distance * Math.random() * -1)), left: ((iter % 2 == 0 ? distance * Math.random() : distance * Math.random() * -1)) }, interval);
}
return jTarget.animate({ top: 0 , left: 0 }, interval);
}
Position had to be absolute on my side, so I changed it to:
jQuery.fn.shake = function(interval, distance, times) {
interval = typeof interval == "undefined" ? 100 : interval;
distance = typeof distance == "undefined" ? 10 : distance;
times = typeof times == "undefined" ? 3 : times;
var jTarget = $(this);
for (var iter=0;iter<(times+1);iter++) {
jTarget.animate({ 'padding-left': ((iter%2==0 ? distance : distance*-1))}, interval);
}
return jTarget.animate({ 'padding-left': 0 } ,interval);
}

Categories