From c30ddccfc11eabec062f80e1974ef26454023330 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Thu, 1 Jul 2021 13:35:04 -0400 Subject: [PATCH 1/2] Account for floating point error in niceNum helper --- src/helpers/helpers.math.js | 2 +- src/scales/scale.linearbase.js | 3 ++- .../scale.linear/tick-step-min-max-step-fp.js | 24 ++++++++++++++++++ .../tick-step-min-max-step-fp.png | Bin 0 -> 15722 bytes 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/scale.linear/tick-step-min-max-step-fp.js create mode 100644 test/fixtures/scale.linear/tick-step-min-max-step-fp.png diff --git a/src/helpers/helpers.math.js b/src/helpers/helpers.math.js index d9e792c08fb..4ce715729cf 100644 --- a/src/helpers/helpers.math.js +++ b/src/helpers/helpers.math.js @@ -23,7 +23,7 @@ export const sign = Math.sign; */ export function niceNum(range) { const niceRange = Math.pow(10, Math.floor(log10(range))); - const fraction = range / niceRange; + const fraction = range / niceRange - 0.000001; const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10; return niceFraction * niceRange; } diff --git a/src/scales/scale.linearbase.js b/src/scales/scale.linearbase.js index 9e53038e394..cccfa46d4bf 100644 --- a/src/scales/scale.linearbase.js +++ b/src/scales/scale.linearbase.js @@ -70,7 +70,8 @@ function generateTicks(generationOptions, dataRange) { // Case 1: If min, max and stepSize are set and they make an evenly spaced scale use it. // spacing = step; // numSpaces = (max - min) / spacing; - numSpaces = Math.min((max - min) / spacing, maxTicks); + // Note that we round here to handle the case where almostWhole translated an FP error + numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks)); spacing = (max - min) / numSpaces; niceMin = min; niceMax = max; diff --git a/test/fixtures/scale.linear/tick-step-min-max-step-fp.js b/test/fixtures/scale.linear/tick-step-min-max-step-fp.js new file mode 100644 index 00000000000..00d3f9c4955 --- /dev/null +++ b/test/fixtures/scale.linear/tick-step-min-max-step-fp.js @@ -0,0 +1,24 @@ +module.exports = { + description: 'https://github.com/chartjs/Chart.js/issues/9334', + config: { + type: 'line', + options: { + scales: { + y: { + display: false, + }, + x: { + type: 'linear', + min: 7.2, + max: 21.6, + ticks: { + stepSize: 1.8 + } + }, + } + } + }, + options: { + spriteText: true + } +}; diff --git a/test/fixtures/scale.linear/tick-step-min-max-step-fp.png b/test/fixtures/scale.linear/tick-step-min-max-step-fp.png new file mode 100644 index 0000000000000000000000000000000000000000..b11e88478e6a043b14c769b58175cad066af7c64 GIT binary patch literal 15722 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 Date: Thu, 1 Jul 2021 14:31:25 -0400 Subject: [PATCH 2/2] Better solution --- src/helpers/helpers.math.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/helpers/helpers.math.js b/src/helpers/helpers.math.js index 4ce715729cf..fea406c0fc6 100644 --- a/src/helpers/helpers.math.js +++ b/src/helpers/helpers.math.js @@ -22,8 +22,10 @@ export const sign = Math.sign; * @return {number} */ export function niceNum(range) { + const roundedRange = Math.round(range); + range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range; const niceRange = Math.pow(10, Math.floor(log10(range))); - const fraction = range / niceRange - 0.000001; + const fraction = range / niceRange; const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10; return niceFraction * niceRange; }