this.ticks = [];
this.unitScale = 1; // How much we scale the unit by, ie 2 means 2x unit per step
+ this.scaleSizeInUnits = 0; // How large the scale is in the base unit (seconds, minutes, etc)
// Set unit override if applicable
if (this.options.time.unit) {
this.tickUnit = this.options.time.unit || 'day';
this.displayFormat = this.options.time.displayFormats[this.tickUnit];
- this.tickRange = Math.ceil(this.lastTick.diff(this.firstTick, this.tickUnit, true));
+ this.scaleSizeInUnits = this.lastTick.diff(this.firstTick, this.tickUnit, true);
+ this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, 1);
} else {
// Determine the smallest needed unit of the time
var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
var innerWidth = this.isHorizontal() ? this.width - (this.paddingLeft + this.paddingRight) : this.height - (this.paddingTop + this.paddingBottom);
- var labelCapacity = innerWidth / (tickFontSize + 10);
- var buffer = this.options.time.round ? 0 : 1;
+
+ // Crude approximation of what the label length might be
+ var tempFirstLabel = this.tickFormatFunction(this.firstTick, 0, []);
+ var tickLabelWidth = tempFirstLabel.length * tickFontSize;
+ var cosRotation = Math.cos(helpers.toRadians(this.options.ticks.maxRotation));
+ var sinRotation = Math.sin(helpers.toRadians(this.options.ticks.maxRotation));
+ tickLabelWidth = (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
+ var labelCapacity = innerWidth / (tickLabelWidth + 10);
// Start as small as possible
this.tickUnit = 'millisecond';
- this.tickRange = Math.ceil(this.lastTick.diff(this.firstTick, this.tickUnit, true) + buffer);
+ this.scaleSizeInUnits = this.lastTick.diff(this.firstTick, this.tickUnit, true);
this.displayFormat = this.options.time.displayFormats[this.tickUnit];
var unitDefinitionIndex = 0;
// Can we scale this unit. If `false` we can scale infinitely
this.unitScale = 1;
- if (helpers.isArray(unitDefinition.steps) && Math.ceil(this.tickRange / labelCapacity) < helpers.max(unitDefinition.steps)) {
+ if (helpers.isArray(unitDefinition.steps) && Math.ceil(this.scaleSizeInUnits / labelCapacity) < helpers.max(unitDefinition.steps)) {
// Use one of the prefedined steps
for (var idx = 0; idx < unitDefinition.steps.length; ++idx) {
- if (unitDefinition.steps[idx] > Math.ceil(this.tickRange / labelCapacity)) {
- this.unitScale = unitDefinition.steps[idx];
+ if (unitDefinition.steps[idx] > Math.ceil(this.scaleSizeInUnits / labelCapacity)) {
+ this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, unitDefinition.steps[idx]);
break;
}
}
break;
- } else if ((unitDefinition.maxStep === false) || (Math.ceil(this.tickRange / labelCapacity) < unitDefinition.maxStep)) {
+ } else if ((unitDefinition.maxStep === false) || (Math.ceil(this.scaleSizeInUnits / labelCapacity) < unitDefinition.maxStep)) {
// We have a max step. Scale this unit
- this.unitScale = Math.ceil(this.tickRange / labelCapacity);
+ this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, Math.ceil(this.scaleSizeInUnits / labelCapacity));
break;
} else {
// Move to the next unit up
unitDefinition = time.units[unitDefinitionIndex];
this.tickUnit = unitDefinition.name;
- this.tickRange = Math.ceil(this.lastTick.diff(this.firstTick, this.tickUnit) + buffer);
+ this.scaleSizeInUnits = this.lastTick.diff(this.firstTick, this.tickUnit, true);
this.displayFormat = this.options.time.displayFormats[unitDefinition.name];
}
}
this.ticks.push(this.firstTick.clone());
// For every unit in between the first and last moment, create a moment and add it to the ticks tick
- for (var i = 1; i < this.tickRange; ++i) {
+ for (var i = 1; i < this.scaleSizeInUnits; ++i) {
var newTick = roundedStart.clone().add(i, this.tickUnit);
// Are we greater than the max time
}
// Always show the right tick
- if (this.options.time.max) {
- this.ticks.push(this.lastTick.clone());
- } else if (this.ticks[this.ticks.length - 1].diff(this.lastTick, this.tickUnit, true) !== 0) {
- this.tickRange = Math.ceil(this.tickRange / this.unitScale) * this.unitScale;
- this.ticks.push(this.firstTick.clone().add(this.tickRange, this.tickUnit));
- this.lastTick = this.ticks[this.ticks.length - 1].clone();
+ if (this.ticks[this.ticks.length - 1].diff(this.lastTick, this.tickUnit) !== 0 || this.scaleSizeInUnits === 0) {
+ // this is a weird case. If the <max> option is the same as the end option, we can't just diff the times because the tick was created from the roundedStart
+ // but the last tick was not rounded.
+ if (this.options.time.max) {
+ this.ticks.push(this.lastTick.clone());
+ this.scaleSizeInUnits = this.lastTick.diff(this.ticks[0], this.tickUnit, true);
+ } else {
+ this.scaleSizeInUnits = Math.ceil(this.scaleSizeInUnits / this.unitScale) * this.unitScale;
+ this.ticks.push(this.firstTick.clone().add(this.scaleSizeInUnits, this.tickUnit));
+ this.lastTick = this.ticks[this.ticks.length - 1].clone();
+ }
}
},
// Get tooltip label
return label;
},
- convertTicksToLabels: function() {
- this.ticks = this.ticks.map(function(tick, index, ticks) {
- var formattedTick = tick.format(this.displayFormat);
+ // Function to format an individual tick mark
+ tickFormatFunction: function tickFormatFunction(tick, index, ticks) {
+ var formattedTick = tick.format(this.displayFormat);
- if (this.options.ticks.userCallback) {
- return this.options.ticks.userCallback(formattedTick, index, ticks);
- } else {
- return formattedTick;
- }
- }, this);
+ if (this.options.ticks.userCallback) {
+ return this.options.ticks.userCallback(formattedTick, index, ticks);
+ } else {
+ return formattedTick;
+ }
+ },
+ convertTicksToLabels: function() {
+ this.ticks = this.ticks.map(this.tickFormatFunction, this);
},
getPixelForValue: function(value, index, datasetIndex, includeOffset) {
var labelMoment = this.getLabelMoment(datasetIndex, index);
if (labelMoment) {
var offset = labelMoment.diff(this.firstTick, this.tickUnit, true);
- var decimal = offset / this.tickRange;
+ var decimal = offset / this.scaleSizeInUnits;
if (this.isHorizontal()) {
var innerWidth = this.width - (this.paddingLeft + this.paddingRight);