]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Better number -> string callback for the radial linear scale (#3281)
authorEvert Timberg <evert.timberg+github@gmail.com>
Sat, 24 Sep 2016 20:56:16 +0000 (16:56 -0400)
committerSimon Brunel <simonbrunel@users.noreply.github.com>
Sat, 24 Sep 2016 20:56:16 +0000 (22:56 +0200)
Also create a new Chart.Ticks namespace to host common tick generators and formatters.

src/chart.js
src/core/core.scale.js
src/core/core.ticks.js [new file with mode: 0644]
src/scales/scale.linear.js
src/scales/scale.linearbase.js
src/scales/scale.logarithmic.js
src/scales/scale.radialLinear.js

index a12890aa06b96f1a79d7df094359f8a6694375af..aa0d46c45cef2bfb430f1ecce9bb690e4552d1c0 100644 (file)
@@ -12,6 +12,7 @@ require('./core/core.datasetController')(Chart);
 require('./core/core.layoutService')(Chart);
 require('./core/core.scaleService')(Chart);
 require('./core/core.plugin.js')(Chart);
+require('./core/core.ticks.js')(Chart);
 require('./core/core.scale')(Chart);
 require('./core/core.title')(Chart);
 require('./core/core.legend')(Chart);
index 808e18e5019f32665d36c1f3d641093da9129188..890e04c42e3aa2d3df9ee13b54e1e7885cd1d939 100644 (file)
@@ -46,9 +46,7 @@ module.exports = function(Chart) {
                        autoSkipPadding: 0,
                        labelOffset: 0,
                        // We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
-                       callback: function(value) {
-                               return helpers.isArray(value) ? value : '' + value;
-                       }
+                       callback: Chart.Ticks.formatters.values
                }
        };
 
diff --git a/src/core/core.ticks.js b/src/core/core.ticks.js
new file mode 100644 (file)
index 0000000..f55b8d4
--- /dev/null
@@ -0,0 +1,193 @@
+'use strict';
+
+module.exports = function(Chart) {
+
+       var helpers = Chart.helpers;
+
+       /**
+        * Namespace to hold static tick generation functions
+        * @namespace Chart.Ticks
+        */
+       Chart.Ticks = {
+               /**
+                * Namespace to hold generators for different types of ticks
+                * @namespace Chart.Ticks.generators
+                */
+               generators: {
+                       /**
+                        * Interface for the options provided to the numeric tick generator
+                        * @interface INumericTickGenerationOptions
+                        */
+                       /**
+                        * The maximum number of ticks to display
+                        * @name INumericTickGenerationOptions#maxTicks
+                        * @type Number
+                        */
+                       /**
+                        * The distance between each tick.
+                        * @name INumericTickGenerationOptions#stepSize
+                        * @type Number
+                        * @optional
+                        */
+                       /**
+                        * Forced minimum for the ticks. If not specified, the minimum of the data range is used to calculate the tick minimum
+                        * @name INumericTickGenerationOptions#min
+                        * @type Number
+                        * @optional
+                        */
+                       /**
+                        * The maximum value of the ticks. If not specified, the maximum of the data range is used to calculate the tick maximum
+                        * @name INumericTickGenerationOptions#max
+                        * @type Number
+                        * @optional
+                        */
+
+                       /**
+                        * Generate a set of linear ticks
+                        * @method Chart.Ticks.generators.linear
+                        * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks
+                        * @param dataRange {IRange} the range of the data
+                        * @returns {Array<Number>} array of tick values
+                        */
+                       linear: function(generationOptions, dataRange) {
+                               var ticks = [];
+                               // To get a "nice" value for the tick spacing, we will use the appropriately named
+                               // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
+                               // for details.
+
+                               var spacing;
+                               if (generationOptions.stepSize && generationOptions.stepSize > 0) {
+                                       spacing = generationOptions.stepSize;
+                               } else {
+                                       var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false);
+                                       spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true);
+                               }
+                               var niceMin = Math.floor(dataRange.min / spacing) * spacing;
+                               var niceMax = Math.ceil(dataRange.max / spacing) * spacing;
+                               var numSpaces = (niceMax - niceMin) / spacing;
+
+                               // If very close to our rounded value, use it.
+                               if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
+                                       numSpaces = Math.round(numSpaces);
+                               } else {
+                                       numSpaces = Math.ceil(numSpaces);
+                               }
+
+                               // Put the values into the ticks array
+                               ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin);
+                               for (var j = 1; j < numSpaces; ++j) {
+                                       ticks.push(niceMin + (j * spacing));
+                               }
+                               ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax);
+
+                               return ticks;
+                       },
+
+                       /**
+                        * Generate a set of logarithmic ticks
+                        * @method Chart.Ticks.generators.logarithmic
+                        * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks
+                        * @param dataRange {IRange} the range of the data
+                        * @returns {Array<Number>} array of tick values
+                        */
+                       logarithmic: function(generationOptions, dataRange) {
+                               var ticks = [];
+                               var getValueOrDefault = helpers.getValueOrDefault;
+
+                               // 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 = getValueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min))));
+
+                               while (tickVal < dataRange.max) {
+                                       ticks.push(tickVal);
+
+                                       var exp;
+                                       var significand;
+
+                                       if (tickVal === 0) {
+                                               exp = Math.floor(helpers.log10(dataRange.minNotZero));
+                                               significand = Math.round(dataRange.minNotZero / Math.pow(10, exp));
+                                       } else {
+                                               exp = Math.floor(helpers.log10(tickVal));
+                                               significand = Math.floor(tickVal / Math.pow(10, exp)) + 1;
+                                       }
+
+                                       if (significand === 10) {
+                                               significand = 1;
+                                               ++exp;
+                                       }
+
+                                       tickVal = significand * Math.pow(10, exp);
+                               }
+
+                               var lastTick = getValueOrDefault(generationOptions.max, tickVal);
+                               ticks.push(lastTick);
+
+                               return ticks;
+                       }
+               },
+
+               /**
+                * Namespace to hold formatters for different types of ticks
+                * @namespace Chart.Ticks.formatters
+                */
+               formatters: {
+                       /**
+                        * Formatter for value labels
+                        * @method Chart.Ticks.formatters.values
+                        * @param value the value to display
+                        * @return {String|Array} the label to display
+                        */
+                       values: function(value) {
+                               return helpers.isArray(value) ? value : '' + value;
+                       },
+
+                       /**
+                        * Formatter for linear numeric ticks
+                        * @method Chart.Ticks.formatters.linear
+                        * @param tickValue {Number} the value to be formatted
+                        * @param index {Number} the position of the tickValue parameter in the ticks array
+                        * @param ticks {Array<Number>} the list of ticks being converted
+                        * @return {String} string representation of the tickValue parameter
+                        */
+                       linear: function(tickValue, index, ticks) {
+                               // If we have lots of ticks, don't use the ones
+                               var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
+
+                               // 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);
+                                       }
+                               }
+
+                               var logDelta = helpers.log10(Math.abs(delta));
+                               var tickString = '';
+
+                               if (tickValue !== 0) {
+                                       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
+                               }
+
+                               return tickString;
+                       },
+
+                       logarithmic: function(tickValue, index, ticks) {
+                               var remain = tickValue / (Math.pow(10, Math.floor(helpers.log10(tickValue))));
+
+                               if (tickValue === 0) {
+                                       return '0';
+                               } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
+                                       return tickValue.toExponential();
+                               }
+                               return '';
+                       }
+               }
+       };
+};
index f2700a3a4ae92ee1952f0b7e8ee5b1e5bbc7a804..e8afa84f8f12f839169fe145b09eaacd2415bbcf 100644 (file)
@@ -7,31 +7,7 @@ module.exports = function(Chart) {
        var defaultConfig = {
                position: 'left',
                ticks: {
-                       callback: function(tickValue, index, ticks) {
-                               // If we have lots of ticks, don't use the ones
-                               var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
-
-                               // 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);
-                                       }
-                               }
-
-                               var logDelta = helpers.log10(Math.abs(delta));
-                               var tickString = '';
-
-                               if (tickValue !== 0) {
-                                       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
-                               }
-
-                               return tickString;
-                       }
+                       callback: Chart.Ticks.formatters.linear
                }
        };
 
index 37caa03593351496ed63094907774b0663cfef74..b8bc5c979e1ca6bfe28ab62f4c06563037330b0e 100644 (file)
@@ -53,49 +53,22 @@ module.exports = function(Chart) {
                buildTicks: function() {
                        var me = this;
                        var opts = me.options;
-                       var ticks = me.ticks = [];
                        var tickOpts = opts.ticks;
-                       var getValueOrDefault = helpers.getValueOrDefault;
 
                        // 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
-
+                       // the graph. Make sure we always have at least 2 ticks
                        var maxTicks = me.getTickLimit();
-
-                       // Make sure we always have at least 2 ticks
                        maxTicks = Math.max(2, maxTicks);
 
-                       // To get a "nice" value for the tick spacing, we will use the appropriately named
-                       // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
-                       // for details.
-
-                       var spacing;
-                       var fixedStepSizeSet = (tickOpts.fixedStepSize && tickOpts.fixedStepSize > 0) || (tickOpts.stepSize && tickOpts.stepSize > 0);
-                       if (fixedStepSizeSet) {
-                               spacing = getValueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize);
-                       } else {
-                               var niceRange = helpers.niceNum(me.max - me.min, false);
-                               spacing = helpers.niceNum(niceRange / (maxTicks - 1), true);
-                       }
-                       var niceMin = Math.floor(me.min / spacing) * spacing;
-                       var niceMax = Math.ceil(me.max / spacing) * spacing;
-                       var numSpaces = (niceMax - niceMin) / spacing;
-
-                       // If very close to our rounded value, use it.
-                       if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
-                               numSpaces = Math.round(numSpaces);
-                       } else {
-                               numSpaces = Math.ceil(numSpaces);
-                       }
-
-                       // Put the values into the ticks array
-                       ticks.push(tickOpts.min !== undefined ? tickOpts.min : niceMin);
-                       for (var j = 1; j < numSpaces; ++j) {
-                               ticks.push(niceMin + (j * spacing));
-                       }
-                       ticks.push(tickOpts.max !== undefined ? tickOpts.max : niceMax);
+                       var numericGeneratorOptions = {
+                               maxTicks: maxTicks,
+                               min: tickOpts.min,
+                               max: tickOpts.max,
+                               stepSize: helpers.getValueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
+                       };
+                       var ticks = me.ticks = Chart.Ticks.generators.linear(numericGeneratorOptions, me);
 
                        me.handleDirectionalChanges();
 
index 50417528a5b582b8f703e3ddbd0ef25a5c7c0d0c..a23f2eed4136b55aa3bbe9f6ffade7b424f29c33 100644 (file)
@@ -9,16 +9,7 @@ module.exports = function(Chart) {
 
                // label settings
                ticks: {
-                       callback: function(value, index, arr) {
-                               var remain = value / (Math.pow(10, Math.floor(helpers.log10(value))));
-
-                               if (value === 0) {
-                                       return '0';
-                               } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === arr.length - 1) {
-                                       return value.toExponential();
-                               }
-                               return '';
-                       }
+                       callback: Chart.Ticks.formatters.logarithmic
                }
        };
 
@@ -124,43 +115,12 @@ module.exports = function(Chart) {
                        var me = this;
                        var opts = me.options;
                        var tickOpts = opts.ticks;
-                       var getValueOrDefault = helpers.getValueOrDefault;
-
-                       // Reset the ticks array. Later on, we will draw a grid line at these positions
-                       // The array simply contains the numerical value of the spots where ticks will be
-                       var ticks = me.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
-                       // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
-                       // the graph
-
-                       var tickVal = getValueOrDefault(tickOpts.min, Math.pow(10, Math.floor(helpers.log10(me.min))));
-
-                       while (tickVal < me.max) {
-                               ticks.push(tickVal);
-
-                               var exp;
-                               var significand;
-
-                               if (tickVal === 0) {
-                                       exp = Math.floor(helpers.log10(me.minNotZero));
-                                       significand = Math.round(me.minNotZero / Math.pow(10, exp));
-                               } else {
-                                       exp = Math.floor(helpers.log10(tickVal));
-                                       significand = Math.floor(tickVal / Math.pow(10, exp)) + 1;
-                               }
-
-                               if (significand === 10) {
-                                       significand = 1;
-                                       ++exp;
-                               }
-
-                               tickVal = significand * Math.pow(10, exp);
-                       }
 
-                       var lastTick = getValueOrDefault(tickOpts.max, tickVal);
-                       ticks.push(lastTick);
+                       var generationOptions = {
+                               min: tickOpts.min,
+                               max: tickOpts.max
+                       };
+                       var ticks = me.ticks = Chart.Ticks.generators.logarithmic(generationOptions, me);
 
                        if (!me.isHorizontal()) {
                                // We are in a vertical orientation. The top value is the highest. So reverse the array
index 361ad3cbab1d3b2947baca4fbfc09daa437a1a12..cc7c6557d7466a51496837e8228cf21c2fc8e2cc 100644 (file)
@@ -31,7 +31,9 @@ module.exports = function(Chart) {
                        backdropPaddingY: 2,
 
                        // Number - The backdrop padding to the side of the label in pixels
-                       backdropPaddingX: 2
+                       backdropPaddingX: 2,
+
+                       callback: Chart.Ticks.formatters.linear
                },
 
                pointLabels: {