New time scale ticks.bounds option (#4556)

`ticks.bounds` (`'data'`(default)|`'label'`): `data` preserves the data range while `labels` ensures that all labels are visible. This option is bypassed by the min/max time options.

Remove the useless time scale `_model` object containing private members: instead, make these members private (prefixed by `_`) part of the scale.
This commit is contained in:
Simon Brunel
2017-07-25 10:12:53 +02:00
committed by GitHub
parent d07fb28462
commit 3aa7a20923
3 changed files with 360 additions and 128 deletions

View File

@@ -336,8 +336,33 @@ module.exports = function(Chart) {
},
ticks: {
autoSkip: false,
mode: 'linear', // 'linear|series'
source: 'auto' // 'auto|labels'
/**
* Ticks distribution along the scale:
* - 'linear': ticks and data are spread according to their time (distances can vary),
* - 'series': ticks and data are spread at the same distance from each other.
* @see https://github.com/chartjs/Chart.js/pull/4507
* @since 2.7.0
*/
mode: 'linear',
/**
* Ticks generation input values:
* - 'labels': generates ticks from user given `data.labels` values ONLY.
* - 'auto': generates "optimal" ticks based on scale size and time options.
* @see https://github.com/chartjs/Chart.js/pull/4507
* @since 2.7.0
*/
source: 'auto',
/**
* Ticks boundary strategy (bypassed by min/max time options)
* - `data`: make sure data are fully visible, labels outside are removed
* - `labels`: make sure labels are fully visible, data outside are truncated
* @see https://github.com/chartjs/Chart.js/pull/4556
* @since 2.7.0
*/
bounds: 'data'
}
};
@@ -383,8 +408,8 @@ module.exports = function(Chart) {
var chart = me.chart;
var options = me.options;
var datasets = chart.data.datasets || [];
var min = MAX_INTEGER;
var max = MIN_INTEGER;
var min = parse(options.time.min, me) || MAX_INTEGER;
var max = parse(options.time.max, me) || MIN_INTEGER;
var timestamps = [];
var labels = [];
var i, j, ilen, jlen, data, timestamp;
@@ -420,29 +445,25 @@ module.exports = function(Chart) {
}
}
// Enforce limits with user min/max options
min = parse(options.time.min, me) || min;
max = parse(options.time.max, me) || max;
// In case there is no valid min/max, let's use today limits
min = min === MAX_INTEGER ? +moment().startOf('day') : min;
max = max === MIN_INTEGER ? +moment().endOf('day') + 1 : max;
me._model = {
datasets: timestamps,
horizontal: me.isHorizontal(),
labels: labels.sort(sorter), // Sort labels **after** data have been converted
min: Math.min(min, max), // Make sure that max is **strictly** higher ...
max: Math.max(min + 1, max), // ... than min (required by the lookup table)
table: []
};
// Make sure that max is strictly higher than min (required by the lookup table)
me.min = Math.min(min, max);
me.max = Math.max(min + 1, max);
// PRIVATE
me._datasets = timestamps;
me._horizontal = me.isHorizontal();
me._labels = labels.sort(sorter); // Sort labels **after** data have been converted
me._table = [];
},
buildTicks: function() {
var me = this;
var model = me._model;
var min = model.min;
var max = model.max;
var min = me.min;
var max = me.max;
var timeOpts = me.options.time;
var ticksOpts = me.options.ticks;
var formats = timeOpts.displayFormats;
@@ -458,14 +479,19 @@ module.exports = function(Chart) {
|| determineStepSize(min, max, unit, capacity);
timestamps = generate(min, max, unit, majorUnit, stepSize, timeOpts);
// Expand min/max to the generated ticks
min = helpers.isNullOrUndef(timeOpts.min) && timestamps.length ? timestamps[0] : min;
max = helpers.isNullOrUndef(timeOpts.max) && timestamps.length ? timestamps[timestamps.length - 1] : max;
} else {
timestamps = model.labels;
timestamps = me._labels;
}
if (ticksOpts.bounds === 'labels' && timestamps.length) {
min = timestamps[0];
max = timestamps[timestamps.length - 1];
}
// Enforce limits with user min/max options
min = parse(timeOpts.min, me) || min;
max = parse(timeOpts.max, me) || max;
// Remove ticks outside the min/max range
for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
timestamp = timestamps[i];
@@ -477,12 +503,13 @@ module.exports = function(Chart) {
me.ticks = ticks;
me.min = min;
me.max = max;
me.unit = unit;
me.majorUnit = majorUnit;
me.displayFormat = formats[unit];
me.majorDisplayFormat = formats[majorUnit];
model.table = buildLookupTable(ticks, min, max, ticksOpts.mode === 'linear');
// PRIVATE
me._unit = unit;
me._majorUnit = majorUnit;
me._displayFormat = formats[unit];
me._majorDisplayFormat = formats[majorUnit];
me._table = buildLookupTable(ticks, min, max, ticksOpts.mode === 'linear');
},
getLabelForIndex: function(index, datasetIndex) {
@@ -510,11 +537,11 @@ module.exports = function(Chart) {
var me = this;
var options = me.options;
var time = tick.valueOf();
var majorUnit = me.majorUnit;
var majorFormat = me.majorDisplayFormat;
var majorTime = tick.clone().startOf(me.majorUnit).valueOf();
var majorUnit = me._majorUnit;
var majorFormat = me._majorDisplayFormat;
var majorTime = tick.clone().startOf(me._majorUnit).valueOf();
var major = majorUnit && majorFormat && time === majorTime;
var formattedTick = tick.format(major ? majorFormat : me.displayFormat);
var formattedTick = tick.format(major ? majorFormat : me._displayFormat);
var tickOpts = major ? options.ticks.major : options.ticks.minor;
var formatter = helpers.valueOrDefault(tickOpts.callback, tickOpts.userCallback);
@@ -543,10 +570,9 @@ module.exports = function(Chart) {
*/
getPixelForOffset: function(time) {
var me = this;
var model = me._model;
var size = model.horizontal ? me.width : me.height;
var start = model.horizontal ? me.left : me.top;
var pos = interpolate(model.table, 'time', time, 'pos');
var size = me._horizontal ? me.width : me.height;
var start = me._horizontal ? me.left : me.top;
var pos = interpolate(me._table, 'time', time, 'pos');
return start + size * pos;
},
@@ -556,7 +582,7 @@ module.exports = function(Chart) {
var time = null;
if (index !== undefined && datasetIndex !== undefined) {
time = me._model.datasets[datasetIndex][index];
time = me._datasets[datasetIndex][index];
}
if (time === null) {
@@ -576,11 +602,10 @@ module.exports = function(Chart) {
getValueForPixel: function(pixel) {
var me = this;
var model = me._model;
var size = model.horizontal ? me.width : me.height;
var start = model.horizontal ? me.left : me.top;
var size = me._horizontal ? me.width : me.height;
var start = me._horizontal ? me.left : me.top;
var pos = size ? (pixel - start) / size : 0;
var time = interpolate(model.table, 'pos', pos, 'time');
var time = interpolate(me._table, 'pos', pos, 'time');
return moment(time);
},
@@ -607,7 +632,7 @@ module.exports = function(Chart) {
getLabelCapacity: function(exampleTime) {
var me = this;
me.displayFormat = me.options.time.displayFormats.millisecond; // Pick the longest format for guestimation
me._displayFormat = me.options.time.displayFormats.millisecond; // Pick the longest format for guestimation
var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, []).value;
var tickLabelWidth = me.getLabelWidth(exampleLabel);

View File

@@ -268,6 +268,9 @@ describe('Deprecations', function() {
time: {
unit: 'hour',
unitStepSize: 2
},
ticks: {
bounds: 'labels'
}
}]
}

View File

@@ -92,6 +92,7 @@ describe('Time scale tests', function() {
mirror: false,
mode: 'linear',
source: 'auto',
bounds: 'data',
padding: 0,
reverse: false,
display: true,
@@ -144,7 +145,8 @@ describe('Time scale tests', function() {
scale.update(1000, 200);
var ticks = getTicksValues(scale.ticks);
expect(ticks).toEqual(['Jan 2015', 'Jan 2', 'Jan 3', 'Jan 4', 'Jan 5', 'Jan 6', 'Jan 7', 'Jan 8', 'Jan 9', 'Jan 10', 'Jan 11']);
// `ticks.bounds === 'data'`: first and last ticks removed since outside the data range
expect(ticks).toEqual(['Jan 2', 'Jan 3', 'Jan 4', 'Jan 5', 'Jan 6', 'Jan 7', 'Jan 8', 'Jan 9', 'Jan 10']);
});
it('should accept labels as date objects', function() {
@@ -155,7 +157,8 @@ describe('Time scale tests', function() {
scale.update(1000, 200);
var ticks = getTicksValues(scale.ticks);
expect(ticks).toEqual(['Jan 2015', 'Jan 2', 'Jan 3', 'Jan 4', 'Jan 5', 'Jan 6', 'Jan 7', 'Jan 8', 'Jan 9', 'Jan 10', 'Jan 11']);
// `ticks.bounds === 'data'`: first and last ticks removed since outside the data range
expect(ticks).toEqual(['Jan 2', 'Jan 3', 'Jan 4', 'Jan 5', 'Jan 6', 'Jan 7', 'Jan 8', 'Jan 9', 'Jan 10']);
});
it('should accept data as xy points', function() {
@@ -203,7 +206,8 @@ describe('Time scale tests', function() {
xScale.update(800, 200);
var ticks = getTicksValues(xScale.ticks);
expect(ticks).toEqual(['Jan 2015', 'Jan 2', 'Jan 3', 'Jan 4', 'Jan 5', 'Jan 6', 'Jan 7', 'Jan 8', 'Jan 9', 'Jan 10', 'Jan 11']);
// `ticks.bounds === 'data'`: first and last ticks removed since outside the data range
expect(ticks).toEqual(['Jan 2', 'Jan 3', 'Jan 4', 'Jan 5', 'Jan 6', 'Jan 7', 'Jan 8', 'Jan 9', 'Jan 10']);
});
it('should accept data as ty points', function() {
@@ -251,7 +255,8 @@ describe('Time scale tests', function() {
tScale.update(800, 200);
var ticks = getTicksValues(tScale.ticks);
expect(ticks).toEqual(['Jan 2015', 'Jan 2', 'Jan 3', 'Jan 4', 'Jan 5', 'Jan 6', 'Jan 7', 'Jan 8', 'Jan 9', 'Jan 10', 'Jan 11']);
// `ticks.bounds === 'data'`: first and last ticks removed since outside the data range
expect(ticks).toEqual(['Jan 2', 'Jan 3', 'Jan 4', 'Jan 5', 'Jan 6', 'Jan 7', 'Jan 8', 'Jan 9', 'Jan 10']);
});
});
@@ -259,12 +264,10 @@ describe('Time scale tests', function() {
var chart = window.acquireChart({
type: 'line',
data: {
labels: ['foo', 'bar'],
datasets: [{
xAxisID: 'xScale0',
data: [{
x: 375068900,
y: 1
}]
data: [0, 1]
}],
},
options: {
@@ -277,8 +280,13 @@ describe('Time scale tests', function() {
unit: 'day',
round: true,
parser: function(label) {
return moment.unix(label);
return label === 'foo' ?
moment(946771200000) : // 02/01/2000 @ 12:00am (UTC)
moment(1462665600000); // 05/08/2016 @ 12:00am (UTC)
}
},
ticks: {
source: 'labels'
}
}],
}
@@ -289,8 +297,8 @@ describe('Time scale tests', function() {
var xScale = chart.scales.xScale0;
// Counts down because the lines are drawn top to bottom
expect(xScale.ticks[0].value).toEqualOneOf(['Nov 19', 'Nov 20', 'Nov 21']); // handle time zone changes
expect(xScale.ticks[1].value).toEqualOneOf(['Nov 19', 'Nov 20', 'Nov 21']); // handle time zone changes
expect(xScale.ticks[0].value).toBe('Jan 2');
expect(xScale.ticks[1].value).toBe('May 8');
});
it('should build ticks using the config unit', function() {
@@ -313,8 +321,14 @@ describe('Time scale tests', function() {
labels: ['2015-01-01T20:00:00', '2015-01-02T21:00:00'], // days
};
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('time'));
config.time.minUnit = 'day';
var config = Chart.helpers.mergeIf({
time: {
minUnit: 'day'
},
ticks: {
bounds: 'labels'
}
}, Chart.scaleService.getScaleDefaults('time'));
var scale = createScale(mockData, config);
var ticks = getTicksValues(scale.ticks);
@@ -327,9 +341,15 @@ describe('Time scale tests', function() {
labels: ['2015-01-01T20:00:00', '2015-02-02T21:00:00', '2015-02-21T01:00:00'], // days
};
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('time'));
config.time.unit = 'week';
config.time.round = 'week';
var config = Chart.helpers.mergeIf({
time: {
unit: 'week',
round: 'week'
},
ticks: {
bounds: 'labels'
}
}, Chart.scaleService.getScaleDefaults('time'));
var scale = createScale(mockData, config);
scale.update(800, 200);
@@ -345,9 +365,15 @@ describe('Time scale tests', function() {
labels: ['2015-01-01T20:00:00', '2015-01-01T21:00:00'],
};
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('time'));
config.time.unit = 'hour';
config.time.stepSize = 2;
var config = Chart.helpers.mergeIf({
time: {
unit: 'hour',
stepSize: 2
},
ticks: {
bounds: 'labels'
}
}, Chart.scaleService.getScaleDefaults('time'));
var scale = createScale(mockData, config);
scale.update(2500, 200);
@@ -394,10 +420,16 @@ describe('Time scale tests', function() {
]
};
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('time'));
config.time.unit = 'week';
// Wednesday
config.time.isoWeekday = 3;
var config = Chart.helpers.mergeIf({
time: {
unit: 'week',
isoWeekday: 3 // Wednesday
},
ticks: {
bounds: 'labels'
}
}, Chart.scaleService.getScaleDefaults('time'));
var scale = createScale(mockData, config);
var ticks = getTicksValues(scale.ticks);
@@ -405,50 +437,64 @@ describe('Time scale tests', function() {
});
describe('when rendering several days', function() {
var chart = window.acquireChart({
type: 'line',
data: {
datasets: [{
xAxisID: 'xScale0',
data: []
}],
labels: ['2015-01-01T20:00:00', '2015-01-02T21:00:00', '2015-01-03T22:00:00', '2015-01-05T23:00:00', '2015-01-07T03:00', '2015-01-08T10:00', '2015-01-10T12:00'], // days
},
options: {
scales: {
xAxes: [{
id: 'xScale0',
type: 'time',
position: 'bottom'
beforeEach(function() {
this.chart = window.acquireChart({
type: 'line',
data: {
datasets: [{
xAxisID: 'xScale0',
data: []
}],
labels: [
'2015-01-01T20:00:00',
'2015-01-02T21:00:00',
'2015-01-03T22:00:00',
'2015-01-05T23:00:00',
'2015-01-07T03:00',
'2015-01-08T10:00',
'2015-01-10T12:00'
]
},
options: {
scales: {
xAxes: [{
id: 'xScale0',
type: 'time',
position: 'bottom'
}],
}
}
}
});
this.scale = this.chart.scales.xScale0;
});
var xScale = chart.scales.xScale0;
it('should be bounded by the nearest week beginnings', function() {
expect(xScale.getValueForPixel(xScale.left)).toBeGreaterThan(moment(chart.data.labels[0]).startOf('week'));
expect(xScale.getValueForPixel(xScale.right)).toBeLessThan(moment(chart.data.labels[chart.data.labels.length - 1]).add(1, 'week').endOf('week'));
var chart = this.chart;
var scale = this.scale;
expect(scale.getValueForPixel(scale.left)).toBeGreaterThan(moment(chart.data.labels[0]).startOf('week'));
expect(scale.getValueForPixel(scale.right)).toBeLessThan(moment(chart.data.labels[chart.data.labels.length - 1]).add(1, 'week').endOf('week'));
});
it('should convert between screen coordinates and times', function() {
var timeRange = moment(xScale.max).valueOf() - moment(xScale.min).valueOf();
var msPerPix = timeRange / xScale.width;
var firstPointOffsetMs = moment(chart.config.data.labels[0]).valueOf() - xScale.min;
var firstPointPixel = xScale.left + firstPointOffsetMs / msPerPix;
var lastPointOffsetMs = moment(chart.config.data.labels[chart.config.data.labels.length - 1]).valueOf() - xScale.min;
var lastPointPixel = xScale.left + lastPointOffsetMs / msPerPix;
var chart = this.chart;
var scale = this.scale;
var timeRange = moment(scale.max).valueOf() - moment(scale.min).valueOf();
var msPerPix = timeRange / scale.width;
var firstPointOffsetMs = moment(chart.config.data.labels[0]).valueOf() - scale.min;
var firstPointPixel = scale.left + firstPointOffsetMs / msPerPix;
var lastPointOffsetMs = moment(chart.config.data.labels[chart.config.data.labels.length - 1]).valueOf() - scale.min;
var lastPointPixel = scale.left + lastPointOffsetMs / msPerPix;
expect(xScale.getPixelForValue('', 0, 0)).toBeCloseToPixel(firstPointPixel);
expect(xScale.getPixelForValue(chart.data.labels[0])).toBeCloseToPixel(firstPointPixel);
expect(xScale.getValueForPixel(firstPointPixel)).toBeCloseToTime({
expect(scale.getPixelForValue('', 0, 0)).toBeCloseToPixel(firstPointPixel);
expect(scale.getPixelForValue(chart.data.labels[0])).toBeCloseToPixel(firstPointPixel);
expect(scale.getValueForPixel(firstPointPixel)).toBeCloseToTime({
value: moment(chart.data.labels[0]),
unit: 'hour',
});
expect(xScale.getPixelForValue('', 6, 0)).toBeCloseToPixel(lastPointPixel);
expect(xScale.getValueForPixel(lastPointPixel)).toBeCloseToTime({
expect(scale.getPixelForValue('', 6, 0)).toBeCloseToPixel(lastPointPixel);
expect(scale.getValueForPixel(lastPointPixel)).toBeCloseToTime({
value: moment(chart.data.labels[6]),
unit: 'hour'
});
@@ -456,51 +502,58 @@ describe('Time scale tests', function() {
});
describe('when rendering several years', function() {
var chart = window.acquireChart({
type: 'line',
data: {
labels: ['2005-07-04', '2017-01-20'],
},
options: {
scales: {
xAxes: [{
id: 'xScale0',
type: 'time',
position: 'bottom'
}],
beforeEach(function() {
this.chart = window.acquireChart({
type: 'line',
data: {
labels: ['2005-07-04', '2017-01-20'],
},
options: {
scales: {
xAxes: [{
id: 'xScale0',
type: 'time',
position: 'bottom',
ticks: {
bounds: 'labels'
}
}],
}
}
}
});
this.scale = this.chart.scales.xScale0;
this.scale.update(800, 200);
});
var xScale = chart.scales.xScale0;
xScale.update(800, 200);
var step = xScale.ticks[1].time - xScale.ticks[0].time;
var stepsAmount = Math.floor((xScale.max - xScale.min) / step);
it('should be bounded by nearest step\'s year start and end', function() {
expect(xScale.getValueForPixel(xScale.left)).toBeCloseToTime({
value: moment(xScale.min).startOf('year'),
var scale = this.scale;
var step = scale.ticks[1].time - scale.ticks[0].time;
var stepsAmount = Math.floor((scale.max - scale.min) / step);
expect(scale.getValueForPixel(scale.left)).toBeCloseToTime({
value: moment(scale.min).startOf('year'),
unit: 'hour',
});
expect(xScale.getValueForPixel(xScale.right)).toBeCloseToTime({
value: moment(xScale.min + step * stepsAmount).endOf('year'),
expect(scale.getValueForPixel(scale.right)).toBeCloseToTime({
value: moment(scale.min + step * stepsAmount).endOf('year'),
unit: 'hour',
});
});
it('should build the correct ticks', function() {
// Where 'correct' is a two year spacing.
expect(getTicksValues(xScale.ticks)).toEqual(['2005', '2007', '2009', '2011', '2013', '2015', '2017', '2019']);
expect(getTicksValues(this.scale.ticks)).toEqual(['2005', '2007', '2009', '2011', '2013', '2015', '2017', '2019']);
});
it('should have ticks with accurate labels', function() {
var ticks = xScale.ticks;
var pixelsPerYear = xScale.width / 14;
var scale = this.scale;
var ticks = scale.ticks;
var pixelsPerYear = scale.width / 14;
for (var i = 0; i < ticks.length - 1; i++) {
var offset = 2 * pixelsPerYear * i;
expect(xScale.getValueForPixel(xScale.left + offset)).toBeCloseToTime({
expect(scale.getValueForPixel(scale.left + offset)).toBeCloseToTime({
value: moment(ticks[i].value + '-01-01'),
unit: 'day',
threshold: 0.5,
@@ -638,7 +691,7 @@ describe('Time scale tests', function() {
expect(scale.min).toEqual(+moment('2012', 'YYYY'));
expect(scale.max).toEqual(+moment('2051', 'YYYY'));
expect(getTicksValues(this.chart.scales.x.ticks)).toEqual([
expect(getTicksValues(scale.ticks)).toEqual([
'2017', '2019', '2020', '2025', '2042']);
});
it ('should remove ticks that are not inside the min and max time range', function() {
@@ -652,7 +705,7 @@ describe('Time scale tests', function() {
expect(scale.min).toEqual(+moment('2022', 'YYYY'));
expect(scale.max).toEqual(+moment('2032', 'YYYY'));
expect(getTicksValues(this.chart.scales.x.ticks)).toEqual([
expect(getTicksValues(scale.ticks)).toEqual([
'2025']);
});
it ('should not duplicate ticks if min and max are the labels limits', function() {
@@ -666,7 +719,7 @@ describe('Time scale tests', function() {
expect(scale.min).toEqual(+moment('2017', 'YYYY'));
expect(scale.max).toEqual(+moment('2042', 'YYYY'));
expect(getTicksValues(this.chart.scales.x.ticks)).toEqual([
expect(getTicksValues(scale.ticks)).toEqual([
'2017', '2019', '2020', '2025', '2042']);
});
it ('should correctly handle empty `data.labels`', function() {
@@ -678,7 +731,7 @@ describe('Time scale tests', function() {
expect(scale.min).toEqual(+moment().startOf('day'));
expect(scale.max).toEqual(+moment().endOf('day') + 1);
expect(getTicksValues(this.chart.scales.x.ticks)).toEqual([]);
expect(getTicksValues(scale.ticks)).toEqual([]);
});
});
});
@@ -834,4 +887,155 @@ describe('Time scale tests', function() {
});
});
});
describe('when ticks.bounds', function() {
describe('is "data"', function() {
it ('should preserve the data range', function() {
var chart = window.acquireChart({
type: 'line',
data: {
labels: ['02/20 08:00', '02/21 09:00', '02/22 10:00', '02/23 11:00'],
datasets: [{data: [0, 1, 2, 3, 4, 5]}]
},
options: {
scales: {
xAxes: [{
id: 'x',
type: 'time',
time: {
parser: 'MM/DD HH:mm',
unit: 'day'
},
ticks: {
bounds: 'data'
}
}],
yAxes: [{
display: false
}]
}
}
});
var scale = chart.scales.x;
expect(scale.min).toEqual(+moment('02/20 08:00', 'MM/DD HH:mm'));
expect(scale.max).toEqual(+moment('02/23 11:00', 'MM/DD HH:mm'));
expect(scale.getPixelForValue('02/20 08:00')).toBeCloseToPixel(scale.left);
expect(scale.getPixelForValue('02/23 11:00')).toBeCloseToPixel(scale.left + scale.width);
expect(getTicksValues(scale.ticks)).toEqual([
'Feb 21', 'Feb 22', 'Feb 23']);
});
});
describe('is "labels"', function() {
it('should preserve the label range', function() {
var chart = window.acquireChart({
type: 'line',
data: {
labels: ['02/20 08:00', '02/21 09:00', '02/22 10:00', '02/23 11:00'],
datasets: [{data: [0, 1, 2, 3, 4, 5]}]
},
options: {
scales: {
xAxes: [{
id: 'x',
type: 'time',
time: {
parser: 'MM/DD HH:mm',
unit: 'day'
},
ticks: {
bounds: 'labels'
}
}],
yAxes: [{
display: false
}]
}
}
});
var scale = chart.scales.x;
var ticks = scale.ticks;
expect(scale.min).toEqual(ticks[0].time);
expect(scale.max).toEqual(ticks[ticks.length - 1].time);
expect(scale.getPixelForValue('02/20 08:00')).toBeCloseToPixel(77);
expect(scale.getPixelForValue('02/23 11:00')).toBeCloseToPixel(412);
expect(getTicksValues(scale.ticks)).toEqual([
'Feb 20', 'Feb 21', 'Feb 22', 'Feb 23', 'Feb 24']);
});
});
});
describe('when time.min and/or time.max are defined', function() {
['auto', 'labels'].forEach(function(source) {
['data', 'labels'].forEach(function(bounds) {
describe('and source is "' + source + '" and bounds "' + bounds + '"', function() {
beforeEach(function() {
this.chart = window.acquireChart({
type: 'line',
data: {
labels: ['02/20 08:00', '02/21 09:00', '02/22 10:00', '02/23 11:00'],
datasets: [{data: [0, 1, 2, 3, 4, 5]}]
},
options: {
scales: {
xAxes: [{
id: 'x',
type: 'time',
time: {
parser: 'MM/DD HH:mm',
unit: 'day'
},
ticks: {
source: source,
bounds: bounds
}
}],
yAxes: [{
display: false
}]
}
}
});
});
it ('should expand scale to the min/max range', function() {
var chart = this.chart;
var scale = chart.scales.x;
var options = chart.options.scales.xAxes[0];
var min = '02/19 07:00';
var max = '02/24 08:00';
options.time.min = min;
options.time.max = max;
chart.update();
expect(scale.min).toEqual(+moment(min, 'MM/DD HH:mm'));
expect(scale.max).toEqual(+moment(max, 'MM/DD HH:mm'));
expect(scale.getPixelForValue(min)).toBeCloseToPixel(scale.left);
expect(scale.getPixelForValue(max)).toBeCloseToPixel(scale.left + scale.width);
});
it ('should shrink scale to the min/max range', function() {
var chart = this.chart;
var scale = chart.scales.x;
var options = chart.options.scales.xAxes[0];
var min = '02/21 07:00';
var max = '02/22 20:00';
options.time.min = min;
options.time.max = max;
chart.update();
expect(scale.min).toEqual(+moment(min, 'MM/DD HH:mm'));
expect(scale.max).toEqual(+moment(max, 'MM/DD HH:mm'));
expect(scale.getPixelForValue(min)).toBeCloseToPixel(scale.left);
expect(scale.getPixelForValue(max)).toBeCloseToPixel(scale.left + scale.width);
});
});
});
});
});
});