mirror of
https://github.com/chartjs/Chart.js.git
synced 2024-10-06 04:09:08 +02:00
Add back Chart.Ticks.formatters (#5088)
This commit is contained in:
parent
fcd463354b
commit
33c7d941f7
@ -13,6 +13,7 @@ Chart.Element = require('./core/core.element');
|
||||
Chart.elements = require('./elements/index');
|
||||
Chart.Interaction = require('./core/core.interaction');
|
||||
Chart.platform = require('./platforms/platform');
|
||||
Chart.Ticks = require('./core/core.ticks');
|
||||
|
||||
require('./core/core.plugin')(Chart);
|
||||
require('./core/core.animation')(Chart);
|
||||
|
@ -7,147 +7,6 @@ var helpers = require('../helpers/index');
|
||||
* @namespace Chart.Ticks
|
||||
*/
|
||||
module.exports = {
|
||||
/**
|
||||
* 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;
|
||||
|
||||
// If min, max and stepSize is set and they make an evenly spaced scale use it.
|
||||
if (generationOptions.min && generationOptions.max && generationOptions.stepSize) {
|
||||
// If very close to our whole number, use it.
|
||||
if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) {
|
||||
niceMin = generationOptions.min;
|
||||
niceMax = generationOptions.max;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
var precision = 1;
|
||||
if (spacing < 1) {
|
||||
precision = Math.pow(10, spacing.toString().length - 2);
|
||||
niceMin = Math.round(niceMin * precision) / precision;
|
||||
niceMax = Math.round(niceMax * precision) / precision;
|
||||
}
|
||||
ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin);
|
||||
for (var j = 1; j < numSpaces; ++j) {
|
||||
ticks.push(Math.round((niceMin + j * spacing) * precision) / precision);
|
||||
}
|
||||
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 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));
|
||||
var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
|
||||
var exp, significand;
|
||||
|
||||
if (tickVal === 0) {
|
||||
exp = Math.floor(helpers.log10(dataRange.minNotZero));
|
||||
significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
|
||||
|
||||
ticks.push(tickVal);
|
||||
tickVal = significand * Math.pow(10, exp);
|
||||
} else {
|
||||
exp = Math.floor(helpers.log10(tickVal));
|
||||
significand = Math.floor(tickVal / Math.pow(10, exp));
|
||||
}
|
||||
var precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
|
||||
|
||||
do {
|
||||
ticks.push(tickVal);
|
||||
|
||||
++significand;
|
||||
if (significand === 10) {
|
||||
significand = 1;
|
||||
++exp;
|
||||
precision = exp >= 0 ? 1 : precision;
|
||||
}
|
||||
|
||||
tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision;
|
||||
} while (exp < endExp || (exp === endExp && significand < endSignificand));
|
||||
|
||||
var lastTick = valueOrDefault(generationOptions.max, tickVal);
|
||||
ticks.push(lastTick);
|
||||
|
||||
return ticks;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Namespace to hold formatters for different types of ticks
|
||||
* @namespace Chart.Ticks.formatters
|
||||
|
@ -1,7 +1,61 @@
|
||||
'use strict';
|
||||
|
||||
var helpers = require('../helpers/index');
|
||||
var Ticks = require('../core/core.ticks');
|
||||
|
||||
/**
|
||||
* Generate a set of linear ticks
|
||||
* @param generationOptions the options used to generate the ticks
|
||||
* @param dataRange the range of the data
|
||||
* @returns {Array<Number>} array of tick values
|
||||
*/
|
||||
function generateTicks(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;
|
||||
|
||||
// If min, max and stepSize is set and they make an evenly spaced scale use it.
|
||||
if (generationOptions.min && generationOptions.max && generationOptions.stepSize) {
|
||||
// If very close to our whole number, use it.
|
||||
if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) {
|
||||
niceMin = generationOptions.min;
|
||||
niceMax = generationOptions.max;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
var precision = 1;
|
||||
if (spacing < 1) {
|
||||
precision = Math.pow(10, spacing.toString().length - 2);
|
||||
niceMin = Math.round(niceMin * precision) / precision;
|
||||
niceMax = Math.round(niceMax * precision) / precision;
|
||||
}
|
||||
ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin);
|
||||
for (var j = 1; j < numSpaces; ++j) {
|
||||
ticks.push(Math.round((niceMin + j * spacing) * precision) / precision);
|
||||
}
|
||||
ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax);
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
|
||||
module.exports = function(Chart) {
|
||||
|
||||
@ -102,7 +156,7 @@ module.exports = function(Chart) {
|
||||
max: tickOpts.max,
|
||||
stepSize: helpers.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
|
||||
};
|
||||
var ticks = me.ticks = Ticks.generators.linear(numericGeneratorOptions, me);
|
||||
var ticks = me.ticks = generateTicks(numericGeneratorOptions, me);
|
||||
|
||||
me.handleDirectionalChanges();
|
||||
|
||||
|
@ -3,6 +3,58 @@
|
||||
var helpers = require('../helpers/index');
|
||||
var Ticks = require('../core/core.ticks');
|
||||
|
||||
/**
|
||||
* Generate a set of logarithmic ticks
|
||||
* @param generationOptions the options used to generate the ticks
|
||||
* @param dataRange the range of the data
|
||||
* @returns {Array<Number>} array of tick values
|
||||
*/
|
||||
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));
|
||||
var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
|
||||
var exp, significand;
|
||||
|
||||
if (tickVal === 0) {
|
||||
exp = Math.floor(helpers.log10(dataRange.minNotZero));
|
||||
significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
|
||||
|
||||
ticks.push(tickVal);
|
||||
tickVal = significand * Math.pow(10, exp);
|
||||
} else {
|
||||
exp = Math.floor(helpers.log10(tickVal));
|
||||
significand = Math.floor(tickVal / Math.pow(10, exp));
|
||||
}
|
||||
var precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
|
||||
|
||||
do {
|
||||
ticks.push(tickVal);
|
||||
|
||||
++significand;
|
||||
if (significand === 10) {
|
||||
significand = 1;
|
||||
++exp;
|
||||
precision = exp >= 0 ? 1 : precision;
|
||||
}
|
||||
|
||||
tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision;
|
||||
} while (exp < endExp || (exp === endExp && significand < endSignificand));
|
||||
|
||||
var lastTick = valueOrDefault(generationOptions.max, tickVal);
|
||||
ticks.push(lastTick);
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var defaultConfig = {
|
||||
@ -167,7 +219,7 @@ module.exports = function(Chart) {
|
||||
min: tickOpts.min,
|
||||
max: tickOpts.max
|
||||
};
|
||||
var ticks = me.ticks = Ticks.generators.logarithmic(generationOptions, me);
|
||||
var ticks = me.ticks = generateTicks(generationOptions, me);
|
||||
|
||||
// At this point, we need to update our max and min given the tick values since we have expanded the
|
||||
// range of the scale
|
||||
|
@ -1,4 +1,13 @@
|
||||
describe('Test tick generators', function() {
|
||||
// formatters are used as default config values so users want to be able to reference them
|
||||
it('Should expose formatters api', 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');
|
||||
});
|
||||
|
||||
it('Should generate linear spaced ticks with correct precision', function() {
|
||||
var chart = window.acquireChart({
|
||||
type: 'line',
|
||||
|
Loading…
Reference in New Issue
Block a user