Automatic precision for custom tick formats.
You can now pass a format specifier to scale.tickFormat (for linear, pow and identity scales). If the format specifier doesn't have a defined precision, the precision will be set automatically by the scale, returning the appropriate format. This provides a convenient, declarative way of specifying a format whose precision will be automatically set by the scale. This works with axes, too! For example, `axis.ticks(10, "%")` will now use a percentage format rather than the default format, while still computing the appropriate precision. This commit also includes a fix to make d3.format more robust when unreasonable precisions are specified. Rather than throwing an error, the nearest reasonable value is used instead. Fixes #912.
This commit is contained in:
Родитель
a82fa305bc
Коммит
d0441e6170
|
@ -638,6 +638,9 @@ d3 = function() {
|
|||
}
|
||||
if (basePrefix === "#") basePrefix = "";
|
||||
if (type == "r" && !precision) type = "g";
|
||||
if (precision != null) {
|
||||
if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision));
|
||||
}
|
||||
type = d3_format_types.get(type) || d3_format_typeDefault;
|
||||
var zcomma = zfill && comma;
|
||||
return function(value) {
|
||||
|
@ -659,7 +662,7 @@ d3 = function() {
|
|||
return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + suffix;
|
||||
};
|
||||
};
|
||||
var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/;
|
||||
var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;
|
||||
var d3_format_types = d3.map({
|
||||
b: function(x) {
|
||||
return x.toString(2);
|
||||
|
@ -2447,8 +2450,8 @@ d3 = function() {
|
|||
scale.ticks = function(m) {
|
||||
return d3_scale_linearTicks(domain, m);
|
||||
};
|
||||
scale.tickFormat = function(m) {
|
||||
return d3_scale_linearTickFormat(domain, m);
|
||||
scale.tickFormat = function(m, format) {
|
||||
return d3_scale_linearTickFormat(domain, m, format);
|
||||
};
|
||||
scale.nice = function() {
|
||||
d3_scale_nice(domain, d3_scale_linearNice);
|
||||
|
@ -2484,8 +2487,11 @@ d3 = function() {
|
|||
function d3_scale_linearTicks(domain, m) {
|
||||
return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
|
||||
}
|
||||
function d3_scale_linearTickFormat(domain, m) {
|
||||
return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f");
|
||||
function d3_scale_linearTickFormat(domain, m, format) {
|
||||
var precision = -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01);
|
||||
return d3.format(format ? format.replace(d3_format_re, function(a, b, c, d, e, f, g, h, i, j) {
|
||||
return [ b, c, d, e, f, g, h, i || "." + (precision - (j === "%") * 2), j ].join("");
|
||||
}) : ",." + precision + "f");
|
||||
}
|
||||
function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
|
||||
var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]);
|
||||
|
@ -2611,8 +2617,8 @@ d3 = function() {
|
|||
scale.ticks = function(m) {
|
||||
return d3_scale_linearTicks(scale.domain(), m);
|
||||
};
|
||||
scale.tickFormat = function(m) {
|
||||
return d3_scale_linearTickFormat(scale.domain(), m);
|
||||
scale.tickFormat = function(m, format) {
|
||||
return d3_scale_linearTickFormat(scale.domain(), m, format);
|
||||
};
|
||||
scale.nice = function() {
|
||||
return scale.domain(d3_scale_nice(scale.domain(), d3_scale_linearNice));
|
||||
|
@ -2837,8 +2843,8 @@ d3 = function() {
|
|||
identity.ticks = function(m) {
|
||||
return d3_scale_linearTicks(domain, m);
|
||||
};
|
||||
identity.tickFormat = function(m) {
|
||||
return d3_scale_linearTickFormat(domain, m);
|
||||
identity.tickFormat = function(m, format) {
|
||||
return d3_scale_linearTickFormat(domain, m, format);
|
||||
};
|
||||
identity.copy = function() {
|
||||
return d3_scale_identity(domain);
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -39,6 +39,12 @@ d3.format = function(specifier) {
|
|||
// If no precision is specified for r, fallback to general notation.
|
||||
if (type == "r" && !precision) type = "g";
|
||||
|
||||
// Ensure that the requested precision is in the supported range.
|
||||
if (precision != null) {
|
||||
if (type == "g") precision = Math.max(1, Math.min(21, precision));
|
||||
else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision));
|
||||
}
|
||||
|
||||
type = d3_format_types.get(type) || d3_format_typeDefault;
|
||||
|
||||
var zcomma = zfill && comma;
|
||||
|
@ -84,7 +90,7 @@ d3.format = function(specifier) {
|
|||
};
|
||||
|
||||
// [[fill]align][sign][#][0][width][,][.precision][type]
|
||||
var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/;
|
||||
var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;
|
||||
|
||||
var d3_format_types = d3.map({
|
||||
b: function(x) { return x.toString(2); },
|
||||
|
|
|
@ -18,8 +18,8 @@ function d3_scale_identity(domain) {
|
|||
return d3_scale_linearTicks(domain, m);
|
||||
};
|
||||
|
||||
identity.tickFormat = function(m) {
|
||||
return d3_scale_linearTickFormat(domain, m);
|
||||
identity.tickFormat = function(m, format) {
|
||||
return d3_scale_linearTickFormat(domain, m, format);
|
||||
};
|
||||
|
||||
identity.copy = function() {
|
||||
|
|
|
@ -55,8 +55,8 @@ function d3_scale_linear(domain, range, interpolate, clamp) {
|
|||
return d3_scale_linearTicks(domain, m);
|
||||
};
|
||||
|
||||
scale.tickFormat = function(m) {
|
||||
return d3_scale_linearTickFormat(domain, m);
|
||||
scale.tickFormat = function(m, format) {
|
||||
return d3_scale_linearTickFormat(domain, m, format);
|
||||
};
|
||||
|
||||
scale.nice = function() {
|
||||
|
@ -105,6 +105,9 @@ function d3_scale_linearTicks(domain, m) {
|
|||
return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
|
||||
}
|
||||
|
||||
function d3_scale_linearTickFormat(domain, m) {
|
||||
return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f");
|
||||
function d3_scale_linearTickFormat(domain, m, format) {
|
||||
var precision = -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01);
|
||||
return d3.format(format
|
||||
? format.replace(d3_format_re, function(a, b, c, d, e, f, g, h, i, j) { return [b, c, d, e, f, g, h, i || "." + (precision - (j === "%") * 2), j].join(""); })
|
||||
: ",." + precision + "f");
|
||||
}
|
||||
|
|
|
@ -24,8 +24,8 @@ function d3_scale_pow(linear, exponent) {
|
|||
return d3_scale_linearTicks(scale.domain(), m);
|
||||
};
|
||||
|
||||
scale.tickFormat = function(m) {
|
||||
return d3_scale_linearTickFormat(scale.domain(), m);
|
||||
scale.tickFormat = function(m, format) {
|
||||
return d3_scale_linearTickFormat(scale.domain(), m, format);
|
||||
};
|
||||
|
||||
scale.nice = function() {
|
||||
|
|
|
@ -325,6 +325,12 @@ suite.addBatch({
|
|||
assert.strictEqual(f(-42), "-42");
|
||||
assert.strictEqual(f(-4200000), "-4,200,000");
|
||||
assert.strictEqual(f(-42000000), "-42,000,000");
|
||||
},
|
||||
"unreasonable precision values are clamped to reasonable values": function(format) {
|
||||
assert.strictEqual(format(".30f")(0), "0.00000000000000000000");
|
||||
assert.strictEqual(format(".0g")(1), "1");
|
||||
assert.strictEqual(format(",.-1f")(12345), "12,345");
|
||||
assert.strictEqual(format("+,.-1%")(123.45), "+12,345%");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -207,19 +207,19 @@ suite.addBatch({
|
|||
assert.equal(t.length, 2);
|
||||
},
|
||||
"passes any arguments to the scale's ticks function": function(axis) {
|
||||
var x = d3.scale.linear(), b = {}, a = axis().ticks(b, 42).scale(x), aa = [],
|
||||
var x = d3.scale.linear(), b = {}, a = axis().ticks(b, "%").scale(x), aa = [],
|
||||
g = d3.select("body").html("").append("svg:g");
|
||||
x.ticks = function() { aa.push(arguments); return [42]; };
|
||||
g.call(a);
|
||||
assert.equal(aa.length, 1);
|
||||
assert.equal(aa[0].length, 2);
|
||||
assert.equal(aa[0][0], b);
|
||||
assert.equal(aa[0][1], 42);
|
||||
assert.equal(aa[0][1], "%");
|
||||
},
|
||||
"passes any arguments to the scale's tickFormat function": function(axis) {
|
||||
var b = {},
|
||||
x = d3.scale.linear(),
|
||||
a = axis().scale(x).ticks(b, 42),
|
||||
a = axis().scale(x).ticks(b, "%"),
|
||||
g = d3.select("body").html("").append("svg:g"),
|
||||
aa = [];
|
||||
|
||||
|
@ -232,13 +232,21 @@ suite.addBatch({
|
|||
assert.equal(aa.length, 1);
|
||||
assert.equal(aa[0].length, 2);
|
||||
assert.equal(aa[0][0], b);
|
||||
assert.equal(aa[0][1], 42);
|
||||
assert.equal(aa[0][1], "%");
|
||||
},
|
||||
"affects the generated ticks": function(axis) {
|
||||
var a = axis().ticks(20),
|
||||
var a = axis().ticks(20, "%"),
|
||||
g = d3.select("body").html("").append("svg:g").call(a),
|
||||
t = g.selectAll("g");
|
||||
assert.equal(t[0].length, 21);
|
||||
assert.equal(t[0][0].textContent, "0%");
|
||||
},
|
||||
"only substitutes precision if not specified": function(axis) {
|
||||
var a = axis().ticks(20, ".5%"),
|
||||
g = d3.select("body").html("").append("svg:g").call(a),
|
||||
t = g.selectAll("g");
|
||||
assert.equal(t[0].length, 21);
|
||||
assert.equal(t[0][0].textContent, "0.00000%");
|
||||
}
|
||||
},
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче