Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only enable the bar borderRadius at the end of the stacks #8941

Merged
merged 9 commits into from Apr 18, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/charts/bar.md
Expand Up @@ -171,6 +171,10 @@ If this value is a number, it is applied to all sides of the rectangle (left, to

If this value is a number, it is applied to all corners of the rectangle (topLeft, topRight, bottomLeft, bottomRight), except corners touching the [`borderSkipped`](#borderskipped). If this value is an object, the `topLeft` property defines the top-left corners border radius. Similarly, the `topRight`, `bottomLeft`, and `bottomRight` properties can also be specified. Omitted corners and those touching the [`borderSkipped`](#borderskipped) are skipped. For example if the `top` border is skipped, the border radius for the corners `topLeft` and `topRight` will be skipped as well.

:::tip Stacked Charts
When the border radius is supplied as a number and the chart is stacked, the radius will only be applied to the bars that are at the edges of the stack or where the bar is floating. The object syntax can be used to override this behavior.
:::

### Interactions

The interaction with each bar can be controlled with the following properties:
Expand Down
2 changes: 2 additions & 0 deletions src/controllers/controller.bar.js
Expand Up @@ -269,10 +269,12 @@ export default class BarController extends DatasetController {
const parsed = me.getParsed(i);
const vpixels = reset || isNullOrUndef(parsed[vScale.axis]) ? {base, head: base} : me._calculateBarValuePixels(i);
const ipixels = me._calculateBarIndexPixels(i, ruler);
const stack = (parsed._stacks || {})[vScale.axis];

const properties = {
horizontal,
base: vpixels.base,
enableBorderRadius: !stack || isFloatBar(parsed._custom) || (me.index === stack._top || me.index === stack._bottom),
x: horizontal ? vpixels.head : ipixels.center,
y: horizontal ? ipixels.center : vpixels.head,
height: horizontal ? ipixels.size : undefined,
Expand Down
14 changes: 14 additions & 0 deletions src/core/core.datasetController.js
Expand Up @@ -127,6 +127,17 @@ function getOrCreateStack(stacks, stackKey, indexValue) {
return subStack[indexValue] || (subStack[indexValue] = {});
}

function getLastIndexInStack(stack, vScale, positive) {
for (const meta of vScale.getMatchingVisibleMetas('bar').reverse()) {
const value = stack[meta.index];
if ((positive && value > 0) || (!positive && value < 0)) {
return meta.index;
}
}

return null;
}

function updateStacks(controller, parsed) {
const {chart, _cachedMeta: meta} = controller;
const stacks = chart._stacks || (chart._stacks = {}); // map structure is {stackKey: {datasetIndex: value}}
Expand All @@ -143,6 +154,9 @@ function updateStacks(controller, parsed) {
const itemStacks = item._stacks || (item._stacks = {});
stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index);
stack[datasetIndex] = value;

stack._top = getLastIndexInStack(stack, vScale, true);
stack._bottom = getLastIndexInStack(stack, vScale, false);
}
}

Expand Down
15 changes: 11 additions & 4 deletions src/elements/element.bar.js
@@ -1,4 +1,5 @@
import Element from '../core/core.element';
import {isObject} from '../helpers';
import {addRoundedRectPath} from '../helpers/helpers.canvas';
import {toTRBL, toTRBLCorners} from '../helpers/helpers.options';

Expand Down Expand Up @@ -83,16 +84,21 @@ function parseBorderWidth(bar, maxW, maxH) {
}

function parseBorderRadius(bar, maxW, maxH) {
const {enableBorderRadius} = bar.getProps(['enableBorderRadius']);
const value = bar.options.borderRadius;
const o = toTRBLCorners(value);
const maxR = Math.min(maxW, maxH);
const skip = parseBorderSkipped(bar);

// If the value is an object, assume the user knows what they are doing
// and apply as directed.
const enableBorder = enableBorderRadius || isObject(value);

return {
topLeft: skipOrLimit(skip.top || skip.left, o.topLeft, 0, maxR),
topRight: skipOrLimit(skip.top || skip.right, o.topRight, 0, maxR),
bottomLeft: skipOrLimit(skip.bottom || skip.left, o.bottomLeft, 0, maxR),
bottomRight: skipOrLimit(skip.bottom || skip.right, o.bottomRight, 0, maxR)
topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR),
topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR),
bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR),
bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR)
};
}

Expand Down Expand Up @@ -224,6 +230,7 @@ BarElement.defaults = {
borderSkipped: 'start',
borderWidth: 0,
borderRadius: 0,
enableBorderRadius: true,
pointStyle: undefined
};

Expand Down
@@ -0,0 +1,42 @@
module.exports = {
threshold: 0.01,
config: {
type: 'bar',
data: {
labels: [0, 1, 2, 3, 4, 5],
datasets: [
{
backgroundColor: 'red',
data: [12, 19, 12, 5, 4, 12],
},
{
backgroundColor: 'green',
data: [12, 19, -4, 5, 8, 3],
type: 'line'
},
{
backgroundColor: 'blue',
data: [7, 11, -12, 12, 0, -7],
}
]
},
options: {
elements: {
bar: {
borderRadius: Number.MAX_VALUE,
borderWidth: 2,
}
},
scales: {
x: {display: false, stacked: true},
y: {display: false, stacked: true}
}
}
},
options: {
canvas: {
height: 256,
width: 512
}
}
};
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,44 @@
module.exports = {
threshold: 0.01,
config: {
type: 'bar',
data: {
labels: [0, 1, 2, 3, 4, 5],
datasets: [
{
backgroundColor: 'red',
data: [12, 19, 12, 5, 4, 12],
order: 2,
},
{
backgroundColor: 'green',
data: [12, 19, -4, 5, 8, 3],
order: 1,
},
{
backgroundColor: 'blue',
data: [7, 11, -12, 12, 0, -7],
order: 0,
}
]
},
options: {
elements: {
bar: {
borderRadius: Number.MAX_VALUE,
borderWidth: 2,
}
},
scales: {
x: {display: false, stacked: true},
y: {display: false, stacked: true}
}
}
},
options: {
canvas: {
height: 256,
width: 512
}
}
};
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,41 @@
module.exports = {
threshold: 0.01,
config: {
type: 'bar',
data: {
labels: [0, 1, 2, 3, 4, 5],
datasets: [
{
backgroundColor: 'red',
data: [12, 19, 12, 5, 4, 12],
},
{
backgroundColor: 'green',
data: [12, 19, -4, 5, 8, 3],
},
{
backgroundColor: 'blue',
data: [7, 11, -12, 12, 0, -7],
}
]
},
options: {
elements: {
bar: {
borderRadius: Number.MAX_VALUE,
borderWidth: 2,
}
},
scales: {
x: {display: false, stacked: true},
y: {display: false, stacked: true}
}
}
},
options: {
canvas: {
height: 256,
width: 512
}
}
};
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 17 additions & 17 deletions test/specs/core.datasetController.tests.js
Expand Up @@ -540,12 +540,12 @@ describe('Chart.DatasetController', function() {

expect(chart._stacks).toEqual({
'x.y.1': {
0: {0: 1, 2: 3},
1: {0: 10, 2: 30}
0: {0: 1, 2: 3, _top: 2, _bottom: null},
1: {0: 10, 2: 30, _top: 2, _bottom: null}
},
'x.y.2': {
0: {1: 2},
1: {1: 20}
0: {1: 2, _top: 1, _bottom: null},
1: {1: 20, _top: 1, _bottom: null}
}
});

Expand All @@ -554,12 +554,12 @@ describe('Chart.DatasetController', function() {

expect(chart._stacks).toEqual({
'x.y.1': {
0: {0: 1},
1: {0: 10}
0: {0: 1, _top: 2, _bottom: null},
1: {0: 10, _top: 2, _bottom: null}
},
'x.y.2': {
0: {1: 2, 2: 3},
1: {1: 20, 2: 30}
0: {1: 2, 2: 3, _top: 2, _bottom: null},
1: {1: 20, 2: 30, _top: 2, _bottom: null}
}
});
});
Expand All @@ -584,12 +584,12 @@ describe('Chart.DatasetController', function() {

expect(chart._stacks).toEqual({
'x.y.1': {
0: {0: 1, 2: 3},
1: {0: 10, 2: 30}
0: {0: 1, 2: 3, _top: 2, _bottom: null},
1: {0: 10, 2: 30, _top: 2, _bottom: null}
},
'x.y.2': {
0: {1: 2},
1: {1: 20}
0: {1: 2, _top: 1, _bottom: null},
1: {1: 20, _top: 1, _bottom: null}
}
});

Expand All @@ -598,12 +598,12 @@ describe('Chart.DatasetController', function() {

expect(chart._stacks).toEqual({
'x.y.1': {
0: {0: 1, 2: 4},
1: {0: 10}
0: {0: 1, 2: 4, _top: 2, _bottom: null},
1: {0: 10, _top: 2, _bottom: null}
},
'x.y.2': {
0: {1: 2},
1: {1: 20}
0: {1: 2, _top: 1, _bottom: null},
1: {1: 20, _top: 1, _bottom: null}
}
});
});
Expand Down Expand Up @@ -719,7 +719,7 @@ describe('Chart.DatasetController', function() {
});

var meta = chart.getDatasetMeta(0);
expect(meta._parsed[0]._stacks).toEqual(jasmine.objectContaining({y: {0: 10, 1: 20}}));
expect(meta._parsed[0]._stacks).toEqual(jasmine.objectContaining({y: {0: 10, 1: 20, _top: null, _bottom: null}}));
});

describe('resolveDataElementOptions', function() {
Expand Down