mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Add ticks.sampleSize option (#6508)
This commit is contained in:
parent
e9f341889f
commit
fc76610b12
@ -28,6 +28,7 @@ The following options are common to all cartesian axes but do not apply to other
|
||||
| ---- | ---- | ------- | -----------
|
||||
| `min` | `number` | | User defined minimum value for the scale, overrides minimum value from data.
|
||||
| `max` | `number` | | User defined maximum value for the scale, overrides maximum value from data.
|
||||
| `sampleSize` | `number` | `ticks.length` | The number of ticks to examine when deciding how many labels will fit. Setting a smaller value will be faster, but may be less accurate when there is large variability in label length.
|
||||
| `autoSkip` | `boolean` | `true` | If true, automatically calculates how many labels can be shown and hides labels accordingly. Labels will be rotated up to `maxRotation` before skipping any. Turn `autoSkip` off to show all labels no matter what.
|
||||
| `autoSkipPadding` | `number` | `0` | Padding between the ticks on the horizontal axis when `autoSkip` is enabled.
|
||||
| `labelOffset` | `number` | `0` | Distance in pixels to offset the label from the centre point of the tick (in the x direction for the x axis, and the y direction for the y axis). *Note: this can cause labels at the edges to be cropped by the edge of the canvas*
|
||||
|
||||
8
docs/general/performance.md
Normal file
8
docs/general/performance.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Performance
|
||||
|
||||
Chart.js charts are rendered on `canvas` elements, which makes rendering quite fast. For large datasets or performance sensitive applications, you may wish to consider the tips below:
|
||||
|
||||
* Set `animation: { duration: 0 }` to disable [animations](../configuration/animations.md).
|
||||
* For large datasets:
|
||||
* You may wish to sample your data before providing it to Chart.js. E.g. if you have a data point for each day, you may find it more performant to pass in a data point for each week instead
|
||||
* Set the [`ticks.sampleSize`](../axes/cartesian/README.md#tick-configuration) option in order to render axes more quickly
|
||||
@ -67,6 +67,19 @@ defaults._set('scale', {
|
||||
}
|
||||
});
|
||||
|
||||
/** Returns a new array containing numItems from arr */
|
||||
function sample(arr, numItems) {
|
||||
var result = [];
|
||||
var increment = arr.length / numItems;
|
||||
var i = 0;
|
||||
var len = arr.length;
|
||||
|
||||
for (; i < len; i += increment) {
|
||||
result.push(arr[Math.floor(i)]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getPixelForGridLine(scale, index, offsetGridLines) {
|
||||
var length = scale.getTicks().length;
|
||||
var validIndex = Math.min(index, length - 1);
|
||||
@ -266,7 +279,8 @@ var Scale = Element.extend({
|
||||
update: function(maxWidth, maxHeight, margins) {
|
||||
var me = this;
|
||||
var tickOpts = me.options.ticks;
|
||||
var i, ilen, labels, label, ticks, tick;
|
||||
var sampleSize = tickOpts.sampleSize;
|
||||
var i, ilen, labels, ticks;
|
||||
|
||||
// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
|
||||
me.beforeUpdate();
|
||||
@ -281,6 +295,8 @@ var Scale = Element.extend({
|
||||
bottom: 0
|
||||
}, margins);
|
||||
|
||||
me._ticks = null;
|
||||
me.ticks = null;
|
||||
me._labelSizes = null;
|
||||
me._maxLabelLines = 0;
|
||||
me.longestLabelWidth = 0;
|
||||
@ -314,35 +330,23 @@ var Scale = Element.extend({
|
||||
// Allow modification of ticks in callback.
|
||||
ticks = me.afterBuildTicks(ticks) || ticks;
|
||||
|
||||
me.beforeTickToLabelConversion();
|
||||
|
||||
// New implementations should return the formatted tick labels but for BACKWARD
|
||||
// COMPAT, we still support no return (`this.ticks` internally changed by calling
|
||||
// this method and supposed to contain only string values).
|
||||
labels = me.convertTicksToLabels(ticks) || me.ticks;
|
||||
|
||||
me.afterTickToLabelConversion();
|
||||
|
||||
me.ticks = labels; // BACKWARD COMPATIBILITY
|
||||
|
||||
// IMPORTANT: below this point, we consider that `this.ticks` will NEVER change!
|
||||
|
||||
// BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
|
||||
for (i = 0, ilen = labels.length; i < ilen; ++i) {
|
||||
label = labels[i];
|
||||
tick = ticks[i];
|
||||
if (!tick) {
|
||||
ticks.push(tick = {
|
||||
label: label,
|
||||
// Ensure ticks contains ticks in new tick format
|
||||
if ((!ticks || !ticks.length) && me.ticks) {
|
||||
ticks = [];
|
||||
for (i = 0, ilen = me.ticks.length; i < ilen; ++i) {
|
||||
ticks.push({
|
||||
value: me.ticks[i],
|
||||
major: false
|
||||
});
|
||||
} else {
|
||||
tick.label = label;
|
||||
}
|
||||
}
|
||||
|
||||
me._ticks = ticks;
|
||||
|
||||
// Compute tick rotation and fit using a sampled subset of labels
|
||||
// We generally don't need to compute the size of every single label for determining scale size
|
||||
labels = me._convertTicksToLabels(sampleSize ? sample(ticks, sampleSize) : ticks);
|
||||
|
||||
// _configure is called twice, once here, once from core.controller.updateLayout.
|
||||
// Here we haven't been positioned yet, but dimensions are correct.
|
||||
// Variables set in _configure are needed for calculateTickRotation, and
|
||||
@ -353,19 +357,28 @@ var Scale = Element.extend({
|
||||
me.beforeCalculateTickRotation();
|
||||
me.calculateTickRotation();
|
||||
me.afterCalculateTickRotation();
|
||||
// Fit
|
||||
|
||||
me.beforeFit();
|
||||
me.fit();
|
||||
me.afterFit();
|
||||
|
||||
// Auto-skip
|
||||
me._ticksToDraw = tickOpts.display && tickOpts.autoSkip ? me._autoSkip(me._ticks) : me._ticks;
|
||||
me._ticksToDraw = tickOpts.display && tickOpts.autoSkip ? me._autoSkip(ticks) : ticks;
|
||||
|
||||
if (sampleSize) {
|
||||
// Generate labels using all non-skipped ticks
|
||||
labels = me._convertTicksToLabels(me._ticksToDraw);
|
||||
}
|
||||
|
||||
me.ticks = labels; // BACKWARD COMPATIBILITY
|
||||
|
||||
// IMPORTANT: after this point, we consider that `this.ticks` will NEVER change!
|
||||
|
||||
me.afterUpdate();
|
||||
|
||||
// TODO(v3): remove minSize as a public property and return value from all layout boxes. It is unused
|
||||
// make maxWidth and maxHeight private
|
||||
return me.minSize;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
@ -673,6 +686,31 @@ var Scale = Element.extend({
|
||||
return rawValue;
|
||||
},
|
||||
|
||||
_convertTicksToLabels: function(ticks) {
|
||||
var me = this;
|
||||
var labels, i, ilen;
|
||||
|
||||
me.ticks = ticks.map(function(tick) {
|
||||
return tick.value;
|
||||
});
|
||||
|
||||
me.beforeTickToLabelConversion();
|
||||
|
||||
// New implementations should return the formatted tick labels but for BACKWARD
|
||||
// COMPAT, we still support no return (`this.ticks` internally changed by calling
|
||||
// this method and supposed to contain only string values).
|
||||
labels = me.convertTicksToLabels(ticks) || me.ticks;
|
||||
|
||||
me.afterTickToLabelConversion();
|
||||
|
||||
// BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
|
||||
for (i = 0, ilen = ticks.length; i < ilen; ++i) {
|
||||
ticks[i].label = labels[i];
|
||||
}
|
||||
|
||||
return labels;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@ -835,11 +873,12 @@ var Scale = Element.extend({
|
||||
for (i = 0; i < tickCount; i++) {
|
||||
tick = ticks[i];
|
||||
|
||||
if (skipRatio > 1 && i % skipRatio > 0) {
|
||||
// leave tick in place but make sure it's not displayed (#4635)
|
||||
if (skipRatio <= 1 || i % skipRatio === 0) {
|
||||
tick._index = i;
|
||||
result.push(tick);
|
||||
} else {
|
||||
delete tick.label;
|
||||
}
|
||||
result.push(tick);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
@ -966,7 +1005,7 @@ var Scale = Element.extend({
|
||||
borderDashOffset = gridLines.borderDashOffset || 0.0;
|
||||
}
|
||||
|
||||
lineValue = getPixelForGridLine(me, i, offsetGridLines);
|
||||
lineValue = getPixelForGridLine(me, tick._index || i, offsetGridLines);
|
||||
|
||||
// Skip if the pixel is out of the range
|
||||
if (lineValue === undefined) {
|
||||
@ -1044,7 +1083,7 @@ var Scale = Element.extend({
|
||||
continue;
|
||||
}
|
||||
|
||||
pixel = me.getPixelForTick(i) + optionTicks.labelOffset;
|
||||
pixel = me.getPixelForTick(tick._index || i) + optionTicks.labelOffset;
|
||||
font = tick.major ? fonts.major : fonts.minor;
|
||||
lineHeight = font.lineHeight;
|
||||
lineCount = isArray(label) ? label.length : 1;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user