|
1 // TODO align |
|
2 d3.format = function(specifier) { |
|
3 var match = d3_format_re.exec(specifier), |
|
4 fill = match[1] || " ", |
|
5 sign = match[3] || "", |
|
6 zfill = match[5], |
|
7 width = +match[6], |
|
8 comma = match[7], |
|
9 precision = match[8], |
|
10 type = match[9], |
|
11 scale = 1, |
|
12 suffix = "", |
|
13 integer = false; |
|
14 |
|
15 if (precision) precision = +precision.substring(1); |
|
16 |
|
17 if (zfill) { |
|
18 fill = "0"; // TODO align = "="; |
|
19 if (comma) width -= Math.floor((width - 1) / 4); |
|
20 } |
|
21 |
|
22 switch (type) { |
|
23 case "n": comma = true; type = "g"; break; |
|
24 case "%": scale = 100; suffix = "%"; type = "f"; break; |
|
25 case "p": scale = 100; suffix = "%"; type = "r"; break; |
|
26 case "d": integer = true; precision = 0; break; |
|
27 case "s": scale = -1; type = "r"; break; |
|
28 } |
|
29 |
|
30 // If no precision is specified for r, fallback to general notation. |
|
31 if (type == "r" && !precision) type = "g"; |
|
32 |
|
33 type = d3_format_types[type] || d3_format_typeDefault; |
|
34 |
|
35 return function(value) { |
|
36 |
|
37 // Return the empty string for floats formatted as ints. |
|
38 if (integer && (value % 1)) return ""; |
|
39 |
|
40 // Convert negative to positive, and record the sign prefix. |
|
41 var negative = (value < 0) && (value = -value) ? "\u2212" : sign; |
|
42 |
|
43 // Apply the scale, computing it from the value's exponent for si format. |
|
44 if (scale < 0) { |
|
45 var prefix = d3.formatPrefix(value, precision); |
|
46 value *= prefix.scale; |
|
47 suffix = prefix.symbol; |
|
48 } else { |
|
49 value *= scale; |
|
50 } |
|
51 |
|
52 // Convert to the desired precision. |
|
53 value = type(value, precision); |
|
54 |
|
55 // If the fill character is 0, the sign and group is applied after the fill. |
|
56 if (zfill) { |
|
57 var length = value.length + negative.length; |
|
58 if (length < width) value = new Array(width - length + 1).join(fill) + value; |
|
59 if (comma) value = d3_format_group(value); |
|
60 value = negative + value; |
|
61 } |
|
62 |
|
63 // Otherwise (e.g., space-filling), the sign and group is applied before. |
|
64 else { |
|
65 if (comma) value = d3_format_group(value); |
|
66 value = negative + value; |
|
67 var length = value.length; |
|
68 if (length < width) value = new Array(width - length + 1).join(fill) + value; |
|
69 } |
|
70 |
|
71 return value + suffix; |
|
72 }; |
|
73 }; |
|
74 |
|
75 // [[fill]align][sign][#][0][width][,][.precision][type] |
|
76 var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/; |
|
77 |
|
78 var d3_format_types = { |
|
79 g: function(x, p) { return x.toPrecision(p); }, |
|
80 e: function(x, p) { return x.toExponential(p); }, |
|
81 f: function(x, p) { return x.toFixed(p); }, |
|
82 r: function(x, p) { return d3.round(x, p = d3_format_precision(x, p)).toFixed(Math.max(0, Math.min(20, p))); } |
|
83 }; |
|
84 |
|
85 function d3_format_precision(x, p) { |
|
86 return p - (x ? 1 + Math.floor(Math.log(x + Math.pow(10, 1 + Math.floor(Math.log(x) / Math.LN10) - p)) / Math.LN10) : 1); |
|
87 } |
|
88 |
|
89 function d3_format_typeDefault(x) { |
|
90 return x + ""; |
|
91 } |
|
92 |
|
93 // Apply comma grouping for thousands. |
|
94 function d3_format_group(value) { |
|
95 var i = value.lastIndexOf("."), |
|
96 f = i >= 0 ? value.substring(i) : (i = value.length, ""), |
|
97 t = []; |
|
98 while (i > 0) t.push(value.substring(i -= 3, i + 3)); |
|
99 return t.reverse().join(",") + f; |
|
100 } |