]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Improved formatting of numeric scale labels (#7007)
authorBen McCann <322311+benmccann@users.noreply.github.com>
Mon, 3 Feb 2020 12:36:31 +0000 (04:36 -0800)
committerGitHub <noreply@github.com>
Mon, 3 Feb 2020 12:36:30 +0000 (07:36 -0500)
* Improved formatting of numeric scale labels

* Put locale on options

* Use scientific notation for big ticks

* Remove extra parameter

docs/getting-started/v3-migration.md
src/core/core.ticks.js
src/scales/scale.linear.js
src/scales/scale.linearbase.js
src/scales/scale.logarithmic.js
src/scales/scale.radialLinear.js
test/specs/core.ticks.tests.js
test/specs/scale.linear.tests.js
test/specs/scale.logarithmic.tests.js
test/specs/scale.radialLinear.tests.js
test/utils.js

index fb36be45997d2d497b01c56f90a334b80c66f9bb..97728b1c24eb811f9138b586c9bc2662867a1714 100644 (file)
@@ -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
 
index ae0180736d664064332c0299d3ad58002dc11962..1e4fa07116c1fbe018e602bc4fa6c44a34e518e7 100644 (file)
@@ -24,49 +24,42 @@ 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 {object[]} 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 = log10(Math.abs(delta));
-                       var tickString = '';
+                       const logDelta = 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 = 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));
+                       const minTick = Math.min(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value));
+                       const locale = this.chart.options.locale;
+                       if (maxTick < 1e-4 || minTick > 1e+7) { // all ticks are small or big numbers; use scientific notation
+                               const logTick = log10(Math.abs(tickValue));
+                               let numExponential = Math.floor(logTick) - Math.floor(logDelta);
+                               numExponential = Math.max(Math.min(numExponential, 20), 0);
+                               return new Intl.NumberFormat(locale, {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(locale, {minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal}).format(tickValue);
                }
        }
 };
index 27a67a76f65d73316e0b2ea0d31e04eed833fce7..189d20962ed8bff5c0a41861fae4653898aa1869 100644 (file)
@@ -7,7 +7,7 @@ import Ticks from '../core/core.ticks';
 
 const defaultConfig = {
        ticks: {
-               callback: Ticks.formatters.linear
+               callback: Ticks.formatters.numeric
        }
 };
 
index f0d555adbd122456108c0c4311e14fb52e746bdd..0932642dd36e67255ebdbc4e86a52256f3ae90c0 100644 (file)
@@ -270,7 +270,7 @@ class LinearScaleBase extends Scale {
        }
 
        getLabelForValue(value) {
-               return new Intl.NumberFormat().format(value);
+               return new Intl.NumberFormat(this.options.locale).format(value);
        }
 }
 
index 3df308276a325f954f1fbf303e30bfa65e1fa39f..33de08c9bc37616a2838d56a2846f1ddcbeb0c4c 100644 (file)
@@ -52,7 +52,7 @@ function generateTicks(generationOptions, dataRange) {
 const defaultConfig = {
        // label settings
        ticks: {
-               callback: Ticks.formatters.logarithmic,
+               callback: Ticks.formatters.numeric,
                major: {
                        enabled: true
                }
@@ -136,7 +136,7 @@ class LogarithmicScale extends Scale {
        }
 
        getLabelForValue(value) {
-               return value === undefined ? 0 : new Intl.NumberFormat().format(value);
+               return value === undefined ? 0 : new Intl.NumberFormat(this.options.locale).format(value);
        }
 
        getPixelForTick(index) {
index 657d07f16386032da941aa2d420012eab2e9034f..03d2c4163a341b77a5102c856a38dd73302ad40c 100644 (file)
@@ -44,7 +44,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: {
index 26b260d0cfbadaacd2bb10f89879d50f1b9d0b26..1352ba860920637ea238f7b0908df38ff8a4dce5 100644 (file)
@@ -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() {
index 073aa31dc222eea03f4f14b9f7f16766eb267890..4f4c31dd9b899f0f586f5a28689f2d4d48aaf2de 100644 (file)
@@ -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() {
index 0cab2eef7d6657433b0d6132fff4b9394257cc6f..15c3065f0983973ad62514385c63a691723f4559 100644 (file)
@@ -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() {
index 576d0b4dcf51350c69795a7b0c22d58a8b8a68c8..4958cfb0d097ad47240efd0fdd45e1bbec0a2efb 100644 (file)
@@ -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() {
index daae1626c119dc7b5be6a638cba17ae36b25c7e5..0a376f7ea8a1e929785ca0c31276e82e4586c938 100644 (file)
@@ -56,6 +56,7 @@ function acquireChart(config, options) {
        config.options.animation = config.options.animation === undefined ? false : config.options.animation;
        config.options.responsive = config.options.responsive === undefined ? false : config.options.responsive;
        config.options.fontFamily = config.options.fontFamily || 'Arial';
+       config.options.locale = config.options.locale || 'en-US';
 
        wrapper.appendChild(canvas);
        window.document.body.appendChild(wrapper);