@@ -31,6 +31,7 @@ function hoverOnBars(pointData, xval, yval, hovermode) {
3131 var isClosest = ( hovermode === 'closest' ) ;
3232 var isWaterfall = ( trace . type === 'waterfall' ) ;
3333 var maxHoverDistance = pointData . maxHoverDistance ;
34+ var maxSpikeDistance = pointData . maxSpikeDistance ;
3435
3536 var posVal , sizeVal , posLetter , sizeLetter , dx , dy , pRangeCalc ;
3637
@@ -61,40 +62,63 @@ function hoverOnBars(pointData, xval, yval, hovermode) {
6162 return Math . max ( thisBarMaxPos ( di ) , di . p + t . bardelta / 2 ) ;
6263 } ;
6364
64- function _positionFn ( _minPos , _maxPos ) {
65+ function hoverPositionFn ( _minPos , _maxPos ) {
6566 // add a little to the pseudo-distance for wider bars, so that like scatter,
6667 // if you are over two overlapping bars, the narrower one wins.
6768 return Fx . inbox ( _minPos - posVal , _maxPos - posVal ,
6869 maxHoverDistance + Math . min ( 1 , Math . abs ( _maxPos - _minPos ) / pRangeCalc ) - 1 ) ;
6970 }
7071
72+ function spikePositionFn ( _minPos , _maxPos ) {
73+ // add a little to the pseudo-distance for wider bars, so that like scatter,
74+ // if you are over two overlapping bars, the narrower one wins.
75+ return Fx . inbox ( _minPos - posVal , _maxPos - posVal ,
76+ maxSpikeDistance + Math . min ( 1 , Math . abs ( _maxPos - _minPos ) / pRangeCalc ) - 1 ) ;
77+ }
78+
7179 function positionFn ( di ) {
72- return _positionFn ( minPos ( di ) , maxPos ( di ) ) ;
80+ return hoverPositionFn ( minPos ( di ) , maxPos ( di ) ) ;
7381 }
7482
7583 function thisBarPositionFn ( di ) {
76- return _positionFn ( thisBarMinPos ( di ) , thisBarMaxPos ( di ) ) ;
84+ return spikePositionFn ( thisBarMinPos ( di ) , thisBarMaxPos ( di ) ) ;
7785 }
7886
79- function sizeFn ( di ) {
80- var v = sizeVal ;
81- var b = di . b ;
87+ function getSize ( di ) {
8288 var s = di [ sizeLetter ] ;
8389
8490 if ( isWaterfall ) {
8591 var rawS = Math . abs ( di . rawS ) || 0 ;
86- if ( v > 0 ) {
92+ if ( sizeVal > 0 ) {
8793 s += rawS ;
88- } else if ( v < 0 ) {
94+ } else if ( sizeVal < 0 ) {
8995 s -= rawS ;
9096 }
9197 }
9298
99+ return s ;
100+ }
101+
102+ function sizeFn ( di ) {
103+ var v = sizeVal ;
104+ var b = di . b ;
105+ var s = getSize ( di ) ;
106+
93107 // add a gradient so hovering near the end of a
94108 // bar makes it a little closer match
95109 return Fx . inbox ( b - v , s - v , maxHoverDistance + ( s - v ) / ( s - b ) - 1 ) ;
96110 }
97111
112+ function thisBarSizeFn ( di ) {
113+ var v = sizeVal ;
114+ var b = di . b ;
115+ var s = getSize ( di ) ;
116+
117+ // add a gradient so hovering near the end of a
118+ // bar makes it a little closer match
119+ return Fx . inbox ( b - v , s - v , maxSpikeDistance + ( s - v ) / ( s - b ) - 1 ) ;
120+ }
121+
98122 if ( trace . orientation === 'h' ) {
99123 posVal = yval ;
100124 sizeVal = xval ;
@@ -158,7 +182,7 @@ function hoverOnBars(pointData, xval, yval, hovermode) {
158182 pointData . baseLabel = hoverLabelText ( sa , di . b ) ;
159183
160184 // spikelines always want "closest" distance regardless of hovermode
161- pointData . spikeDistance = ( sizeFn ( di ) + thisBarPositionFn ( di ) ) / 2 - maxHoverDistance ;
185+ pointData . spikeDistance = ( thisBarSizeFn ( di ) + thisBarPositionFn ( di ) ) / 2 ;
162186 // they also want to point to the data value, regardless of where the label goes
163187 // in case of bars shifted within groups
164188 pointData [ posLetter + 'Spike' ] = pa . c2p ( di . p , true ) ;
0 commit comments