mirror of
https://github.com/chartjs/Chart.js.git
synced 2026-03-05 16:04:03 +01:00
Merge pull request #1794 from nnnick/update-scale-lifecycle
Update Scale Lifcycle
This commit is contained in:
@@ -16,6 +16,20 @@ Name | Type | Default | Description
|
||||
--- |:---:| --- | ---
|
||||
type | String | Chart specific. | Type of scale being employed. Custom scales can be created and registered with a string key. Options: ["category"](#scales-category-scale), ["linear"](#scales-linear-scale), ["logarithmic"](#scales-logarithmic-scale), ["time"](#scales-time-scale), ["radialLinear"](#scales-radial-linear-scale)
|
||||
display | Boolean | true | If true, show the scale including gridlines, ticks, and labels. Overrides *gridLines.display*, *scaleLabel.display*, and *ticks.display*.
|
||||
beforeUpdate | Function | undefined | Callback called before the update process starts. Passed a single argument, the scale instance.
|
||||
beforeSetDimensions | Function | undefined | Callback that runs before dimensions are set. Passed a single argument, the scale instance.
|
||||
afterSetDimensions | Function | undefined | Callback that runs after dimensions are set. Passed a single argument, the scale instance.
|
||||
beforeDataLimits | Function | undefined | Callback that runs before data limits are determined. Passed a single argument, the scale instance.
|
||||
afterDataLimits | Function | undefined | Callback that runs after data limits are determined. Passed a single argument, the scale instance.
|
||||
beforeBuildTicks | Function | undefined | Callback that runs before ticks are created. Passed a single argument, the scale instance.
|
||||
afterBuildTicks | Function | undefined | Callback that runs after ticks are created. Useful for filtering ticks. Passed a single argument, the scale instance.
|
||||
beforeTickToLabelConversion | Function | undefined | Callback that runs before ticks are converted into strings. Passed a single argument, the scale instance.
|
||||
afterTickToLabelConversion | Function | undefined | Callback that runs after ticks are converted into strings. Passed a single argument, the scale instance.
|
||||
beforeCalculateTickRotation | Function | undefined | Callback that runs before tick rotation is determined. Passed a single argument, the scale instance.
|
||||
afterCalculateTickRotation | Function | undefined | Callback that runs after tick rotation is determined. Passed a single argument, the scale instance.
|
||||
beforeFit | Function | undefined | Callback that runs before the scale fits to the canvas. Passed a single argument, the scale instance.
|
||||
afterFit | Function | undefined | Callback that runs after the scale fits to the canvas. Passed a single argument, the scale instance.
|
||||
afterUpdate | Function | undefined | Callback that runs at the end of the update process. Passed a single argument, the scale instance.
|
||||
**gridLines** | Array | - | Options for the grid lines that run perpendicular to the axis.
|
||||
*gridLines*.display | Boolean | true |
|
||||
*gridLines*.color | Color | "rgba(0, 0, 0, 0.1)" | Color of the grid lines.
|
||||
|
||||
@@ -229,6 +229,9 @@ To work with Chart.js, custom scale types must implement the following interface
|
||||
|
||||
```javascript
|
||||
{
|
||||
// Determines the data limits. Should set this.min and this.max to be the data max/min
|
||||
determineDataLimits: function() {},
|
||||
|
||||
// Generate tick marks. this.chart is the chart instance. The data object can be accessed as this.chart.data
|
||||
// buildTicks() should create a ticks array on the scale instance, if you intend to use any of the implementations from the base class
|
||||
buildTicks: function() {},
|
||||
|
||||
@@ -848,4 +848,10 @@
|
||||
isDatasetVisible = helpers.isDatasetVisible = function(dataset) {
|
||||
return !dataset.hidden;
|
||||
};
|
||||
|
||||
helpers.callCallback = function(fn, args, _tArg) {
|
||||
if (fn && typeof fn.call === 'function') {
|
||||
fn.apply(_tArg, args);
|
||||
}
|
||||
}
|
||||
}).call(this);
|
||||
|
||||
@@ -58,7 +58,9 @@
|
||||
// Any function defined here is inherited by all scale types.
|
||||
// Any function can be extended by the scale type
|
||||
|
||||
beforeUpdate: helpers.noop,
|
||||
beforeUpdate: function() {
|
||||
helpers.callCallback(this.options.beforeUpdate, [this]);
|
||||
},
|
||||
update: function(maxWidth, maxHeight, margins) {
|
||||
|
||||
// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
|
||||
@@ -78,6 +80,12 @@
|
||||
this.beforeSetDimensions();
|
||||
this.setDimensions();
|
||||
this.afterSetDimensions();
|
||||
|
||||
// Data min/max
|
||||
this.beforeDataLimits();
|
||||
this.determineDataLimits();
|
||||
this.afterDataLimits();
|
||||
|
||||
// Ticks
|
||||
this.beforeBuildTicks();
|
||||
this.buildTicks();
|
||||
@@ -101,11 +109,15 @@
|
||||
return this.minSize;
|
||||
|
||||
},
|
||||
afterUpdate: helpers.noop,
|
||||
afterUpdate: function() {
|
||||
helpers.callCallback(this.options.afterUpdate, [this]);
|
||||
},
|
||||
|
||||
//
|
||||
|
||||
beforeSetDimensions: helpers.noop,
|
||||
beforeSetDimensions: function() {
|
||||
helpers.callCallback(this.options.beforeSetDimensions, [this]);
|
||||
},
|
||||
setDimensions: function() {
|
||||
// Set the unconstrained dimension before label rotation
|
||||
if (this.isHorizontal()) {
|
||||
@@ -127,15 +139,31 @@
|
||||
this.paddingRight = 0;
|
||||
this.paddingBottom = 0;
|
||||
},
|
||||
afterSetDimensions: helpers.noop,
|
||||
afterSetDimensions: function() {
|
||||
helpers.callCallback(this.options.afterSetDimensions, [this]);
|
||||
},
|
||||
|
||||
// Data limits
|
||||
beforeDataLimits: function() {
|
||||
helpers.callCallback(this.options.beforeDataLimits, [this]);
|
||||
},
|
||||
determineDataLimits: helpers.noop,
|
||||
afterDataLimits: function() {
|
||||
helpers.callCallback(this.options.afterDataLimits, [this]);
|
||||
},
|
||||
|
||||
//
|
||||
|
||||
beforeBuildTicks: helpers.noop,
|
||||
beforeBuildTicks: function() {
|
||||
helpers.callCallback(this.options.beforeBuildTicks, [this]);
|
||||
},
|
||||
buildTicks: helpers.noop,
|
||||
afterBuildTicks: helpers.noop,
|
||||
afterBuildTicks: function() {
|
||||
helpers.callCallback(this.options.afterBuildTicks, [this]);
|
||||
},
|
||||
|
||||
beforeTickToLabelConversion: helpers.noop,
|
||||
beforeTickToLabelConversion: function() {
|
||||
helpers.callCallback(this.options.beforeTickToLabelConversion, [this]);
|
||||
},
|
||||
convertTicksToLabels: function() {
|
||||
// Convert ticks to strings
|
||||
this.ticks = this.ticks.map(function(numericalTick, index, ticks) {
|
||||
@@ -146,11 +174,15 @@
|
||||
},
|
||||
this);
|
||||
},
|
||||
afterTickToLabelConversion: helpers.noop,
|
||||
afterTickToLabelConversion: function() {
|
||||
helpers.callCallback(this.options.afterTickToLabelConversion, [this]);
|
||||
},
|
||||
|
||||
//
|
||||
|
||||
beforeCalculateTickRotation: helpers.noop,
|
||||
beforeCalculateTickRotation: function() {
|
||||
helpers.callCallback(this.options.beforeCalculateTickRotation, [this]);
|
||||
},
|
||||
calculateTickRotation: function() {
|
||||
//Get the width of each grid by calculating the difference
|
||||
//between x offsets between 0 and 1.
|
||||
@@ -218,11 +250,15 @@
|
||||
this.paddingRight = Math.max(this.paddingRight, 0);
|
||||
}
|
||||
},
|
||||
afterCalculateTickRotation: helpers.noop,
|
||||
afterCalculateTickRotation: function() {
|
||||
helpers.callCallback(this.options.afterCalculateTickRotation, [this]);
|
||||
},
|
||||
|
||||
//
|
||||
|
||||
beforeFit: helpers.noop,
|
||||
beforeFit: function() {
|
||||
helpers.callCallback(this.options.beforeFit, [this]);
|
||||
},
|
||||
fit: function() {
|
||||
|
||||
this.minSize = {
|
||||
@@ -319,7 +355,9 @@
|
||||
this.height = this.minSize.height;
|
||||
|
||||
},
|
||||
afterFit: helpers.noop,
|
||||
afterFit: function() {
|
||||
helpers.callCallback(this.options.afterFit, [this]);
|
||||
},
|
||||
|
||||
// Shared Methods
|
||||
isHorizontal: function() {
|
||||
|
||||
@@ -36,8 +36,7 @@
|
||||
};
|
||||
|
||||
var LinearScale = Chart.Scale.extend({
|
||||
buildTicks: function() {
|
||||
|
||||
determineDataLimits: function() {
|
||||
// First Calculate the range
|
||||
this.min = null;
|
||||
this.max = null;
|
||||
@@ -114,32 +113,6 @@
|
||||
}, this);
|
||||
}
|
||||
|
||||
// Then calulate the ticks
|
||||
this.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 maxTicks;
|
||||
|
||||
if (this.isHorizontal()) {
|
||||
maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11,
|
||||
Math.ceil(this.width / 50));
|
||||
} else {
|
||||
// The factor of 2 used to scale the font size has been experimentally determined.
|
||||
maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11,
|
||||
Math.ceil(this.height / (2 * this.options.ticks.fontSize)));
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
|
||||
// do nothing since that would make the chart weird. If the user really wants a weird chart
|
||||
// axis, they can manually override it
|
||||
@@ -172,6 +145,34 @@
|
||||
this.min--;
|
||||
this.max++;
|
||||
}
|
||||
},
|
||||
buildTicks: function() {
|
||||
|
||||
// Then calulate the ticks
|
||||
this.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 maxTicks;
|
||||
|
||||
if (this.isHorizontal()) {
|
||||
maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11,
|
||||
Math.ceil(this.width / 50));
|
||||
} else {
|
||||
// The factor of 2 used to scale the font size has been experimentally determined.
|
||||
maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11,
|
||||
Math.ceil(this.height / (2 * this.options.ticks.fontSize)));
|
||||
}
|
||||
|
||||
// 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 niceRange = helpers.niceNum(this.max - this.min, false);
|
||||
var spacing = helpers.niceNum(niceRange / (maxTicks - 1), true);
|
||||
|
||||
@@ -23,10 +23,8 @@
|
||||
};
|
||||
|
||||
var LogarithmicScale = Chart.Scale.extend({
|
||||
buildTicks: function() {
|
||||
|
||||
// Calculate Range (we may break this out into it's own lifecycle function)
|
||||
|
||||
determineDataLimits: function() {
|
||||
// Calculate Range
|
||||
this.min = null;
|
||||
this.max = null;
|
||||
|
||||
@@ -102,8 +100,8 @@
|
||||
this.max = 10;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
buildTicks: function() {
|
||||
// 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
|
||||
this.tickValues = [];
|
||||
@@ -129,19 +127,6 @@
|
||||
tickVal = significand * Math.pow(10, exp);
|
||||
}
|
||||
|
||||
/*var minExponent = Math.floor(helpers.log10(this.min));
|
||||
var maxExponent = Math.ceil(helpers.log10(this.max));
|
||||
|
||||
for (var exponent = minExponent; exponent < maxExponent; ++exponent) {
|
||||
for (var i = 1; i < 10; ++i) {
|
||||
if (this.options.ticks.min) {
|
||||
|
||||
} else {
|
||||
this.tickValues.push(i * Math.pow(10, exponent));
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
var lastTick = this.options.ticks.max !== undefined ? this.options.ticks.max : tickVal;
|
||||
this.tickValues.push(lastTick);
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
var minSize = helpers.min([this.height, this.width]);
|
||||
this.drawingArea = (this.options.display) ? (minSize / 2) - (this.options.ticks.fontSize / 2 + this.options.ticks.backdropPaddingY) : (minSize / 2);
|
||||
},
|
||||
buildTicks: function() {
|
||||
determineDataLimits: function() {
|
||||
this.min = null;
|
||||
this.max = null;
|
||||
|
||||
@@ -95,20 +95,6 @@
|
||||
this.max++;
|
||||
}
|
||||
|
||||
this.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 maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11,
|
||||
Math.ceil(this.drawingArea / (1.5 * this.options.ticks.fontSize)));
|
||||
maxTicks = Math.max(2, maxTicks); // Make sure we always have at least 2 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.
|
||||
|
||||
// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
|
||||
// do nothing since that would make the chart weird. If the user really wants a weird chart
|
||||
// axis, they can manually override it
|
||||
@@ -124,6 +110,23 @@
|
||||
this.min = 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
buildTicks: function() {
|
||||
|
||||
|
||||
this.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 maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11,
|
||||
Math.ceil(this.drawingArea / (1.5 * this.options.ticks.fontSize)));
|
||||
maxTicks = Math.max(2, maxTicks); // Make sure we always have at least 2 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 niceRange = helpers.niceNum(this.max - this.min, false);
|
||||
var spacing = helpers.niceNum(niceRange / (maxTicks - 1), true);
|
||||
|
||||
@@ -71,8 +71,9 @@
|
||||
getLabelMoment: function(datasetIndex, index) {
|
||||
return this.labelMoments[datasetIndex][index];
|
||||
},
|
||||
|
||||
buildLabelMoments: function() {
|
||||
determineDataLimits: function() {
|
||||
this.labelMoments = [];
|
||||
|
||||
// Only parse these once. If the dataset does not have data as x,y pairs, we will use
|
||||
// these
|
||||
var scaleLabelMoments = [];
|
||||
@@ -128,15 +129,11 @@
|
||||
this.firstTick = this.firstTick.clone();
|
||||
this.lastTick = this.lastTick.clone();
|
||||
},
|
||||
|
||||
buildTicks: function(index) {
|
||||
|
||||
this.ticks = [];
|
||||
this.labelMoments = [];
|
||||
this.unitScale = 1; // How much we scale the unit by, ie 2 means 2x unit per step
|
||||
|
||||
this.buildLabelMoments();
|
||||
|
||||
// Set unit override if applicable
|
||||
if (this.options.time.unit) {
|
||||
this.tickUnit = this.options.time.unit || 'day';
|
||||
|
||||
@@ -82,7 +82,7 @@ describe('Linear Scale', function() {
|
||||
scale.width = 50;
|
||||
scale.height = 400;
|
||||
|
||||
scale.buildTicks();
|
||||
scale.determineDataLimits();
|
||||
expect(scale.min).toBe(-100);
|
||||
expect(scale.max).toBe(150);
|
||||
});
|
||||
@@ -121,7 +121,7 @@ describe('Linear Scale', function() {
|
||||
scale.width = 50;
|
||||
scale.height = 400;
|
||||
|
||||
scale.buildTicks();
|
||||
scale.determineDataLimits();
|
||||
expect(scale.min).toBe(-100);
|
||||
expect(scale.max).toBe(150);
|
||||
});
|
||||
@@ -161,6 +161,7 @@ describe('Linear Scale', function() {
|
||||
scale.width = 50;
|
||||
scale.height = 400;
|
||||
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
expect(scale.min).toBe(-100);
|
||||
expect(scale.max).toBe(80);
|
||||
@@ -204,6 +205,7 @@ describe('Linear Scale', function() {
|
||||
verticalScale.width = 50;
|
||||
verticalScale.height = 400;
|
||||
|
||||
verticalScale.determineDataLimits();
|
||||
verticalScale.buildTicks();
|
||||
expect(verticalScale.min).toBe(0);
|
||||
expect(verticalScale.max).toBe(100);
|
||||
@@ -223,6 +225,7 @@ describe('Linear Scale', function() {
|
||||
horizontalScale.width = 400;
|
||||
horizontalScale.height = 50;
|
||||
|
||||
horizontalScale.determineDataLimits();
|
||||
horizontalScale.buildTicks();
|
||||
expect(horizontalScale.min).toBe(-20);
|
||||
expect(horizontalScale.max).toBe(100);
|
||||
@@ -267,6 +270,7 @@ describe('Linear Scale', function() {
|
||||
scale.width = 50;
|
||||
scale.height = 400;
|
||||
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
expect(scale.min).toBe(-150);
|
||||
expect(scale.max).toBe(200);
|
||||
@@ -309,6 +313,7 @@ describe('Linear Scale', function() {
|
||||
scale.width = 50;
|
||||
scale.height = 400;
|
||||
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
expect(scale.min).toBe(-150);
|
||||
expect(scale.max).toBe(200);
|
||||
@@ -336,6 +341,7 @@ describe('Linear Scale', function() {
|
||||
scale.width = 50;
|
||||
scale.height = 400;
|
||||
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
expect(scale.min).toBe(-1);
|
||||
expect(scale.max).toBe(1);
|
||||
@@ -369,6 +375,7 @@ describe('Linear Scale', function() {
|
||||
scale.width = 50;
|
||||
scale.height = 400;
|
||||
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
expect(scale.min).toBe(-10);
|
||||
expect(scale.max).toBe(10);
|
||||
@@ -402,6 +409,7 @@ describe('Linear Scale', function() {
|
||||
scale.width = 50;
|
||||
scale.height = 400;
|
||||
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
expect(scale.min).toBe(-1010);
|
||||
expect(scale.max).toBe(1010);
|
||||
@@ -436,18 +444,22 @@ describe('Linear Scale', function() {
|
||||
scale.width = 50;
|
||||
scale.height = 400;
|
||||
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
expect(scale.ticks).toEqual([50, 45, 40, 35, 30, 25, 20]);
|
||||
|
||||
config.ticks.beginAtZero = true;
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
expect(scale.ticks).toEqual([50, 45, 40, 35, 30, 25, 20, 15, 10, 5, 0]);
|
||||
|
||||
mockData.datasets[0].data = [-20, -30, -40, -50];
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
expect(scale.ticks).toEqual([0, -5, -10, -15, -20, -25, -30, -35, -40, -45, -50]);
|
||||
|
||||
config.ticks.beginAtZero = false;
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
expect(scale.ticks).toEqual([-20, -25, -30, -35, -40, -45, -50]);
|
||||
});
|
||||
@@ -477,6 +489,7 @@ describe('Linear Scale', function() {
|
||||
scale.width = 50;
|
||||
scale.height = 400;
|
||||
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
|
||||
// Counts down because the lines are drawn top to bottom
|
||||
@@ -511,6 +524,7 @@ describe('Linear Scale', function() {
|
||||
scale.width = 50;
|
||||
scale.height = 400;
|
||||
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
|
||||
// Reverse mode makes this count up
|
||||
|
||||
@@ -389,6 +389,7 @@ describe('Logarithmic Scale tests', function() {
|
||||
scale.width = 50;
|
||||
scale.height = 400;
|
||||
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
|
||||
// Counts down because the lines are drawn top to bottom
|
||||
@@ -424,6 +425,7 @@ describe('Logarithmic Scale tests', function() {
|
||||
scale.width = 50;
|
||||
scale.height = 400;
|
||||
|
||||
scale.determineDataLimits();
|
||||
scale.buildTicks();
|
||||
|
||||
// Counts down because the lines are drawn top to bottom
|
||||
|
||||
Reference in New Issue
Block a user