Commit 3b0356a1 by Torkel Ödegaard Committed by GitHub

Decimals: Improving auto decimals logic for high numbers and scaled units (#30262)

* Big improvement to decimals logic is finally working

* Removed unused elements from old solution

* Updated test
parent 3d7748d9
import { getDecimalsForValue, getDisplayProcessor, getRawDisplayProcessor } from './displayProcessor';
import { getDisplayProcessor, getRawDisplayProcessor } from './displayProcessor';
import { DisplayProcessor, DisplayValue } from '../types/displayValue';
import { MappingType, ValueMapping } from '../types/valueMapping';
import { FieldConfig, FieldType, ThresholdsMode } from '../types';
......@@ -147,14 +147,20 @@ describe('Format value', () => {
it('should set auto decimals, 1 significant', () => {
const value = 3.23;
const instance = getDisplayProcessorFromConfig({ decimals: null });
expect(instance(value).text).toEqual('3.2');
expect(instance(value).text).toEqual('3.23');
});
it('should set auto decimals, 2 significant', () => {
const value = 0.0245;
const instance = getDisplayProcessorFromConfig({ decimals: null });
expect(instance(value).text).toEqual('0.025');
expect(instance(value).text).toEqual('0.0245');
});
it('should set auto decimals correctly for value 0.333333333333', () => {
const value = 1 / 3;
const instance = getDisplayProcessorFromConfig({ decimals: null });
expect(instance(value).text).toEqual('0.333');
});
it('should use override decimals', () => {
......@@ -205,7 +211,7 @@ describe('Format value', () => {
const value = 1000;
const instance = getDisplayProcessorFromConfig({ decimals: null, unit: 'short' });
const disp = instance(value);
expect(disp.text).toEqual('1.000');
expect(disp.text).toEqual('1.0');
expect(disp.suffix).toEqual(' K');
});
......@@ -213,7 +219,7 @@ describe('Format value', () => {
const value = 1200;
const instance = getDisplayProcessorFromConfig({ decimals: null, unit: 'short' });
const disp = instance(value);
expect(disp.text).toEqual('1.200');
expect(disp.text).toEqual('1.2');
expect(disp.suffix).toEqual(' K');
});
......@@ -221,7 +227,7 @@ describe('Format value', () => {
const value = 1250;
const instance = getDisplayProcessorFromConfig({ decimals: null, unit: 'short' });
const disp = instance(value);
expect(disp.text).toEqual('1.250');
expect(disp.text).toEqual('1.25');
expect(disp.suffix).toEqual(' K');
});
......@@ -229,7 +235,15 @@ describe('Format value', () => {
const value = 1000000;
const instance = getDisplayProcessorFromConfig({ decimals: null, unit: 'short' });
const disp = instance(value);
expect(disp.text).toEqual('1.000');
expect(disp.text).toEqual('1.0');
expect(disp.suffix).toEqual(' Mil');
});
it('with value 15000000 and unit short', () => {
const value = 1500000;
const instance = getDisplayProcessorFromConfig({ decimals: null, unit: 'short' });
const disp = instance(value);
expect(disp.text).toEqual('1.5');
expect(disp.suffix).toEqual(' Mil');
});
});
......@@ -349,21 +363,3 @@ describe('getRawDisplayProcessor', () => {
expect(result).toEqual({ text: expected, numeric: null });
});
});
describe('getDecimalsForValue', () => {
it.each`
value | expected
${0} | ${0}
${13.37} | ${0}
${-13.37} | ${0}
${12679.3712345811212} | ${0}
${-12679.3712345811212} | ${0}
${0.3712345} | ${2}
${-0.37123458} | ${2}
${-0.04671994403853774} | ${3}
${0.04671994403853774} | ${3}
`('should return correct suggested decimal count', ({ value, expected }) => {
const result = getDecimalsForValue(value);
expect(result.decimals).toEqual(expected);
});
});
......@@ -137,41 +137,49 @@ function toStringProcessor(value: any): DisplayValue {
return { text: _.toString(value), numeric: toNumber(value) };
}
function getSignificantDigitCount(n: number) {
//remove decimal and make positive
n = Math.abs(+String(n).replace('.', ''));
if (n === 0) {
return 0;
}
// kill the 0s at the end of n
while (n !== 0 && n % 10 === 0) {
n /= 10;
}
// get number of digits
return Math.floor(Math.log(n) / Math.LN10) + 1;
}
export function getDecimalsForValue(value: number, decimalOverride?: DecimalCount): DecimalInfo {
if (_.isNumber(decimalOverride)) {
// It's important that scaledDecimals is null here
return { decimals: decimalOverride, scaledDecimals: null };
}
let dec = -Math.floor(Math.log(Math.abs(value)) / Math.LN10) + 1;
if (value === 0) {
return { decimals: 0, scaledDecimals: 0 };
}
const digits = getSignificantDigitCount(value);
const log10 = Math.floor(Math.log(Math.abs(value)) / Math.LN10);
let dec = -log10 + 1;
const magn = Math.pow(10, -dec);
const norm = value / magn; // norm is between 1.0 and 10.0
let size;
if (norm < 1.5) {
size = 1;
} else if (norm < 3) {
size = 2;
// special case for 2.5, requires an extra decimal
if (norm > 2.25) {
size = 2.5;
++dec;
}
} else if (norm < 7.5) {
size = 5;
} else {
size = 10;
}
size *= magn;
// reduce starting decimals if not needed
if (value % 1 === 0) {
dec = 0;
}
const decimals = Math.max(0, dec);
const scaledDecimals = decimals - Math.floor(Math.log(size) / Math.LN10) + 2;
const scaledDecimals = decimals - log10 + digits - 1;
return { decimals, scaledDecimals };
}
......
......@@ -257,7 +257,7 @@ describe('SingleStatCtrl', () => {
});
it('should set formatted value', () => {
expect(ctx.data.display!.text).toBe('100');
expect(ctx.data.display!.text).toBe('100.0');
});
}
);
......@@ -373,7 +373,7 @@ describe('SingleStatCtrl', () => {
});
it('should set formatted falue', () => {
expect(ctx.data.display!.text).toBe('100');
expect(ctx.data.display!.text).toBe('100.0');
});
}
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment