Skip to content

Commit

Permalink
fix(slider): resolve step & snap floating point precision (#10148)
Browse files Browse the repository at this point in the history
**Related Issue:** #9684

## Summary

Resolve floating point precision issue when using `snap` and `step`
properties.

repro: https://codepen.io/benelan/pen/jOjxbRg
  • Loading branch information
benelan authored Aug 27, 2024
1 parent eb0cecb commit 613bc47
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 2 deletions.
13 changes: 13 additions & 0 deletions packages/calcite-components/src/components/slider/slider.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,19 @@ describe("calcite-slider", () => {
});
});

// skipped due to a bug where value is rounded down instead of up:
// https://github.com/Esri/calcite-design-system/issues/9684
it.skip("step floating point precision", async () => {
const page = await newE2EPage();
await page.setContent(
html`<calcite-slider value="1.4" label-handles max="10" min="0.1" snap step="0.1"></calcite-slider>`,
);
const slider = await page.find("calcite-slider");

await page.waitForChanges();
expect((await slider.getProperty("value")).toString()).toBe("1.4");
});

it("only selects values on step interval when snap prop is passed", async () => {
const page = await newE2EPage();
await page.setContent(`
Expand Down
11 changes: 9 additions & 2 deletions packages/calcite-components/src/components/slider/slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
import { clamp, decimalPlaces } from "../../utils/math";
import { ColorStop, DataSeries } from "../graph/interfaces";
import { Scale } from "../interfaces";
import { BigDecimal } from "../../utils/number";
import { CSS, maxTickElementThreshold } from "./resources";
import { ActiveSliderProperty, SetValueProperty, SideOffset, ThumbType } from "./interfaces";

Expand Down Expand Up @@ -964,8 +965,14 @@ export class Slider
*/
private getClosestStep(value: number): number {
const { max, min, step } = this;
let snappedValue = Math.floor((value - min) / step) * step + min;
snappedValue = Math.min(Math.max(snappedValue, min), max);

// prevents floating point precision issues
const bigDecimalString = new BigDecimal(`${Math.floor((value - min) / step)}`)
.multiply(`${step}`)
.add(`${min}`)
.toString();

let snappedValue = this.clamp(Number(bigDecimalString));

if (snappedValue > max) {
snappedValue -= step;
Expand Down

0 comments on commit 613bc47

Please sign in to comment.