@@ -396,7 +396,7 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
396396 Drawing . singlePointStyle ( di , sel , trace , styleFns , gd ) ;
397397 }
398398
399- appendBarText ( gd , plotinfo , bar , cd , i , x0 , x1 , y0 , y1 , lxFunc , lyFunc , opts , makeOnCompleteCallback ) ;
399+ appendBarText ( gd , plotinfo , bar , cd , i , x0 , x1 , y0 , y1 , lxFunc , lyFunc , r , opts , makeOnCompleteCallback ) ;
400400
401401 if ( plotinfo . layerClipId ) {
402402 Drawing . hideOutsideRangePoint ( di , bar . select ( 'text' ) , xa , ya , trace . xcalendar , trace . ycalendar ) ;
@@ -413,7 +413,7 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
413413 Registry . getComponentMethod ( 'errorbars' , 'plot' ) ( gd , bartraces , plotinfo , opts ) ;
414414}
415415
416- function appendBarText ( gd , plotinfo , bar , cd , i , x0 , x1 , y0 , y1 , lxFunc , lyFunc , opts , makeOnCompleteCallback ) {
416+ function appendBarText ( gd , plotinfo , bar , cd , i , x0 , x1 , y0 , y1 , lxFunc , lyFunc , r , opts , makeOnCompleteCallback ) {
417417 var xa = plotinfo . xaxis ;
418418 var ya = plotinfo . yaxis ;
419419
@@ -450,6 +450,7 @@ function appendBarText(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, lxFunc, lyFunc,
450450
451451 var calcBar = cd [ i ] ;
452452 var isOutmostBar = ! inStackOrRelativeMode || calcBar . _outmost ;
453+ var hasB = calcBar . hasB ;
453454
454455 if ( ! text ||
455456 textPosition === 'none' ||
@@ -532,6 +533,8 @@ function appendBarText(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, lxFunc, lyFunc,
532533 ( barWidth >= textWidth * ( barHeight / textHeight ) ) :
533534 ( barHeight >= textHeight * ( barWidth / textWidth ) ) ;
534535
536+ // TODO: Rounding needs to be considered when deciding
537+ // whether text fits inside bar
535538 if ( textHasSize && (
536539 fitsInside ||
537540 fitsInsideIfRotated ||
@@ -592,6 +595,8 @@ function appendBarText(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, lxFunc, lyFunc,
592595 anchor : insidetextanchor ,
593596 lxFunc : lxFunc ,
594597 lyFunc : lyFunc ,
598+ hasB : hasB ,
599+ r : r ,
595600 } ) ;
596601 }
597602
@@ -628,22 +633,14 @@ function toMoveInsideBar(x0, x1, y0, y1, textBB, opts) {
628633 var leftToRight = opts . leftToRight || 0 ; // left: -1, center: 0, right: 1
629634 var toRight = ( leftToRight + 1 ) / 2 ;
630635 var toLeft = 1 - toRight ;
631- var lxFunc = opts . lxFunc ;
632- var lyFunc = opts . lyFunc ;
636+ var hasB = opts . hasB ;
637+ var r = opts . r ;
633638
634639 var textWidth = textBB . width ;
635640 var textHeight = textBB . height ;
636641
637- var lx , ly , refPos ;
638- if ( isHorizontal ) {
639- refPos = ( anchor === 'middle' ) ? Math . abs ( x1 - x0 ) / 2 : TEXTPAD ;
640- lx = Math . abs ( x1 - x0 ) ;
641- ly = lyFunc ? lyFunc ( refPos ) : Math . abs ( y1 - y0 ) ;
642- } else {
643- refPos = ( anchor === 'middle' ) ? Math . abs ( y1 - y0 ) / 2 : TEXTPAD ;
644- lx = lxFunc ? lxFunc ( refPos ) : Math . abs ( x1 - x0 ) ;
645- ly = Math . abs ( y1 - y0 ) ;
646- }
642+ var lx = Math . abs ( x1 - x0 ) ;
643+ var ly = Math . abs ( y1 - y0 ) ;
647644
648645 // compute remaining space
649646 var textpad = (
@@ -658,21 +655,31 @@ function toMoveInsideBar(x0, x1, y0, y1, textBB, opts) {
658655 if ( ( angle === 'auto' ) &&
659656 ! ( textWidth <= lx && textHeight <= ly ) &&
660657 ( textWidth > lx || textHeight > ly ) && (
661- ! ( textWidth > ly || textHeight > lx ) ||
662- ( ( textWidth < textHeight ) !== ( lx < ly ) )
663- ) ) {
658+ ! ( textWidth > ly || textHeight > lx ) ||
659+ ( ( textWidth < textHeight ) !== ( lx < ly ) )
660+ ) ) {
664661 rotate += 90 ;
665662 }
666663
667664 var t = getRotatedTextSize ( textBB , rotate ) ;
668665
669- var scale = 1 ;
670- if ( constrained ) {
671- scale = Math . min (
672- 1 ,
673- lx / t . x ,
674- ly / t . y
675- ) ;
666+ var scale , padForRounding ;
667+ // Scale text for rounded bars
668+ if ( r && r > TEXTPAD ) {
669+ var scaleAndPad = scaleTextForRoundedBar ( x0 , x1 , y0 , y1 , t , r , isHorizontal , hasB ) ;
670+ scale = scaleAndPad . scale ;
671+ padForRounding = scaleAndPad . pad ;
672+ // Scale text for non-rounded bars
673+ } else {
674+ scale = 1 ;
675+ if ( constrained ) {
676+ scale = Math . min (
677+ 1 ,
678+ lx / t . x ,
679+ ly / t . y
680+ ) ;
681+ }
682+ padForRounding = 0 ;
676683 }
677684
678685 // compute text and target positions
@@ -690,6 +697,11 @@ function toMoveInsideBar(x0, x1, y0, y1, textBB, opts) {
690697 var anchorY = 0 ;
691698 if ( isStart || isEnd ) {
692699 var extrapad = ( isHorizontal ? t . x : t . y ) / 2 ;
700+
701+ if ( r && ( hasB || isEnd ) ) {
702+ extrapad += padForRounding ;
703+ }
704+
693705 var dir = isHorizontal ? dirSign ( x0 , x1 ) : dirSign ( y0 , y1 ) ;
694706
695707 if ( isHorizontal ) {
@@ -723,6 +735,54 @@ function toMoveInsideBar(x0, x1, y0, y1, textBB, opts) {
723735 } ;
724736}
725737
738+ function scaleTextForRoundedBar ( x0 , x1 , y0 , y1 , t , r , isHorizontal , hasB ) {
739+ var barWidth = Math . max ( 0 , Math . abs ( x1 - x0 ) - 2 * TEXTPAD ) ;
740+ var barHeight = Math . max ( 0 , Math . abs ( y1 - y0 ) - 2 * TEXTPAD ) ;
741+ var R = r - TEXTPAD ;
742+ var rX = hasB ? R * 2 : ( isHorizontal ? R : 2 * R ) ;
743+ var rY = hasB ? R * 2 : ( isHorizontal ? 2 * R : R ) ;
744+ var a , b , c ;
745+ var scale , pad ;
746+
747+ // Calculate how much extra padding is needed for bar
748+ // TODO: This is the equation I worked out, but it seems to give a value that's too small
749+ if ( isHorizontal ) {
750+ pad = Math . max ( 0 , R - Math . sqrt ( R * R + ( t . y - barHeight ) / 2 - R ) ) ;
751+ } else {
752+ pad = Math . max ( 0 , R - Math . sqrt ( R * R + ( t . x - barWidth ) / 2 - R ) ) ;
753+ }
754+
755+ if ( t . y / t . x >= barHeight / ( barWidth - rX ) ) {
756+ // Case 1 (Tall text)
757+ scale = barHeight / t . y ;
758+ pad = 0 ;
759+ } else if ( t . y / t . x <= ( barHeight - rY ) / barWidth ) {
760+ // Case 2 (Wide text)
761+ scale = barWidth / t . x ;
762+ pad = 0 ;
763+ } else if ( ! hasB && isHorizontal ) {
764+ // Case 3a (Quadratic case, two side corners are rounded)
765+ a = t . x * t . x + t . y * t . y / 4 ;
766+ b = t . y * ( 2 * R - barHeight ) + 2 * t . x * ( R - barWidth ) ;
767+ c = ( R - barHeight / 2 ) * ( R - barHeight / 2 ) + ( R - barWidth ) * ( R - barWidth ) - R * R ;
768+ scale = ( - b + Math . sqrt ( b * b - 4 * a * c ) ) / ( 2 * a ) ;
769+ } else if ( ! hasB ) {
770+ // Case 3b (Quadratic case, two top/bottom corners are rounded)
771+ a = t . x * t . x / 4 + t . y * t . y ;
772+ b = 2 * t . x * ( R - barHeight ) + t . y * ( 2 * R - barWidth ) ;
773+ c = ( R - barHeight ) * ( R - barHeight ) + ( R - barWidth / 2 ) * ( R - barWidth / 2 ) - R * R ;
774+ scale = ( - b + Math . sqrt ( b * b - 4 * a * c ) ) / ( 2 * a ) ;
775+ } else {
776+ // Case 4 (Quadratic case, all four corners are rounded)
777+ // TODO: This gives a scale factor that's way too large, text overflows boundaries
778+ a = ( t . x * t . x + t . y * t . y ) / 4 ;
779+ b = t . y * ( 2 * R - barHeight ) + t . x * ( 2 * R - barWidth ) ;
780+ c = ( R - barHeight / 2 ) * ( R - barHeight / 2 ) + ( R - barWidth / 2 ) * ( R - barWidth / 2 ) - R * R ;
781+ scale = ( - b + Math . sqrt ( b * b - 4 * a * c ) ) / ( 2 * a ) ;
782+ }
783+ return { scale : scale , pad : pad } ;
784+ }
785+
726786function toMoveOutsideBar ( x0 , x1 , y0 , y1 , textBB , opts ) {
727787 var isHorizontal = ! ! opts . isHorizontal ;
728788 var constrained = ! ! opts . constrained ;
0 commit comments