Skip to content

Commit

Permalink
Simplify the tick generation code
Browse files Browse the repository at this point in the history
  • Loading branch information
nagix committed Dec 28, 2018
1 parent 48aecb4 commit 572f8a3
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 48 deletions.
21 changes: 13 additions & 8 deletions 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');
Expand Down Expand Up @@ -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;
Expand Down
60 changes: 24 additions & 36 deletions src/scales/scale.linearbase.js
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -180,7 +169,6 @@ module.exports = function(Chart) {

var numericGeneratorOptions = {
maxTicks: maxTicks,
maxTicksLimit: tickOpts.maxTicksLimit,
min: tickOpts.min,
max: tickOpts.max,
precision: tickOpts.precision,
Expand Down
19 changes: 16 additions & 3 deletions src/scales/scale.radialLinear.js
Expand Up @@ -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;
Expand Down
8 changes: 7 additions & 1 deletion test/specs/scale.linear.tests.js
Expand Up @@ -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() {
Expand Down Expand Up @@ -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() {
Expand Down
6 changes: 6 additions & 0 deletions test/specs/scale.radialLinear.tests.js
Expand Up @@ -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() {
Expand Down

0 comments on commit 572f8a3

Please sign in to comment.