Skip to content

Commit 903fbb0

Browse files
committed
Merge branch 'format-align' of git://github.com/jasondavies/d3 into 3.0
Conflicts: src/core/format.js
2 parents 6d7b742 + 4946a8c commit 903fbb0

4 files changed

Lines changed: 150 additions & 40 deletions

File tree

d3.js

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3412,10 +3412,11 @@
34123412
return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener);
34133413
};
34143414
d3.format = function(specifier) {
3415-
var match = d3_format_re.exec(specifier), fill = match[1] || " ", sign = match[3] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false;
3415+
var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", basePrefix = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false;
34163416
if (precision) precision = +precision.substring(1);
3417-
if (zfill) {
3418-
fill = "0";
3417+
if (zfill || fill === "0" && align === "=") {
3418+
zfill = fill = "0";
3419+
align = "=";
34193420
if (comma) width -= Math.floor((width - 1) / 4);
34203421
}
34213422
switch (type) {
@@ -3433,6 +3434,12 @@
34333434
suffix = "%";
34343435
type = "r";
34353436
break;
3437+
case "b":
3438+
case "o":
3439+
case "x":
3440+
case "X":
3441+
if (basePrefix) basePrefix = "0" + type.toLowerCase();
3442+
case "c":
34363443
case "d":
34373444
integer = true;
34383445
precision = 0;
@@ -3442,11 +3449,13 @@
34423449
type = "r";
34433450
break;
34443451
}
3452+
if (basePrefix === "#") basePrefix = "";
34453453
if (type == "r" && !precision) type = "g";
34463454
type = d3_format_types.get(type) || d3_format_typeDefault;
3455+
var zcomma = zfill && comma;
34473456
return function(value) {
34483457
if (integer && value % 1) return "";
3449-
var negative = value < 0 && (value = -value) ? "-" : sign;
3458+
var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign;
34503459
if (scale < 0) {
34513460
var prefix = d3.formatPrefix(value, precision);
34523461
value = prefix.scale(value);
@@ -3455,22 +3464,30 @@
34553464
value *= scale;
34563465
}
34573466
value = type(value, precision);
3458-
if (zfill) {
3459-
var length = value.length + negative.length;
3460-
if (length < width) value = (new Array(width - length + 1)).join(fill) + value;
3461-
if (comma) value = d3_format_group(value);
3462-
value = negative + value;
3463-
} else {
3464-
if (comma) value = d3_format_group(value);
3465-
value = negative + value;
3466-
var length = value.length;
3467-
if (length < width) value = (new Array(width - length + 1)).join(fill) + value;
3468-
}
3469-
return value.replace(".", d3_format_decimalPoint) + suffix;
3467+
if (!zfill && comma) value = d3_format_group(value);
3468+
var length = basePrefix.length + value.length + (zcomma ? 0 : negative.length), padding = length < width ? (new Array(length = width - length + 1)).join(fill) : "";
3469+
if (zcomma) value = d3_format_group(padding + value);
3470+
negative += basePrefix;
3471+
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;
34703472
};
34713473
};
34723474
var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/;
34733475
var d3_format_types = d3.map({
3476+
b: function(x) {
3477+
return x.toString(2);
3478+
},
3479+
c: function(x) {
3480+
return String.fromCharCode(x);
3481+
},
3482+
o: function(x) {
3483+
return x.toString(8);
3484+
},
3485+
x: function(x) {
3486+
return x.toString(16);
3487+
},
3488+
X: function(x) {
3489+
return x.toString(16).toUpperCase();
3490+
},
34743491
g: function(x, p) {
34753492
return x.toPrecision(p);
34763493
},

d3.min.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/core/format.js

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
// TODO align
21
d3.format = function(specifier) {
32
var match = d3_format_re.exec(specifier),
43
fill = match[1] || " ",
4+
align = match[2] || ">",
55
sign = match[3] || "",
6+
basePrefix = match[4] || "",
67
zfill = match[5],
78
width = +match[6],
89
comma = match[7],
@@ -14,31 +15,41 @@ d3.format = function(specifier) {
1415

1516
if (precision) precision = +precision.substring(1);
1617

17-
if (zfill) {
18-
fill = "0"; // TODO align = "=";
18+
if (zfill || fill === "0" && align === "=") {
19+
zfill = fill = "0";
20+
align = "=";
1921
if (comma) width -= Math.floor((width - 1) / 4);
2022
}
2123

2224
switch (type) {
2325
case "n": comma = true; type = "g"; break;
2426
case "%": scale = 100; suffix = "%"; type = "f"; break;
2527
case "p": scale = 100; suffix = "%"; type = "r"; break;
28+
case "b":
29+
case "o":
30+
case "x":
31+
case "X": if (basePrefix) basePrefix = "0" + type.toLowerCase();
32+
case "c":
2633
case "d": integer = true; precision = 0; break;
2734
case "s": scale = -1; type = "r"; break;
2835
}
2936

37+
if (basePrefix === "#") basePrefix = "";
38+
3039
// If no precision is specified for r, fallback to general notation.
3140
if (type == "r" && !precision) type = "g";
3241

3342
type = d3_format_types.get(type) || d3_format_typeDefault;
3443

44+
var zcomma = zfill && comma;
45+
3546
return function(value) {
3647

3748
// Return the empty string for floats formatted as ints.
3849
if (integer && (value % 1)) return "";
3950

4051
// Convert negative to positive, and record the sign prefix.
41-
var negative = value < 0 && (value = -value) ? "-" : sign;
52+
var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign;
4253

4354
// Apply the scale, computing it from the value's exponent for si format.
4455
if (scale < 0) {
@@ -52,30 +63,27 @@ d3.format = function(specifier) {
5263
// Convert to the desired precision.
5364
value = type(value, precision);
5465

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.replace(".", d3_format_decimalPoint) + suffix;
66+
if (!zfill && comma) value = d3_format_group(value);
67+
var length = basePrefix.length + value.length + (zcomma ? 0 : negative.length),
68+
padding = length < width ? new Array(length = width - length + 1).join(fill) : "";
69+
if (zcomma) value = d3_format_group(padding + value);
70+
negative += basePrefix;
71+
return (align === "<" ? negative + value + padding
72+
: align === ">" ? padding + negative + value
73+
: align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length)
74+
: negative + (zcomma ? value : padding + value)) + suffix;
7275
};
7376
};
7477

7578
// [[fill]align][sign][#][0][width][,][.precision][type]
7679
var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/;
7780

7881
var d3_format_types = d3.map({
82+
b: function(x) { return x.toString(2); },
83+
c: function(x) { return String.fromCharCode(x); },
84+
o: function(x) { return x.toString(8); },
85+
x: function(x) { return x.toString(16); },
86+
X: function(x) { return x.toString(16).toUpperCase(); },
7987
g: function(x, p) { return x.toPrecision(p); },
8088
e: function(x, p) { return x.toExponential(p); },
8189
f: function(x, p) { return x.toFixed(p); },

test/core/format-test.js

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ suite.addBatch({
164164
assert.strictEqual(format("08,d")(0), "0,000,000");
165165
assert.strictEqual(format("013,d")(0), "0,000,000,000");
166166
assert.strictEqual(format("021,d")(0), "0,000,000,000,000,000");
167+
assert.strictEqual(format("013,d")(-42000000), "-0,042,000,000");
167168
},
168169
"can group thousands and zero fill with overflow": function(format) {
169170
assert.strictEqual(format("01,d")(1), "1");
@@ -220,6 +221,90 @@ suite.addBatch({
220221
"will not display non-integers in integer format": function(format) {
221222
assert.strictEqual(format("d")(4.2), "");
222223
},
224+
"unicode character": function(format) {
225+
assert.strictEqual(format("c")(9731), "☃");
226+
},
227+
"binary": function(format) {
228+
assert.strictEqual(format("b")(10), "1010");
229+
},
230+
"binary with prefix": function(format) {
231+
assert.strictEqual(format("#b")(10), "0b1010");
232+
},
233+
"octal": function(format) {
234+
assert.strictEqual(format("o")(10), "12");
235+
},
236+
"octal with prefix": function(format) {
237+
assert.strictEqual(format("#o")(10), "0o12");
238+
},
239+
"hexadecimal (lowercase)": function(format) {
240+
assert.strictEqual(format("x")(3735928559), "deadbeef");
241+
},
242+
"hexadecimal (lowercase) with prefix": function(format) {
243+
assert.strictEqual(format("#x")(3735928559), "0xdeadbeef");
244+
},
245+
"hexadecimal (uppercase)": function(format) {
246+
assert.strictEqual(format("X")(3735928559), "DEADBEEF");
247+
},
248+
"hexadecimal (uppercase) with prefix": function(format) {
249+
assert.strictEqual(format("#X")(3735928559), "0xDEADBEEF");
250+
},
251+
"fill respects prefix": function(format) {
252+
assert.strictEqual(format("#20x")(3735928559), " 0xdeadbeef");
253+
},
254+
"align left": function(format) {
255+
assert.strictEqual(format("<1,d")(0), "0");
256+
assert.strictEqual(format("<1,d")(0), "0");
257+
assert.strictEqual(format("<2,d")(0), "0 ");
258+
assert.strictEqual(format("<3,d")(0), "0 ");
259+
assert.strictEqual(format("<5,d")(0), "0 ");
260+
assert.strictEqual(format("<8,d")(0), "0 ");
261+
assert.strictEqual(format("<13,d")(0), "0 ");
262+
assert.strictEqual(format("<21,d")(0), "0 ");
263+
},
264+
"align right": function(format) {
265+
assert.strictEqual(format(">1,d")(0), "0");
266+
assert.strictEqual(format(">1,d")(0), "0");
267+
assert.strictEqual(format(">2,d")(0), " 0");
268+
assert.strictEqual(format(">3,d")(0), " 0");
269+
assert.strictEqual(format(">5,d")(0), " 0");
270+
assert.strictEqual(format(">8,d")(0), " 0");
271+
assert.strictEqual(format(">13,d")(0), " 0");
272+
assert.strictEqual(format(">21,d")(0), " 0");
273+
},
274+
"align center": function(format) {
275+
assert.strictEqual(format("^1,d")(0), "0");
276+
assert.strictEqual(format("^1,d")(0), "0");
277+
assert.strictEqual(format("^2,d")(0), " 0");
278+
assert.strictEqual(format("^3,d")(0), " 0 ");
279+
assert.strictEqual(format("^5,d")(0), " 0 ");
280+
assert.strictEqual(format("^8,d")(0), " 0 ");
281+
assert.strictEqual(format("^13,d")(0), " 0 ");
282+
assert.strictEqual(format("^21,d")(0), " 0 ");
283+
},
284+
"pad after sign": function(format) {
285+
assert.strictEqual(format("=+1,d")(0), "+0");
286+
assert.strictEqual(format("=+1,d")(0), "+0");
287+
assert.strictEqual(format("=+2,d")(0), "+0");
288+
assert.strictEqual(format("=+3,d")(0), "+ 0");
289+
assert.strictEqual(format("=+5,d")(0), "+ 0");
290+
assert.strictEqual(format("=+8,d")(0), "+ 0");
291+
assert.strictEqual(format("=+13,d")(0), "+ 0");
292+
assert.strictEqual(format("=+21,d")(0), "+ 0");
293+
},
294+
"a space can denote positive numbers": function(format) {
295+
assert.strictEqual(format(" 1,d")(-1), "-1");
296+
assert.strictEqual(format(" 1,d")(0), " 0");
297+
assert.strictEqual(format(" 2,d")(0), " 0");
298+
assert.strictEqual(format(" 3,d")(0), " 0");
299+
assert.strictEqual(format(" 5,d")(0), " 0");
300+
assert.strictEqual(format(" 8,d")(0), " 0");
301+
assert.strictEqual(format(" 13,d")(0), " 0");
302+
assert.strictEqual(format(" 21,d")(0), " 0");
303+
},
304+
"can format negative zero": function(format) {
305+
assert.strictEqual(format("1d")(-0), "-0");
306+
assert.strictEqual(format("1f")(-0), "-0");
307+
},
223308
"supports \"n\" as an alias for \",g\"": function(format) {
224309
var f = format("n");
225310
assert.strictEqual(f(.0042), "0.0042");

0 commit comments

Comments
 (0)