-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Binary prefix, Currency prefix (Merge #70 #81) #96
Changes from all commits
1dfc9ad
1841fbc
b43ed9e
2fb8dbd
e33a8f1
e249b2e
d1ed244
fad5de7
3fa19c7
7ee5a2c
a0de748
76c6681
1299824
b05d382
4bc47b3
fffdb7d
9794256
03ffad2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -133,9 +133,9 @@ The *symbol* can be: | |
|
||
The *zero* (`0`) option enables zero-padding; this implicitly sets *fill* to `0` and *align* to `=`. The *width* defines the minimum field width; if not specified, then the width will be determined by the content. The *comma* (`,`) option enables the use of a group separator, such as a comma for thousands. | ||
|
||
Depending on the *type*, the *precision* either indicates the number of digits that follow the decimal point (types `f` and `%`), or the number of significant digits (types ``, `e`, `g`, `r`, `s` and `p`). If the precision is not specified, it defaults to 6 for all types except `` (none), which defaults to 12. Precision is ignored for integer formats (types `b`, `o`, `d`, `x`, `X` and `c`). See [precisionFixed](#precisionFixed) and [precisionRound](#precisionRound) for help picking an appropriate precision. | ||
Depending on the *type*, the *precision* either indicates the number of digits that follow the decimal point (types `f` and `%`), or the number of significant digits (types ``, `e`, `g`, `K`, `r`, `s` and `p`). If the precision is not specified, it defaults to 6 for all types except `` (none), which defaults to 12. Precision is ignored for integer formats (types `b`, `o`, `d`, `x`, `X` and `c`). See [precisionFixed](#precisionFixed) and [precisionRound](#precisionRound) for help picking an appropriate precision. | ||
|
||
The `~` option trims insignificant trailing zeros across all format types. This is most commonly used in conjunction with types `r`, `e`, `s` and `%`. For example: | ||
The `~` option trims insignificant trailing zeros across all format types. This is most commonly used in conjunction with types `r`, `e`, `s`, `K` and `%`. For example: | ||
|
||
```js | ||
d3.format("s")(1500); // "1.50000k" | ||
|
@@ -149,6 +149,7 @@ The available *type* values are: | |
* `g` - either decimal or exponent notation, rounded to significant digits. | ||
* `r` - decimal notation, rounded to significant digits. | ||
* `s` - decimal notation with an [SI prefix](#locale_formatPrefix), rounded to significant digits. | ||
* `K` - decimal notation with a [currency prefix](#locale_formatCurrencyPrefix), rounded to significant digits. | ||
* `%` - multiply by 100, and then decimal notation with a percent sign. | ||
* `p` - multiply by 100, round to significant digits, and then decimal notation with a percent sign. | ||
* `b` - binary notation, rounded to integer. | ||
|
@@ -167,7 +168,7 @@ d3.format(".1")(42); // "4e+1" | |
d3.format(".1")(4.2); // "4" | ||
``` | ||
|
||
<a name="locale_formatPrefix" href="#locale_formatPrefix">#</a> <i>locale</i>.<b>formatPrefix</b>(<i>specifier</i>, <i>value</i>) [<>](https://github.com/d3/d3-format/blob/master/src/locale.js#L127 "Source") | ||
<a name="locale_formatPrefix" href="#locale_formatPrefix">#</a> <i>locale</i>.<b>formatPrefix</b>(<i>specifier</i>, <i>value</i>) [<>](https://github.com/d3/d3-format/blob/master/src/locale.js#L152 "Source") | ||
|
||
Equivalent to [*locale*.format](#locale_format), except the returned function will convert values to the units of the appropriate [SI prefix](https://en.wikipedia.org/wiki/Metric_prefix#List_of_SI_prefixes) for the specified numeric reference *value* before formatting in fixed point notation. The following prefixes are supported: | ||
|
||
|
@@ -199,6 +200,16 @@ f(0.0042); // "4,200µ" | |
|
||
This method is useful when formatting multiple numbers in the same units for easy comparison. See [precisionPrefix](#precisionPrefix) for help picking an appropriate precision, and [bl.ocks.org/9764126](http://bl.ocks.org/mbostock/9764126) for an example. | ||
|
||
<a name="locale_formatCurrencyPrefix" href="#locale_formatCurrencyPrefix">#</a> <i>locale</i>.<b>formatCurrencyPrefix</b>(<i>specifier</i>, <i>value</i>) [<>](https://github.com/d3/d3-format/blob/master/src/locale.js#L153 "Source") | ||
|
||
Equivalent to [*locale*.locale_formatPrefix](#locale_formatPrefix), except it uses common currency abbreviations: | ||
|
||
* `` (none) - 10⁰ | ||
* `K` - thousands, 10³ | ||
* `M` - millions, 10⁶ | ||
* `B` - billions, 10⁹ | ||
* `T` - trillions, 10¹² | ||
|
||
<a name="formatSpecifier" href="#formatSpecifier">#</a> d3.<b>formatSpecifier</b>(<i>specifier</i>) [<>](https://github.com/d3/d3-format/blob/master/src/formatSpecifier.js "Source") | ||
|
||
Parses the specified *specifier*, returning an object with exposed fields that correspond to the [format specification mini-language](#locale_format) and a toString method that reconstructs the specifier. For example, `formatSpecifier("s")` returns: | ||
|
@@ -290,6 +301,10 @@ f(1.2e6); // "1.2M" | |
f(1.3e6); // "1.3M" | ||
``` | ||
|
||
<a name="currencyPrecisionPrefix" href="#currencyPrecisionPrefix">#</a> d3.<b>currencyPrecisionPrefix</b>(<i>step</i>, <i>value</i>) [<>](https://github.com/d3/d3-format/blob/master/src/currencyPrecisionPrefix.js "Source") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these necessarily related to currency? IMO this formatter is useful for formatting large numbers in general, not specific to dealing with currency. Although, the currency use case gives some concrete grounding for decisions, which is great. Probably it's fine to call it |
||
|
||
Returns a suggested decimal precision for use with [*locale*.formatCurrencyPrefix](#locale_formatCurrencyPrefix) given the specified numeric *step* and reference *value*. This is the equivalent of [*locale*.precisionPrefix](#locale_precisionPrefix) using common currency abbreviations instead of SI prefixes. | ||
|
||
<a name="precisionRound" href="#precisionRound">#</a> d3.<b>precisionRound</b>(<i>step</i>, <i>max</i>) [<>](https://github.com/d3/d3-format/blob/master/src/precisionRound.js "Source") | ||
|
||
Returns a suggested decimal precision for format types that round to significant digits given the specified numeric *step* and *max* values. The *step* represents the minimum absolute difference between values that will be formatted, and the *max* represents the largest absolute value that will be formatted. (This assumes that the values to be formatted are also multiples of *step*.) For example, given the numbers 0.99, 1.0, and 1.01, the *step* should be 0.01, the *max* should be 1.01, and the suggested precision is 3: | ||
|
@@ -331,6 +346,7 @@ Returns a *locale* object for the specified *definition* with [*locale*.format]( | |
* `thousands` - the group separator (e.g., `","`). | ||
* `grouping` - the array of group sizes (e.g., `[3]`), cycled as needed. | ||
* `currency` - the currency prefix and suffix (e.g., `["$", ""]`). | ||
* `currencyAbbreviations` - the list of abbreviated suffixes for currency values; an array of elements for each: units, thousands, millions, billions and trillions; defaults to `["", "K", "M", "B", "T"]`. The number of elements can vary. | ||
* `numerals` - optional; an array of ten strings to replace the numerals 0-9. | ||
* `percent` - optional; the percent sign (defaults to `"%"`). | ||
* `minus` - optional; the minus sign (defaults to hyphen-minus, `"-"`). | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { createPrecisionPrefix } from "./precisionPrefix.js"; | ||
|
||
export default createPrecisionPrefix(0, 4); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
export var binaryPrefixExponent; | ||
|
||
export default function(x, p) { | ||
var binaryExponent = 0; | ||
if (x === Infinity) return binaryPrefixExponent = 0, x; | ||
|
||
while (Math.round(x) >= 1024 && binaryExponent < 80) { | ||
binaryExponent += 10; | ||
x /= 1024; | ||
} | ||
|
||
if (p <= 3 && Math.round(x) >= 1000) { | ||
// Unlike SI prefixes, integers can take three digits. | ||
binaryExponent += 10; | ||
x /= 1024; | ||
} | ||
|
||
binaryPrefixExponent = Math.max(0, Math.min(8, Math.floor(binaryExponent / 10))) * 10; | ||
var i = binaryExponent - binaryPrefixExponent + 1, | ||
coefficient = x * i, | ||
split = ('' + coefficient).split('.'), | ||
integer = split[0], | ||
fraction = split[1] || '', | ||
n = (integer + fraction).length; | ||
|
||
if (n === p) return coefficient; | ||
|
||
if (n > p) { | ||
var fractionLength = Math.max(0, p - integer.length); | ||
|
||
while (+coefficient.toFixed(fractionLength) === 0) { | ||
fractionLength += 1; | ||
} | ||
|
||
coefficient = coefficient.toFixed(fractionLength); | ||
} else { | ||
coefficient = integer + '.' + fraction; | ||
|
||
while (n < p) { | ||
coefficient += '0'; | ||
n += 1; | ||
} | ||
} | ||
|
||
return coefficient; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,9 @@ | ||
import exponent from "./exponent.js"; | ||
|
||
export default function(step, value) { | ||
return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step))); | ||
export function createPrecisionPrefix(minimumPrefixOrder, maximumPrefixOrder) { | ||
return function (step, value) { | ||
return Math.max(0, Math.max(minimumPrefixOrder, Math.min(maximumPrefixOrder, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step))); | ||
} | ||
} | ||
|
||
export default createPrecisionPrefix(-8, 8); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
var tape = require("tape"), | ||
format = require("../"); | ||
|
||
// For currencies, only 4 prefixes are commonly used: | ||
// thousands (K), millions (M), billions (B) and trillions (T) | ||
|
||
tape("precisionPrefix(step, value) returns zero between 1 and 100 (unit step)", function (test) { | ||
test.equal(format.currencyPrecisionPrefix(1e+0, 1e+0), 0); // 1 | ||
test.equal(format.currencyPrecisionPrefix(1e+0, 1e+1), 0); // 10 | ||
test.equal(format.currencyPrecisionPrefix(1e+0, 1e+2), 0); // 100 | ||
test.end() | ||
}); | ||
|
||
tape("precisionPrefix(step, value) returns zero between 1 and 100 (thousand step)", function (test) { | ||
test.equal(format.currencyPrecisionPrefix(1e+3, 1e+3), 0); // 1K | ||
test.equal(format.currencyPrecisionPrefix(1e+3, 1e+4), 0); // 10K | ||
test.equal(format.currencyPrecisionPrefix(1e+3, 1e+5), 0); // 100K | ||
test.end() | ||
}); | ||
|
||
tape("precisionPrefix(step, value) returns zero between 1 and 100 (million step)", function (test) { | ||
test.equal(format.currencyPrecisionPrefix(1e+6, 1e+6), 0); // 1M | ||
test.equal(format.currencyPrecisionPrefix(1e+6, 1e+7), 0); // 10M | ||
test.equal(format.currencyPrecisionPrefix(1e+6, 1e+8), 0); // 100M | ||
test.end() | ||
}); | ||
|
||
tape("precisionPrefix(step, value) returns zero between 1 and 100 (billion step)", function (test) { | ||
test.equal(format.currencyPrecisionPrefix(1e+9, 1e+9), 0); // 1B | ||
test.equal(format.currencyPrecisionPrefix(1e+9, 1e+10), 0); // 10B | ||
test.equal(format.currencyPrecisionPrefix(1e+9, 1e+11), 0); // 100B | ||
test.end() | ||
}); | ||
|
||
tape("currencyPrecisionPrefix(step, value) returns the expected precision when value is greater than one trillion", function(test) { | ||
test.equal(format.currencyPrecisionPrefix(1e+12, 1e+12), 0); // 1T | ||
test.equal(format.currencyPrecisionPrefix(1e+12, 1e+13), 0); // 10T | ||
test.equal(format.currencyPrecisionPrefix(1e+12, 1e+14), 0); // 100T | ||
test.equal(format.currencyPrecisionPrefix(1e+12, 1e+15), 0); // 1000T | ||
test.equal(format.currencyPrecisionPrefix(1e+11, 1e+15), 1); // 1000.0T | ||
test.end(); | ||
}); | ||
|
||
tape("currencyPrecisionPrefix(step, value) returns the expected precision when value is less than one unit", function(test) { | ||
test.equal(format.currencyPrecisionPrefix(1e+0, 1e+0), 0); // 1 | ||
test.equal(format.currencyPrecisionPrefix(1e-1, 1e-1), 1); // 0.1 | ||
test.equal(format.currencyPrecisionPrefix(1e-2, 1e-2), 2); // 0.01 | ||
test.equal(format.currencyPrecisionPrefix(1e-3, 1e-3), 3); // 0.001 | ||
test.equal(format.currencyPrecisionPrefix(1e-4, 1e-4), 4); // 0.0001 | ||
test.end(); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to mention here that these are for US English locale specifically.