Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invert function does not work correctly on scaleTime #268

Open
nilsofue opened this issue Oct 5, 2022 · 2 comments · May be fixed by #281
Open

Invert function does not work correctly on scaleTime #268

nilsofue opened this issue Oct 5, 2022 · 2 comments · May be fixed by #281

Comments

@nilsofue
Copy link

nilsofue commented Oct 5, 2022

After an update of d3 I noticed that since version 5.15.0 of d3 the invert() function of scaleTime() sometimes does not return an exact date. It is then missing 1ms.

I have created an example in StackBlitz.

I noticed the error when I converted the value in pixels to a date and then converted this value back to a date. Then the two dates are different. I hope the problem can be solved soon.

@Fil
Copy link
Member

Fil commented Oct 5, 2022

This change seems to have been introduced between version 0.8 and 0.9 of d3-scale
v0.8.0...v0.9.0

So probably somewhere here? d3/d3-time@v0.2.0...v0.3.0

@mbostock
Copy link
Member

It’s easier to see what’s happening with a linear scale (and the only difference between a time scale and a linear scale is that scale.invert calls new Date(time) to convert milliseconds since UNIX epoch back into a Date instance):

The domain is [2022-08-31T22:00Z, 2022-09-30T21:59:59.999Z] which is [1661983200000, 1664575199999]. The range is [0, 946].

The input is 2022-09-04T22:00Z which is 1662328800000.

The scaled output is 126.13333338199588 which is a * (1 - t) + b * t given t = (1662328800000 - 1661983200000) / (1664575199999 - 1661983200000), a = 0, b = 946.

Inverting the scaled output back to the input is 1662328799999.9998, which is a * (1 - t) + b * t given t = (126.13333338199588 - 0) / (946 - 0), a = 1661983200000, b = 1664575199999. This is less than the input by 0.000244140625ms, but within the expected floating point precision (0.9999999999999999×).

The issue arises that new Date(number) floors the input. And hence new Date(1662328799999.9998) is equivalent to new Date(1662328799999), which is off by 1ms, for an error of 0.9999999999993985×. This is a ~4,000× increase in error due to millisecond rounding.

To improve this, we need to call new Date(Math.round(number)) instead.

@mbostock mbostock linked a pull request Aug 20, 2023 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging a pull request may close this issue.

3 participants