@@ -39,6 +39,13 @@ var YSHIFTY = Math.sin(YA_RADIANS);
3939var HOVERARROWSIZE = constants . HOVERARROWSIZE ;
4040var HOVERTEXTPAD = constants . HOVERTEXTPAD ;
4141
42+ var multipleHoverPoints = {
43+ box : true ,
44+ ohlc : true ,
45+ violin : true ,
46+ candlestick : true
47+ } ;
48+
4249// fx.hover: highlight data on hover
4350// evt can be a mousemove event, or an object with data about what points
4451// to hover on
@@ -651,39 +658,58 @@ function _hover(gd, evt, subplot, noHoverEvent) {
651658 } ;
652659 sortHoverData ( ) ;
653660
654- // If in compare mode, select every point at position
655661 if (
656662 helpers . isXYhover ( _mode ) &&
657663 hoverData [ 0 ] . length !== 0 &&
658664 hoverData [ 0 ] . trace . type !== 'splom' // TODO: add support for splom
659665 ) {
666+ // pick winning point
660667 var winningPoint = hoverData [ 0 ] ;
668+ // discard other points
669+ if ( multipleHoverPoints [ winningPoint . trace . type ] ) {
670+ hoverData = hoverData . filter ( function ( d ) {
671+ return d . trace . index === winningPoint . trace . index ;
672+ } ) ;
673+ } else {
674+ hoverData = [ winningPoint ] ;
675+ }
676+ var initLen = hoverData . length ;
661677
662- var customXVal = customVal ( 'x' , winningPoint , fullLayout ) ;
663- var customYVal = customVal ( 'y' , winningPoint , fullLayout ) ;
678+ var winX = getCoord ( 'x' , winningPoint , fullLayout ) ;
679+ var winY = getCoord ( 'y' , winningPoint , fullLayout ) ;
664680
665- findHoverPoints ( customXVal , customYVal ) ;
681+ // in compare mode, select every point at position
682+ findHoverPoints ( winX , winY ) ;
666683
667684 var finalPoints = [ ] ;
668685 var seen = { } ;
669- var insert = function ( hd ) {
670- var type = hd . trace . type ;
671- var key = (
672- type === 'box' ||
673- type === 'violin' ||
674- type === 'ohlc' ||
675- type === 'candlestick'
676- ) ? hoverDataKey ( hd ) : hd . trace . index ;
686+ var id = 0 ;
687+ var insert = function ( newHd ) {
688+ var key = multipleHoverPoints [ newHd . trace . type ] ? hoverDataKey ( newHd ) : newHd . trace . index ;
677689 if ( ! seen [ key ] ) {
678- seen [ key ] = true ;
679- finalPoints . push ( hd ) ;
690+ id ++ ;
691+ seen [ key ] = id ;
692+ finalPoints . push ( newHd ) ;
693+ } else {
694+ var oldId = seen [ key ] - 1 ;
695+ var oldHd = finalPoints [ oldId ] ;
696+ if ( oldId > 0 &&
697+ Math . abs ( newHd . distance ) <
698+ Math . abs ( oldHd . distance )
699+ ) {
700+ // replace with closest
701+ finalPoints [ oldId ] = newHd ;
702+ }
680703 }
681704 } ;
682705
683- // insert the winnig point first
684- insert ( winningPoint ) ;
706+ var k ;
707+ // insert the winnig point(s) first
708+ for ( k = 0 ; k < initLen ; k ++ ) {
709+ insert ( hoverData [ k ] ) ;
710+ }
685711 // override from the end
686- for ( var k = hoverData . length - 1 ; k > 0 ; k -- ) {
712+ for ( k = hoverData . length - 1 ; k > initLen - 1 ; k -- ) {
687713 insert ( hoverData [ k ] ) ;
688714 }
689715 hoverData = finalPoints ;
@@ -1045,8 +1071,9 @@ function createHoverText(hoverData, opts, gd) {
10451071 legendDraw ( gd , mockLegend ) ;
10461072
10471073 // Position the hover
1048- var ly = Lib . mean ( hoverData . map ( function ( c ) { return ( c . y0 + c . y1 ) / 2 ; } ) ) ;
1049- var lx = Lib . mean ( hoverData . map ( function ( c ) { return ( c . x0 + c . x1 ) / 2 ; } ) ) ;
1074+ var winningPoint = hoverData [ 0 ] ;
1075+ var ly = ( winningPoint . y0 + winningPoint . y1 ) / 2 ;
1076+ var lx = ( winningPoint . x0 + winningPoint . x1 ) / 2 ;
10501077 var legendContainer = container . select ( 'g.legend' ) ;
10511078 var tbb = legendContainer . node ( ) . getBoundingClientRect ( ) ;
10521079 lx += xa . _offset ;
@@ -1892,7 +1919,7 @@ function orderRangePoints(hoverData, hovermode) {
18921919 return first . concat ( second ) . concat ( last ) ;
18931920}
18941921
1895- function customVal ( axLetter , winningPoint , fullLayout ) {
1922+ function getCoord ( axLetter , winningPoint , fullLayout ) {
18961923 var ax = winningPoint [ axLetter + 'a' ] ;
18971924 var val = winningPoint [ axLetter + 'Val' ] ;
18981925
0 commit comments