Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/docs/charts/bar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
55 changes: 32 additions & 23 deletions src/controllers/controller.bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
};
Expand Down Expand Up @@ -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 = [];
Expand All @@ -379,19 +380,19 @@ 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,
pixels,
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
};
}

Expand Down Expand Up @@ -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 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 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);
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,
Expand Down Expand Up @@ -512,6 +520,7 @@ BarController.defaults = {

categoryPercentage: 0.8,
barPercentage: 0.9,
grouped: true,

animations: {
numbers: {
Expand Down
134 changes: 134 additions & 0 deletions test/fixtures/controller.bar/not-grouped/on-time.js
Original file line number Diff line number Diff line change
@@ -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
}
}
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.