Skip to content

Commit 1a4d1e1

Browse files
nagixetimberg
authored andcommitted
Support object values for bar charts (chartjs#6323)
* Support object values for bar charts * Check if null or undefined * Refactor category scale code * Make isNullOrUndef global
1 parent 870ac76 commit 1a4d1e1

File tree

2 files changed

+204
-39
lines changed

2 files changed

+204
-39
lines changed

src/scales/scale.category.js

Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
'use strict';
22

3+
var helpers = require('../helpers/index');
34
var Scale = require('../core/core.scale');
45

6+
var isNullOrUndef = helpers.isNullOrUndef;
7+
58
var defaultConfig = {
69
position: 'bottom'
710
};
@@ -10,31 +13,43 @@ module.exports = Scale.extend({
1013
determineDataLimits: function() {
1114
var me = this;
1215
var labels = me._getLabels();
13-
me.minIndex = 0;
14-
me.maxIndex = labels.length - 1;
16+
var ticksOpts = me.options.ticks;
17+
var min = ticksOpts.min;
18+
var max = ticksOpts.max;
19+
var minIndex = 0;
20+
var maxIndex = labels.length - 1;
1521
var findIndex;
1622

17-
if (me.options.ticks.min !== undefined) {
23+
if (min !== undefined) {
1824
// user specified min value
19-
findIndex = labels.indexOf(me.options.ticks.min);
20-
me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
25+
findIndex = labels.indexOf(min);
26+
if (findIndex >= 0) {
27+
minIndex = findIndex;
28+
}
2129
}
2230

23-
if (me.options.ticks.max !== undefined) {
31+
if (max !== undefined) {
2432
// user specified max value
25-
findIndex = labels.indexOf(me.options.ticks.max);
26-
me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
33+
findIndex = labels.indexOf(max);
34+
if (findIndex >= 0) {
35+
maxIndex = findIndex;
36+
}
2737
}
2838

29-
me.min = labels[me.minIndex];
30-
me.max = labels[me.maxIndex];
39+
me.minIndex = minIndex;
40+
me.maxIndex = maxIndex;
41+
me.min = labels[minIndex];
42+
me.max = labels[maxIndex];
3143
},
3244

3345
buildTicks: function() {
3446
var me = this;
3547
var labels = me._getLabels();
48+
var minIndex = me.minIndex;
49+
var maxIndex = me.maxIndex;
50+
3651
// If we are viewing some subset of labels, slice the original array
37-
me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1);
52+
me.ticks = (minIndex === 0 && maxIndex === labels.length - 1) ? labels : labels.slice(minIndex, maxIndex + 1);
3853
},
3954

4055
getLabelForIndex: function(index, datasetIndex) {
@@ -49,61 +64,58 @@ module.exports = Scale.extend({
4964
},
5065

5166
// Used to get data value locations. Value can either be an index or a numerical value
52-
getPixelForValue: function(value, index) {
67+
getPixelForValue: function(value, index, datasetIndex) {
5368
var me = this;
5469
var offset = me.options.offset;
70+
5571
// 1 is added because we need the length but we have the indexes
56-
var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1)), 1);
72+
var offsetAmt = Math.max(me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1), 1);
73+
74+
var isHorizontal = me.isHorizontal();
75+
var valueDimension = (isHorizontal ? me.width : me.height) / offsetAmt;
76+
var valueCategory, labels, idx, pixel;
77+
78+
if (!isNullOrUndef(index) && !isNullOrUndef(datasetIndex)) {
79+
value = me.chart.data.datasets[datasetIndex].data[index];
80+
}
5781

5882
// If value is a data object, then index is the index in the data array,
5983
// not the index of the scale. We need to change that.
60-
var valueCategory;
61-
if (value !== undefined && value !== null) {
62-
valueCategory = me.isHorizontal() ? value.x : value.y;
84+
if (!isNullOrUndef(value)) {
85+
valueCategory = isHorizontal ? value.x : value.y;
6386
}
6487
if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
65-
var labels = me._getLabels();
66-
value = valueCategory || value;
67-
var idx = labels.indexOf(value);
88+
labels = me._getLabels();
89+
value = helpers.valueOrDefault(valueCategory, value);
90+
idx = labels.indexOf(value);
6891
index = idx !== -1 ? idx : index;
6992
}
7093

71-
if (me.isHorizontal()) {
72-
var valueWidth = me.width / offsetAmt;
73-
var widthOffset = (valueWidth * (index - me.minIndex));
74-
75-
if (offset) {
76-
widthOffset += (valueWidth / 2);
77-
}
78-
79-
return me.left + widthOffset;
80-
}
81-
var valueHeight = me.height / offsetAmt;
82-
var heightOffset = (valueHeight * (index - me.minIndex));
94+
pixel = valueDimension * (index - me.minIndex);
8395

8496
if (offset) {
85-
heightOffset += (valueHeight / 2);
97+
pixel += valueDimension / 2;
8698
}
8799

88-
return me.top + heightOffset;
100+
return (isHorizontal ? me.left : me.top) + pixel;
89101
},
90102

91103
getPixelForTick: function(index) {
92-
return this.getPixelForValue(this.ticks[index], index + this.minIndex, null);
104+
return this.getPixelForValue(this.ticks[index], index + this.minIndex);
93105
},
94106

95107
getValueForPixel: function(pixel) {
96108
var me = this;
97109
var offset = me.options.offset;
110+
var offsetAmt = Math.max(me._ticks.length - (offset ? 0 : 1), 1);
111+
var isHorizontal = me.isHorizontal();
112+
var valueDimension = (isHorizontal ? me.width : me.height) / offsetAmt;
98113
var value;
99-
var offsetAmt = Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
100-
var horz = me.isHorizontal();
101-
var valueDimension = (horz ? me.width : me.height) / offsetAmt;
102114

103-
pixel -= horz ? me.left : me.top;
115+
pixel -= isHorizontal ? me.left : me.top;
104116

105117
if (offset) {
106-
pixel -= (valueDimension / 2);
118+
pixel -= valueDimension / 2;
107119
}
108120

109121
if (pixel <= 0) {

test/specs/scale.category.tests.js

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,4 +390,157 @@ describe('Category scale tests', function() {
390390
expect(yScale.getPixelForValue(0, 1, 0)).toBeCloseToPixel(107);
391391
expect(yScale.getPixelForValue(0, 3, 0)).toBeCloseToPixel(407);
392392
});
393+
394+
it('Should get the correct pixel for an object value when horizontal', function() {
395+
var chart = window.acquireChart({
396+
type: 'line',
397+
data: {
398+
datasets: [{
399+
xAxisID: 'xScale0',
400+
yAxisID: 'yScale0',
401+
data: [
402+
{x: 0, y: 10},
403+
{x: 1, y: 5},
404+
{x: 2, y: 0},
405+
{x: 3, y: 25},
406+
{x: 0, y: 78}
407+
]
408+
}],
409+
labels: [0, 1, 2, 3]
410+
},
411+
options: {
412+
scales: {
413+
xAxes: [{
414+
id: 'xScale0',
415+
type: 'category',
416+
position: 'bottom'
417+
}],
418+
yAxes: [{
419+
id: 'yScale0',
420+
type: 'linear'
421+
}]
422+
}
423+
}
424+
});
425+
426+
var xScale = chart.scales.xScale0;
427+
expect(xScale.getPixelForValue({x: 0, y: 10}, 0, 0)).toBeCloseToPixel(29);
428+
expect(xScale.getPixelForValue({x: 3, y: 25}, 3, 0)).toBeCloseToPixel(506);
429+
expect(xScale.getPixelForValue({x: 0, y: 78}, 4, 0)).toBeCloseToPixel(29);
430+
});
431+
432+
it('Should get the correct pixel for an object value when vertical', function() {
433+
var chart = window.acquireChart({
434+
type: 'line',
435+
data: {
436+
datasets: [{
437+
xAxisID: 'xScale0',
438+
yAxisID: 'yScale0',
439+
data: [
440+
{x: 0, y: 2},
441+
{x: 1, y: 4},
442+
{x: 2, y: 0},
443+
{x: 3, y: 3},
444+
{x: 0, y: 1}
445+
]
446+
}],
447+
labels: [0, 1, 2, 3],
448+
yLabels: [0, 1, 2, 3, 4]
449+
},
450+
options: {
451+
scales: {
452+
xAxes: [{
453+
id: 'xScale0',
454+
type: 'category',
455+
position: 'bottom'
456+
}],
457+
yAxes: [{
458+
id: 'yScale0',
459+
type: 'category',
460+
position: 'left'
461+
}]
462+
}
463+
}
464+
});
465+
466+
var yScale = chart.scales.yScale0;
467+
expect(yScale.getPixelForValue({x: 0, y: 2}, 0, 0)).toBeCloseToPixel(257);
468+
expect(yScale.getPixelForValue({x: 0, y: 1}, 4, 0)).toBeCloseToPixel(144);
469+
});
470+
471+
it('Should get the correct pixel for an object value in a bar chart', function() {
472+
var chart = window.acquireChart({
473+
type: 'bar',
474+
data: {
475+
datasets: [{
476+
xAxisID: 'xScale0',
477+
yAxisID: 'yScale0',
478+
data: [
479+
{x: 0, y: 10},
480+
{x: 1, y: 5},
481+
{x: 2, y: 0},
482+
{x: 3, y: 25},
483+
{x: 0, y: 78}
484+
]
485+
}],
486+
labels: [0, 1, 2, 3]
487+
},
488+
options: {
489+
scales: {
490+
xAxes: [{
491+
id: 'xScale0',
492+
type: 'category',
493+
position: 'bottom'
494+
}],
495+
yAxes: [{
496+
id: 'yScale0',
497+
type: 'linear'
498+
}]
499+
}
500+
}
501+
});
502+
503+
var xScale = chart.scales.xScale0;
504+
expect(xScale.getPixelForValue(null, 0, 0)).toBeCloseToPixel(89);
505+
expect(xScale.getPixelForValue(null, 3, 0)).toBeCloseToPixel(449);
506+
expect(xScale.getPixelForValue(null, 4, 0)).toBeCloseToPixel(89);
507+
});
508+
509+
it('Should get the correct pixel for an object value in a horizontal bar chart', function() {
510+
var chart = window.acquireChart({
511+
type: 'horizontalBar',
512+
data: {
513+
datasets: [{
514+
xAxisID: 'xScale0',
515+
yAxisID: 'yScale0',
516+
data: [
517+
{x: 10, y: 0},
518+
{x: 5, y: 1},
519+
{x: 0, y: 2},
520+
{x: 25, y: 3},
521+
{x: 78, y: 0}
522+
]
523+
}],
524+
labels: [0, 1, 2, 3]
525+
},
526+
options: {
527+
scales: {
528+
xAxes: [{
529+
id: 'xScale0',
530+
type: 'linear',
531+
position: 'bottom'
532+
}],
533+
yAxes: [{
534+
id: 'yScale0',
535+
type: 'category'
536+
}]
537+
}
538+
}
539+
});
540+
541+
var yScale = chart.scales.yScale0;
542+
expect(yScale.getPixelForValue(null, 0, 0)).toBeCloseToPixel(88);
543+
expect(yScale.getPixelForValue(null, 3, 0)).toBeCloseToPixel(426);
544+
expect(yScale.getPixelForValue(null, 4, 0)).toBeCloseToPixel(88);
545+
});
393546
});

0 commit comments

Comments
 (0)