Counter with thousands separator - javascript

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));

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">

Is it possible to pass a parameter name as an argument in string form to use as parameter name in function? [duplicate]

This question already has answers here:
Accessing an object property with a dynamically-computed name
(19 answers)
Closed 3 years ago.
I have a number of calls to the same function where I am passing objects as well as specific object parameters as arguments. I've had no issue passing the object alone or passing an object parameter in the form object.param. However, I would also like to pass the object name and the parameter name as separate arguments so that I can combine them freely in the function. However, I can't figure out the syntax (or if my idea is supported).
The primary question is is my syntax correct: foo(param) and this[objectName].param?
My simple example below seems to work on playcode.io, but the same principle isn't working in my primary code.
Here is the simple version of the code:
var options = {
bar: 0
};
foo('bar'); // parameter name as string
function foo(param) {
var objectName = "options";
this[objectName].param = 2; // assembling object name with parameter name as string here
console.log('param = ' + this[objectName].param)
}
UPDATE: Here is an example of the working code using #CertainPerformance suggesting of not using .this.
const optionNames = {
optionsA: {
startMin: 3
},
// other option names
};
const constObjectNames = {
optionsConstA: {
maxVolume: 1
// etc
}
// other const object names
};
var objectName = "optionsA";
var constObjectName = "optionsConstA";
function callCalculateNewValue(optionName, constOptionName) {
var param = optionName;
return param;
}
foo('startMin');
function foo(param) {
optionNames[objectName][param] = callCalculateNewValue(optionNames[objectName][param], constObjectNames[constObjectName]);
console.log('= ' + optionNames[objectName][param]);
}
Here is my actual code for context The ridiculously named function callCallCalculateNewValue is the one in question:
function getRandom(min, max) { // returns a random number between min and max (both included)
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function valBetween(v, min, max) { // current value, min/max that I want to make sure v doesn't go under/over
return (Math.min(max, Math.max(min, v)));
}
var optionsConstA = {
// not recalculating each stage
soundFileName: 'audio/60.wav',
maxVolume: 1,
startMinSeparation: 1000, // the minimum distance appart the min/max values can be
slaveStatusMin: 'master',
minSeparation: 1000,
// recalculating each stage
startMin: 1050, // min time function waits before a sound is played
startMax: 8000, // max time function waits before a sound is played
playDurationMin: 15000, // min play time for each sound
playDurationMax: 20000, // max play time for each sound
fadeInMin: 10, // for individual sounds
fadeInMax: 8000, // for individual sounds
fadeOutMin: 8000, // for individual sounds
fadeOutMax: 8000, // for individual sounds
chanceRandomMin: 90, // values below the result won't be random, so for less chance variables are random, make min/max high
chanceRandomMax: 99, // values below the result won't be random
rampMin: 0,
rampMax: 4,
rampVolumeMin: 0, // number of stages the sounds will be faded in (total volume at each stage will be reduced by a percentage)
rampVolumeMax: 4,
volatilityMin: 1, // result is multiplied by CalculatedChange. ## This should possibly be unique for each parameter pair, though it is now calculating randomly within these values.
volatilityMax: 1 // result is multiplied by CalculatedChange
};
var optionsA = {
startMin: 0,
startMax: 0
};
function calculateNewValue(oldValue, min, max, volatilityMin, volatilityMax, slaveStatus, chanceRandomMin, chanceRandomMax, minSeparation, newMasterValue) {
var randomThreshold = getRandom(chanceRandomMin, chanceRandomMax);
var randomValue = getRandom(0, 100); // random number used against the threshold to see if the paramater should be reandomly determined
console.log("random value: " + randomValue) // the random number between 0-100 that if > the threshold value, it will use the random function
if (randomValue > randomThreshold || oldValue == 0) { // if random = yes OR if the oldValue is 0 (which would mean that it's the very first tiem the function is being called and this will keep it from getting stuck near the Min value to start) parameter is determined randomly
newValue = getRandom(min, max); // yes, it's random, so move randomly not incrementally from old value
console.log('Was random: ' + newValue)
}
else { // if not random, determine its move from oldValue
var changeLimit = (max - min) * .1; // ## I'm setting the max possible incremental move at a pecentage (e.g., 10%) of difference betten max and min value. I can make this more detailed per parameter later. Maybe send a percentage artument along.
var calculatedChange = getRandom(-changeLimit, changeLimit); // determines base value for parameter change (aka, change from oldValue)
console.log('Calculated change: ' + calculatedChange)
var volatility = getRandom(volatilityMin, volatilityMax); // # I should refine volatility's relationship with calculatedChange
newValue = valBetween(oldValue + (calculatedChange * volatility), min, max); // make sure calculatedChange can be negative
}
if (slaveStatus == 'master') {
newValue = valBetween(newValue, min, max - minSeparation); // if master (aka Min value), make sure Min is not so large that it doesn't have room for minSeparation (if it is added to Max)
}
if (slaveStatus !== 'master') { // now that the the value is determined, if you are a slave (aka a Max value which goes second), make sure you are >= to your master
if (newValue < newMasterValue) { // if newValue is less than the calculated value of its min/max counterpart...
newValue = newMasterValue;
}
if (newValue - newMasterValue < minSeparation) { // i.e, there isn't enough separation between the Max value and the newly defined Min Value
newValue = newValue + (minSeparation - (newValue - newMasterValue)); // adds needed separation value
console.log('Max: Separation added')
}
}
return newValue;
}
function callCalculateNewValue(objectName, constObjectName) {
objectName = calculateNewValue(constObjectName.startMin, constObjectName.startMin, constObjectName.startMax, constObjectName.volatilityMin, constObjectName.volatilityMax, constObjectName.slaveStatusMin, constObjectName.chanceRandomMin, constObjectName.chanceRandomMax, constObjectName.minSeparation);
return objectName;
}
var masterLoopStage = 0;
var calc = (function masterLoop(i) {
setTimeout(function () {
++i;
masterLoopStage = i;
console.log('masterLoopStage is: ' + i);
callCallCalculateNewValue('startMin');
function callCallCalculateNewValue(param) {
var objectName = "optionsA";
var constObjectName = "optionsConstA";
this[objectName].param = callCalculateNewValue(this[objectName].param, this[constObjectName]);
console.log('optionsA.startMin: ' + this[objectName].param)
}
optionsA.startMax = calculateNewValue(optionsA.startMax, optionsConstA.startMin, optionsConstA.startMax, optionsConstA.volatilityMin, optionsConstA.volatilityMax, optionsConstA.startMin, optionsConstA.chanceRandomMin, optionsConstA.chanceRandomMax, optionsConstA.minSeparation, optionsA.startMin);
console.log('Min: ' + optionsA.startMin);
console.log('Max: ' + optionsA.startMax);
console.log('______________');
/////////////////
masterLoop(i);
}, 3000) // time between increments
})(1);
console.log('____________');
console.log('Min: ' + optionsA.startMin);
console.log('Max: ' + optionsA.startMax);
With your current setup, it's not possible without eval, which should not be used - however, if you change around the data structure so that everything that can be an objectName is a property of a larger object, rather than a standalone variable (and do the same for the dynamic constObjectName), it would be doable. For example:
const optionNames = {
optionsA: {
startMin: 0,
startMax: 0
},
// other option names
};
const constObjectNames = {
optionsConstA: {
soundFileName: 'audio/60.wav',
maxVolume: 1,
// etc
}
// other const object names
};
Then, you can use ordinary bracket notation, just like your foo function in the first snippet is doing. Your param also contains a string which is the property name you want to access, so you need to use bracket notation when using param too, eg [param] rather than .param. In full:
const optionNames = {
optionsA: {
startMin: 1,
},
// other option names
};
const constObjectNames = {
optionsConstA: {
startMinB: 1,
}
// other const object names
};
function calculate(optionName, constOptionName) {
var value = optionName + constOptionName.startMinB;
return value;
}
foo('startMin'); // I'm still not sure what the syntax is for passing parameter name, or if I can
function foo(param) {
var objectName = "optionsA";
var constObjectName = "optionsConstA";
optionNames[objectName][param] = calculate(optionNames[objectName][param], constObjectNames[constObjectName]);
console.log('= ' + optionNames[objectName][param])
}
Your use of this will only work if the code in question is operating on the top level, which is not a good idea to depend on (you'd be polluting the global scope unnecessarily).

Jquery not looping function correctly

I'm new to develop jquery plugin,I have stuck with my function on my function call my plugging repeat same value on elements.I do expect replace all values of my page,respectively
( function ($) {
$.fn.siPrifixx = function (value, options) {
// This is the easiest way to have default options.
var settings = $.extend({
// These are the defaults.
maxDigits: 8,
seperator: true,
decimal: 1,
popUp: true,
index: "tool tip message"
}, options);
console.log(settings.index);
$(this).addClass('tooltip', 'test');
$(this).tooltipster({
theme: 'tooltipster-default',
functionInit: function () {
return value
}
})
// $('.tooltip').prop(settings.index, value);
var number = value;
if (typeof value === 'string') {
var parts = value.split(",");
number = (parseInt(parts.join("")));
}
if (typeof number !== 'undefined' && !isNaN(number)) {
// if the number is alreadey comma seperated convert to number
var n = settings.decimal
// 2 decimal places => 100, 3 => 1000, etc
var decPlace = Math.pow(10, n);
// Enumerate number abbreviations
var abbrev = ["K", "M", "B", "T"];
// Go through the array backwards, so we do the largest first
for (var i = abbrev.length - 1; i >= 0; i--) {
// Convert array index to "1000", "1000000", etc
var size = Math.pow(10, (i + 1) * 3);
// If the number is bigger or equal do the abbreviation
if (size <= number) {
// Here, we multiply by decPlaces, round, and then divide by decPlaces.
// This gives us nice rounding to a particular decimal place.
number = Math.round(number * decPlace / size) / decPlace;
// Handle special case where we round up to the next abbreviation
if ((number == 1000) && (i < abbrev.length - 1)) {
number = 1;
i++;
}
// Add the letter for the abbreviation
number += abbrev[i];
// We are done... stop
break;
}
}
$(this).html(number)
console.log(number)
// return number;
} else {
$(this).html(number)
console.log(number)
// return value;
}
};
}(jQuery));
I'm calling function on a loop like this.
$.each($(plugin.element).find('.widget-data'), function(index, value)
{
var index = $(this).data('index');
var value = data.stats[index];
$('.widget-data').siPrifixx(value,{
decimal:2,
index:index
});
What's the wrong with my code?
When you call $('.widget-data').siPrifixx, you're still addressing all elements with the widget-data class. Since you're already iterating that set, you shouldn't targets all elements in every iteration. Instead call $(this).siPrifixx(...);
Can you try with following code:
$(plugin.element).find('.widget-data').each(function(index)
{
var index_current = $(this).data('index');
var value = data.stats[index_current];
$(this).siPrifixx(value,{
decimal:2,
index:index_current
});
});

Spin counter to a number containing two digits

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.

Dynamically-changing variables random intergers

The numbers themselves aren't relevant. I have a list of variables that are used to track a moving vehicle.
UTC Time:, Latitude:, Longitude:, Speed:, Heading:, Steering:, Odometer:(PPM), GPS Status:, STWS Status:
Like i said the numbers aren't relevant, and neither is the math. I just need to simulate dynamically changing integers for each variable. For instance, Speed:25. then the 25 become a 26, then a 28, then a 15 and so on. I will implement this code, and then set the min and max for each variable.
I just need to show customers that the vehicle tracking system monitor can display changing values for each variable.
Thank you.
$("#the_span_id").text(n); and hook it up to a JavaScript timer event.
It sounds like what you need is a jQuery countdown. Take a look at this link:
http://www.tripwiremagazine.com/2011/04/9-cool-jquery-countdown-scripts.html
You could do something along the following lines:
var DynVar = {
variables: [],
timer: 0,
numIntervals: 0,
counter: 0,
updateVar: function(v) {
v.value = Math.random() * (v.max - v.min) + v.min;
},
createVar: function(name, min, max) {
var v = {"name": name, "min": min, "max": max};
DynVar.updateVar(v);
DynVar.variables.push(v);
return v;
},
update: function() {
for (i = 0; i < DynVar.variables.length; ++i) {
var v = DynVar.variables[i];
DynVar.updateVar(v);
console.log(DynVar.counter + ": " + v.name + ": " + v.value);
}
if (DynVar.counter++ >= DynVar.numIntervals) {
clearInterval(DynVar.timer);
}
},
start: function(interval, numIntervals) {
DynVar.counter = 0;
DynVar.numIntervals = numIntervals;
DynVar.timer = setInterval(DynVar.update, interval);
}
};
DynVar.createVar("speed", 10, 30);
DynVar.createVar("latitude", 20, 22);
DynVar.start(1000, 3);

Categories