@@ -772,59 +772,138 @@ function createHoverText(hoverData, opts, gd) {
772
772
var commonBgColor = commonLabelOpts . bgcolor || Color . defaultLine ;
773
773
var commonStroke = commonLabelOpts . bordercolor || Color . contrast ( commonBgColor ) ;
774
774
var contrastColor = Color . contrast ( commonBgColor ) ;
775
+ var commonLabelFont = {
776
+ family : commonLabelOpts . font . family || fontFamily ,
777
+ size : commonLabelOpts . font . size || fontSize ,
778
+ color : commonLabelOpts . font . color || contrastColor
779
+ } ;
775
780
776
781
lpath . style ( {
777
782
fill : commonBgColor ,
778
783
stroke : commonStroke
779
784
} ) ;
780
785
781
786
ltext . text ( t0 )
782
- . call ( Drawing . font ,
783
- commonLabelOpts . font . family || fontFamily ,
784
- commonLabelOpts . font . size || fontSize ,
785
- commonLabelOpts . font . color || contrastColor
786
- )
787
+ . call ( Drawing . font , commonLabelFont )
787
788
. call ( svgTextUtils . positionText , 0 , 0 )
788
789
. call ( svgTextUtils . convertToTspans , gd ) ;
789
790
790
791
label . attr ( 'transform' , '' ) ;
791
792
792
793
var tbb = ltext . node ( ) . getBoundingClientRect ( ) ;
794
+ var lx , ly ;
795
+
793
796
if ( hovermode === 'x' ) {
797
+ var topsign = xa . side === 'top' ? '-' : '' ;
798
+
794
799
ltext . attr ( 'text-anchor' , 'middle' )
795
800
. call ( svgTextUtils . positionText , 0 , ( xa . side === 'top' ?
796
801
( outerTop - tbb . bottom - HOVERARROWSIZE - HOVERTEXTPAD ) :
797
802
( outerTop - tbb . top + HOVERARROWSIZE + HOVERTEXTPAD ) ) ) ;
798
803
799
- var topsign = xa . side === 'top' ? '-' : '' ;
800
- lpath . attr ( 'd' , 'M0,0' +
801
- 'L' + HOVERARROWSIZE + ',' + topsign + HOVERARROWSIZE +
802
- 'H' + ( HOVERTEXTPAD + tbb . width / 2 ) +
803
- 'v' + topsign + ( HOVERTEXTPAD * 2 + tbb . height ) +
804
- 'H-' + ( HOVERTEXTPAD + tbb . width / 2 ) +
805
- 'V' + topsign + HOVERARROWSIZE + 'H-' + HOVERARROWSIZE + 'Z' ) ;
806
-
807
- label . attr ( 'transform' , 'translate(' +
808
- ( xa . _offset + ( c0 . x0 + c0 . x1 ) / 2 ) + ',' +
809
- ( ya . _offset + ( xa . side === 'top' ? 0 : ya . _length ) ) + ')' ) ;
804
+ lx = xa . _offset + ( c0 . x0 + c0 . x1 ) / 2 ;
805
+ ly = ya . _offset + ( xa . side === 'top' ? 0 : ya . _length ) ;
806
+
807
+ var halfWidth = tbb . width / 2 + HOVERTEXTPAD ;
808
+
809
+ if ( lx < halfWidth ) {
810
+ lx = halfWidth ;
811
+
812
+ lpath . attr ( 'd' , 'M-' + ( halfWidth - HOVERARROWSIZE ) + ',0' +
813
+ 'L-' + ( halfWidth - HOVERARROWSIZE * 2 ) + ',' + topsign + HOVERARROWSIZE +
814
+ 'H' + ( HOVERTEXTPAD + tbb . width / 2 ) +
815
+ 'v' + topsign + ( HOVERTEXTPAD * 2 + tbb . height ) +
816
+ 'H-' + halfWidth +
817
+ 'V' + topsign + HOVERARROWSIZE +
818
+ 'Z' ) ;
819
+ } else if ( lx > ( fullLayout . width - halfWidth ) ) {
820
+ lx = fullLayout . width - halfWidth ;
821
+
822
+ lpath . attr ( 'd' , 'M' + ( halfWidth - HOVERARROWSIZE ) + ',0' +
823
+ 'L' + halfWidth + ',' + topsign + HOVERARROWSIZE +
824
+ 'v' + topsign + ( HOVERTEXTPAD * 2 + tbb . height ) +
825
+ 'H-' + halfWidth +
826
+ 'V' + topsign + HOVERARROWSIZE +
827
+ 'H' + ( halfWidth - HOVERARROWSIZE * 2 ) + 'Z' ) ;
828
+ } else {
829
+ lpath . attr ( 'd' , 'M0,0' +
830
+ 'L' + HOVERARROWSIZE + ',' + topsign + HOVERARROWSIZE +
831
+ 'H' + ( HOVERTEXTPAD + tbb . width / 2 ) +
832
+ 'v' + topsign + ( HOVERTEXTPAD * 2 + tbb . height ) +
833
+ 'H-' + ( HOVERTEXTPAD + tbb . width / 2 ) +
834
+ 'V' + topsign + HOVERARROWSIZE +
835
+ 'H-' + HOVERARROWSIZE + 'Z' ) ;
836
+ }
810
837
} else {
811
- ltext . attr ( 'text-anchor' , ya . side === 'right' ? 'start' : 'end' )
812
- . call ( svgTextUtils . positionText ,
813
- ( ya . side === 'right' ? 1 : - 1 ) * ( HOVERTEXTPAD + HOVERARROWSIZE ) ,
814
- outerTop - tbb . top - tbb . height / 2 ) ;
838
+ var anchor ;
839
+ var sgn ;
840
+ var leftsign ;
841
+ if ( ya . side === 'right' ) {
842
+ anchor = 'start' ;
843
+ sgn = 1 ;
844
+ leftsign = '' ;
845
+ lx = xa . _offset + xa . _length ;
846
+ } else {
847
+ anchor = 'end' ;
848
+ sgn = - 1 ;
849
+ leftsign = '-' ;
850
+ lx = xa . _offset ;
851
+ }
852
+
853
+ ly = ya . _offset + ( c0 . y0 + c0 . y1 ) / 2 ;
854
+
855
+ ltext . attr ( 'text-anchor' , anchor ) ;
815
856
816
- var leftsign = ya . side === 'right' ? '' : '-' ;
817
857
lpath . attr ( 'd' , 'M0,0' +
818
858
'L' + leftsign + HOVERARROWSIZE + ',' + HOVERARROWSIZE +
819
859
'V' + ( HOVERTEXTPAD + tbb . height / 2 ) +
820
860
'h' + leftsign + ( HOVERTEXTPAD * 2 + tbb . width ) +
821
861
'V-' + ( HOVERTEXTPAD + tbb . height / 2 ) +
822
862
'H' + leftsign + HOVERARROWSIZE + 'V-' + HOVERARROWSIZE + 'Z' ) ;
823
863
824
- label . attr ( 'transform' , 'translate(' +
825
- ( xa . _offset + ( ya . side === 'right' ? xa . _length : 0 ) ) + ',' +
826
- ( ya . _offset + ( c0 . y0 + c0 . y1 ) / 2 ) + ')' ) ;
864
+ var halfHeight = tbb . height / 2 ;
865
+ var lty = outerTop - tbb . top - halfHeight ;
866
+ var clipId = 'clip' + fullLayout . _uid + 'commonlabel' + ya . _id ;
867
+ var clipPath ;
868
+
869
+ if ( lx < ( tbb . width + 2 * HOVERTEXTPAD + HOVERARROWSIZE ) ) {
870
+ clipPath = 'M-' + ( HOVERARROWSIZE + HOVERTEXTPAD ) + '-' + halfHeight +
871
+ 'h-' + ( tbb . width - HOVERTEXTPAD ) +
872
+ 'V' + halfHeight +
873
+ 'h' + ( tbb . width - HOVERTEXTPAD ) + 'Z' ;
874
+
875
+ var ltx = tbb . width - lx + HOVERTEXTPAD ;
876
+ svgTextUtils . positionText ( ltext , ltx , lty ) ;
877
+
878
+ // shift each line (except the longest) so that start-of-line
879
+ // is always visible
880
+ if ( anchor === 'end' ) {
881
+ ltext . selectAll ( 'tspan' ) . each ( function ( ) {
882
+ var s = d3 . select ( this ) ;
883
+ var dummy = Drawing . tester . append ( 'text' )
884
+ . text ( s . text ( ) )
885
+ . call ( Drawing . font , commonLabelFont ) ;
886
+ var dummyBB = dummy . node ( ) . getBoundingClientRect ( ) ;
887
+ if ( dummyBB . width < tbb . width ) {
888
+ s . attr ( 'x' , ltx - dummyBB . width ) ;
889
+ }
890
+ dummy . remove ( ) ;
891
+ } ) ;
892
+ }
893
+ } else {
894
+ svgTextUtils . positionText ( ltext , sgn * ( HOVERTEXTPAD + HOVERARROWSIZE ) , lty ) ;
895
+ clipPath = null ;
896
+ }
897
+
898
+ var textClip = fullLayout . _topclips . selectAll ( '#' + clipId ) . data ( clipPath ? [ 0 ] : [ ] ) ;
899
+ textClip . enter ( ) . append ( 'clipPath' ) . attr ( 'id' , clipId ) . append ( 'path' ) ;
900
+ textClip . exit ( ) . remove ( ) ;
901
+ textClip . select ( 'path' ) . attr ( 'd' , clipPath ) ;
902
+ Drawing . setClipUrl ( ltext , clipPath ? clipId : null , gd ) ;
827
903
}
904
+
905
+ label . attr ( 'transform' , 'translate(' + lx + ',' + ly + ')' ) ;
906
+
828
907
// remove the "close but not quite" points
829
908
// because of error bars, only take up to a space
830
909
hoverData = hoverData . filter ( function ( d ) {
0 commit comments