Skip to content

Commit 0a72feb

Browse files
authored
feat: use better formatting for small values (#87)
1 parent 80bd3bc commit 0a72feb

File tree

3 files changed

+53
-14
lines changed

3 files changed

+53
-14
lines changed

pages/common/formatters.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,32 @@ export function numberFormatter(value: null | number) {
2121
if (value === null) {
2222
return "";
2323
}
24-
return Math.abs(value) >= 1e9
25-
? (value / 1e9).toFixed(1).replace(/\.0$/, "") + "G"
26-
: Math.abs(value) >= 1e6
27-
? (value / 1e6).toFixed(1).replace(/\.0$/, "") + "M"
28-
: Math.abs(value) >= 1e3
29-
? (value / 1e3).toFixed(1).replace(/\.0$/, "") + "K"
30-
: value.toFixed(2);
24+
25+
const format = (num: number) => parseFloat(num.toFixed(2)).toString(); // trims unnecessary decimals
26+
27+
const absValue = Math.abs(value);
28+
29+
if (absValue === 0) {
30+
return "0";
31+
}
32+
33+
if (absValue < 0.01) {
34+
return value.toExponential(0);
35+
}
36+
37+
if (absValue >= 1e9) {
38+
return format(value / 1e9) + "G";
39+
}
40+
41+
if (absValue >= 1e6) {
42+
return format(value / 1e6) + "M";
43+
}
44+
45+
if (absValue >= 1e3) {
46+
return format(value / 1e3) + "K";
47+
}
48+
49+
return format(value);
3150
}
3251

3352
export function moneyFormatter(value: null | number) {

src/core/__tests__/chart-core-axes.test.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ describe("CoreChart: axes", () => {
126126
test("uses default numeric axes formatters for integer values", () => {
127127
renderChart({ highcharts, options: { series, xAxis: { title: { text: "X" } }, yAxis: { title: { text: "Y" } } } });
128128
getAxisOptionsFormatters().forEach((formatter) => {
129+
expect(formatter.call(mockAxisContext({ value: 0 }))).toBe("0");
129130
expect(formatter.call(mockAxisContext({ value: 1 }))).toBe("1");
130131
expect(formatter.call(mockAxisContext({ value: 1_000 }))).toBe("1K");
131132
expect(formatter.call(mockAxisContext({ value: 1_000_000 }))).toBe("1M");
@@ -138,6 +139,8 @@ describe("CoreChart: axes", () => {
138139
getAxisOptionsFormatters().forEach((formatter) => {
139140
expect(formatter.call(mockAxisContext({ value: 2.0 }))).toBe("2");
140141
expect(formatter.call(mockAxisContext({ value: 2.03 }))).toBe("2.03");
142+
expect(formatter.call(mockAxisContext({ value: 0.03 }))).toBe("0.03");
143+
expect(formatter.call(mockAxisContext({ value: 0.003 }))).toBe("3e-3");
141144
});
142145
});
143146

src/core/formatters.tsx

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,28 @@ function secondFormatter(value: number) {
104104

105105
function numberFormatter(value: number): string {
106106
const format = (num: number) => parseFloat(num.toFixed(2)).toString(); // trims unnecessary decimals
107-
return Math.abs(value) >= 1e9
108-
? format(value / 1e9) + "G"
109-
: Math.abs(value) >= 1e6
110-
? format(value / 1e6) + "M"
111-
: Math.abs(value) >= 1e3
112-
? format(value / 1e3) + "K"
113-
: format(value);
107+
108+
const absValue = Math.abs(value);
109+
110+
if (absValue === 0) {
111+
return "0";
112+
}
113+
114+
if (absValue < 0.01) {
115+
return value.toExponential(0);
116+
}
117+
118+
if (absValue >= 1e9) {
119+
return format(value / 1e9) + "G";
120+
}
121+
122+
if (absValue >= 1e6) {
123+
return format(value / 1e6) + "M";
124+
}
125+
126+
if (absValue >= 1e3) {
127+
return format(value / 1e3) + "K";
128+
}
129+
130+
return format(value);
114131
}

0 commit comments

Comments
 (0)