I want to recreate the spinner feature found in input type=number.
<input type=number step=0.3/>
When clicking on the up arrow of the spinner, the value increases by 0.3 (0.3, 0.6 , 0.9 , 1.2 , 1.5 ...etc).
However, if the current value is 1.4 and I click increase, it jumps to 1.5 which is a 0.1 increment, while at 1.3 it's a 0.2 increment.
My question is how can I determine the closest step increment when increasing the current value?!
Below is my solution:
export class Spinner {
increase(currentValue, step) {
const step = step || 1;
const decimalSize = getDecimalSize(step);
const current = normalize(currentValue, decimalSize);
const ratio = Math.ceil(normalize(current / step, decimalSize));
let increment = normalize(ratio * step, decimalSize);
if (
normalize(current % step, decimalSize) === 0 ||
current === increment ||
normalize(current % step, decimalSize) === 1
) {
increment = normalize(current + step, decimalSize);
}
}
}
export function getDecimalSize(value: number) {
if (Math.floor(value) === value) return 0;
return value.toString().split(".")[1]?.length || 0;
}
export function normalize(value: number, decimalSize: number): number {
decimalSize = decimalSize || 1;
const n = Math.pow(10, decimalSize + 1);
return Math.round(value * n) / n;
}
This logic works well for positive numbers but not as expected with negative values.
For example, when the current value is -2
with a step of 0.3
, it results in -1.8
instead of -1.7