Skip to content

Commit

Permalink
fix(Math.ts): updated decimatedClamp implementation (#5284)
Browse files Browse the repository at this point in the history
  • Loading branch information
scffs authored Jul 12, 2023
1 parent c5da338 commit 5631f38
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 29 deletions.
33 changes: 12 additions & 21 deletions packages/vkui/src/helpers/math.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@
import { clamp, precisionRound, rescale } from './math';
import { clamp, rescale } from './math';

describe(clamp, () => {
it('clamps min', () => expect(clamp(10, 20, 30)).toBe(20));
it('clamps max', () => expect(clamp(40, 20, 30)).toBe(30));
});

describe(precisionRound, () => {
it('rounds to precision', () => {
expect(precisionRound(0.3 + 0.6, 1)).toBe(0.9);
expect(precisionRound(0.88, 1)).toBe(0.9);
expect(precisionRound(0.881, 2)).toBe(0.88);
});
it('can integer-round', () => {
expect(precisionRound(1.1, 0)).toBe(1);
expect(precisionRound(0.9, 0)).toBe(1);
});
});

describe(rescale, () => {
it('scales value', () => {
expect(rescale(0.5, [0, 1], [3, 5])).toBe(4);
Expand All @@ -34,13 +22,16 @@ describe(rescale, () => {
it('rounds precision', () => {
expect(rescale(3.1415926, [3, 4], [3, 4], { step: 0.01 })).toBe(3.14);
});
describe('non-divisor step', () => {
it('rounds to min + k * step when min != n * step', () => {
expect(rescale(0.1, [0.1, 3.1], [0.1, 3.1], { step: 2 })).toBe(0.1);
expect(rescale(3, [1, 5], [1, 5], { step: 2 })).toBe(3);
});
it('clamps to min + min(max, min + k * step) when max != min + n * step', () => {
expect(rescale(3, [0, 3], [0, 3], { step: 2 })).toBe(2);
});
it('rounds to min when min != n * step', () => {
expect(rescale(0.1, [0.1, 3.1], [0.1, 3.1], { step: 2 })).toBe(0.1);
});
it('rounds to max when max != n * step', () => {
expect(rescale(3, [1, 5], [1, 5], { step: 2 })).toBe(3);
expect(rescale(3, [0, 3], [0, 3], { step: 2 })).toBe(3);
});
describe('check use cases', () =>
// см. https://github.com/VKCOM/VKUI/pull/5284
it('should return 20000', () => {
expect(rescale(100, [0, 100], [250, 20000], { step: 115 })).toBe(20000);
}));
});
30 changes: 22 additions & 8 deletions packages/vkui/src/helpers/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,34 @@ export function precisionRound(number: number, precision = 1) {
return Math.round(number * factor) / factor;
}

function precision(number: number) {
return (`${number}`.split('.')[1] || '').length;
/**
* Решение скопировано без изменений у MUI:
* https://github.com/mui/material-ui/blob/v5.13.7/packages/mui-base/src/useSlider/useSlider.ts#L89-L105
*/
function getDecimalPrecision(num: number) {
// This handles the case when num is very small (0.00000001), js will turn this into 1e-8.
// When num is bigger than 1 or less than -1 it won't get converted to this notation so it's fine.
if (Math.abs(num) < 1) {
const parts = num.toExponential().split('e-');
const matissaDecimalPart = parts[0].split('.')[1];
return (matissaDecimalPart ? matissaDecimalPart.length : 0) + parseInt(parts[1], 10);
}

const decimalPart = num.toString().split('.')[1];
return decimalPart ? decimalPart.length : 0;
}

function roundValueToStep(value: number, step: number, min: number) {
const nearest = Math.round((value - min) / step) * step + min;
return Number(nearest.toFixed(getDecimalPrecision(step)));
}

function decimatedClamp(val: number, min: number, max: number, step?: number) {
if (step == null || step <= 0) {
return clamp(val, min, max);
}
const prec = precision(step);
// Round value to nearest min + k1 * step
const decimatedOffset = precisionRound(Math.round((val - min) / step) * step, prec);
// Round range length _down_ to nearest min + k2 * step
const decimatedRange = precisionRound(Math.floor((max - min) / step) * step, prec);
return min + clamp(decimatedOffset, 0, decimatedRange);
const roundedValue = roundValueToStep(val, step, min);
return clamp(roundedValue, min, max);
}

export function rescale(
Expand Down

0 comments on commit 5631f38

Please sign in to comment.