Skip to content

Commit

Permalink
Improve tick generation for linear scales
Browse files Browse the repository at this point in the history
  • Loading branch information
nagix committed Dec 26, 2018
1 parent 4b6e53a commit 48aecb4
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 10 deletions.
4 changes: 2 additions & 2 deletions src/scales/scale.linear.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,11 @@ module.exports = function(Chart) {
var tickOpts = me.options.ticks;

if (me.isHorizontal()) {
maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50));
maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, 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 / (2 * tickFontSize)));
maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (1.5 * tickFontSize)));
}

return maxTicks;
Expand Down
26 changes: 22 additions & 4 deletions src/scales/scale.linearbase.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,30 @@ function generateTicks(generationOptions, dataRange) {
var stepSize = generationOptions.stepSize;
var min = generationOptions.min;
var max = generationOptions.max;
var spacing, precision, factor, niceRange, niceMin, niceMax, numSpaces;
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 {
niceRange = helpers.niceNum(dataRange.max - dataRange.min, false);
spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true);
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)) {
Expand Down Expand Up @@ -155,14 +172,15 @@ module.exports = function(Chart) {
var tickOpts = opts.ticks;

// Figure out what the max number of ticks we can support it is based on the size of
// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
// the axis area. For now, we say that the minimum tick spacing in pixels must be 40
// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
// the graph. Make sure we always have at least 2 ticks
var maxTicks = me.getTickLimit();
maxTicks = Math.max(2, maxTicks);

var numericGeneratorOptions = {
maxTicks: maxTicks,
maxTicksLimit: tickOpts.maxTicksLimit,
min: tickOpts.min,
max: tickOpts.max,
precision: tickOpts.precision,
Expand Down
4 changes: 0 additions & 4 deletions src/scales/scale.logarithmic.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ function generateTicks(generationOptions, dataRange) {
var ticks = [];
var valueOrDefault = helpers.valueOrDefault;

// Figure out what the max number of ticks we can support it is based on the size of
// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
// the graph
var tickVal = valueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min))));

var endExp = Math.floor(helpers.log10(dataRange.max));
Expand Down
41 changes: 41 additions & 0 deletions test/specs/scale.linear.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,47 @@ describe('Linear Scale', function() {
expect(chart.scales.yScale0.ticks).toEqual(['0.06', '0.05', '0.04', '0.03', '0.02', '0.01', '0']);
});

it('Should correctly limit the maximum number of ticks', function() {
var chart = window.acquireChart({
type: 'bar',
data: {
labels: ['a', 'b'],
datasets: [{
data: [0.5, 2.5]
}]
},
options: {
scales: {
yAxes: [{
id: 'yScale'
}]
}
}
});

expect(chart.scales.yScale.ticks).toEqual(['2.5', '2.0', '1.5', '1.0', '0.5']);

chart.options.scales.yAxes[0].ticks.maxTicksLimit = 11;
chart.update();

expect(chart.scales.yScale.ticks).toEqual(['2.5', '2.0', '1.5', '1.0', '0.5']);

chart.options.scales.yAxes[0].ticks.maxTicksLimit = 21;
chart.update();

expect(chart.scales.yScale.ticks).toEqual([
'2.5', '2.4', '2.3', '2.2', '2.1', '2.0', '1.9', '1.8', '1.7', '1.6',
'1.5', '1.4', '1.3', '1.2', '1.1', '1.0', '0.9', '0.8', '0.7', '0.6',
'0.5'
]);

chart.options.scales.yAxes[0].ticks.maxTicksLimit = 11;
chart.options.scales.yAxes[0].ticks.stepSize = 0.01;
chart.update();

expect(chart.scales.yScale.ticks).toEqual(['2.5', '2.0', '1.5', '1.0', '0.5']);
});

it('Should build labels using the user supplied callback', function() {
var chart = window.acquireChart({
type: 'bar',
Expand Down
31 changes: 31 additions & 0 deletions test/specs/scale.radialLinear.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,37 @@ describe('Test the radial linear scale', function() {
expect(chart.scale.end).toBe(0);
});

it('Should correctly limit the maximum number of ticks', function() {
var chart = window.acquireChart({
type: 'radar',
data: {
labels: ['label1', 'label2', 'label3'],
datasets: [{
data: [0.5, 1.5, 2.5]
}]
},
options: {
scale: {
pointLabels: {
display: false
}
}
}
});

expect(chart.scale.ticks).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);

chart.options.scale.ticks.maxTicksLimit = 11;
chart.update();

expect(chart.scale.ticks).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);

chart.options.scale.ticks.stepSize = 0.01;
chart.update();

expect(chart.scale.ticks).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);
});

it('Should build labels using the user supplied callback', function() {
var chart = window.acquireChart({
type: 'radar',
Expand Down

0 comments on commit 48aecb4

Please sign in to comment.