UNPKG

sugar

Version:

A Javascript library for working with native objects.

429 lines (396 loc) 12.2 kB
/*** * @package Number * @dependency core * @description Number formatting, rounding (with precision), and ranges. Aliases to Math methods. * ***/ function abbreviateNumber(num, roundTo, str, mid, limit, bytes) { var fixed = num.toFixed(20), decimalPlace = fixed.search(/\./), numeralPlace = fixed.search(/[1-9]/), significant = decimalPlace - numeralPlace, unit, i, divisor; if(significant > 0) { significant -= 1; } i = math.max(math.min((significant / 3).floor(), limit === false ? str.length : limit), -mid); unit = str.charAt(i + mid - 1); if(significant < -9) { i = -3; roundTo = significant.abs() - 9; unit = str.slice(0,1); } divisor = bytes ? (2).pow(10 * i) : (10).pow(i * 3); return (num / divisor).round(roundTo || 0).format() + unit.trim(); } extend(number, false, false, { /*** * @method Number.random([n1], [n2]) * @returns Number * @short Returns a random integer between [n1] and [n2]. * @extra If only 1 number is passed, the other will be 0. If none are passed, the number will be either 0 or 1. * @example * * Number.random(50, 100) -> ex. 85 * Number.random(50) -> ex. 27 * Number.random() -> ex. 0 * ***/ 'random': function(n1, n2) { var min, max; if(arguments.length == 1) n2 = n1, n1 = 0; min = math.min(n1 || 0, isUndefined(n2) ? 1 : n2); max = math.max(n1 || 0, isUndefined(n2) ? 1 : n2) + 1; return floor((math.random() * (max - min)) + min); } }); extend(number, true, false, { /*** * @method log(<base> = Math.E) * @returns Number * @short Returns the logarithm of the number with base <base>, or natural logarithm of the number if <base> is undefined. * @example * * (64).log(2) -> 6 * (9).log(3) -> 2 * (5).log() -> 1.6094379124341003 * ***/ 'log': function(base) { return math.log(this) / (base ? math.log(base) : 1); }, /*** * @method abbr([precision] = 0) * @returns String * @short Returns an abbreviated form of the number. * @extra [precision] will round to the given precision. * @example * * (1000).abbr() -> "1k" * (1000000).abbr() -> "1m" * (1280).abbr(1) -> "1.3k" * ***/ 'abbr': function(precision) { return abbreviateNumber(this, precision, 'kmbt', 0, 4); }, /*** * @method metric([precision] = 0, [limit] = 1) * @returns String * @short Returns the number as a string in metric notation. * @extra [precision] will round to the given precision. Both very large numbers and very small numbers are supported. [limit] is the upper limit for the units. The default is %1%, which is "kilo". If [limit] is %false%, the upper limit will be "exa". The lower limit is "nano", and cannot be changed. * @example * * (1000).metric() -> "1k" * (1000000).metric() -> "1,000k" * (1000000).metric(0, false) -> "1M" * (1249).metric(2) + 'g' -> "1.25kg" * (0.025).metric() + 'm' -> "25mm" * ***/ 'metric': function(precision, limit) { return abbreviateNumber(this, precision, 'nμm kMGTPE', 4, isUndefined(limit) ? 1 : limit); }, /*** * @method bytes([precision] = 0, [limit] = 4) * @returns String * @short Returns an abbreviated form of the number, considered to be "Bytes". * @extra [precision] will round to the given precision. [limit] is the upper limit for the units. The default is %4%, which is "terabytes" (TB). If [limit] is %false%, the upper limit will be "exa". * @example * * (1000).bytes() -> "1kB" * (1000).bytes(2) -> "0.98kB" * ((10).pow(20)).bytes() -> "90,949,470TB" * ((10).pow(20)).bytes(0, false) -> "87EB" * ***/ 'bytes': function(precision, limit) { return abbreviateNumber(this, precision, 'kMGTPE', 0, isUndefined(limit) ? 4 : limit, true) + 'B'; }, /*** * @method isInteger() * @returns Boolean * @short Returns true if the number has no trailing decimal. * @example * * (420).isInteger() -> true * (4.5).isInteger() -> false * ***/ 'isInteger': function() { return this % 1 == 0; }, /*** * @method isOdd() * @returns Boolean * @short Returns true if the number is odd. * @example * * (3).isOdd() -> true * (18).isOdd() -> false * ***/ 'isOdd': function() { return !isNaN(this) && !this.isMultipleOf(2); }, /*** * @method isEven() * @returns Boolean * @short Returns true if the number is even. * @example * * (6).isEven() -> true * (17).isEven() -> false * ***/ 'isEven': function() { return this.isMultipleOf(2); }, /*** * @method isMultipleOf(<num>) * @returns Boolean * @short Returns true if the number is a multiple of <num>. * @example * * (6).isMultipleOf(2) -> true * (17).isMultipleOf(2) -> false * (32).isMultipleOf(4) -> true * (34).isMultipleOf(4) -> false * ***/ 'isMultipleOf': function(num) { return this % num === 0; }, /*** * @method format([place] = 0, [thousands] = ',', [decimal] = '.') * @returns String * @short Formats the number to a readable string. * @extra If [place] is %undefined%, will automatically determine the place. [thousands] is the character used for the thousands separator. [decimal] is the character used for the decimal point. * @example * * (56782).format() -> '56,782' * (56782).format(2) -> '56,782.00' * (4388.43).format(2, ' ') -> '4 388.43' * (4388.43).format(2, '.', ',') -> '4.388,43' * ***/ 'format': function(place, thousands, decimal) { var i, str, split, integer, fraction, result = ''; if(isUndefined(thousands)) { thousands = ','; } if(isUndefined(decimal)) { decimal = '.'; } str = (isNumber(place) ? round(this, place || 0).toFixed(math.max(place, 0)) : this.toString()).replace(/^-/, ''); split = str.split('.'); integer = split[0]; fraction = split[1]; for(i = integer.length; i > 0; i -= 3) { if(i < integer.length) { result = thousands + result; } result = integer.slice(math.max(0, i - 3), i) + result; } if(fraction) { result += decimal + repeatString((place || 0) - fraction.length, '0') + fraction; } return (this < 0 ? '-' : '') + result; }, /*** * @method hex([pad] = 1) * @returns String * @short Converts the number to hexidecimal. * @extra [pad] will pad the resulting string to that many places. * @example * * (255).hex() -> 'ff'; * (255).hex(4) -> '00ff'; * (23654).hex() -> '5c66'; * ***/ 'hex': function(pad) { return this.pad(pad || 1, false, 16); }, /*** * @method upto(<num>, [fn], [step] = 1) * @returns Array * @short Returns an array containing numbers from the number up to <num>. * @extra Optionally calls [fn] callback for each number in that array. [step] allows multiples greater than 1. * @example * * (2).upto(6) -> [2, 3, 4, 5, 6] * (2).upto(6, function(n) { * // This function is called 5 times receiving n as the value. * }); * (2).upto(8, null, 2) -> [2, 4, 6, 8] * ***/ 'upto': function(num, fn, step) { return getRange(this, num, fn, step || 1); }, /*** * @method downto(<num>, [fn], [step] = 1) * @returns Array * @short Returns an array containing numbers from the number down to <num>. * @extra Optionally calls [fn] callback for each number in that array. [step] allows multiples greater than 1. * @example * * (8).downto(3) -> [8, 7, 6, 5, 4, 3] * (8).downto(3, function(n) { * // This function is called 6 times receiving n as the value. * }); * (8).downto(2, null, 2) -> [8, 6, 4, 2] * ***/ 'downto': function(num, fn, step) { return getRange(this, num, fn, -(step || 1)); }, /*** * @method times(<fn>) * @returns Number * @short Calls <fn> a number of times equivalent to the number. * @example * * (8).times(function(i) { * // This function is called 8 times. * }); * ***/ 'times': function(fn) { if(fn) { for(var i = 0; i < this; i++) { fn.call(this, i); } } return this.toNumber(); }, /*** * @method chr() * @returns String * @short Returns a string at the code point of the number. * @example * * (65).chr() -> "A" * (75).chr() -> "K" * ***/ 'chr': function() { return string.fromCharCode(this); }, /*** * @method pad(<place> = 0, [sign] = false, [base] = 10) * @returns String * @short Pads a number with "0" to <place>. * @extra [sign] allows you to force the sign as well (+05, etc). [base] can change the base for numeral conversion. * @example * * (5).pad(2) -> '05' * (-5).pad(4) -> '-0005' * (82).pad(3, true) -> '+082' * ***/ 'pad': function(place, sign, base) { return padNumber(this, place, sign, base); }, /*** * @method ordinalize() * @returns String * @short Returns an ordinalized (English) string, i.e. "1st", "2nd", etc. * @example * * (1).ordinalize() -> '1st'; * (2).ordinalize() -> '2nd'; * (8).ordinalize() -> '8th'; * ***/ 'ordinalize': function() { var suffix, num = this.abs(), last = parseInt(num.toString().slice(-2)); return this + getOrdinalizedSuffix(last); }, /*** * @method toNumber() * @returns Number * @short Returns a number. This is mostly for compatibility reasons. * @example * * (420).toNumber() -> 420 * ***/ 'toNumber': function() { return parseFloat(this, 10); } }); /*** * @method round(<precision> = 0) * @returns Number * @short Shortcut for %Math.round% that also allows a <precision>. * * @example * * (3.241).round() -> 3 * (-3.841).round() -> -4 * (3.241).round(2) -> 3.24 * (3748).round(-2) -> 3800 * *** * @method ceil(<precision> = 0) * @returns Number * @short Shortcut for %Math.ceil% that also allows a <precision>. * * @example * * (3.241).ceil() -> 4 * (-3.241).ceil() -> -3 * (3.241).ceil(2) -> 3.25 * (3748).ceil(-2) -> 3800 * *** * @method floor(<precision> = 0) * @returns Number * @short Shortcut for %Math.floor% that also allows a <precision>. * * @example * * (3.241).floor() -> 3 * (-3.841).floor() -> -4 * (3.241).floor(2) -> 3.24 * (3748).floor(-2) -> 3700 * *** * @method [math]() * @returns Number * @short Math related functions are mapped as shortcuts to numbers and are identical. Note that %Number#log% provides some special defaults. * * @set * abs * sin * asin * cos * acos * tan * atan * sqrt * exp * pow * * @example * * (3).pow(3) -> 27 * (-3).abs() -> 3 * (1024).sqrt() -> 32 * ***/ function buildNumber() { extendSimilar(number, true, false, 'round,floor,ceil', function(methods, name) { methods[name] = function(precision) { return round(this, precision, name); } }); extendSimilar(number, true, false, 'abs,pow,sin,asin,cos,acos,tan,atan,exp,pow,sqrt', function(methods, name) { methods[name] = function(a, b) { return math[name](this, a, b); } }); } buildNumber();