From 19589a3e31349a44e0f6e0971ef25c4ca1e39790 Mon Sep 17 00:00:00 2001 From: Dan Vanderkam Date: Sun, 24 Apr 2011 01:16:32 -0400 Subject: [PATCH] add back Dygraph.floatFormat --- dygraph.js | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/dygraph.js b/dygraph.js index 377e830..698d8da 100644 --- a/dygraph.js +++ b/dygraph.js @@ -103,6 +103,7 @@ Dygraph.DEFAULT_ATTRS = { yValueFormatter: function(a,b) { return Dygraph.numberFormatter(a,b); }, digitsAfterDecimal: 2, maxNumberWidth: 6, + sigFigs: null, strokeWidth: 1.0, @@ -1792,8 +1793,46 @@ Dygraph.prototype.getSelection = function() { return -1; }; -Dygraph.zeropad = function(x) { - if (x < 10) return "0" + x; else return "" + x; +/** + * Number formatting function which mimicks the behavior of %g in printf, i.e. + * either exponential or fixed format (without trailing 0s) is used depending on + * the length of the generated string. The advantage of this format is that + * there is a predictable upper bound on the resulting string length, + * significant figures are not dropped, and normal numbers are not displayed in + * exponential notation. + * + * NOTE: JavaScript's native toPrecision() is NOT a drop-in replacement for %g. + * It creates strings which are too long for absolute values between 10^-4 and + * 10^-6, e.g. '0.00001' instead of '1e-5'. See tests/number-format.html for + * output examples. + * + * @param {Number} x The number to format + * @param {Number} opt_precision The precision to use, default 2. + * @return {String} A string formatted like %g in printf. The max generated + * string length should be precision + 6 (e.g 1.123e+300). + */ +Dygraph.floatFormat = function(x, opt_precision) { + // Avoid invalid precision values; [1, 21] is the valid range. + var p = Math.min(Math.max(1, opt_precision || 2), 21); + + // This is deceptively simple. The actual algorithm comes from: + // + // Max allowed length = p + 4 + // where 4 comes from 'e+n' and '.'. + // + // Length of fixed format = 2 + y + p + // where 2 comes from '0.' and y = # of leading zeroes. + // + // Equating the two and solving for y yields y = 2, or 0.00xxxx which is + // 1.0e-3. + // + // Since the behavior of toPrecision() is identical for larger numbers, we + // don't have to worry about the other bound. + // + // Finally, the argument for toExponential() is the number of trailing digits, + // so we take off 1 for the value before the '.'. + return (Math.abs(x) < 1.0e-3 && x != 0.0) ? + x.toExponential(p - 1) : x.toPrecision(p); }; /** @@ -1803,17 +1842,30 @@ Dygraph.zeropad = function(x) { * @param {Dygraph} g The dygraph object */ Dygraph.numberFormatter = function(x, g) { + var sigFigs = g.attr_('sigFigs'); + + if (sigFigs !== null) { + // User has opted for a fixed number of significant figures. + return Dygraph.floatFormat(x, sigFigs); + } + var digits = g.attr_('digitsAfterDecimal'); var maxNumberWidth = g.attr_('maxNumberWidth'); - if (Math.abs(x) >= Math.pow(10, maxNumberWidth) || - Math.abs(x) < Math.pow(10, -digits)) { - // switch to scientific notation. + // switch to scientific notation if we underflow or overflow fixed display. + if (x !== 0.0 && + (Math.abs(x) >= Math.pow(10, maxNumberWidth) || + Math.abs(x) < Math.pow(10, -digits))) { + return x.toExponential(digits); } else { return '' + Dygraph.round_(x, digits); } }; +Dygraph.zeropad = function(x) { + if (x < 10) return "0" + x; else return "" + x; +}; + /** * Return a string version of the hours, minutes and seconds portion of a date. * @param {Number} date The JavaScript date (ms since epoch) -- 2.7.4