From 572f8a3014eacb6c65948d8ffcf99c6d59da7972 Mon Sep 17 00:00:00 2001 From: Akihiko Kusanagi Date: Sat, 29 Dec 2018 00:03:44 +0800 Subject: [PATCH] Simplify the tick generation code --- src/scales/scale.linear.js | 21 +++++---- src/scales/scale.linearbase.js | 60 +++++++++++--------------- src/scales/scale.radialLinear.js | 19 ++++++-- test/specs/scale.linear.tests.js | 8 +++- test/specs/scale.radialLinear.tests.js | 6 +++ 5 files changed, 66 insertions(+), 48 deletions(-) diff --git a/src/scales/scale.linear.js b/src/scales/scale.linear.js index 228ce099849..36655559ad3 100644 --- a/src/scales/scale.linear.js +++ b/src/scales/scale.linear.js @@ -1,6 +1,5 @@ 'use strict'; -var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); var scaleService = require('../core/core.scaleService'); var Ticks = require('../core/core.ticks'); @@ -134,16 +133,22 @@ module.exports = function(Chart) { this.handleTickRangeOptions(); }, getTickLimit: function() { - var maxTicks; var me = this; var tickOpts = me.options.ticks; - - if (me.isHorizontal()) { - maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 40)); + var stepSize = tickOpts.stepSize; + var maxTicksLimit = tickOpts.maxTicksLimit; + var maxTicks, tickFont; + + if (stepSize > 0) { + maxTicks = Math.ceil(me.max / stepSize) - Math.floor(me.min / stepSize) + 1; + } else if (me.isHorizontal()) { + maxTicks = Math.ceil(me.width / 40); } else { - // The factor of 2 used to scale the font size has been experimentally determined. - var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, defaults.global.defaultFontSize); - maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (1.5 * tickFontSize))); + tickFont = helpers.options._parseFont(tickOpts); + maxTicks = Math.ceil(me.height / tickFont.lineHeight); + } + if (maxTicksLimit || !(stepSize > 0)) { + maxTicks = Math.min(maxTicksLimit || 11, maxTicks); } return maxTicks; diff --git a/src/scales/scale.linearbase.js b/src/scales/scale.linearbase.js index 490bc2ab6b8..2d1b261ecd5 100644 --- a/src/scales/scale.linearbase.js +++ b/src/scales/scale.linearbase.js @@ -16,52 +16,41 @@ function generateTicks(generationOptions, dataRange) { // for details. var stepSize = generationOptions.stepSize; + var unit = stepSize > 0 ? stepSize : 1; + var maxNumSpaces = generationOptions.maxTicks - 1; var min = generationOptions.min; var max = generationOptions.max; - var spacing, precision, factor, niceMin, niceMax, numSpaces, maxNumSpaces; - - if (stepSize && stepSize > 0) { - spacing = stepSize; - if (generationOptions.maxTicksLimit) { - maxNumSpaces = generationOptions.maxTicksLimit - 1; - // spacing is set to stepSize multiplied by a nice number of - // Math.ceil((max - min) / maxNumSpaces / stepSize) = num of steps that should be grouped - spacing *= helpers.niceNum(Math.ceil((dataRange.max - dataRange.min) / maxNumSpaces / stepSize)); - numSpaces = Math.ceil(dataRange.max / spacing) - Math.floor(dataRange.min / spacing); - if (numSpaces > maxNumSpaces) { - // If the calculated num of spaces exceeds maxNumSpaces, recalculate it - spacing = helpers.niceNum(Math.ceil(numSpaces * spacing / maxNumSpaces / stepSize)) * stepSize; - } - } - } else { - maxNumSpaces = generationOptions.maxTicks - 1; - // spacing is set to a nice number of (max - min) / maxNumSpaces - spacing = helpers.niceNum((dataRange.max - dataRange.min) / maxNumSpaces); - numSpaces = Math.ceil(dataRange.max / spacing) - Math.floor(dataRange.min / spacing); - if (numSpaces > maxNumSpaces) { - // If the calculated num of spaces exceeds maxNumSpaces, recalculate it - spacing = helpers.niceNum(numSpaces * spacing / maxNumSpaces); - } - - precision = generationOptions.precision; - if (!helpers.isNullOrUndef(precision)) { - // 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 precision = generationOptions.precision; + var spacing, factor, niceMin, niceMax, numSpaces; + + // spacing is set to a nice number of the dataRange devided by maxNumSpaces. + // stepSize is used as a minimum unit if it is specified. + spacing = helpers.niceNum((dataRange.max - dataRange.min) / maxNumSpaces / unit) * unit; + numSpaces = Math.ceil(dataRange.max / spacing) - Math.floor(dataRange.min / spacing); + if (numSpaces > maxNumSpaces) { + // If the calculated num of spaces exceeds maxNumSpaces, recalculate it + spacing = helpers.niceNum(numSpaces * spacing / maxNumSpaces / unit) * unit; } - // If a precision is not specified, calculate factor based on spacing - if (!factor) { + + if (!(stepSize > 0) && !helpers.isNullOrUndef(precision)) { + // If the user specified a precision, round to that number of decimal places + factor = Math.pow(10, precision); + spacing = Math.ceil(spacing * factor) / factor; + } else { + // If a precision is not specified, calculate factor based on spacing factor = Math.pow(10, helpers.decimalPlaces(spacing)); } + niceMin = Math.floor(dataRange.min / spacing) * spacing; niceMax = Math.ceil(dataRange.max / spacing) * spacing; // If min, max and stepSize is set and they make an evenly spaced scale use it. - if (!helpers.isNullOrUndef(min) && !helpers.isNullOrUndef(max) && stepSize) { + if (stepSize > 0) { // If very close to our whole number, use it. - if (helpers.almostWhole((max - min) / stepSize, spacing / 1000)) { + if (!helpers.isNullOrUndef(min) && helpers.almostWhole(min / spacing, spacing / 1000)) { niceMin = min; + } + if (!helpers.isNullOrUndef(max) && helpers.almostWhole(max / spacing, spacing / 1000)) { niceMax = max; } } @@ -180,7 +169,6 @@ module.exports = function(Chart) { var numericGeneratorOptions = { maxTicks: maxTicks, - maxTicksLimit: tickOpts.maxTicksLimit, min: tickOpts.min, max: tickOpts.max, precision: tickOpts.precision, diff --git a/src/scales/scale.radialLinear.js b/src/scales/scale.radialLinear.js index f0c38317e8a..aaeb33cd10b 100644 --- a/src/scales/scale.radialLinear.js +++ b/src/scales/scale.radialLinear.js @@ -358,10 +358,23 @@ module.exports = function(Chart) { me.handleTickRangeOptions(); }, getTickLimit: function() { - var opts = this.options; + var me = this; + var opts = me.options; var tickOpts = opts.ticks; - var tickBackdropHeight = getTickBackdropHeight(opts); - return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / tickBackdropHeight)); + var stepSize = tickOpts.stepSize; + var maxTicksLimit = tickOpts.maxTicksLimit; + var maxTicks; + + if (stepSize > 0) { + maxTicks = Math.ceil(me.max / stepSize) - Math.floor(me.min / stepSize) + 1; + } else { + maxTicks = Math.ceil(me.drawingArea / getTickBackdropHeight(opts)); + } + if (maxTicksLimit || !(stepSize > 0)) { + maxTicks = Math.min(maxTicksLimit || 11, maxTicks); + } + + return maxTicks; }, convertTicksToLabels: function() { var me = this; diff --git a/test/specs/scale.linear.tests.js b/test/specs/scale.linear.tests.js index 9b866a5a762..a186c6cc7fe 100644 --- a/test/specs/scale.linear.tests.js +++ b/test/specs/scale.linear.tests.js @@ -570,7 +570,7 @@ describe('Linear Scale', function() { expect(chart.scales.yScale0).not.toEqual(undefined); // must construct expect(chart.scales.yScale0.min).toBe(1); expect(chart.scales.yScale0.max).toBe(11); - expect(chart.scales.yScale0.ticks).toEqual(['11', '9', '7', '5', '3', '1']); + expect(chart.scales.yScale0.ticks).toEqual(['11', '10', '8', '6', '4', '2', '1']); }); it('Should create decimal steps if stepSize is a decimal number', function() { @@ -788,6 +788,12 @@ describe('Linear Scale', function() { chart.update(); expect(chart.scales.yScale.ticks).toEqual(['2.5', '2.0', '1.5', '1.0', '0.5']); + + chart.options.scales.yAxes[0].ticks.min = 0.3; + chart.options.scales.yAxes[0].ticks.max = 2.8; + chart.update(); + + expect(chart.scales.yScale.ticks).toEqual(['2.8', '2.5', '2.0', '1.5', '1.0', '0.5', '0.3']); }); it('Should build labels using the user supplied callback', function() { diff --git a/test/specs/scale.radialLinear.tests.js b/test/specs/scale.radialLinear.tests.js index b564564ec66..2102bfaefc9 100644 --- a/test/specs/scale.radialLinear.tests.js +++ b/test/specs/scale.radialLinear.tests.js @@ -311,6 +311,12 @@ describe('Test the radial linear scale', function() { chart.update(); expect(chart.scale.ticks).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']); + + chart.options.scale.ticks.min = 0.3; + chart.options.scale.ticks.max = 2.8; + chart.update(); + + expect(chart.scale.ticks).toEqual(['0.3', '0.5', '1.0', '1.5', '2.0', '2.5', '2.8']); }); it('Should build labels using the user supplied callback', function() {