diff --git a/README.md b/README.md
index 2259cde..3f9415d 100644
--- a/README.md
+++ b/README.md
@@ -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 an [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"
```
-# locale.formatPrefix(specifier, value) [<>](https://github.com/d3/d3-format/blob/master/src/locale.js#L127 "Source")
+# locale.formatPrefix(specifier, value) [<>](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.
+# locale.formatCurrencyPrefix(specifier, value) [<>](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¹²
+
# d3.formatSpecifier(specifier) [<>](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"
```
+# d3.currencyPrecisionPrefix(step, value) [<>](https://github.com/d3/d3-format/blob/master/src/currencyPrecisionPrefix.js "Source")
+
+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.
+
# d3.precisionRound(step, max) [<>](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, `"-"`).
diff --git a/locale/de-DE.json b/locale/de-DE.json
index a249762..320d2b0 100644
--- a/locale/de-DE.json
+++ b/locale/de-DE.json
@@ -2,5 +2,6 @@
"decimal": ",",
"thousands": ".",
"grouping": [3],
- "currency": ["", "\u00a0€"]
+ "currency": ["", "\u00a0€"],
+ "currencyAbbreviations": ["", "", "\u00a0Mio.", "\u00a0Mrd.", "\u00a0Bio."]
}
diff --git a/locale/en-GB.json b/locale/en-GB.json
index 3d22d7a..d370be3 100644
--- a/locale/en-GB.json
+++ b/locale/en-GB.json
@@ -2,5 +2,6 @@
"decimal": ".",
"thousands": ",",
"grouping": [3],
- "currency": ["£", ""]
+ "currency": ["£", ""],
+ "currencyAbbreviations": ["", "K", "M", "B", "T"]
}
diff --git a/locale/en-US.json b/locale/en-US.json
index f075b86..d9aa81b 100644
--- a/locale/en-US.json
+++ b/locale/en-US.json
@@ -2,5 +2,6 @@
"decimal": ".",
"thousands": ",",
"grouping": [3],
- "currency": ["$", ""]
+ "currency": ["$", ""],
+ "currencyAbbreviations": ["", "K", "M", "B", "T"]
}
diff --git a/locale/es-ES.json b/locale/es-ES.json
index a249762..2ffed3a 100644
--- a/locale/es-ES.json
+++ b/locale/es-ES.json
@@ -2,5 +2,6 @@
"decimal": ",",
"thousands": ".",
"grouping": [3],
- "currency": ["", "\u00a0€"]
+ "currency": ["", "\u00a0€"],
+ "currencyAbbreviations": ["", "\u00a0mil", "\u00a0M", "\u00a0mil M", "\u00a0B"]
}
diff --git a/locale/fr-FR.json b/locale/fr-FR.json
index e0cf89d..151c02d 100644
--- a/locale/fr-FR.json
+++ b/locale/fr-FR.json
@@ -3,5 +3,6 @@
"thousands": "\u00a0",
"grouping": [3],
"currency": ["", "\u00a0€"],
- "percent": "\u202f%"
+ "percent": "\u202f%",
+ "currencyAbbreviations": ["", "\u00a0k", "\u00a0M", "\u00a0Md", "\u00a0Bn"]
}
diff --git a/locale/it-IT.json b/locale/it-IT.json
index 564ed46..202322a 100644
--- a/locale/it-IT.json
+++ b/locale/it-IT.json
@@ -2,5 +2,6 @@
"decimal": ",",
"thousands": ".",
"grouping": [3],
- "currency": ["€", ""]
+ "currency": ["€", ""],
+ "currencyAbbreviations": ["", "", "\u00a0Mio", "\u00a0Mrd", "\u00a0Bln"]
}
diff --git a/locale/nl-NL.json b/locale/nl-NL.json
index 7176b37..78ab0ab 100644
--- a/locale/nl-NL.json
+++ b/locale/nl-NL.json
@@ -2,5 +2,6 @@
"decimal": ",",
"thousands": ".",
"grouping": [3],
- "currency": ["€\u00a0", ""]
+ "currency": ["€\u00a0", ""],
+ "currencyAbbreviations": ["", "K", "\u00a0mln.", "\u00a0mld.", "\u00a0bln."]
}
diff --git a/src/currencyPrecisionPrefix.js b/src/currencyPrecisionPrefix.js
new file mode 100644
index 0000000..e4cb9c5
--- /dev/null
+++ b/src/currencyPrecisionPrefix.js
@@ -0,0 +1,3 @@
+import { createPrecisionPrefix } from "./precisionPrefix.js";
+
+export default createPrecisionPrefix(0, 4);
diff --git a/src/defaultLocale.js b/src/defaultLocale.js
index 9ecf0fa..200725b 100644
--- a/src/defaultLocale.js
+++ b/src/defaultLocale.js
@@ -2,6 +2,7 @@ import formatLocale from "./locale.js";
var locale;
export var format;
+export var formatCurrencyPrefix;
export var formatPrefix;
defaultLocale({
@@ -15,6 +16,7 @@ defaultLocale({
export default function defaultLocale(definition) {
locale = formatLocale(definition);
format = locale.format;
+ formatCurrencyPrefix = locale.formatCurrencyPrefix;
formatPrefix = locale.formatPrefix;
return locale;
}
diff --git a/src/formatPrefixAuto.js b/src/formatPrefixAuto.js
index c7ef7be..d11bce8 100644
--- a/src/formatPrefixAuto.js
+++ b/src/formatPrefixAuto.js
@@ -2,15 +2,25 @@ import formatDecimal from "./formatDecimal.js";
export var prefixExponent;
-export default function(x, p) {
+function formatSignificantDigitsForPrefixes(x, p, minPrefixOrder, maxPrefixOrder) {
var d = formatDecimal(x, p);
if (!d) return x + "";
var coefficient = d[0],
exponent = d[1],
- i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
+ i = exponent - (prefixExponent = Math.max(minPrefixOrder, Math.min(maxPrefixOrder, Math.floor(exponent / 3))) * 3) + 1,
n = coefficient.length;
return i === n ? coefficient
: i > n ? coefficient + new Array(i - n + 1).join("0")
: i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
- : "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y!
+ : "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than the smallest prefix
+}
+
+export function createFormatCurrencyPrefixAutoForLocale(currencyAbbreviations) {
+ return function formatCurrencyPrefixAuto(x, p) {
+ return formatSignificantDigitsForPrefixes(x, p, 0, currencyAbbreviations.length - 1);
+ }
+}
+
+export default function(x, p) {
+ return formatSignificantDigitsForPrefixes(x, p, -8, 8);
}
diff --git a/src/formatTypes.js b/src/formatTypes.js
index c0efa50..a37d03e 100644
--- a/src/formatTypes.js
+++ b/src/formatTypes.js
@@ -1,5 +1,5 @@
import formatBinaryPrefixAuto from "./formatBinaryPrefixAuto.js";
-import formatPrefixAuto from "./formatPrefixAuto.js";
+import formatPrefixAuto, { createFormatCurrencyPrefixAutoForLocale } from "./formatPrefixAuto.js";
import formatRounded from "./formatRounded.js";
export default {
@@ -11,6 +11,7 @@ export default {
"e": function(x, p) { return x.toExponential(p); },
"f": function(x, p) { return x.toFixed(p); },
"g": function(x, p) { return x.toPrecision(p); },
+ "K": createFormatCurrencyPrefixAutoForLocale, // depends of the current locale
"o": function(x) { return Math.round(x).toString(8); },
"p": function(x, p) { return formatRounded(x * 100, p); },
"r": formatRounded,
diff --git a/src/index.js b/src/index.js
index 22ae6b2..5baab41 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,4 +1,5 @@
-export {default as formatDefaultLocale, format, formatPrefix} from "./defaultLocale.js";
+export {default as currencyPrecisionPrefix} from "./currencyPrecisionPrefix.js";
+export { default as formatDefaultLocale, format, formatCurrencyPrefix, formatPrefix} from "./defaultLocale.js";
export {default as formatLocale} from "./locale.js";
export {default as formatSpecifier, FormatSpecifier} from "./formatSpecifier.js";
export {default as precisionFixed} from "./precisionFixed.js";
diff --git a/src/locale.js b/src/locale.js
index 30513ab..68c42d3 100644
--- a/src/locale.js
+++ b/src/locale.js
@@ -9,11 +9,13 @@ import {binaryPrefixExponent} from "./formatBinaryPrefixAuto.js";
import identity from "./identity.js";
var map = Array.prototype.map,
- prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],
- binaryPrefixes = ["", "Ki","Mi","Gi","Ti","Pi","Ei","Zi","Yi"];
+ SIprefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],
+ binaryPrefixes = ["", "Ki","Mi","Gi","Ti","Pi","Ei","Zi","Yi"],
+ defaultCurrencyAbbreviations = ["", "K", "M", "B", "T"];
export default function(locale) {
var group = locale.grouping === undefined || locale.thousands === undefined ? identity : formatGroup(map.call(locale.grouping, Number), locale.thousands + ""),
+ currencyAbbreviations = locale.currencyAbbreviations === undefined ? defaultCurrencyAbbreviations : locale.currencyAbbreviations,
currencyPrefix = locale.currency === undefined ? "" : locale.currency[0] + "",
currencySuffix = locale.currency === undefined ? "" : locale.currency[1] + "",
decimal = locale.decimal === undefined ? "." : locale.decimal + "",
@@ -54,14 +56,18 @@ export default function(locale) {
// Is this an integer type?
// Can this type generate exponential notation?
var formatType = formatTypes[type],
- maybeSuffix = /[Bdefgprs%]/.test(type);
+ maybeSuffix = /[BdefgKprs%]/.test(type);
+
+ if (type === 'K')
+ formatType = formatType(currencyAbbreviations);
// Set the default precision if not specified,
// or clamp the specified precision to the supported range.
// For significant precision, it must be in [1, 21].
// For fixed precision, it must be in [0, 20].
- precision = precision === undefined ? 6
- : /[Bgprs]/.test(type) ? Math.max(1, Math.min(21, precision))
+ // For financial type, default precision is 3 significant digits instead of 6.
+ precision = precision === undefined ? (type === "K" ? 3 : 6)
+ : /[BgKprs]/.test(type) ? Math.max(1, Math.min(21, precision))
: Math.max(0, Math.min(20, precision));
function format(value) {
@@ -89,11 +95,19 @@ export default function(locale) {
// Compute the prefix and suffix.
valuePrefix = (valueNegative ? (sign === "(" ? sign : minus) : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
- valueSuffix = (
- type === "s" ? prefixes[8 + prefixExponent / 3]
- : type === "B" ? binaryPrefixes[binaryPrefixExponent / 10]
- : ""
- ) + valueSuffix + (valueNegative && sign === "(" ? ")" : "");
+
+ switch (type) {
+ case "s":
+ valueSuffix = SIprefixes[8 + prefixExponent / 3] + valueSuffix;
+ break;
+ case "K":
+ valueSuffix = currencyAbbreviations[prefixExponent / 3] + valueSuffix;
+ break;
+ case "B":
+ valueSuffix = binaryPrefixes[binaryPrefixExponent / 10] + valueSuffix;
+ break;
+ }
+ valueSuffix += valueNegative && sign === "(" ? ")" : "";
// Break the formatted value into the integer “value” part that can be
// grouped, and fractional or exponential “suffix” part that is not.
@@ -137,18 +151,24 @@ export default function(locale) {
return format;
}
- function formatPrefix(specifier, value) {
- var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
- e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
+ function createFormatPrefix(prefixes, minimumPrefixOrder, maximumPrefixOrder) {
+ return function(specifier, value) {
+ var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
+ e = Math.max(minimumPrefixOrder, Math.min(maximumPrefixOrder, Math.floor(exponent(value) / 3))) * 3,
k = Math.pow(10, -e),
- prefix = prefixes[8 + e / 3];
- return function(value) {
- return f(k * value) + prefix;
- };
+ prefix = prefixes[(-1 * minimumPrefixOrder) + e / 3];
+ return function (value) {
+ return f(k * value) + prefix;
+ };
+ }
}
+ var formatPrefix = createFormatPrefix(SIprefixes, -8, 8);
+ var formatCurrencyPrefix = createFormatPrefix(currencyAbbreviations, 0, currencyAbbreviations.length - 1);
+
return {
format: newFormat,
+ formatCurrencyPrefix: formatCurrencyPrefix,
formatPrefix: formatPrefix
};
}
diff --git a/src/precisionPrefix.js b/src/precisionPrefix.js
index fd6af84..3e2e28e 100644
--- a/src/precisionPrefix.js
+++ b/src/precisionPrefix.js
@@ -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);
diff --git a/test/currencyPrecisionPrefix-test.js b/test/currencyPrecisionPrefix-test.js
new file mode 100644
index 0000000..49aed8e
--- /dev/null
+++ b/test/currencyPrecisionPrefix-test.js
@@ -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();
+});
+
diff --git a/test/format-type-K-test.js b/test/format-type-K-test.js
new file mode 100644
index 0000000..ed5c1ab
--- /dev/null
+++ b/test/format-type-K-test.js
@@ -0,0 +1,91 @@
+var tape = require("tape"),
+ format = require("../dist/d3-format");
+
+tape("format(\"K\") outputs currency prefix notation with default 3 significant digits", function(test) {
+ var f = format.format("K");
+ test.equal(f(0), "0.00");
+ test.equal(f(0.2), "0.20");
+ test.equal(f(1), "1.00");
+ test.equal(f(10), "10.0");
+ test.equal(f(100), "100");
+ test.equal(f(1000), "1.00K");
+ test.end();
+});
+
+tape("format(\"[.precision]K\") outputs currency-prefix notation with precision significant digits", function(test) {
+ var f1 = format.format(".2K");
+ test.equal(f1(0), "0.0");
+ test.equal(f1(1), "1.0");
+ test.equal(f1(10), "10");
+ test.equal(f1(100), "100");
+ test.equal(f1(999.5), "1.0K");
+ test.equal(f1(999500), "1.0M");
+ test.equal(f1(1000), "1.0K");
+ test.equal(f1(1500.5), "1.5K");
+ test.equal(f1(145500000), "150M");
+ test.equal(f1(145999999.999999347), "150M");
+ test.equal(f1(1e17), "100000T");
+ test.equal(f1(.000001), "0.000001");
+ var f2 = format.format(".4K");
+ test.equal(f2(999.5), "999.5");
+ test.equal(f2(999500), "999.5K");
+ test.end();
+});
+
+tape("format(\"K\") formats numbers smaller than 1", function(test) {
+ var f = format.format(".2K");
+ test.equal(f(1.29e-2), "0.0129");
+ test.equal(f(1.29e-3), "0.00129");
+ test.equal(f(-1.29e-2), "-0.0129");
+ test.equal(f(-1.29e-3), "-0.00129");
+ test.end();
+});
+
+tape("format(\"K\") formats numbers larger than thousands of trillions", function(test) {
+ var f = format.format(".2K");
+ test.equal(f(1.23e+15), "1200T");
+ test.equal(f(1.23e+16), "12000T");
+ test.equal(f(-1.23e+15), "-1200T");
+ test.equal(f(-1.23e+16), "-12000T");
+ test.end();
+});
+
+tape("format(\"$K\") outputs currency-prefix notation with a currency symbol", function(test) {
+ var f1 = format.format("$.2K");
+ test.equal(f1(0), "$0.0");
+ test.equal(f1(2.5e5), "$250K");
+ test.equal(f1(-2.5e8), "-$250M");
+ test.equal(f1(2.5e11), "$250B");
+ var f2 = format.format("$.3K");
+ test.equal(f2(0), "$0.00");
+ test.equal(f2(1), "$1.00");
+ test.equal(f2(10), "$10.0");
+ test.equal(f2(100), "$100");
+ test.equal(f2(999.5), "$1.00K");
+ test.equal(f2(999500), "$1.00M");
+ test.equal(f2(1000), "$1.00K");
+ test.equal(f2(1500.5), "$1.50K");
+ test.equal(f2(145500000), "$146M");
+ test.equal(f2(145999999.999999347), "$146M");
+ test.equal(f2(1e18), "$1000000T");
+ test.equal(f2(.000001), "$0.000001");
+ test.equal(f2(.009995), "$0.01");
+ var f3 = format.format("$.4K");
+ test.equal(f3(999.5), "$999.5");
+ test.equal(f3(999500), "$999.5K");
+ test.equal(f3(.009995), "$0.001");
+ test.end();
+});
+
+tape("format(\"0[width],K\") will group thousands due to zero fill", function(test) {
+ var f = format.format("015,K");
+ test.equal(f(42), "0,000,000,042.0");
+ test.equal(f(42e12), "0,000,000,042.0T");
+ test.end();
+});
+
+tape("format(\",K\") will group thousands for very large numbers", function(test) {
+ var f = format.format(",K");
+ test.equal(f(42e30), "42,000,000,000,000,000,000T");
+ test.end();
+});
diff --git a/test/formatCurrencyPrefix-test.js b/test/formatCurrencyPrefix-test.js
new file mode 100644
index 0000000..23fa7b4
--- /dev/null
+++ b/test/formatCurrencyPrefix-test.js
@@ -0,0 +1,48 @@
+var tape = require("tape"),
+ format = require("../dist/d3-format");
+
+tape("formatCurrencyPrefix(\"K\", value)(number) formats with the thousands prefix if appropriate to the specified value", function(test) {
+ test.equal(format.formatCurrencyPrefix(",.0K", 1e3)(42000), "42K");
+ test.equal(format.formatCurrencyPrefix(",.0K", 1e3)(420000), "420K");
+ test.equal(format.formatCurrencyPrefix(",.3K", 1e3)(420), "0.420K");
+ test.end();
+});
+
+tape("formatCurrencyPrefix(\"K\", value)(number) formats with the millions prefix if appropriate to the specified value", function(test) {
+ test.equal(format.formatCurrencyPrefix(",.0K", 1e6)(42000000), "42M");
+ test.equal(format.formatCurrencyPrefix(",.0K", 1e6)(420000000), "420M");
+ test.equal(format.formatCurrencyPrefix(",.3K", 1e6)(420000), "0.420M");
+ test.end();
+});
+
+tape("formatCurrencyPrefix(\"K\", value)(number) formats with the billions prefix if appropriate to the specified value", function(test) {
+ test.equal(format.formatCurrencyPrefix(",.0K", 1e9)(42 * 1e9), "42B");
+ test.equal(format.formatCurrencyPrefix(",.0K", 1e9)(420 * 1e9), "420B");
+ test.equal(format.formatCurrencyPrefix(",.3K", 1e9)(420 * 1e6), "0.420B");
+ test.end();
+});
+
+tape("formatCurrencyPrefix(\"K\", value)(number) formats with the trillions prefix if appropriate to the specified value", function(test) {
+ test.equal(format.formatCurrencyPrefix(",.0K", 1e12)(42 * 1e12), "42T");
+ test.equal(format.formatCurrencyPrefix(",.0K", 1e12)(420 * 1e12), "420T");
+ test.equal(format.formatCurrencyPrefix(",.3K", 1e12)(420 * 1e9), "0.420T");
+ test.end();
+});
+
+
+tape("formatCurrencyPrefix(\"K\", value)(number) uses nothing for very small reference values", function(test) {
+ test.equal(format.formatCurrencyPrefix(",.3K", 1e-3)(0.1), "0.100");
+ test.end();
+});
+
+tape("formatCurrencyPrefix(\"K\", value)(number) uses trillions for very large reference values", function(test) {
+ test.equal(format.formatCurrencyPrefix(",.0K", 1e15)(1e15), "1,000T");
+ test.end();
+});
+
+tape("formatCurrencyPrefix(\"$,K\", value)(number) formats with the associated currency", function(test) {
+ var f = format.formatCurrencyPrefix(" $12,.1K", 1e9);
+ test.equal(f(-42e9), " -$42.0B");
+ test.equal(f(+4.2e9), " $4.2B");
+ test.end();
+});
diff --git a/test/locale-test.js b/test/locale-test.js
index 394811d..dc3716c 100644
--- a/test/locale-test.js
+++ b/test/locale-test.js
@@ -21,6 +21,16 @@ tape("formatLocale({currency: [prefix, suffix]}) places the currency suffix afte
test.end();
});
+tape("formatLocale({currencyAbbreviations: [list of abbreviations]}) should abbreviate thousands, millions, billions and trillions", function (test) {
+ test.equal(d3.formatLocale({ currencyAbbreviations: ["", "\u00a0k", "\u00a0M", "\u00a0Md", "\u00a0Bn"] }).format("$.3K")(1.2e9), "1.20\u00a0Md");
+ test.end();
+});
+
+tape("formatLocale({currencyAbbreviations: [list of abbreviations]}) should abbreviate only specified levels", function (test) {
+ test.equal(d3.formatLocale({ currencyAbbreviations: ["", "\u00a0k", "\u00a0M", "\u00a0Md", "\u00a0Bn"] }).format("$.3K")(1.2e15), "1200\u00a0Bn");
+ test.end();
+});
+
tape("formatLocale({grouping: undefined}) does not perform any grouping", function(test) {
test.equal(d3.formatLocale({decimal: "."}).format("012,.2f")(2), "000000002.00");
test.end();