From 9fbac8893865fc6f7efdab7f49d480e6a730c669 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sun, 1 Apr 2018 12:56:45 -0400 Subject: [PATCH] Add `ticks.precision` option to linear scale. (#4841) If defined and `stepSize` is not specified, the step size will be rounded to this many decimal places. --- docs/axes/cartesian/linear.md | 1 + docs/axes/radial/linear.md | 1 + src/scales/scale.linearbase.js | 13 ++++++- test/specs/scale.linear.tests.js | 60 ++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/docs/axes/cartesian/linear.md b/docs/axes/cartesian/linear.md index 1d0292074a8..3f68b79ff1d 100644 --- a/docs/axes/cartesian/linear.md +++ b/docs/axes/cartesian/linear.md @@ -12,6 +12,7 @@ The following options are provided by the linear scale. They are all located in | `min` | `Number` | | User defined minimum number for the scale, overrides minimum value from data. [more...](#axis-range-settings) | `max` | `Number` | | User defined maximum number for the scale, overrides maximum value from data. [more...](#axis-range-settings) | `maxTicksLimit` | `Number` | `11` | Maximum number of ticks and gridlines to show. +| `precision` | `Number` | | if defined and `stepSize` is not specified, the step size will be rounded to this many decimal places. | `stepSize` | `Number` | | User defined fixed step size for the scale. [more...](#step-size) | `suggestedMax` | `Number` | | Adjustment used when calculating the maximum data value. [more...](#axis-range-settings) | `suggestedMin` | `Number` | | Adjustment used when calculating the minimum data value. [more...](#axis-range-settings) diff --git a/docs/axes/radial/linear.md b/docs/axes/radial/linear.md index 14009be6a5c..594901db335 100644 --- a/docs/axes/radial/linear.md +++ b/docs/axes/radial/linear.md @@ -27,6 +27,7 @@ The following options are provided by the linear scale. They are all located in | `min` | `Number` | | User defined minimum number for the scale, overrides minimum value from data. [more...](#axis-range-settings) | `max` | `Number` | | User defined maximum number for the scale, overrides maximum value from data. [more...](#axis-range-settings) | `maxTicksLimit` | `Number` | `11` | Maximum number of ticks and gridlines to show. +| `precision` | `Number` | | if defined and `stepSize` is not specified, the step size will be rounded to this many decimal places. | `stepSize` | `Number` | | User defined fixed step size for the scale. [more...](#step-size) | `suggestedMax` | `Number` | | Adjustment used when calculating the maximum data value. [more...](#axis-range-settings) | `suggestedMin` | `Number` | | Adjustment used when calculating the minimum data value. [more...](#axis-range-settings) diff --git a/src/scales/scale.linearbase.js b/src/scales/scale.linearbase.js index 3e4b5c083f3..5ac01b92a4f 100644 --- a/src/scales/scale.linearbase.js +++ b/src/scales/scale.linearbase.js @@ -14,12 +14,22 @@ function generateTicks(generationOptions, dataRange) { // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks // for details. + var factor; + var precision; var spacing; + if (generationOptions.stepSize && generationOptions.stepSize > 0) { spacing = generationOptions.stepSize; } else { var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false); spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true); + + precision = generationOptions.precision; + if (precision !== undefined) { + // If the user specified a precision, round to that number of decimal places + factor = Math.pow(10, precision); + spacing = Math.ceil(spacing * factor) / factor; + } } var niceMin = Math.floor(dataRange.min / spacing) * spacing; var niceMax = Math.ceil(dataRange.max / spacing) * spacing; @@ -41,7 +51,7 @@ function generateTicks(generationOptions, dataRange) { numSpaces = Math.ceil(numSpaces); } - var precision = 1; + precision = 1; if (spacing < 1) { precision = Math.pow(10, spacing.toString().length - 2); niceMin = Math.round(niceMin * precision) / precision; @@ -154,6 +164,7 @@ module.exports = function(Chart) { maxTicks: maxTicks, min: tickOpts.min, max: tickOpts.max, + precision: tickOpts.precision, stepSize: helpers.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize) }; var ticks = me.ticks = generateTicks(numericGeneratorOptions, me); diff --git a/test/specs/scale.linear.tests.js b/test/specs/scale.linear.tests.js index 60dd07698c0..b42675d8a8d 100644 --- a/test/specs/scale.linear.tests.js +++ b/test/specs/scale.linear.tests.js @@ -548,6 +548,66 @@ describe('Linear Scale', function() { expect(chart.scales.yScale0.ticks).toEqual(['11', '9', '7', '5', '3', '1']); }); + describe('precision', function() { + it('Should create integer steps if precision is 0', function() { + var chart = window.acquireChart({ + type: 'bar', + data: { + datasets: [{ + yAxisID: 'yScale0', + data: [0, 1, 2, 1, 0, 1] + }], + labels: ['a', 'b', 'c', 'd', 'e', 'f'] + }, + options: { + scales: { + yAxes: [{ + id: 'yScale0', + type: 'linear', + ticks: { + precision: 0 + } + }] + } + } + }); + + expect(chart.scales.yScale0).not.toEqual(undefined); // must construct + expect(chart.scales.yScale0.min).toBe(0); + expect(chart.scales.yScale0.max).toBe(2); + expect(chart.scales.yScale0.ticks).toEqual(['2', '1', '0']); + }); + + it('Should round the step size to the given number of decimal places', function() { + var chart = window.acquireChart({ + type: 'bar', + data: { + datasets: [{ + yAxisID: 'yScale0', + data: [0, 0.001, 0.002, 0.003, 0, 0.001] + }], + labels: ['a', 'b', 'c', 'd', 'e', 'f'] + }, + options: { + scales: { + yAxes: [{ + id: 'yScale0', + type: 'linear', + ticks: { + precision: 2 + } + }] + } + } + }); + + expect(chart.scales.yScale0).not.toEqual(undefined); // must construct + expect(chart.scales.yScale0.min).toBe(0); + expect(chart.scales.yScale0.max).toBe(0.01); + expect(chart.scales.yScale0.ticks).toEqual(['0.01', '0']); + }); + }); + it('should forcibly include 0 in the range if the beginAtZero option is used', function() { var chart = window.acquireChart({