openexchangerates / accounting.js

A lightweight JavaScript library for number, money and currency formatting - fully localisable, zero dependencies.
http://openexchangerates.github.io/accounting.js
MIT License
4.95k stars 532 forks source link

Add fixed-length large number formats for money (&bytes) #26

Open jimbomorrison opened 12 years ago

jimbomorrison commented 12 years ago

It would be super-useful to be able to control formatting of large numbers a la:

( and also kinda useful to be able to divide by 1024 for filesizes )

Thanks!

jimbomorrison commented 12 years ago

This is kinda the thing I mean ( bit rough.. )

https://github.com/jimbomorrison/accounting.js/commit/b3df5a3e54fe1050196c02c30360dde29437f725

(yikes - hit comment & close by mistake!)

wjcrowcroft commented 12 years ago

Hey, thanks - this is a great idea. I'll have a think about ways this could work in the context of the rest of the library and let you know how it goes.

jimbomorrison commented 12 years ago

Great, thanks.

I've had a quick play at it and will keep pushing my changes up to my fork (see issue for the link, I think).

Great library - thanks!

J.

wjcrowcroft commented 12 years ago

Ok, I like the idea so was just playing around in the console, and came up with this - it's quick and dirty but the logic should work:

// Some example vars:
var num = 92615, 
    base = 1000, 
    units = ['K', 'M', 'B', 'TR'], 
    unit, 
    precision = 2;

// Divide number by base until it's smaller than base or has reached the largest unit
while ( num > base && units.length ) {
  num /= base; // divide number by base
  unit = units.shift(); // get next unit
}

// The result:
console.log(accounting.formatNumber(num, precision) + unit);  // "92.62K"

// Try with these values:
var num = 123,     // "123.00"
var num = 1234,    // "1.23K"
var num = 1234567, // "1.23M"
var num = 6541e7,  // "65.41B"

// Won't exceed maximum number of units, eg:
    units = ['K'], 

var num = 1234567, // "1,234.57K"

I can see potential for this to work really well, just a question of figuring out the best way of integrating it so as not to make everything really complex.

Issues:

wjcrowcroft commented 12 years ago

Just another thought, this is probably a pretty standard problem so there must be other places where this is solved... will search around for inspiration.

jimbomorrison commented 12 years ago

Hi Joss,

That's a good point - I honestly haven't looked. Your solution looks great though. I'll drop it into where I'm using it to see how it works in practice.

( I'm using it for the re-build of twiDAQ.com where I've tables of stock data where say the MarCap column might range from $10's for some stocks to $100,000,000 for others... ( need a consistent width/display ))

Will let you know how it goes!

Thanks, J.

wjcrowcroft commented 12 years ago

Hey, that's cool! Hope to see it in action soon.

Let me know how you get on - that code will need to be cleaned up and functionised, let me know if you're ok doing that or need a hand with it, happy to help out so that you can test it out.

In the mean time I'll have a think about a better way to design the method.

jimbomorrison commented 12 years ago

Hi Joss,

That's working really well.

I've thrown it in here ( http://goo.gl/34CYe ) for now. My original attempt is just below (in the code)... similar but not as slick.

The only thing that I can't quite get my head around is that I think the precision should change depending on the numeral length of the string.. ( so 20K => 20.23K whereas 200K => 200.2K ( so that they both have four numerals )) ... easy enough to hack in for my one use-case but not quite sure how sane it is or how one would present the arguments. (See Volume & Earnings in the second screenshot ).. I guess what I'm trying to say is a "max number of numerals" rather than a "precision".. does that make sense?

Anyhow - some (top-secret) screenshots for you to see it in action (new twiDAQ's not live yet). All numbers are going through your method.

Thanks!

J.

[image: Screen shot 2011-09-23 at 11.42.37.png]

And..

[image: Screen shot 2011-09-23 at 11.43.11.png]

wjcrowcroft commented 12 years ago

Hey mate,

Sounds good - screenshots didn't get attached via the email, maybe you could upload them somewhere or email them directly to josscrowcroft [at] gmail ?

Thanks, looking forward to seeing it!

wjcrowcroft commented 12 years ago

Ok, making progress - I've just pushed a new file to the dev branch called accounting-units.js, which adds a method accounting.formatUnits(number, base, units, callback).

The usage is documented in that file.

The callback receives number and unit as parameters - basically, because formatUnits returns a string (eg 1000000 => "1M"), you need a way to apply a callback to that number to format the raw value and add the units after (4th param)

So the usage looks like this:

accounting.formatUnits(1234567890, 1000, ["K", "M"], function(num, units) {
    // Apply formatNumber() to the value with 2 decimal places, then add the units:
    return accounting.formatNumber(num, 2) + " " + units; 
}); // "1,234.57 M"

That callback function could be used to do formatMoney as well, or any other logic can go in there. Basically gives you access to the raw value plus the unit that the value requires, and the rest is up to you.

If you don't provide a callback, it just returns the string, (eg. above would return 1234.56789M)

This may not be the final solution, but I'm happy to keep it as an extension until it's proven useful and effective enough to include in the main app.

Would you be able to try it out in your app and let me know how it gets on? You just gotta add that file after accounting.js and then the function is available.

Even if we end up changing it, the functionality will always be available if you need it via this extension (won't be deprecated or anything) so it's a fairly safe choice to use in your code - having said that, it is a first-try so if you find any bugs, please let me know.

jimbomorrison commented 12 years ago

Brilliant, thanks. I'll give it a try this [UK] afternoon and let you know how I get on.

Thanks Joss, great library!

J

ryrych commented 10 years ago

Hey, is it stable now and part of the API? I found something similar: http://adamwdraper.github.io/Numeral-js/

ryrych commented 10 years ago
price = accounting.formatUnits(1000, 1000, ["k", "M", "G"], function(num, units) {
    return accounting.formatMoney(num) + units; 
});
// returns "1,000undefined"

this should solve this:

if ( number <= base || base === 1 ) {...}