]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Add `reverse` support to time scale (#5927)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Thu, 20 Dec 2018 15:08:13 +0000 (17:08 +0200)
committerSimon Brunel <simonbrunel@users.noreply.github.com>
Thu, 20 Dec 2018 15:08:13 +0000 (16:08 +0100)
src/scales/scale.time.js
test/specs/scale.time.tests.js

index dbdb4ef67722caca95909dd81822afe4542cfb5e..a2892bfd6cd55b146e8c9c6c556afa48f618343e 100644 (file)
@@ -356,19 +356,19 @@ function generate(min, max, capacity, options) {
 }
 
 /**
- * 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;
@@ -376,14 +376,14 @@ function computeOffsets(table, ticks, min, max, options) {
                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) {
@@ -645,6 +645,10 @@ module.exports = function() {
                        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);
                },
 
@@ -706,11 +710,13 @@ module.exports = function() {
                 */
                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) {
@@ -741,7 +747,7 @@ module.exports = function() {
                        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);
index 964e25e080a2bea09ab305611ad73a814690553b..fc575f3b58e68dc619a3e8f0134e04d62887123b 100755 (executable)
@@ -1317,4 +1317,191 @@ describe('Time scale tests', function() {
                        });
                });
        });
+
+       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));
+                       });
+               });
+       });
 });