mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Add a new `offset` option to scales to add extra space at edges and remove the `includeOffset` argument from `getPixelForValue()` and `getPixelForTick()`. The bar controller now automatically calculates the bar width to avoid overlaps. When `offsetGridLines` is true, grid lines move to the left by one half of the tick interval, and labels don't move.
1173 lines
32 KiB
JavaScript
Executable File
1173 lines
32 KiB
JavaScript
Executable File
// Time scale tests
|
|
describe('Time scale tests', function() {
|
|
function createScale(data, options) {
|
|
var scaleID = 'myScale';
|
|
var mockContext = window.createMockContext();
|
|
var Constructor = Chart.scaleService.getScaleConstructor('time');
|
|
var scale = new Constructor({
|
|
ctx: mockContext,
|
|
options: options,
|
|
chart: {
|
|
data: data
|
|
},
|
|
id: scaleID
|
|
});
|
|
|
|
scale.update(400, 50);
|
|
return scale;
|
|
}
|
|
|
|
function getTicksLabels(scale) {
|
|
return scale.ticks;
|
|
}
|
|
|
|
beforeEach(function() {
|
|
// Need a time matcher for getValueFromPixel
|
|
jasmine.addMatchers({
|
|
toBeCloseToTime: function() {
|
|
return {
|
|
compare: function(actual, expected) {
|
|
var result = false;
|
|
|
|
var diff = actual.diff(expected.value, expected.unit, true);
|
|
result = Math.abs(diff) < (expected.threshold !== undefined ? expected.threshold : 0.01);
|
|
|
|
return {
|
|
pass: result
|
|
};
|
|
}
|
|
};
|
|
}
|
|
});
|
|
});
|
|
|
|
it('should load moment.js as a dependency', function() {
|
|
expect(window.moment).not.toBe(undefined);
|
|
});
|
|
|
|
it('should register the constructor with the scale service', function() {
|
|
var Constructor = Chart.scaleService.getScaleConstructor('time');
|
|
expect(Constructor).not.toBe(undefined);
|
|
expect(typeof Constructor).toBe('function');
|
|
});
|
|
|
|
it('should have the correct default config', function() {
|
|
var defaultConfig = Chart.scaleService.getScaleDefaults('time');
|
|
expect(defaultConfig).toEqual({
|
|
display: true,
|
|
gridLines: {
|
|
color: 'rgba(0, 0, 0, 0.1)',
|
|
drawBorder: true,
|
|
drawOnChartArea: true,
|
|
drawTicks: true,
|
|
tickMarkLength: 10,
|
|
lineWidth: 1,
|
|
offsetGridLines: false,
|
|
display: true,
|
|
zeroLineColor: 'rgba(0,0,0,0.25)',
|
|
zeroLineWidth: 1,
|
|
zeroLineBorderDash: [],
|
|
zeroLineBorderDashOffset: 0.0,
|
|
borderDash: [],
|
|
borderDashOffset: 0.0
|
|
},
|
|
position: 'bottom',
|
|
offset: false,
|
|
scaleLabel: {
|
|
display: false,
|
|
labelString: '',
|
|
lineHeight: 1.2
|
|
},
|
|
bounds: 'data',
|
|
distribution: 'linear',
|
|
ticks: {
|
|
beginAtZero: false,
|
|
minRotation: 0,
|
|
maxRotation: 50,
|
|
mirror: false,
|
|
source: 'auto',
|
|
padding: 0,
|
|
reverse: false,
|
|
display: true,
|
|
callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below,
|
|
autoSkip: false,
|
|
autoSkipPadding: 0,
|
|
labelOffset: 0,
|
|
minor: {},
|
|
major: {},
|
|
},
|
|
time: {
|
|
parser: false,
|
|
format: false,
|
|
unit: false,
|
|
round: false,
|
|
isoWeekday: false,
|
|
displayFormat: false,
|
|
minUnit: 'millisecond',
|
|
displayFormats: {
|
|
millisecond: 'h:mm:ss.SSS a', // 11:20:01.123 AM
|
|
second: 'h:mm:ss a', // 11:20:01 AM
|
|
minute: 'h:mm a', // 11:20 AM
|
|
hour: 'hA', // 5PM
|
|
day: 'MMM D', // Sep 4
|
|
week: 'll', // Week 46, or maybe "[W]WW - YYYY" ?
|
|
month: 'MMM YYYY', // Sept 2015
|
|
quarter: '[Q]Q - YYYY', // Q3
|
|
year: 'YYYY' // 2015
|
|
},
|
|
}
|
|
});
|
|
|
|
// Is this actually a function
|
|
expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
|
|
});
|
|
|
|
describe('when given inputs of different types', function() {
|
|
// Helper to build date objects
|
|
function newDateFromRef(days) {
|
|
return moment('01/01/2015 12:00', 'DD/MM/YYYY HH:mm').add(days, 'd').toDate();
|
|
}
|
|
|
|
it('should accept labels as strings', function() {
|
|
var mockData = {
|
|
labels: ['2015-01-01T12: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
|
|
};
|
|
|
|
var scaleOptions = Chart.scaleService.getScaleDefaults('time');
|
|
var scale = createScale(mockData, scaleOptions);
|
|
scale.update(1000, 200);
|
|
var ticks = getTicksLabels(scale);
|
|
|
|
// `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() {
|
|
var mockData = {
|
|
labels: [newDateFromRef(0), newDateFromRef(1), newDateFromRef(2), newDateFromRef(4), newDateFromRef(6), newDateFromRef(7), newDateFromRef(9)], // days
|
|
};
|
|
var scale = createScale(mockData, Chart.scaleService.getScaleDefaults('time'));
|
|
scale.update(1000, 200);
|
|
var ticks = getTicksLabels(scale);
|
|
|
|
// `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() {
|
|
var chart = window.acquireChart({
|
|
type: 'line',
|
|
data: {
|
|
datasets: [{
|
|
xAxisID: 'xScale0',
|
|
data: [{
|
|
x: newDateFromRef(0),
|
|
y: 1
|
|
}, {
|
|
x: newDateFromRef(1),
|
|
y: 10
|
|
}, {
|
|
x: newDateFromRef(2),
|
|
y: 0
|
|
}, {
|
|
x: newDateFromRef(4),
|
|
y: 5
|
|
}, {
|
|
x: newDateFromRef(6),
|
|
y: 77
|
|
}, {
|
|
x: newDateFromRef(7),
|
|
y: 9
|
|
}, {
|
|
x: newDateFromRef(9),
|
|
y: 5
|
|
}]
|
|
}],
|
|
},
|
|
options: {
|
|
scales: {
|
|
xAxes: [{
|
|
id: 'xScale0',
|
|
type: 'time',
|
|
position: 'bottom'
|
|
}],
|
|
}
|
|
}
|
|
});
|
|
|
|
var xScale = chart.scales.xScale0;
|
|
xScale.update(800, 200);
|
|
var ticks = getTicksLabels(xScale);
|
|
|
|
// `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() {
|
|
var chart = window.acquireChart({
|
|
type: 'line',
|
|
data: {
|
|
datasets: [{
|
|
xAxisID: 'tScale0',
|
|
data: [{
|
|
t: newDateFromRef(0),
|
|
y: 1
|
|
}, {
|
|
t: newDateFromRef(1),
|
|
y: 10
|
|
}, {
|
|
t: newDateFromRef(2),
|
|
y: 0
|
|
}, {
|
|
t: newDateFromRef(4),
|
|
y: 5
|
|
}, {
|
|
t: newDateFromRef(6),
|
|
y: 77
|
|
}, {
|
|
t: newDateFromRef(7),
|
|
y: 9
|
|
}, {
|
|
t: newDateFromRef(9),
|
|
y: 5
|
|
}]
|
|
}],
|
|
},
|
|
options: {
|
|
scales: {
|
|
xAxes: [{
|
|
id: 'tScale0',
|
|
type: 'time',
|
|
position: 'bottom'
|
|
}],
|
|
}
|
|
}
|
|
});
|
|
|
|
var tScale = chart.scales.tScale0;
|
|
tScale.update(800, 200);
|
|
var ticks = getTicksLabels(tScale);
|
|
|
|
// `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 allow custom time parsers', function() {
|
|
var chart = window.acquireChart({
|
|
type: 'line',
|
|
data: {
|
|
labels: ['foo', 'bar'],
|
|
datasets: [{
|
|
xAxisID: 'xScale0',
|
|
data: [0, 1]
|
|
}],
|
|
},
|
|
options: {
|
|
scales: {
|
|
xAxes: [{
|
|
id: 'xScale0',
|
|
type: 'time',
|
|
position: 'bottom',
|
|
time: {
|
|
unit: 'day',
|
|
round: true,
|
|
parser: function(label) {
|
|
return label === 'foo' ?
|
|
moment('2000/01/02', 'YYYY/MM/DD') :
|
|
moment('2016/05/08', 'YYYY/MM/DD');
|
|
}
|
|
},
|
|
ticks: {
|
|
source: 'labels'
|
|
}
|
|
}],
|
|
}
|
|
}
|
|
});
|
|
|
|
// Counts down because the lines are drawn top to bottom
|
|
var xScale = chart.scales.xScale0;
|
|
|
|
// Counts down because the lines are drawn top to bottom
|
|
expect(xScale.ticks[0]).toBe('Jan 2');
|
|
expect(xScale.ticks[1]).toBe('May 8');
|
|
});
|
|
|
|
it('should build ticks using the config unit', function() {
|
|
var mockData = {
|
|
labels: ['2015-01-01T20:00:00', '2015-01-02T21:00:00'], // days
|
|
};
|
|
|
|
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('time'));
|
|
config.time.unit = 'hour';
|
|
|
|
var scale = createScale(mockData, config);
|
|
scale.update(2500, 200);
|
|
var ticks = getTicksLabels(scale);
|
|
|
|
expect(ticks).toEqual(['8PM', '9PM', '10PM', '11PM', 'Jan 2', '1AM', '2AM', '3AM', '4AM', '5AM', '6AM', '7AM', '8AM', '9AM', '10AM', '11AM', '12PM', '1PM', '2PM', '3PM', '4PM', '5PM', '6PM', '7PM', '8PM', '9PM']);
|
|
});
|
|
|
|
it('build ticks honoring the minUnit', function() {
|
|
var mockData = {
|
|
labels: ['2015-01-01T20:00:00', '2015-01-02T21:00:00'], // days
|
|
};
|
|
|
|
var config = Chart.helpers.mergeIf({
|
|
bounds: 'ticks',
|
|
time: {
|
|
minUnit: 'day'
|
|
}
|
|
}, Chart.scaleService.getScaleDefaults('time'));
|
|
|
|
var scale = createScale(mockData, config);
|
|
var ticks = getTicksLabels(scale);
|
|
|
|
expect(ticks).toEqual(['Jan 2015', 'Jan 2', 'Jan 3']);
|
|
});
|
|
|
|
it('should build ticks using the config diff', function() {
|
|
var mockData = {
|
|
labels: ['2015-01-01T20:00:00', '2015-02-02T21:00:00', '2015-02-21T01:00:00'], // days
|
|
};
|
|
|
|
var config = Chart.helpers.mergeIf({
|
|
bounds: 'ticks',
|
|
time: {
|
|
unit: 'week',
|
|
round: 'week'
|
|
}
|
|
}, Chart.scaleService.getScaleDefaults('time'));
|
|
|
|
var scale = createScale(mockData, config);
|
|
scale.update(800, 200);
|
|
var ticks = getTicksLabels(scale);
|
|
|
|
// last date is feb 15 because we round to start of week
|
|
expect(ticks).toEqual(['Dec 28, 2014', 'Jan 4, 2015', 'Jan 11, 2015', 'Jan 18, 2015', 'Jan 25, 2015', 'Feb 2015', 'Feb 8, 2015', 'Feb 15, 2015']);
|
|
});
|
|
|
|
describe('config step size', function() {
|
|
it('should use the stepSize property', function() {
|
|
var mockData = {
|
|
labels: ['2015-01-01T20:00:00', '2015-01-01T21:00:00'],
|
|
};
|
|
|
|
var config = Chart.helpers.mergeIf({
|
|
bounds: 'ticks',
|
|
time: {
|
|
unit: 'hour',
|
|
stepSize: 2
|
|
}
|
|
}, Chart.scaleService.getScaleDefaults('time'));
|
|
|
|
var scale = createScale(mockData, config);
|
|
scale.update(2500, 200);
|
|
var ticks = getTicksLabels(scale);
|
|
|
|
expect(ticks).toEqual(['8PM', '10PM']);
|
|
});
|
|
});
|
|
|
|
describe('when specifying limits', function() {
|
|
var mockData = {
|
|
labels: ['2015-01-01T20:00:00', '2015-01-02T20:00:00', '2015-01-03T20:00:00'],
|
|
};
|
|
|
|
var config;
|
|
beforeEach(function() {
|
|
config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('time'));
|
|
});
|
|
|
|
it('should use the min option', function() {
|
|
config.time.unit = 'day';
|
|
config.time.min = '2014-12-29T04:00:00';
|
|
|
|
var scale = createScale(mockData, config);
|
|
expect(scale.ticks[0]).toEqual('Dec 31');
|
|
});
|
|
|
|
it('should use the max option', function() {
|
|
config.time.unit = 'day';
|
|
config.time.max = '2015-01-05T06:00:00';
|
|
|
|
var scale = createScale(mockData, config);
|
|
|
|
expect(scale.ticks[scale.ticks.length - 1]).toEqual('Jan 5');
|
|
});
|
|
});
|
|
|
|
it('should use the isoWeekday option', function() {
|
|
var mockData = {
|
|
labels: [
|
|
'2015-01-01T20:00:00', // Thursday
|
|
'2015-01-02T20:00:00', // Friday
|
|
'2015-01-03T20:00:00' // Saturday
|
|
]
|
|
};
|
|
|
|
var config = Chart.helpers.mergeIf({
|
|
bounds: 'ticks',
|
|
time: {
|
|
unit: 'week',
|
|
isoWeekday: 3 // Wednesday
|
|
}
|
|
}, Chart.scaleService.getScaleDefaults('time'));
|
|
|
|
var scale = createScale(mockData, config);
|
|
var ticks = getTicksLabels(scale);
|
|
|
|
expect(ticks).toEqual(['Dec 31, 2014', 'Jan 7, 2015']);
|
|
});
|
|
|
|
describe('when rendering several days', function() {
|
|
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;
|
|
});
|
|
|
|
it('should be bounded by the nearest week beginnings', function() {
|
|
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 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(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(scale.getPixelForValue('', 6, 0)).toBeCloseToPixel(lastPointPixel);
|
|
expect(scale.getValueForPixel(lastPointPixel)).toBeCloseToTime({
|
|
value: moment(chart.data.labels[6]),
|
|
unit: 'hour'
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('when rendering several years', function() {
|
|
beforeEach(function() {
|
|
this.chart = window.acquireChart({
|
|
type: 'line',
|
|
data: {
|
|
labels: ['2005-07-04', '2017-01-20'],
|
|
},
|
|
options: {
|
|
scales: {
|
|
xAxes: [{
|
|
id: 'xScale0',
|
|
type: 'time',
|
|
bounds: 'ticks',
|
|
position: 'bottom'
|
|
}],
|
|
}
|
|
}
|
|
});
|
|
|
|
this.scale = this.chart.scales.xScale0;
|
|
this.scale.update(800, 200);
|
|
});
|
|
|
|
it('should be bounded by nearest step\'s year start and end', function() {
|
|
var scale = this.scale;
|
|
var ticks = scale.getTicks();
|
|
var step = ticks[1].value - ticks[0].value;
|
|
var stepsAmount = Math.floor((scale.max - scale.min) / step);
|
|
|
|
expect(scale.getValueForPixel(scale.left)).toBeCloseToTime({
|
|
value: moment(scale.min).startOf('year'),
|
|
unit: 'hour',
|
|
});
|
|
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(getTicksLabels(this.scale)).toEqual(['2005', '2007', '2009', '2011', '2013', '2015', '2017', '2019']);
|
|
});
|
|
|
|
it('should have ticks with accurate labels', function() {
|
|
var scale = this.scale;
|
|
var ticks = scale.getTicks();
|
|
var pixelsPerYear = scale.width / 14;
|
|
|
|
for (var i = 0; i < ticks.length - 1; i++) {
|
|
var offset = 2 * pixelsPerYear * i;
|
|
expect(scale.getValueForPixel(scale.left + offset)).toBeCloseToTime({
|
|
value: moment(ticks[i].label + '-01-01'),
|
|
unit: 'day',
|
|
threshold: 0.5,
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
it('should get the correct label for a data value', function() {
|
|
var chart = window.acquireChart({
|
|
type: 'line',
|
|
data: {
|
|
datasets: [{
|
|
xAxisID: 'xScale0',
|
|
data: [null, 10, 3]
|
|
}],
|
|
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'
|
|
}],
|
|
}
|
|
}
|
|
});
|
|
|
|
var xScale = chart.scales.xScale0;
|
|
expect(xScale.getLabelForIndex(0, 0)).toBeTruthy();
|
|
expect(xScale.getLabelForIndex(0, 0)).toBe('2015-01-01T20:00:00');
|
|
expect(xScale.getLabelForIndex(6, 0)).toBe('2015-01-10T12:00');
|
|
});
|
|
|
|
it('should get the correct pixel for only one data in the dataset', function() {
|
|
var chart = window.acquireChart({
|
|
type: 'line',
|
|
data: {
|
|
labels: ['2016-05-27'],
|
|
datasets: [{
|
|
xAxisID: 'xScale0',
|
|
data: [5]
|
|
}]
|
|
},
|
|
options: {
|
|
scales: {
|
|
xAxes: [{
|
|
id: 'xScale0',
|
|
display: true,
|
|
type: 'time'
|
|
}]
|
|
}
|
|
}
|
|
});
|
|
|
|
var xScale = chart.scales.xScale0;
|
|
var pixel = xScale.getPixelForValue('', 0, 0);
|
|
|
|
expect(xScale.getValueForPixel(pixel).valueOf()).toEqual(moment(chart.data.labels[0]).valueOf());
|
|
});
|
|
|
|
it('does not create a negative width chart when hidden', function() {
|
|
var chart = window.acquireChart({
|
|
type: 'line',
|
|
data: {
|
|
datasets: [{
|
|
data: []
|
|
}]
|
|
},
|
|
options: {
|
|
scales: {
|
|
xAxes: [{
|
|
type: 'time',
|
|
time: {
|
|
min: moment().subtract(1, 'months'),
|
|
max: moment(),
|
|
}
|
|
}],
|
|
},
|
|
responsive: true,
|
|
},
|
|
}, {
|
|
wrapper: {
|
|
style: 'display: none',
|
|
},
|
|
});
|
|
expect(chart.scales['y-axis-0'].width).toEqual(0);
|
|
expect(chart.scales['y-axis-0'].maxWidth).toEqual(0);
|
|
expect(chart.width).toEqual(0);
|
|
});
|
|
|
|
describe('when ticks.source', function() {
|
|
describe('is "labels"', function() {
|
|
beforeEach(function() {
|
|
this.chart = window.acquireChart({
|
|
type: 'line',
|
|
data: {
|
|
labels: ['2017', '2019', '2020', '2025', '2042'],
|
|
datasets: [{data: [0, 1, 2, 3, 4, 5]}]
|
|
},
|
|
options: {
|
|
scales: {
|
|
xAxes: [{
|
|
id: 'x',
|
|
type: 'time',
|
|
time: {
|
|
parser: 'YYYY'
|
|
},
|
|
ticks: {
|
|
source: 'labels'
|
|
}
|
|
}]
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
it ('should generate ticks from "data.labels"', function() {
|
|
var scale = this.chart.scales.x;
|
|
|
|
expect(scale.min).toEqual(+moment('2017', 'YYYY'));
|
|
expect(scale.max).toEqual(+moment('2042', 'YYYY'));
|
|
expect(getTicksLabels(scale)).toEqual([
|
|
'2017', '2019', '2020', '2025', '2042']);
|
|
});
|
|
it ('should not add ticks for min and max if they extend the labels range', function() {
|
|
var chart = this.chart;
|
|
var scale = chart.scales.x;
|
|
var options = chart.options.scales.xAxes[0];
|
|
|
|
options.time.min = '2012';
|
|
options.time.max = '2051';
|
|
chart.update();
|
|
|
|
expect(scale.min).toEqual(+moment('2012', 'YYYY'));
|
|
expect(scale.max).toEqual(+moment('2051', 'YYYY'));
|
|
expect(getTicksLabels(scale)).toEqual([
|
|
'2017', '2019', '2020', '2025', '2042']);
|
|
});
|
|
it ('should not duplicate ticks if min and max are the labels limits', function() {
|
|
var chart = this.chart;
|
|
var scale = chart.scales.x;
|
|
var options = chart.options.scales.xAxes[0];
|
|
|
|
options.time.min = '2017';
|
|
options.time.max = '2042';
|
|
chart.update();
|
|
|
|
expect(scale.min).toEqual(+moment('2017', 'YYYY'));
|
|
expect(scale.max).toEqual(+moment('2042', 'YYYY'));
|
|
expect(getTicksLabels(scale)).toEqual([
|
|
'2017', '2019', '2020', '2025', '2042']);
|
|
});
|
|
it ('should correctly handle empty `data.labels`', function() {
|
|
var chart = this.chart;
|
|
var scale = chart.scales.x;
|
|
|
|
chart.data.labels = [];
|
|
chart.update();
|
|
|
|
expect(scale.min).toEqual(+moment().startOf('day'));
|
|
expect(scale.max).toEqual(+moment().endOf('day') + 1);
|
|
expect(getTicksLabels(scale)).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('is "data"', function() {
|
|
beforeEach(function() {
|
|
this.chart = window.acquireChart({
|
|
type: 'line',
|
|
data: {
|
|
labels: ['2017', '2019', '2020', '2025', '2042'],
|
|
datasets: [
|
|
{data: [0, 1, 2, 3, 4, 5]},
|
|
{data: [
|
|
{t: '2018', y: 6},
|
|
{t: '2020', y: 7},
|
|
{t: '2043', y: 8}
|
|
]}
|
|
]
|
|
},
|
|
options: {
|
|
scales: {
|
|
xAxes: [{
|
|
id: 'x',
|
|
type: 'time',
|
|
time: {
|
|
parser: 'YYYY'
|
|
},
|
|
ticks: {
|
|
source: 'data'
|
|
}
|
|
}]
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
it ('should generate ticks from "datasets.data"', function() {
|
|
var scale = this.chart.scales.x;
|
|
|
|
expect(scale.min).toEqual(+moment('2017', 'YYYY'));
|
|
expect(scale.max).toEqual(+moment('2043', 'YYYY'));
|
|
expect(getTicksLabels(scale)).toEqual([
|
|
'2017', '2018', '2019', '2020', '2025', '2042', '2043']);
|
|
});
|
|
it ('should not add ticks for min and max if they extend the labels range', function() {
|
|
var chart = this.chart;
|
|
var scale = chart.scales.x;
|
|
var options = chart.options.scales.xAxes[0];
|
|
|
|
options.time.min = '2012';
|
|
options.time.max = '2051';
|
|
chart.update();
|
|
|
|
expect(scale.min).toEqual(+moment('2012', 'YYYY'));
|
|
expect(scale.max).toEqual(+moment('2051', 'YYYY'));
|
|
expect(getTicksLabels(scale)).toEqual([
|
|
'2017', '2018', '2019', '2020', '2025', '2042', '2043']);
|
|
});
|
|
it ('should not duplicate ticks if min and max are the labels limits', function() {
|
|
var chart = this.chart;
|
|
var scale = chart.scales.x;
|
|
var options = chart.options.scales.xAxes[0];
|
|
|
|
options.time.min = '2017';
|
|
options.time.max = '2043';
|
|
chart.update();
|
|
|
|
expect(scale.min).toEqual(+moment('2017', 'YYYY'));
|
|
expect(scale.max).toEqual(+moment('2043', 'YYYY'));
|
|
expect(getTicksLabels(scale)).toEqual([
|
|
'2017', '2018', '2019', '2020', '2025', '2042', '2043']);
|
|
});
|
|
it ('should correctly handle empty `data.labels`', function() {
|
|
var chart = this.chart;
|
|
var scale = chart.scales.x;
|
|
|
|
chart.data.labels = [];
|
|
chart.update();
|
|
|
|
expect(scale.min).toEqual(+moment('2018', 'YYYY'));
|
|
expect(scale.max).toEqual(+moment('2043', 'YYYY'));
|
|
expect(getTicksLabels(scale)).toEqual([
|
|
'2018', '2020', '2043']);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('when distribution', function() {
|
|
describe('is "series"', function() {
|
|
beforeEach(function() {
|
|
this.chart = window.acquireChart({
|
|
type: 'line',
|
|
data: {
|
|
labels: ['2017', '2019', '2020', '2025', '2042'],
|
|
datasets: [{data: [0, 1, 2, 3, 4, 5]}]
|
|
},
|
|
options: {
|
|
scales: {
|
|
xAxes: [{
|
|
id: 'x',
|
|
type: 'time',
|
|
time: {
|
|
parser: 'YYYY'
|
|
},
|
|
distribution: 'series',
|
|
ticks: {
|
|
source: 'labels'
|
|
}
|
|
}],
|
|
yAxes: [{
|
|
display: false
|
|
}]
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
it ('should space data out with the same gap, whatever their time values', function() {
|
|
var scale = this.chart.scales.x;
|
|
var start = scale.left;
|
|
var slice = scale.width / 4;
|
|
|
|
expect(scale.getPixelForValue('2017')).toBeCloseToPixel(start);
|
|
expect(scale.getPixelForValue('2019')).toBeCloseToPixel(start + slice);
|
|
expect(scale.getPixelForValue('2020')).toBeCloseToPixel(start + slice * 2);
|
|
expect(scale.getPixelForValue('2025')).toBeCloseToPixel(start + slice * 3);
|
|
expect(scale.getPixelForValue('2042')).toBeCloseToPixel(start + slice * 4);
|
|
});
|
|
it ('should add a step before if scale.min is before the first data', function() {
|
|
var chart = this.chart;
|
|
var scale = chart.scales.x;
|
|
var options = chart.options.scales.xAxes[0];
|
|
|
|
options.time.min = '2012';
|
|
chart.update();
|
|
|
|
var start = scale.left;
|
|
var slice = scale.width / 5;
|
|
|
|
expect(scale.getPixelForValue('2017')).toBeCloseToPixel(start + slice);
|
|
expect(scale.getPixelForValue('2042')).toBeCloseToPixel(start + slice * 5);
|
|
});
|
|
it ('should add a step after if scale.max is after the last data', function() {
|
|
var chart = this.chart;
|
|
var scale = chart.scales.x;
|
|
var options = chart.options.scales.xAxes[0];
|
|
|
|
options.time.max = '2050';
|
|
chart.update();
|
|
|
|
var start = scale.left;
|
|
var slice = scale.width / 5;
|
|
|
|
expect(scale.getPixelForValue('2017')).toBeCloseToPixel(start);
|
|
expect(scale.getPixelForValue('2042')).toBeCloseToPixel(start + slice * 4);
|
|
});
|
|
it ('should add steps before and after if scale.min/max are outside the data range', function() {
|
|
var chart = this.chart;
|
|
var scale = chart.scales.x;
|
|
var options = chart.options.scales.xAxes[0];
|
|
|
|
options.time.min = '2012';
|
|
options.time.max = '2050';
|
|
chart.update();
|
|
|
|
var start = scale.left;
|
|
var slice = scale.width / 6;
|
|
|
|
expect(scale.getPixelForValue('2017')).toBeCloseToPixel(start + slice);
|
|
expect(scale.getPixelForValue('2042')).toBeCloseToPixel(start + slice * 5);
|
|
});
|
|
});
|
|
describe('is "linear"', function() {
|
|
beforeEach(function() {
|
|
this.chart = window.acquireChart({
|
|
type: 'line',
|
|
data: {
|
|
labels: ['2017', '2019', '2020', '2025', '2042'],
|
|
datasets: [{data: [0, 1, 2, 3, 4, 5]}]
|
|
},
|
|
options: {
|
|
scales: {
|
|
xAxes: [{
|
|
id: 'x',
|
|
type: 'time',
|
|
time: {
|
|
parser: 'YYYY'
|
|
},
|
|
distribution: 'linear',
|
|
ticks: {
|
|
source: 'labels'
|
|
}
|
|
}],
|
|
yAxes: [{
|
|
display: false
|
|
}]
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
it ('should space data out with a gap relative to their time values', function() {
|
|
var scale = this.chart.scales.x;
|
|
var start = scale.left;
|
|
var slice = scale.width / (2042 - 2017);
|
|
|
|
expect(scale.getPixelForValue('2017')).toBeCloseToPixel(start);
|
|
expect(scale.getPixelForValue('2019')).toBeCloseToPixel(start + slice * (2019 - 2017));
|
|
expect(scale.getPixelForValue('2020')).toBeCloseToPixel(start + slice * (2020 - 2017));
|
|
expect(scale.getPixelForValue('2025')).toBeCloseToPixel(start + slice * (2025 - 2017));
|
|
expect(scale.getPixelForValue('2042')).toBeCloseToPixel(start + slice * (2042 - 2017));
|
|
});
|
|
it ('should take in account scale min and max if outside the ticks range', function() {
|
|
var chart = this.chart;
|
|
var scale = chart.scales.x;
|
|
var options = chart.options.scales.xAxes[0];
|
|
|
|
options.time.min = '2012';
|
|
options.time.max = '2050';
|
|
chart.update();
|
|
|
|
var start = scale.left;
|
|
var slice = scale.width / (2050 - 2012);
|
|
|
|
expect(scale.getPixelForValue('2017')).toBeCloseToPixel(start + slice * (2017 - 2012));
|
|
expect(scale.getPixelForValue('2019')).toBeCloseToPixel(start + slice * (2019 - 2012));
|
|
expect(scale.getPixelForValue('2020')).toBeCloseToPixel(start + slice * (2020 - 2012));
|
|
expect(scale.getPixelForValue('2025')).toBeCloseToPixel(start + slice * (2025 - 2012));
|
|
expect(scale.getPixelForValue('2042')).toBeCloseToPixel(start + slice * (2042 - 2012));
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('when 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',
|
|
bounds: 'data',
|
|
time: {
|
|
parser: 'MM/DD HH:mm',
|
|
unit: 'day'
|
|
}
|
|
}],
|
|
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(getTicksLabels(scale)).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',
|
|
bounds: 'ticks',
|
|
time: {
|
|
parser: 'MM/DD HH:mm',
|
|
unit: 'day'
|
|
}
|
|
}],
|
|
yAxes: [{
|
|
display: false
|
|
}]
|
|
}
|
|
}
|
|
});
|
|
|
|
var scale = chart.scales.x;
|
|
var ticks = scale.getTicks();
|
|
|
|
expect(scale.min).toEqual(ticks[0].value);
|
|
expect(scale.max).toEqual(ticks[ticks.length - 1].value);
|
|
expect(scale.getPixelForValue('02/20 08:00')).toBeCloseToPixel(60);
|
|
expect(scale.getPixelForValue('02/23 11:00')).toBeCloseToPixel(426);
|
|
expect(getTicksLabels(scale)).toEqual([
|
|
'Feb 20', 'Feb 21', 'Feb 22', 'Feb 23', 'Feb 24']);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('when time.min and/or time.max are defined', function() {
|
|
['auto', 'data', 'labels'].forEach(function(source) {
|
|
['data', 'ticks'].forEach(function(bounds) {
|
|
describe('and ticks.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',
|
|
bounds: bounds,
|
|
time: {
|
|
parser: 'MM/DD HH:mm',
|
|
unit: 'day'
|
|
},
|
|
ticks: {
|
|
source: source
|
|
}
|
|
}],
|
|
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);
|
|
scale.getTicks().forEach(function(tick) {
|
|
expect(tick.value >= +moment(min, 'MM/DD HH:mm')).toBeTruthy();
|
|
expect(tick.value <= +moment(max, 'MM/DD HH:mm')).toBeTruthy();
|
|
});
|
|
});
|
|
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);
|
|
scale.getTicks().forEach(function(tick) {
|
|
expect(tick.value >= +moment(min, 'MM/DD HH:mm')).toBeTruthy();
|
|
expect(tick.value <= +moment(max, 'MM/DD HH:mm')).toBeTruthy();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
['auto', 'data', 'labels'].forEach(function(source) {
|
|
['series', 'linear'].forEach(function(distribution) {
|
|
describe('when ticks.source is "' + source + '" and distribution is "' + distribution + '"', function() {
|
|
beforeEach(function() {
|
|
this.chart = window.acquireChart({
|
|
type: 'line',
|
|
data: {
|
|
labels: ['2017', '2019', '2020', '2025', '2042'],
|
|
datasets: [{data: [0, 1, 2, 3, 4, 5]}]
|
|
},
|
|
options: {
|
|
scales: {
|
|
xAxes: [{
|
|
id: 'x',
|
|
type: 'time',
|
|
time: {
|
|
parser: 'YYYY'
|
|
},
|
|
ticks: {
|
|
source: source
|
|
},
|
|
distribution: distribution
|
|
}]
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
it ('should not add offset from the edges', function() {
|
|
var scale = this.chart.scales.x;
|
|
|
|
expect(scale.getPixelForValue('2017')).toBeCloseToPixel(scale.left);
|
|
expect(scale.getPixelForValue('2042')).toBeCloseToPixel(scale.left + scale.width);
|
|
});
|
|
|
|
it ('should add offset from the edges if offset is true', function() {
|
|
var chart = this.chart;
|
|
var scale = chart.scales.x;
|
|
var options = chart.options.scales.xAxes[0];
|
|
|
|
options.offset = true;
|
|
chart.update();
|
|
|
|
var numTicks = scale.ticks.length;
|
|
var firstTickInterval = scale.getPixelForTick(1) - scale.getPixelForTick(0);
|
|
var lastTickInterval = scale.getPixelForTick(numTicks - 1) - scale.getPixelForTick(numTicks - 2);
|
|
|
|
expect(scale.getPixelForValue('2017')).toBeCloseToPixel(scale.left + firstTickInterval / 2);
|
|
expect(scale.getPixelForValue('2042')).toBeCloseToPixel(scale.left + scale.width - lastTickInterval / 2);
|
|
});
|
|
|
|
it ('should not add offset if min and max extend the labels range', function() {
|
|
var chart = this.chart;
|
|
var scale = chart.scales.x;
|
|
var options = chart.options.scales.xAxes[0];
|
|
|
|
options.time.min = '2012';
|
|
options.time.max = '2051';
|
|
chart.update();
|
|
|
|
expect(scale.getPixelForValue('2012')).toBeCloseToPixel(scale.left);
|
|
expect(scale.getPixelForValue('2051')).toBeCloseToPixel(scale.left + scale.width);
|
|
});
|
|
|
|
it ('should not add offset if min and max extend the labels range and offset is true', function() {
|
|
var chart = this.chart;
|
|
var scale = chart.scales.x;
|
|
var options = chart.options.scales.xAxes[0];
|
|
|
|
options.time.min = '2012';
|
|
options.time.max = '2051';
|
|
options.offset = true;
|
|
chart.update();
|
|
|
|
expect(scale.getPixelForValue('2012')).toBeCloseToPixel(scale.left);
|
|
expect(scale.getPixelForValue('2051')).toBeCloseToPixel(scale.left + scale.width);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|