diff --git a/src/scales/scale.linearbase.js b/src/scales/scale.linearbase.js index d2da5501eb7..0e5368ecd8b 100644 --- a/src/scales/scale.linearbase.js +++ b/src/scales/scale.linearbase.js @@ -59,8 +59,13 @@ function generateTicks(generationOptions, dataRange) { } if (bounds === 'ticks') { - niceMin = Math.floor(rmin / spacing) * spacing; - niceMax = Math.ceil(rmax / spacing) * spacing; + // Both are whole multiples of spacing, so they never need more decimals than + // spacing itself. Round the floating point error off here, otherwise + // _decimalPlaces below reports it as significant and the factor grows large + // enough that rounding the tick values becomes a no-op. + const spacingFactor = Math.pow(10, _decimalPlaces(spacing)); + niceMin = Math.round(Math.floor(rmin / spacing) * spacing * spacingFactor) / spacingFactor; + niceMax = Math.round(Math.ceil(rmax / spacing) * spacing * spacingFactor) / spacingFactor; } else { niceMin = rmin; niceMax = rmax; diff --git a/test/specs/scale.linear.tests.js b/test/specs/scale.linear.tests.js index a8ad53995b1..b60489a91e1 100644 --- a/test/specs/scale.linear.tests.js +++ b/test/specs/scale.linear.tests.js @@ -706,6 +706,33 @@ describe('Linear Scale', function() { expect(chart.scales.x.ticks[chart.scales.x.ticks.length - 1].value).toBeLessThanOrEqual(2.4143e-8); }); + it('Should generate ticks free of floating point drift when min and max are not round', function() { + var chart = window.acquireChart({ + type: 'line', + options: { + scales: { + y: { + type: 'linear', + min: 49.894, + max: 51.5264, + }, + }, + }, + }); + + var values = chart.scales.y.ticks.map(function(tick) { + return tick.value; + }); + + // the ticks between the bounds are multiples of the 0.2 spacing, + // so none of them needs more than four decimals to be written exactly + values.forEach(function(value) { + expect(value).toBe(Math.round(value * 1e4) / 1e4); + }); + expect(values).toContain(50); + expect(values).toContain(51); + }); + it('Should not generate insane amounts of ticks with small stepSize and large range', function() { var chart = window.acquireChart({ type: 'bar',