From ac9324c4eaf26a852b74f9522259726506c87959 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sun, 14 Jun 2015 17:49:55 -0700 Subject: [PATCH] formatPrefix takes a value, not a prefix. --- README.md | 8 ++++---- src/localeFormat.js | 7 ++++--- test/formatPrefix-test.js | 21 +++++++++++++-------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index bc9534c..bcab0ed 100644 --- a/README.md +++ b/README.md @@ -122,9 +122,9 @@ The available *type* values are: The type `n` is also supported as shorthand for `,g`. -# locale.formatPrefix(specifier, prefix) +# locale.formatPrefix(specifier, value) -Equivalent to [*locale*.format](#locale_format), except the returned function will convert values to the units of the specified SI *prefix* before formatting in fixed point notation. The following prefixes are supported: +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 *value* before formatting in fixed point notation. The following prefixes are supported: * `y` - yocto, 10⁻²⁴ * `z` - zepto, 10⁻²¹ @@ -144,10 +144,10 @@ Equivalent to [*locale*.format](#locale_format), except the returned function wi * `Z` - zetta, 10²¹ * `Y` - yotta, 10²⁴ -Unlike [*locale*.format](#locale_format) with the `s` format type, this method allows you to specify the SI *prefix* explicitly, rather than computing it dynamically based on the formatted number. In addition, the *precision* for the given *specifier* represents the number of digits past the decimal point (as with `f` fixed point notation), not the number of significant digits. For example: +Unlike [*locale*.format](#locale_format) with the `s` format type, this method returns a formatter with a consistent SI prefix, rather than computing the prefix dynamically for each number. In addition, the *precision* for the given *specifier* represents the number of digits past the decimal point (as with `f` fixed point notation), not the number of significant digits. For example: ```js -var f = formatPrefix(",.0", "µ"); +var f = formatPrefix(",.0", 1e-6); f(.00042); // "420µ" f(.0042); // "4,200µ" ``` diff --git a/src/localeFormat.js b/src/localeFormat.js index 6ced9de..0de6d5c 100644 --- a/src/localeFormat.js +++ b/src/localeFormat.js @@ -100,10 +100,11 @@ export default function(locale) { }; } - function formatPrefix(specifier, prefix) { + function formatPrefix(specifier, value) { var f = format((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)), - i = prefixes.indexOf(prefix), - k = Math.pow(10, (i < 0 ? (prefix = "", 0) : 8 - i) * 3); + i = Math.max(-8, Math.min(8, Math.floor((Math.log(value) / (Math.LN10 * 3) + 1e-12)))), + k = Math.pow(10, -i * 3), + prefix = prefixes[8 + i]; return function(value) { return f(k * value) + prefix; }; diff --git a/test/formatPrefix-test.js b/test/formatPrefix-test.js index 4a95e1c..e92bc1a 100644 --- a/test/formatPrefix-test.js +++ b/test/formatPrefix-test.js @@ -1,20 +1,25 @@ var tape = require("tape"), format = require("../"); -tape("formatPrefix(\"s\", prefix)(number) formats with the specified SI prefix", function(test) { - test.equal(format.formatPrefix(",.0s", "µ")(.00042), "420µ"); - test.equal(format.formatPrefix(",.0s", "µ")(.0042), "4,200µ"); - test.equal(format.formatPrefix(",.3s", "m")(.00042), "0.420m"); +tape("formatPrefix(\"s\", value)(number) formats with the SI prefix appropriate to the specified value", function(test) { + test.equal(format.formatPrefix(",.0s", 1e-6)(.00042), "420µ"); + test.equal(format.formatPrefix(",.0s", 1e-6)(.0042), "4,200µ"); + test.equal(format.formatPrefix(",.3s", 1e-3)(.00042), "0.420m"); test.end(); }); -tape("formatPrefix(\"s\", prefix)(number) treats unknown SI prefix as the empty string", function(test) { - test.equal(format.formatPrefix(",.0s", "F")(42), "42"); +tape("formatPrefix(\"s\", value)(number) uses yocto for very small reference values", function(test) { + test.equal(format.formatPrefix(",.0s", 1e-27)(1e-24), "1y"); test.end(); }); -tape("formatPrefix(\"$,s\", prefix)(number) formats with the specified SI prefix", function(test) { - var f = format.formatPrefix(" $12,.1s", "M"); +tape("formatPrefix(\"s\", value)(number) uses yotta for very small reference values", function(test) { + test.equal(format.formatPrefix(",.0s", 1e27)(1e24), "1Y"); + test.end(); +}); + +tape("formatPrefix(\"$,s\", value)(number) formats with the specified SI prefix", function(test) { + var f = format.formatPrefix(" $12,.1s", 1e6); test.equal(f(-42e6), " -$42.0M"); test.equal(f(+4.2e6), " $4.2M"); test.end();