Skip to content

Add option for rounded corners on bar charts #6761

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

Merged
merged 81 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
024f05f
add basic cornerradius for bar charts
emilykl Oct 18, 2023
31c3ac2
update plot-schema
emilykl Oct 18, 2023
b0c6258
add layout.barcornerradius property
emilykl Oct 31, 2023
d71fe49
handle negative bars
emilykl Nov 2, 2023
bb78c78
formatting
emilykl Nov 2, 2023
5dfd686
round corners of legend icon if bar is rounded
emilykl Nov 8, 2023
64912d4
change the way layout.barcornerradius is handled
emilykl Nov 8, 2023
cc1e6ff
rename mock
emilykl Nov 8, 2023
dc2c54c
handle reversed x and y axes
emilykl Nov 9, 2023
3b725fa
cleanup and simplify bar path logic for rounded corners
emilykl Nov 22, 2023
870d4c9
don't round corners of bars which are not top of stack
emilykl Nov 22, 2023
aa8ba1e
fix outmost bar logic
emilykl Nov 27, 2023
5845e0e
extend rounding to lower bars
emilykl Dec 15, 2023
85f47c6
remove 0 default for bar.marker.cornerradius
emilykl Dec 30, 2023
578712a
only set helper values for rounded corners if needed
emilykl Dec 30, 2023
8f77cde
better pct string handling
emilykl Dec 30, 2023
45689ae
remove cornerradius attr from barpolar and funnel
emilykl Dec 30, 2023
137e185
fix rounding for grouped barmode
emilykl Dec 30, 2023
795235b
handle stacked traces with different cornerradius
emilykl Jan 2, 2024
dd717b6
handle label text position inside bars
emilykl Jan 5, 2024
35e0c8f
fix function name
emilykl Jan 6, 2024
7aa7496
test label position for cornerradius in mock
emilykl Jan 6, 2024
250bf31
adjust cornerradius standardization for stacked bars
emilykl Jan 6, 2024
495d950
update plot-schema
emilykl Jan 6, 2024
be0ddff
don't coerce marker.cornerradius
emilykl Jan 6, 2024
819e8bf
add draftlog
emilykl Jan 6, 2024
ed69422
syntax
emilykl Jan 6, 2024
4a44291
syntax
emilykl Jan 6, 2024
65d3b55
add image baseline
emilykl Jan 6, 2024
e8cdde1
update draftlog
emilykl Jan 6, 2024
9c4227e
fix rounding for relative barmode
emilykl Jan 6, 2024
dabcaf0
fix NaN bug
emilykl Jan 6, 2024
701fd8c
fix bug with stacking in group mode
emilykl Jan 6, 2024
29589e8
coerce marker.cornerradius for histograms
emilykl Jan 8, 2024
d0b9a90
fix histogram2d
emilykl Jan 8, 2024
3e5a957
fix behavior for negative bars in stacked barmode
emilykl Jan 8, 2024
582ce13
fix behavior for negative bars in stacked barmode (2)
emilykl Jan 8, 2024
a238c87
Cast radius parameter to number
emilykl Jan 9, 2024
ac329f7
validate cornerradius value in supply defaults
emilykl Jan 9, 2024
8a607e6
export validateCornerradius
emilykl Jan 9, 2024
338b4e6
Change cornerradius editType to calc
emilykl Jan 9, 2024
60c918e
Change barcornerradius editType to calc
emilykl Jan 9, 2024
9dd0896
better handling of text placement on rounded horizontal bars
emilykl Jan 9, 2024
1628b5c
avoid using Math.sign
emilykl Jan 10, 2024
bfbd397
lint
emilykl Jan 10, 2024
71e4896
update plot-schema
emilykl Jan 10, 2024
4e794d0
bugfix
emilykl Jan 11, 2024
dedce2a
bugfix
emilykl Jan 11, 2024
b137b25
store cornerradius in t instead of trace; general cleanup
emilykl Jan 11, 2024
fdd6d03
small cleanup and add comments
emilykl Jan 17, 2024
8fcc3a5
Merge branch 'master' into rounded-bars
emilykl Jan 17, 2024
71b53c3
update baseline
emilykl Jan 17, 2024
90cf5c3
add text to zz-bar-rounded-corners
archmoj Jan 19, 2024
510c66b
rounded-bar display_height_zero line_width
archmoj Jan 19, 2024
5599ea6
round bar_gantt-chart
archmoj Jan 19, 2024
8dffbbe
round hist_cum_stacked
archmoj Jan 19, 2024
c165f6a
round histogram_colorscale
archmoj Jan 19, 2024
ee2451a
round histogram-offsetgroups
archmoj Jan 19, 2024
256a87e
round period_positioning9
archmoj Jan 19, 2024
b122521
round bar_stackto100_negative
archmoj Jan 19, 2024
015b881
round bar_attrs_relative
archmoj Jan 19, 2024
8b57fb5
round worldcup
archmoj Jan 19, 2024
ec44d87
bugfix
emilykl Jan 19, 2024
2913c6e
text position DRAFT
emilykl Jan 24, 2024
9e3c249
update baselines
archmoj Jan 24, 2024
f986349
fix text padding for rounded bars
emilykl Jan 26, 2024
99352d0
update baselines
archmoj Jan 26, 2024
6f685c0
fix text scale and pad for rounded bars
emilykl Jan 26, 2024
f093ee7
fix text position for stacked rounded bars
emilykl Jan 30, 2024
e3cd5a5
simplify logic in cross_trace_calc
emilykl Jan 30, 2024
98356b4
update baselines
emilykl Jan 30, 2024
a2befea
fix variable declaration
emilykl Jan 30, 2024
781fbe2
remove lxFunc and lyFunc
emilykl Jan 31, 2024
97f0b0e
use absolute arcs for bar path
emilykl Feb 1, 2024
c52890c
simplify text placement logic
emilykl Feb 1, 2024
10e38f4
Update docstring
emilykl Feb 1, 2024
f7d4b4a
Update docstring
emilykl Feb 1, 2024
4335ba0
more permissive text inside/outside logic for rounded bars
emilykl Feb 1, 2024
e9043e9
Merge branch 'rounded-bars' of https://github.com/plotly/plotly.js in…
emilykl Feb 1, 2024
4624132
updated baselines
archmoj Feb 1, 2024
8c45d15
update schema
archmoj Feb 1, 2024
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
7 changes: 6 additions & 1 deletion src/components/legend/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,14 +334,19 @@ module.exports = function style(s, gd, legend) {
var marker = trace.marker || {};
var markerLine = marker.line || {};

// If bar has rounded corners, round corners of legend icon
var pathStr = marker.cornerradius ?
'M6,3a3,3,0,0,1-3,3H-3a3,3,0,0,1-3-3V-3a3,3,0,0,1,3-3H3a3,3,0,0,1,3,3Z' : // Square with rounded corners
'M6,6H-6V-6H6Z'; // Normal square

var isVisible = (!desiredType) ? Registry.traceIs(trace, 'bar') :
(trace.visible && trace.type === desiredType);

var barpath = d3.select(lThis).select('g.legendpoints')
.selectAll('path.legend' + desiredType)
.data(isVisible ? [d] : []);
barpath.enter().append('path').classed('legend' + desiredType, true)
.attr('d', 'M6,6H-6V-6H6Z')
.attr('d', pathStr)
.attr('transform', centerTransform);
barpath.exit().remove();

Expand Down
11 changes: 10 additions & 1 deletion src/traces/bar/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,16 @@ var marker = extendFlat({
editType: 'style',
description: 'Sets the opacity of the bars.'
},
pattern: pattern
pattern: pattern,
cornerradius: {
valType: 'any',
dflt: 0,
editType: 'plot',
description: [
'Sets the rounding of corners. May be an integer number of pixels,',
'or a percentage of bar width(as a string).'
].join(' ')
},
});

module.exports = {
Expand Down
29 changes: 28 additions & 1 deletion src/traces/bar/cross_trace_calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ function setGroupPositions(gd, pa, sa, calcTraces, opts) {
}
break;
}

collectExtents(calcTraces, pa);
}

Expand Down Expand Up @@ -713,6 +712,21 @@ function normalizeBars(sa, sieve, opts) {
}
}

// Add an `_sMin` and `_sMax` value for each bar representing the min and max size value
// across all bars sharing the same position as that bar. These values are used for rounded
// bar corners, to carry rounding down to lower bars in the stack as needed.
function setHelperValuesForRoundedCorners(calcTraces, sMinByPos, sMaxByPos) {
// Set `_sMin` and `_sMax` value for each bar
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only need these when having bars with rounded corners.
This function is pretty slow and it should not be called when it is not really needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@archmoj Yes good point. Would it make sense then to check whether any of the traces in calcTraces have a cornerradius value, and skip this function if not?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that's a good idea.

for(var i = 0; i < calcTraces.length; i++) {
var calcTrace = calcTraces[i];
for(var j = 0; j < calcTrace.length; j++) {
var bar = calcTrace[j];
bar._sMin = sMinByPos[bar.p];
bar._sMax = sMaxByPos[bar.p];
}
}
}

// find the full position span of bars at each position
// for use by hover, to ensure labels move in if bars are
// narrower than the space they're in.
Expand Down Expand Up @@ -745,6 +759,12 @@ function collectExtents(calcTraces, pa) {
return String(Math.round(roundFactor * (p - pMin)));
};

// Find min and max size axis extent for each position
// This is used for rounded bar corners, to carry rounding
// down to lower bars in the case of stacked bars
var sMinByPos = {};
var sMaxByPos = {};

for(i = 0; i < calcTraces.length; i++) {
cd = calcTraces[i];
cd[0].t.extents = extents;
Expand All @@ -770,8 +790,15 @@ function collectExtents(calcTraces, pa) {
di.p1 = di.p0 + di.w;
di.s0 = di.b;
di.s1 = di.s0 + di.s;

var sMin = Math.min(di.s0, di.s1);
var sMax = Math.max(di.s0, di.s1);

sMinByPos[di.p] = (di.p in sMinByPos) ? Math.min(sMinByPos[di.p], sMin) : sMin;
sMaxByPos[di.p] = (di.p in sMaxByPos) ? Math.max(sMaxByPos[di.p], sMax) : sMax;
}
}
setHelperValuesForRoundedCorners(calcTraces, sMinByPos, sMaxByPos);
}

function getAxisLetter(ax) {
Expand Down
18 changes: 10 additions & 8 deletions src/traces/bar/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
});

handleStyleDefaults(traceIn, traceOut, coerce, defaultColor, layout);

var lineColor = (traceOut.marker.line || {}).color;

// override defaultColor for error bars with defaultLine
Expand All @@ -61,16 +60,19 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function crossTraceDefaults(fullData, fullLayout) {
var traceIn, traceOut;

function coerce(attr) {
return Lib.coerce(traceOut._input, traceOut, attributes, attr);
function coerce(attr, dflt) {
return Lib.coerce(traceOut._input, traceOut, attributes, attr, dflt);
}

if(fullLayout.barmode === 'group') {
for(var i = 0; i < fullData.length; i++) {
traceOut = fullData[i];
for(var i = 0; i < fullData.length; i++) {
traceOut = fullData[i];

if(traceOut.type === 'bar') {
traceIn = traceOut._input;
if(traceOut.type === 'bar') {
traceIn = traceOut._input;
// This needs to happen here rather than in handleStyleDefaults() because
// it needs to happen after `layout.barcornerradius` has been coerced
coerce('marker.cornerradius', fullLayout.barcornerradius);
Copy link
Contributor

@archmoj archmoj Jan 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's validate inputs here. Something like:

            var r = coerce('marker.cornerradius', fullLayout.barcornerradius);
            var validR = false;
            if(isNumeric(r)) {
              r = +r;
              if(r >= 0) validR = true;
            } else if(typeof r === 'string' && r.slice(-1) === '%') {
                r = +r.slice(0, -1);
                if(r >= 0 && r <= 50) {
                  r += '%';
                  validR = true;
                }
            }
            traceOut.marker.cornerradius = validR ? r : undefined;

We need similar logic for histogram as well as barcornerradius.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good -- I think there should be no upper bound on the percentage though; it will be limited to 50% at the plotting step anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexcjohnson what do you think here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds reasonable to not put an upper bound - say someone uses a calculation for this, and the calculation accidentally goes over 50% (whether to 50.1% or to 200%), I think it'd be friendlier to result in maximum rounding rather than discard it and give no rounding.

if(fullLayout.barmode === 'group') {
handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce);
}
}
Expand Down
11 changes: 10 additions & 1 deletion src/traces/bar/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,14 @@ module.exports = {
'Sets the gap (in plot fraction) between bars of',
'the same location coordinate.'
].join(' ')
}
},
barcornerradius: {
valType: 'any',
dflt: 0,
editType: 'plot',
description: [
'Sets the rounding of corners. May be an integer number of pixels,',
'or a percentage of bar width(as a string).'
].join(' ')
},
};
1 change: 1 addition & 0 deletions src/traces/bar/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,5 @@ module.exports = function(layoutIn, layoutOut, fullData) {

coerce('bargap', (shouldBeGapless && !gappedAnyway) ? 0 : 0.2);
coerce('bargroupgap');
coerce('barcornerradius');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use validateCornerradius to validate the inputs here as well .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that necessary? layout.barcornerradius is used only as a default value for trace.marker.cornerradius; it's never referenced again after that.

So the only reason to validate it would be for internal consistency within the plot object, which I guess is a good enough reason if that's consistent with what we do elsewhere.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. It does not seem necessary.
So we could skip it for now and possibly add a line comment?

};
125 changes: 120 additions & 5 deletions src/traces/bar/plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
var trace = cd[0].trace;
var isWaterfall = (trace.type === 'waterfall');
var isFunnel = (trace.type === 'funnel');
var isHistogram = (trace.type === 'histogram');
var isBar = (trace.type === 'bar');
var shouldDisplayZeros = (isBar || isFunnel);

Expand Down Expand Up @@ -215,27 +216,140 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
(v > vc ? Math.ceil(v) : Math.floor(v));
}

var op = Color.opacity(mc);
var fixpx = (op < 1 || lw > 0.01) ? roundWithLine : expandToVisible;
if(!gd._context.staticPlot) {
// if bars are not fully opaque or they have a line
// around them, round to integer pixels, mainly for
// safari so we prevent overlaps from its expansive
// pixelation. if the bars ARE fully opaque and have
// no line, expand to a full pixel to make sure we
// can see them

var op = Color.opacity(mc);
var fixpx = (op < 1 || lw > 0.01) ? roundWithLine : expandToVisible;

x0 = fixpx(x0, x1, isHorizontal);
x1 = fixpx(x1, x0, isHorizontal);
y0 = fixpx(y0, y1, !isHorizontal);
y1 = fixpx(y1, y0, !isHorizontal);
}

// Function to convert from size axis values to pixels
var c2p = isHorizontal ? xa.c2p : ya.c2p;

// Calculate corner radius of bar in pixels
function calcCornerRadius(radiusParam) {
var barWidth = isHorizontal ? Math.abs(y1 - y0) : Math.abs(x1 - x0);
var barLength = isHorizontal ? Math.abs(x1 - x0) : Math.abs(y1 - y0);
var stackedBarTotalLength = fixpx(Math.abs(
di.s > 0 ? c2p(di._sMax, true) - c2p(0, true) : c2p(di._sMin, true) - c2p(0, true)
));
var maxRadius = di.hasB ? Math.min(barWidth / 2, barLength / 2) : Math.min(barWidth / 2, stackedBarTotalLength);
var rPx;
if(!radiusParam) {
return 0;
} else if(typeof radiusParam === 'string') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't get into this if statement, if the value is presented in a string but not having a percentage at the end.
Also we may replace parseFloat by unary plus operator to get NaN when the remaining string is not a number.
Something like:

                } else if(typeof radiusParam === 'string' && radiusParam.slice(-1) === '%') {
                    // If radius is given as a percentage string, convert to number of pixels
                    var rPercent = Math.min(50, +radiusParam.slice(0, -1));

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to use isNumeric to find if the value is a number, it's our standard method of finding either number type or numeric string:

if(!radiusParam) {
    return 0;
else if(isNumeric(radiusParam)) {
    rPx = +radiusParam;
else {
    var rPercent = ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If cornerradius value is invalid (e.g. string not ending in %) should we log an error message or just ignore?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore if it’s invalid. Plotlyjs has a separate validation utility that will alert you if any attributes you provide were not accepted, but if you don’t explicitly call that our convention is to silently ignore invalid items.

// If radius is given as a percentage string, convert to number of pixels
var rPercent = Math.min(parseFloat(radiusParam.replace('%', '')), 50);
rPx = barWidth * (rPercent / 100);
} else {
// Otherwise, it's already a number of pixels
rPx = radiusParam;
}
return fixpx(Math.max(Math.min(rPx, maxRadius), 0));
}
// Exclude waterfall and funnel charts from rounding
// Could potentially support rounded waterfall charts in the future,
// but need to make sure trace.marker.cornerradius is set in the defaults
// and also check visuals with respect to the lines connecting the waterfall bars
var r = (isBar || isHistogram) ? calcCornerRadius(trace.marker.cornerradius) : 0;

// Construct path string for bar
var path, h;
if(r && di.s) {
// Bar has cornerradius
// Check amount of 'overhead' (bars stacked above this one)
// to see whether we need to round or not
var overhead = fixpx(Math.abs(
di.s > 0 ? c2p(di._sMax, true) - c2p(di.s1, true) : c2p(di._sMin, true) - c2p(di.s1, true)
));

if(overhead < r) {
// Calculate parameters for rounded corners
var xdir = dirSign(x0, x1);
var ydir = dirSign(y0, y1);
// Sweep direction for rounded corner arcs
var cornersweep = (xdir === -ydir) ? 1 : 0;
if(isHorizontal) {
// Horizontal bars
if(di.hasB) {
// Floating base: Round 1st & 2nd, and 3rd & 4th corners
path = 'M' + (x0 + r * xdir) + ',' + y0 +
'a ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + r * -xdir + ',' + r * ydir +
'V' + (y1 - r * ydir) +
'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + (x0 + r * xdir) + ',' + y1 +
'H' + (x1 - r * xdir) +
'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + x1 + ',' + (y1 - r * ydir) +
'V' + (y0 + r * ydir) +
'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + (x1 - r * xdir) + ',' + y0 +
'Z';
} else {
// Base on axis: Round 3rd and 4th corners

// Helper variables to help with extending rounding down to lower bars
h = Math.abs(x1 - x0) + overhead;
var dy1 = (h < r) ? r - Math.sqrt(h * (2 * r - h)) : 0;
var dy2 = (overhead > 0) ? Math.sqrt(overhead * (2 * r - overhead)) : 0;
var xminfunc = xdir > 0 ? Math.max : Math.min;

path = 'M' + x0 + ',' + y0 +
'V' + (y1 - dy1 * ydir) +
'H' + xminfunc(x1 - (r - overhead) * xdir, x0) +
'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + x1 + ',' + (y1 - r * ydir - dy2) +
'V' + (y0 + r * ydir + dy2) +
'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + xminfunc(x1 - (r - overhead) * xdir, x0) + ',' + (y0 + dy1 * ydir) +
'Z';
}
} else {
// Vertical bars
if(di.hasB) {
// Floating base: Round 1st & 4th, and 2nd & 3rd corners
path = 'M' + (x0 + r * xdir) + ',' + y0 +
'a ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + r * -xdir + ',' + r * ydir +
'V' + (y1 - r * ydir) +
'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + (x0 + r * xdir) + ',' + y1 +
'H' + (x1 - r * xdir) +
'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + x1 + ',' + (y1 - r * ydir) +
'V' + (y0 + r * ydir) +
'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + (x1 - r * xdir) + ',' + y0 +
'Z';
} else {
// Base on axis: Round 2nd and 3rd corners

// Helper variables to help with extending rounding down to lower bars
h = Math.abs(y1 - y0) + overhead;
var dx1 = (h < r) ? r - Math.sqrt(h * (2 * r - h)) : 0;
var dx2 = (overhead > 0) ? Math.sqrt(overhead * (2 * r - overhead)) : 0;
var yminfunc = ydir > 0 ? Math.max : Math.min;

path = 'M' + (x0 + dx1 * xdir) + ',' + y0 +
'V' + yminfunc(y1 - (r - overhead) * ydir, y0) +
'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + (x0 + r * xdir - dx2) + ',' + y1 +
'H' + (x1 - r * xdir + dx2) +
'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + (x1 - dx1 * xdir) + ',' + yminfunc(y1 - (r - overhead) * ydir, y0) +
'V' + y0 + 'Z';
}
}
} else {
// There is a cornerradius, but bar is too far down the stack to be rounded; just draw a rectangle
path = 'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z';
}
} else {
// No cornerradius, just draw a rectangle
path = 'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z';
}

var sel = transition(Lib.ensureSingle(bar, 'path'), fullLayout, opts, makeOnCompleteCallback);
sel
.style('vector-effect', isStatic ? 'none' : 'non-scaling-stroke')
.attr('d', (isNaN((x1 - x0) * (y1 - y0)) || (isBlank && gd._context.staticPlot)) ? 'M0,0Z' : 'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z')
.attr('d', (isNaN((x1 - x0) * (y1 - y0)) || (isBlank && gd._context.staticPlot)) ? 'M0,0Z' : path)
.call(Drawing.setClipUrl, plotinfo.layerClipId, gd);

if(!fullLayout.uniformtext.mode && withTransition) {
Expand Down Expand Up @@ -350,6 +464,7 @@ function appendBarText(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, opts, makeOnCom
if(textPosition === 'auto') {
if(isOutmostBar) {
// draw text using insideTextFont and check if it fits inside bar
// TODO: Need to consider `cornerradius` here
textPosition = 'inside';

font = Lib.ensureUniformFontSize(gd, insideTextFont);
Expand Down
1 change: 1 addition & 0 deletions src/traces/bar/style_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module.exports = function handleStyleDefaults(traceIn, traceOut, coerce, default

coerce('marker.line.width');
coerce('marker.opacity');
coerce('marker.cornerradius');
coercePattern(coerce, 'marker.pattern', markerColor, hasMarkerColorscale);
coerce('selected.marker.color');
coerce('unselected.marker.color');
Expand Down
Loading