Add option to turn off grouping of bar datasets (#8641)

* Add option to turn off grouping of bar datasets

* Disregard time offset
This commit is contained in:
Jukka Kurkela 2021-03-14 17:27:57 +02:00 committed by GitHub
parent f744c3bde6
commit 85123ac074
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 166 additions and 22 deletions

View File

@ -173,6 +173,7 @@ The bar chart accepts the following configuration from the associated dataset op
| `categoryPercentage` | `number` | `0.8` | Percent (0-1) of the available width each category should be within the sample width. [more...](#barpercentage-vs-categorypercentage)
| `barThickness` | `number`\|`string` | | Manually set width of each bar in pixels. If set to `'flex'`, it computes "optimal" sample widths that globally arrange bars side by side. If not set (default), bars are equally sized based on the smallest interval. [more...](#barthickness)
| `base` | `number` | | Base value for the bar in data units along the value axis. If not set, defaults to the value axis base value.
| `grouped` | `boolean` | `true` | Should the bars be grouped on index axis. When `true`, all the datasets at same index value will be placed next to each other centering on that index value. When `false`, each bar is placed on its actual index-axis value.
| `maxBarThickness` | `number` | | Set this to ensure that bars are not sized thicker than this.
| `minBarLength` | `number` | | Set this to ensure that bars have a minimum length in pixels.

View File

@ -255,9 +255,9 @@ export default class BarController extends DatasetController {
updateElements(bars, start, count, mode) {
const me = this;
const reset = mode === 'reset';
const vscale = me._cachedMeta.vScale;
const base = vscale.getBasePixel();
const horizontal = vscale.isHorizontal();
const vScale = me._cachedMeta.vScale;
const base = vScale.getBasePixel();
const horizontal = vScale.isHorizontal();
const ruler = me._getRuler();
const firstOpts = me.resolveDataElementOptions(start, mode);
const sharedOptions = me.getSharedOptions(firstOpts);
@ -266,14 +266,14 @@ export default class BarController extends DatasetController {
me.updateSharedOptions(sharedOptions, mode, firstOpts);
for (let i = start; i < start + count; i++) {
const vpixels = me._calculateBarValuePixels(i);
const vpixels = reset ? {base, head: base} : me._calculateBarValuePixels(i);
const ipixels = me._calculateBarIndexPixels(i, ruler);
const properties = {
horizontal,
base: reset ? base : vpixels.base,
x: horizontal ? reset ? base : vpixels.head : ipixels.center,
y: horizontal ? ipixels.center : reset ? base : vpixels.head,
base: vpixels.base,
x: horizontal ? vpixels.head : ipixels.center,
y: horizontal ? ipixels.center : vpixels.head,
height: horizontal ? ipixels.size : undefined,
width: horizontal ? undefined : ipixels.size
};
@ -370,6 +370,7 @@ export default class BarController extends DatasetController {
*/
_getRuler() {
const me = this;
const opts = me.options;
const meta = me._cachedMeta;
const iScale = meta.iScale;
const pixels = [];
@ -379,11 +380,8 @@ export default class BarController extends DatasetController {
pixels.push(iScale.getPixelForValue(me.getParsed(i)[iScale.axis], i));
}
// Note: a potential optimization would be to skip computing this
// only if the barThickness option is defined
// Since a scriptable option may return null or undefined that
// means the option would have to be of type number
const min = computeMinSampleSize(iScale);
const barThickness = opts.barThickness;
const min = barThickness || computeMinSampleSize(iScale);
return {
min,
@ -391,7 +389,10 @@ export default class BarController extends DatasetController {
start: iScale._startPixel,
end: iScale._endPixel,
stackCount: me._getStackCount(),
scale: iScale
scale: iScale,
grouped: opts.grouped,
// bar thickness ratio used for non-grouped bars
ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage
};
}
@ -459,17 +460,24 @@ export default class BarController extends DatasetController {
*/
_calculateBarIndexPixels(index, ruler) {
const me = this;
const scale = ruler.scale;
const options = me.options;
const stackCount = options.skipNull ? me._getStackCount(index) : ruler.stackCount;
const range = options.barThickness === 'flex'
? computeFlexCategoryTraits(index, ruler, options, stackCount)
: computeFitCategoryTraits(index, ruler, options, stackCount);
const maxBarThickness = valueOrDefault(options.maxBarThickness, Infinity);
let center, size;
if (ruler.grouped) {
const stackCount = options.skipNull ? me._getStackCount(index) : ruler.stackCount;
const range = options.barThickness === 'flex'
? computeFlexCategoryTraits(index, ruler, options, stackCount)
: computeFitCategoryTraits(index, ruler, options, stackCount);
const stackIndex = me._getStackIndex(me.index, me._cachedMeta.stack);
const center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
const size = Math.min(
valueOrDefault(options.maxBarThickness, Infinity),
range.chunk * range.ratio);
const stackIndex = me._getStackIndex(me.index, me._cachedMeta.stack);
center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
size = Math.min(maxBarThickness, range.chunk * range.ratio);
} else {
// For non-grouped bar charts, exact pixel values are used
center = scale.getPixelForValue(me.getParsed(index)[scale.axis], index);
size = Math.min(maxBarThickness, ruler.min * ruler.ratio);
}
return {
base: center - size / 2,
@ -512,6 +520,7 @@ BarController.defaults = {
categoryPercentage: 0.8,
barPercentage: 0.9,
grouped: true,
animations: {
numbers: {

View File

@ -0,0 +1,134 @@
const data1 = [
{
x: '2017-11-02T20:30:00',
y: 27
},
{
x: '2017-11-03T20:53:00',
y: 30
},
{
x: '2017-11-06T05:46:00',
y: 19
},
{
x: '2017-11-06T21:03:00',
y: 28
},
{
x: '2017-11-07T20:49:00',
y: 29
},
{
x: '2017-11-08T21:52:00',
y: 33
}
];
const data2 = [
{
x: '2017-11-03T13:07:00',
y: 45
},
{
x: '2017-11-04T04:50:00',
y: 40
},
{
x: '2017-11-06T12:48:00',
y: 38
},
{
x: '2017-11-07T12:28:00',
y: 42
},
{
x: '2017-11-08T12:45:00',
y: 51
},
{
x: '2017-11-09T05:23:00',
y: 57
}
];
const data3 = [
{
x: '2017-11-03T16:30:00',
y: 32
},
{
x: '2017-11-04T11:50:00',
y: 34
},
{
x: '2017-11-06T18:30:00',
y: 28
},
{
x: '2017-11-07T15:51:00',
y: 31
},
{
x: '2017-11-08T17:27:00',
y: 36
},
{
x: '2017-11-09T06:53:00',
y: 31
}
];
module.exports = {
description: 'https://github.com/chartjs/Chart.js/issues/5139',
config: {
type: 'bar',
data: {
datasets: [
{
data: data1,
backgroundColor: 'rgb(0,0,255)',
},
{
data: data2,
backgroundColor: 'rgb(255,0,0)',
},
{
data: data3,
backgroundColor: 'rgb(0,255,0)',
},
]
},
options: {
barThickness: 10,
grouped: false,
scales: {
x: {
bounds: 'ticks',
type: 'time',
offset: false,
position: 'bottom',
display: true,
time: {
isoWeekday: true,
unit: 'day'
},
grid: {
offset: false
}
},
y: {
beginAtZero: true,
display: false
}
},
}
},
options: {
spriteText: true,
canvas: {
width: 1000,
height: 300
}
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB