mirror of
https://github.com/chartjs/Chart.js.git
synced 2026-03-12 03:06:54 +01:00
New time scale ticks.source: 'data' option (#4568)
This new option value generates ticks from data (including labels from {t|x|y} data objects).
This commit is contained in:
@@ -260,12 +260,13 @@ function determineMajorUnit(unit) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates timestamps between min and max, rounded to the `minor` unit, aligned on
|
||||
* the `major` unit, spaced with `stepSize` and using the given scale time `options`.
|
||||
* Generates a maximum of `capacity` timestamps between min and max, rounded to the
|
||||
* `minor` unit, aligned on the `major` unit and using the given scale time `options`.
|
||||
* Important: this method can return ticks outside the min and max range, it's the
|
||||
* responsibility of the calling code to clamp values if needed.
|
||||
*/
|
||||
function generate(min, max, minor, major, stepSize, options) {
|
||||
function generate(min, max, minor, major, capacity, options) {
|
||||
var stepSize = helpers.valueOrDefault(options.stepSize, options.unitStepSize);
|
||||
var weekday = minor === 'week' ? options.isoWeekday : false;
|
||||
var interval = INTERVALS[minor];
|
||||
var first = moment(min);
|
||||
@@ -273,6 +274,10 @@ function generate(min, max, minor, major, stepSize, options) {
|
||||
var ticks = [];
|
||||
var time;
|
||||
|
||||
if (!stepSize) {
|
||||
stepSize = determineStepSize(min, max, minor, capacity);
|
||||
}
|
||||
|
||||
// For 'week' unit, handle the first day of week option
|
||||
if (weekday) {
|
||||
first = first.isoWeekday(weekday);
|
||||
@@ -348,8 +353,9 @@ module.exports = function(Chart) {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* - 'data': generates ticks from data (including labels from data {t|x|y} objects).
|
||||
* - 'labels': generates ticks from user given `data.labels` values ONLY.
|
||||
* @see https://github.com/chartjs/Chart.js/pull/4507
|
||||
* @since 2.7.0
|
||||
*/
|
||||
@@ -472,15 +478,22 @@ module.exports = function(Chart) {
|
||||
var majorUnit = determineMajorUnit(unit);
|
||||
var timestamps = [];
|
||||
var ticks = [];
|
||||
var i, ilen, timestamp, stepSize;
|
||||
var hash = {};
|
||||
var i, ilen, timestamp;
|
||||
|
||||
if (ticksOpts.source === 'auto') {
|
||||
stepSize = helpers.valueOrDefault(timeOpts.stepSize, timeOpts.unitStepSize)
|
||||
|| determineStepSize(min, max, unit, capacity);
|
||||
|
||||
timestamps = generate(min, max, unit, majorUnit, stepSize, timeOpts);
|
||||
} else {
|
||||
switch (ticksOpts.source) {
|
||||
case 'data':
|
||||
for (i = 0, ilen = me._datasets.length; i < ilen; ++i) {
|
||||
timestamps.push.apply(timestamps, me._datasets[i]);
|
||||
}
|
||||
timestamps.sort(sorter);
|
||||
break;
|
||||
case 'labels':
|
||||
timestamps = me._labels;
|
||||
break;
|
||||
case 'auto':
|
||||
default:
|
||||
timestamps = generate(min, max, unit, majorUnit, capacity, timeOpts);
|
||||
}
|
||||
|
||||
if (ticksOpts.bounds === 'labels' && timestamps.length) {
|
||||
@@ -492,10 +505,12 @@ module.exports = function(Chart) {
|
||||
min = parse(timeOpts.min, me) || min;
|
||||
max = parse(timeOpts.max, me) || max;
|
||||
|
||||
// Remove ticks outside the min/max range
|
||||
// Remove ticks outside the min/max range and duplicated entries
|
||||
for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
|
||||
timestamp = timestamps[i];
|
||||
if (timestamp >= min && timestamp <= max) {
|
||||
if (timestamp >= min && timestamp <= max && !hash[timestamp]) {
|
||||
// hash is used to efficiently detect timestamp duplicates
|
||||
hash[timestamp] = true;
|
||||
ticks.push(timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,8 +281,8 @@ describe('Time scale tests', function() {
|
||||
round: true,
|
||||
parser: function(label) {
|
||||
return label === 'foo' ?
|
||||
moment(946771200000) : // 02/01/2000 @ 12:00am (UTC)
|
||||
moment(1462665600000); // 05/08/2016 @ 12:00am (UTC)
|
||||
moment('2000/01/02', 'YYYY/MM/DD') :
|
||||
moment('2016/05/08', 'YYYY/MM/DD');
|
||||
}
|
||||
},
|
||||
ticks: {
|
||||
@@ -694,20 +694,6 @@ describe('Time scale tests', function() {
|
||||
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() {
|
||||
var chart = this.chart;
|
||||
var scale = chart.scales.x;
|
||||
var options = chart.options.scales.xAxes[0];
|
||||
|
||||
options.time.min = '2022';
|
||||
options.time.max = '2032';
|
||||
chart.update();
|
||||
|
||||
expect(scale.min).toEqual(+moment('2022', 'YYYY'));
|
||||
expect(scale.max).toEqual(+moment('2032', 'YYYY'));
|
||||
expect(getTicksValues(scale.ticks)).toEqual([
|
||||
'2025']);
|
||||
});
|
||||
it ('should not duplicate ticks if min and max are the labels limits', function() {
|
||||
var chart = this.chart;
|
||||
var scale = chart.scales.x;
|
||||
@@ -734,6 +720,88 @@ describe('Time scale tests', function() {
|
||||
expect(getTicksValues(scale.ticks)).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(getTicksValues(scale.ticks)).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(getTicksValues(scale.ticks)).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(getTicksValues(scale.ticks)).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(getTicksValues(scale.ticks)).toEqual([
|
||||
'2018', '2020', '2043']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when ticks.mode', function() {
|
||||
@@ -970,7 +1038,7 @@ describe('Time scale tests', function() {
|
||||
});
|
||||
|
||||
describe('when time.min and/or time.max are defined', function() {
|
||||
['auto', 'labels'].forEach(function(source) {
|
||||
['auto', 'data', 'labels'].forEach(function(source) {
|
||||
['data', 'labels'].forEach(function(bounds) {
|
||||
describe('and source is "' + source + '" and bounds "' + bounds + '"', function() {
|
||||
beforeEach(function() {
|
||||
@@ -1017,6 +1085,10 @@ describe('Time scale tests', function() {
|
||||
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.ticks.forEach(function(tick) {
|
||||
expect(tick.time >= +moment(min, 'MM/DD HH:mm')).toBeTruthy();
|
||||
expect(tick.time <= +moment(max, 'MM/DD HH:mm')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
it ('should shrink scale to the min/max range', function() {
|
||||
var chart = this.chart;
|
||||
@@ -1033,6 +1105,10 @@ describe('Time scale tests', function() {
|
||||
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.ticks.forEach(function(tick) {
|
||||
expect(tick.time >= +moment(min, 'MM/DD HH:mm')).toBeTruthy();
|
||||
expect(tick.time <= +moment(max, 'MM/DD HH:mm')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user