Formatting: Make SI number formats more robust (#50117)

Closes #49372
This commit is contained in:
kay delaney 2022-06-07 10:48:17 +01:00 committed by GitHub
parent 3df7ee81f3
commit a9a276a9da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 26 additions and 62 deletions

View File

@ -13,7 +13,7 @@ describe('currency', () => {
${1000000} | ${'M'} | ${'1'}
${1000000000} | ${'B'} | ${'1'}
${1000000000000} | ${'T'} | ${'1'}
${1000000000000000} | ${undefined} | ${'NA'}
${1000000000000000} | ${'T'} | ${'1000'}
${-1000000000000} | ${'T'} | ${'-1'}
${-1000000000} | ${'B'} | ${'-1'}
${-1000000} | ${'M'} | ${'-1'}
@ -38,7 +38,7 @@ describe('currency', () => {
${1000000} | ${'M@'} | ${'1'}
${1000000000} | ${'B@'} | ${'1'}
${1000000000000} | ${'T@'} | ${'1'}
${1000000000000000} | ${undefined} | ${'NA'}
${1000000000000000} | ${'T@'} | ${'1000'}
${-1000000000000} | ${'T@'} | ${'-1'}
${-1000000000} | ${'B@'} | ${'-1'}
${-1000000} | ${'M@'} | ${'-1'}

View File

@ -19,54 +19,22 @@ export function currency(symbol: string, asSuffix?: boolean): ValueFormatter {
};
}
const SI_PREFIXES = ['f', 'p', 'n', 'µ', 'm', '', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
const SI_BASE_INDEX = SI_PREFIXES.indexOf('');
export function getOffsetFromSIPrefix(c: string): number {
switch (c) {
case 'f':
return -5;
case 'p':
return -4;
case 'n':
return -3;
case 'μ': // Two different unicode chars for µ
case 'µ':
return -2;
case 'm':
return -1;
case '':
return 0;
case 'k':
return 1;
case 'M':
return 2;
case 'G':
return 3;
case 'T':
return 4;
case 'P':
return 5;
case 'E':
return 6;
case 'Z':
return 7;
case 'Y':
return 8;
}
return 0;
const charIndex = SI_PREFIXES.findIndex((prefix) => prefix.normalize('NFKD') === c.normalize('NFKD'));
return charIndex < 0 ? 0 : charIndex - SI_BASE_INDEX;
}
const BIN_PREFIXES = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'];
export function binaryPrefix(unit: string, offset = 0): ValueFormatter {
const prefixes = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'].slice(offset);
const units = prefixes.map((p) => {
return ' ' + p + unit;
});
return scaledUnits(1024, units);
const units = BIN_PREFIXES.map((p) => ' ' + p + unit);
return scaledUnits(1024, units, offset);
}
export function SIPrefix(unit: string, offset = 0): ValueFormatter {
let prefixes = ['f', 'p', 'n', 'µ', 'm', '', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
prefixes = prefixes.slice(5 + (offset || 0));
const units = prefixes.map((p) => {
return ' ' + p + unit;
});
return scaledUnits(1000, units);
const units = SI_PREFIXES.map((p) => ' ' + p + unit);
return scaledUnits(1000, units, SI_BASE_INDEX + offset);
}

View File

@ -1,3 +1,5 @@
import { clamp } from 'lodash';
import { TimeZone } from '../types';
import { DecimalCount } from '../types/displayValue';
@ -129,31 +131,25 @@ export function booleanValueFormatter(t: string, f: string): ValueFormatter {
};
}
// Formatter which scales the unit string geometrically according to the given
// numeric factor. Repeatedly scales the value down by the factor until it is
// less than the factor in magnitude, or the end of the array is reached.
export function scaledUnits(factor: number, extArray: string[]): ValueFormatter {
return (size: number, decimals?: DecimalCount, scaledDecimals?: DecimalCount) => {
const logb = (b: number, x: number) => Math.log10(x) / Math.log10(b);
export function scaledUnits(factor: number, extArray: string[], offset = 0): ValueFormatter {
return (size: number, decimals?: DecimalCount) => {
if (size === null) {
return { text: '' };
}
if (size === Number.NEGATIVE_INFINITY || size === Number.POSITIVE_INFINITY || isNaN(size)) {
return { text: size.toLocaleString() };
}
let steps = 0;
const limit = extArray.length;
const siIndex = Math.floor(logb(factor, Math.abs(size)));
const suffix = extArray[clamp(offset + siIndex, 0, extArray.length - 1)];
while (Math.abs(size) >= factor) {
steps++;
size /= factor;
if (steps >= limit) {
return { text: 'NA' };
}
}
return { text: toFixed(size, decimals), suffix: extArray[steps] };
return {
text: toFixed(size / factor ** clamp(siIndex, -offset, extArray.length - offset - 1), decimals),
suffix,
};
};
}