Skip to content

Commit

Permalink
Improved formatting of numeric scale labels
Browse files Browse the repository at this point in the history
  • Loading branch information
benmccann committed Jan 27, 2020
1 parent 47c7a42 commit 29a2f62
Show file tree
Hide file tree
Showing 9 changed files with 30 additions and 39 deletions.
1 change: 1 addition & 0 deletions docs/getting-started/v3-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Chart.js 3.0 introduces a number of breaking changes. Chart.js 2.0 was released

* `options.ticks.userCallback` was renamed to `options.ticks.callback`
* `options.ticks.major` and `options.ticks.minor` were replaced with scriptable options for tick fonts.
* `Chart.Ticks.formatters.linear` and `Chart.Ticks.formatters.logarithmic` were replaced with `Chart.Ticks.formatters.numeric`.

### Tooltip

Expand Down
51 changes: 21 additions & 30 deletions src/core/core.ticks.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,49 +24,40 @@ export default {
},

/**
* Formatter for linear numeric ticks
* @method Chart.Ticks.formatters.linear
* Formatter for numeric ticks
* @method Chart.Ticks.formatters.numeric
* @param tickValue {number} the value to be formatted
* @param index {number} the position of the tickValue parameter in the ticks array
* @param ticks {number[]} the list of ticks being converted
* @return {string} string representation of the tickValue parameter
*/
linear: function(tickValue, index, ticks) {
numeric: function(tickValue, index, ticks) {
if (tickValue === 0) {
return '0'; // never show decimal places for 0
}

// If we have lots of ticks, don't use the ones
var delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value;
let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value;

// If we have a number like 2.5 as the delta, figure out how many decimal places we need
if (Math.abs(delta) > 1) {
if (tickValue !== Math.floor(tickValue)) {
// not an integer
delta = tickValue - Math.floor(tickValue);
}
if (Math.abs(delta) > 1 && tickValue !== Math.floor(tickValue)) {
// not an integer
delta = tickValue - Math.floor(tickValue);
}

var logDelta = math.log10(Math.abs(delta));
var tickString = '';
const logDelta = math.log10(Math.abs(delta));

if (tickValue !== 0) {
var maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value));
if (maxTick < 1e-4) { // all ticks are small numbers; use scientific notation
var logTick = math.log10(Math.abs(tickValue));
var numExponential = Math.floor(logTick) - Math.floor(logDelta);
numExponential = Math.max(Math.min(numExponential, 20), 0);
tickString = tickValue.toExponential(numExponential);
} else {
var numDecimal = -1 * Math.floor(logDelta);
numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
tickString = tickValue.toFixed(numDecimal);
}
} else {
tickString = '0'; // never show decimal places for 0
const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value));
if (maxTick < 1e-4) { // all ticks are small numbers; use scientific notation
const logTick = math.log10(Math.abs(tickValue));
let numExponential = Math.floor(logTick) - Math.floor(logDelta);
numExponential = Math.max(Math.min(numExponential, 20), 0);
return new Intl.NumberFormat(navigator.languages, {notation: 'scientific', minimumFractionDigits: numExponential, maximumFractionDigits: numExponential}).format(tickValue);
}

return tickString;
},

logarithmic: function(tickValue) {
return tickValue === 0 ? '0' : tickValue.toExponential();
let numDecimal = -1 * Math.floor(logDelta);
numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
return new Intl.NumberFormat(navigator.languages, {minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal}).format(tickValue);
}
}
};
2 changes: 1 addition & 1 deletion src/scales/scale.linear.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Ticks from '../core/core.ticks';

const defaultConfig = {
ticks: {
callback: Ticks.formatters.linear
callback: Ticks.formatters.numeric
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/scales/scale.logarithmic.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function generateTicks(generationOptions, dataRange) {
const defaultConfig = {
// label settings
ticks: {
callback: Ticks.formatters.logarithmic,
callback: Ticks.formatters.numeric,
major: {
enabled: true
}
Expand Down
2 changes: 1 addition & 1 deletion src/scales/scale.radialLinear.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const defaultConfig = {
// Number - The backdrop padding to the side of the label in pixels
backdropPaddingX: 2,

callback: Ticks.formatters.linear
callback: Ticks.formatters.numeric
},

pointLabels: {
Expand Down
3 changes: 1 addition & 2 deletions test/specs/core.ticks.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ describe('Test tick generators', function() {
expect(typeof Chart.Ticks).toBeDefined();
expect(typeof Chart.Ticks.formatters).toBeDefined();
expect(typeof Chart.Ticks.formatters.values).toBe('function');
expect(typeof Chart.Ticks.formatters.linear).toBe('function');
expect(typeof Chart.Ticks.formatters.logarithmic).toBe('function');
expect(typeof Chart.Ticks.formatters.numeric).toBe('function');
});

it('Should generate linear spaced ticks with correct precision', function() {
Expand Down
4 changes: 2 additions & 2 deletions test/specs/scale.linear.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -541,8 +541,8 @@ describe('Linear Scale', function() {
expect(chart.scales.y.min).toBe(-1010);
expect(chart.scales.y.max).toBe(1010);
var labels = getLabels(chart.scales.y);
expect(labels[0]).toBe('1010');
expect(labels[labels.length - 1]).toBe('-1010');
expect(labels[0]).toBe('1,010');
expect(labels[labels.length - 1]).toBe('-1,010');
});

it('Should use min, max and stepSize to create fixed spaced ticks', function() {
Expand Down
2 changes: 1 addition & 1 deletion test/specs/scale.logarithmic.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ describe('Logarithmic Scale tests', function() {
}
});

expect(getLabels(chart.scales.y)).toEqual(['8e+1', '7e+1', '6e+1', '5e+1', '4e+1', '3e+1', '2e+1', '1e+1', '9e+0', '8e+0', '7e+0', '6e+0', '5e+0', '4e+0', '3e+0', '2e+0', '1e+0']);
expect(getLabels(chart.scales.y)).toEqual(['80', '70', '60', '50', '40', '30', '20', '10', '9', '8', '7', '6', '5', '4', '3', '2', '1']);
});

it('should build labels using the user supplied callback', function() {
Expand Down
2 changes: 1 addition & 1 deletion test/specs/scale.radialLinear.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ describe('Test the radial linear scale', function() {

expect(chart.scales.r.min).toBe(-1010);
expect(chart.scales.r.max).toBe(1010);
expect(getLabels(chart.scales.r)).toEqual(['-1010', '-1000', '-500', '0', '500', '1000', '1010']);
expect(getLabels(chart.scales.r)).toEqual(['-1,010', '-1,000', '-500', '0', '500', '1,000', '1,010']);
});

it('should forcibly include 0 in the range if the beginAtZero option is used', function() {
Expand Down

0 comments on commit 29a2f62

Please sign in to comment.