}
/**
- * Returns the right and left offsets from edges in the form of {left, right}.
+ * Returns the end and start offsets from edges in the form of {start, end}.
* Offsets are added when the `offset` option is true.
*/
function computeOffsets(table, ticks, min, max, options) {
- var left = 0;
- var right = 0;
+ var start = 0;
+ var end = 0;
var upper, lower;
if (options.offset && ticks.length) {
if (!options.time.min) {
upper = ticks.length > 1 ? ticks[1] : max;
lower = ticks[0];
- left = (
+ start = (
interpolate(table, 'time', upper, 'pos') -
interpolate(table, 'time', lower, 'pos')
) / 2;
if (!options.time.max) {
upper = ticks[ticks.length - 1];
lower = ticks.length > 1 ? ticks[ticks.length - 2] : min;
- right = (
+ end = (
interpolate(table, 'time', upper, 'pos') -
interpolate(table, 'time', lower, 'pos')
) / 2;
}
}
- return {left: left, right: right};
+ return options.ticks.reverse ? {start: end, end: start} : {start: start, end: end};
}
function ticksFromTimestamps(values, majorUnit) {
me._offsets = computeOffsets(me._table, ticks, min, max, options);
me._labelFormat = determineLabelFormat(me._timestamps.data, timeOpts);
+ if (options.ticks.reverse) {
+ ticks.reverse();
+ }
+
return ticksFromTimestamps(ticks, me._majorUnit);
},
*/
getPixelForOffset: function(time) {
var me = this;
+ var isReverse = me.options.ticks.reverse;
var size = me._horizontal ? me.width : me.height;
- var start = me._horizontal ? me.left : me.top;
+ var start = me._horizontal ? isReverse ? me.right : me.left : isReverse ? me.bottom : me.top;
var pos = interpolate(me._table, 'time', time, 'pos');
+ var offset = size * (me._offsets.start + pos) / (me._offsets.start + 1 + me._offsets.end);
- return start + size * (me._offsets.left + pos) / (me._offsets.left + 1 + me._offsets.right);
+ return isReverse ? start - offset : start + offset;
},
getPixelForValue: function(value, index, datasetIndex) {
var me = this;
var size = me._horizontal ? me.width : me.height;
var start = me._horizontal ? me.left : me.top;
- var pos = (size ? (pixel - start) / size : 0) * (me._offsets.left + 1 + me._offsets.left) - me._offsets.right;
+ var pos = (size ? (pixel - start) / size : 0) * (me._offsets.start + 1 + me._offsets.start) - me._offsets.end;
var time = interpolate(me._table, 'pos', pos, 'time');
return moment(time);
});
});
});
+
+ describe('when ticks.reverse', function() {
+ describe('is "true"', function() {
+ it ('should reverse the labels', 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',
+ reverse: true
+ }
+ }],
+ yAxes: [{
+ display: false
+ }]
+ }
+ }
+ });
+ var scale = this.chart.scales.x;
+ expect(scale.getPixelForValue('2017')).toBeCloseToPixel(scale.left + scale.width);
+ expect(scale.getPixelForValue('2042')).toBeCloseToPixel(scale.left);
+ });
+ });
+ });
+
+ describe('when ticks.reverse is "true" and 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',
+ reverse: true
+ }
+ }],
+ yAxes: [{
+ display: false
+ }]
+ }
+ }
+ });
+ });
+
+ it ('should reverse the labels and 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 + slice * 4);
+ expect(scale.getPixelForValue('2019')).toBeCloseToPixel(start + slice * 3);
+ expect(scale.getPixelForValue('2020')).toBeCloseToPixel(start + slice * 2);
+ expect(scale.getPixelForValue('2025')).toBeCloseToPixel(start + slice);
+ expect(scale.getPixelForValue('2042')).toBeCloseToPixel(start);
+ });
+
+ it ('should reverse the labels and 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 * 4);
+ expect(scale.getPixelForValue('2042')).toBeCloseToPixel(start);
+ });
+
+ it ('should reverse the labels and 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 + slice * 5);
+ expect(scale.getPixelForValue('2042')).toBeCloseToPixel(start + slice);
+ });
+
+ it ('should reverse the labels and 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 * 5);
+ expect(scale.getPixelForValue('2042')).toBeCloseToPixel(start + slice);
+ });
+ });
+ 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',
+ reverse: true
+ }
+ }],
+ yAxes: [{
+ display: false
+ }]
+ }
+ }
+ });
+ });
+
+ it ('should reverse the labels and 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 + slice * (2042 - 2017));
+ expect(scale.getPixelForValue('2019')).toBeCloseToPixel(start + slice * (2042 - 2019));
+ expect(scale.getPixelForValue('2020')).toBeCloseToPixel(start + slice * (2042 - 2020));
+ expect(scale.getPixelForValue('2025')).toBeCloseToPixel(start + slice * (2042 - 2025));
+ expect(scale.getPixelForValue('2042')).toBeCloseToPixel(start);
+ });
+
+ it ('should reverse the labels and 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 * (2050 - 2017));
+ expect(scale.getPixelForValue('2019')).toBeCloseToPixel(start + slice * (2050 - 2019));
+ expect(scale.getPixelForValue('2020')).toBeCloseToPixel(start + slice * (2050 - 2020));
+ expect(scale.getPixelForValue('2025')).toBeCloseToPixel(start + slice * (2050 - 2025));
+ expect(scale.getPixelForValue('2042')).toBeCloseToPixel(start + slice * (2050 - 2042));
+ });
+ });
+ });
});