]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Support object values for bar charts (#6323)
authorAkihiko Kusanagi <nagi@nagi-p.com>
Wed, 19 Jun 2019 11:10:04 +0000 (19:10 +0800)
committerEvert Timberg <evert.timberg@gmail.com>
Wed, 19 Jun 2019 11:10:03 +0000 (07:10 -0400)
* Support object values for bar charts

* Check if null or undefined

* Refactor category scale code

* Make isNullOrUndef global

src/scales/scale.category.js
test/specs/scale.category.tests.js

index 1d8949d4df608c04a892a57812b3a5174c9449a2..bd01587369c45dc4dff5a5b92535bdd55e2bd06e 100644 (file)
@@ -1,7 +1,10 @@
 'use strict';
 
+var helpers = require('../helpers/index');
 var Scale = require('../core/core.scale');
 
+var isNullOrUndef = helpers.isNullOrUndef;
+
 var defaultConfig = {
        position: 'bottom'
 };
@@ -10,31 +13,43 @@ module.exports = Scale.extend({
        determineDataLimits: function() {
                var me = this;
                var labels = me._getLabels();
-               me.minIndex = 0;
-               me.maxIndex = labels.length - 1;
+               var ticksOpts = me.options.ticks;
+               var min = ticksOpts.min;
+               var max = ticksOpts.max;
+               var minIndex = 0;
+               var maxIndex = labels.length - 1;
                var findIndex;
 
-               if (me.options.ticks.min !== undefined) {
+               if (min !== undefined) {
                        // user specified min value
-                       findIndex = labels.indexOf(me.options.ticks.min);
-                       me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
+                       findIndex = labels.indexOf(min);
+                       if (findIndex >= 0) {
+                               minIndex = findIndex;
+                       }
                }
 
-               if (me.options.ticks.max !== undefined) {
+               if (max !== undefined) {
                        // user specified max value
-                       findIndex = labels.indexOf(me.options.ticks.max);
-                       me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
+                       findIndex = labels.indexOf(max);
+                       if (findIndex >= 0) {
+                               maxIndex = findIndex;
+                       }
                }
 
-               me.min = labels[me.minIndex];
-               me.max = labels[me.maxIndex];
+               me.minIndex = minIndex;
+               me.maxIndex = maxIndex;
+               me.min = labels[minIndex];
+               me.max = labels[maxIndex];
        },
 
        buildTicks: function() {
                var me = this;
                var labels = me._getLabels();
+               var minIndex = me.minIndex;
+               var maxIndex = me.maxIndex;
+
                // If we are viewing some subset of labels, slice the original array
-               me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1);
+               me.ticks = (minIndex === 0 && maxIndex === labels.length - 1) ? labels : labels.slice(minIndex, maxIndex + 1);
        },
 
        getLabelForIndex: function(index, datasetIndex) {
@@ -49,61 +64,58 @@ module.exports = Scale.extend({
        },
 
        // Used to get data value locations.  Value can either be an index or a numerical value
-       getPixelForValue: function(value, index) {
+       getPixelForValue: function(value, index, datasetIndex) {
                var me = this;
                var offset = me.options.offset;
+
                // 1 is added because we need the length but we have the indexes
-               var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1)), 1);
+               var offsetAmt = Math.max(me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1), 1);
+
+               var isHorizontal = me.isHorizontal();
+               var valueDimension = (isHorizontal ? me.width : me.height) / offsetAmt;
+               var valueCategory, labels, idx, pixel;
+
+               if (!isNullOrUndef(index) && !isNullOrUndef(datasetIndex)) {
+                       value = me.chart.data.datasets[datasetIndex].data[index];
+               }
 
                // If value is a data object, then index is the index in the data array,
                // not the index of the scale. We need to change that.
-               var valueCategory;
-               if (value !== undefined && value !== null) {
-                       valueCategory = me.isHorizontal() ? value.x : value.y;
+               if (!isNullOrUndef(value)) {
+                       valueCategory = isHorizontal ? value.x : value.y;
                }
                if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
-                       var labels = me._getLabels();
-                       value = valueCategory || value;
-                       var idx = labels.indexOf(value);
+                       labels = me._getLabels();
+                       value = helpers.valueOrDefault(valueCategory, value);
+                       idx = labels.indexOf(value);
                        index = idx !== -1 ? idx : index;
                }
 
-               if (me.isHorizontal()) {
-                       var valueWidth = me.width / offsetAmt;
-                       var widthOffset = (valueWidth * (index - me.minIndex));
-
-                       if (offset) {
-                               widthOffset += (valueWidth / 2);
-                       }
-
-                       return me.left + widthOffset;
-               }
-               var valueHeight = me.height / offsetAmt;
-               var heightOffset = (valueHeight * (index - me.minIndex));
+               pixel = valueDimension * (index - me.minIndex);
 
                if (offset) {
-                       heightOffset += (valueHeight / 2);
+                       pixel += valueDimension / 2;
                }
 
-               return me.top + heightOffset;
+               return (isHorizontal ? me.left : me.top) + pixel;
        },
 
        getPixelForTick: function(index) {
-               return this.getPixelForValue(this.ticks[index], index + this.minIndex, null);
+               return this.getPixelForValue(this.ticks[index], index + this.minIndex);
        },
 
        getValueForPixel: function(pixel) {
                var me = this;
                var offset = me.options.offset;
+               var offsetAmt = Math.max(me._ticks.length - (offset ? 0 : 1), 1);
+               var isHorizontal = me.isHorizontal();
+               var valueDimension = (isHorizontal ? me.width : me.height) / offsetAmt;
                var value;
-               var offsetAmt = Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
-               var horz = me.isHorizontal();
-               var valueDimension = (horz ? me.width : me.height) / offsetAmt;
 
-               pixel -= horz ? me.left : me.top;
+               pixel -= isHorizontal ? me.left : me.top;
 
                if (offset) {
-                       pixel -= (valueDimension / 2);
+                       pixel -= valueDimension / 2;
                }
 
                if (pixel <= 0) {
index d6529324ec38d112692d49c9a4644d2c89a7b1a7..96883e31c9c416fc12d816dc6e3e5eaad4ef1d40 100644 (file)
@@ -390,4 +390,157 @@ describe('Category scale tests', function() {
                expect(yScale.getPixelForValue(0, 1, 0)).toBeCloseToPixel(107);
                expect(yScale.getPixelForValue(0, 3, 0)).toBeCloseToPixel(407);
        });
+
+       it('Should get the correct pixel for an object value when horizontal', function() {
+               var chart = window.acquireChart({
+                       type: 'line',
+                       data: {
+                               datasets: [{
+                                       xAxisID: 'xScale0',
+                                       yAxisID: 'yScale0',
+                                       data: [
+                                               {x: 0, y: 10},
+                                               {x: 1, y: 5},
+                                               {x: 2, y: 0},
+                                               {x: 3, y: 25},
+                                               {x: 0, y: 78}
+                                       ]
+                               }],
+                               labels: [0, 1, 2, 3]
+                       },
+                       options: {
+                               scales: {
+                                       xAxes: [{
+                                               id: 'xScale0',
+                                               type: 'category',
+                                               position: 'bottom'
+                                       }],
+                                       yAxes: [{
+                                               id: 'yScale0',
+                                               type: 'linear'
+                                       }]
+                               }
+                       }
+               });
+
+               var xScale = chart.scales.xScale0;
+               expect(xScale.getPixelForValue({x: 0, y: 10}, 0, 0)).toBeCloseToPixel(29);
+               expect(xScale.getPixelForValue({x: 3, y: 25}, 3, 0)).toBeCloseToPixel(506);
+               expect(xScale.getPixelForValue({x: 0, y: 78}, 4, 0)).toBeCloseToPixel(29);
+       });
+
+       it('Should get the correct pixel for an object value when vertical', function() {
+               var chart = window.acquireChart({
+                       type: 'line',
+                       data: {
+                               datasets: [{
+                                       xAxisID: 'xScale0',
+                                       yAxisID: 'yScale0',
+                                       data: [
+                                               {x: 0, y: 2},
+                                               {x: 1, y: 4},
+                                               {x: 2, y: 0},
+                                               {x: 3, y: 3},
+                                               {x: 0, y: 1}
+                                       ]
+                               }],
+                               labels: [0, 1, 2, 3],
+                               yLabels: [0, 1, 2, 3, 4]
+                       },
+                       options: {
+                               scales: {
+                                       xAxes: [{
+                                               id: 'xScale0',
+                                               type: 'category',
+                                               position: 'bottom'
+                                       }],
+                                       yAxes: [{
+                                               id: 'yScale0',
+                                               type: 'category',
+                                               position: 'left'
+                                       }]
+                               }
+                       }
+               });
+
+               var yScale = chart.scales.yScale0;
+               expect(yScale.getPixelForValue({x: 0, y: 2}, 0, 0)).toBeCloseToPixel(257);
+               expect(yScale.getPixelForValue({x: 0, y: 1}, 4, 0)).toBeCloseToPixel(144);
+       });
+
+       it('Should get the correct pixel for an object value in a bar chart', function() {
+               var chart = window.acquireChart({
+                       type: 'bar',
+                       data: {
+                               datasets: [{
+                                       xAxisID: 'xScale0',
+                                       yAxisID: 'yScale0',
+                                       data: [
+                                               {x: 0, y: 10},
+                                               {x: 1, y: 5},
+                                               {x: 2, y: 0},
+                                               {x: 3, y: 25},
+                                               {x: 0, y: 78}
+                                       ]
+                               }],
+                               labels: [0, 1, 2, 3]
+                       },
+                       options: {
+                               scales: {
+                                       xAxes: [{
+                                               id: 'xScale0',
+                                               type: 'category',
+                                               position: 'bottom'
+                                       }],
+                                       yAxes: [{
+                                               id: 'yScale0',
+                                               type: 'linear'
+                                       }]
+                               }
+                       }
+               });
+
+               var xScale = chart.scales.xScale0;
+               expect(xScale.getPixelForValue(null, 0, 0)).toBeCloseToPixel(89);
+               expect(xScale.getPixelForValue(null, 3, 0)).toBeCloseToPixel(449);
+               expect(xScale.getPixelForValue(null, 4, 0)).toBeCloseToPixel(89);
+       });
+
+       it('Should get the correct pixel for an object value in a horizontal bar chart', function() {
+               var chart = window.acquireChart({
+                       type: 'horizontalBar',
+                       data: {
+                               datasets: [{
+                                       xAxisID: 'xScale0',
+                                       yAxisID: 'yScale0',
+                                       data: [
+                                               {x: 10, y: 0},
+                                               {x: 5, y: 1},
+                                               {x: 0, y: 2},
+                                               {x: 25, y: 3},
+                                               {x: 78, y: 0}
+                                       ]
+                               }],
+                               labels: [0, 1, 2, 3]
+                       },
+                       options: {
+                               scales: {
+                                       xAxes: [{
+                                               id: 'xScale0',
+                                               type: 'linear',
+                                               position: 'bottom'
+                                       }],
+                                       yAxes: [{
+                                               id: 'yScale0',
+                                               type: 'category'
+                                       }]
+                               }
+                       }
+               });
+
+               var yScale = chart.scales.yScale0;
+               expect(yScale.getPixelForValue(null, 0, 0)).toBeCloseToPixel(88);
+               expect(yScale.getPixelForValue(null, 3, 0)).toBeCloseToPixel(426);
+               expect(yScale.getPixelForValue(null, 4, 0)).toBeCloseToPixel(88);
+       });
 });