33var axisIds = require ( '../../plots/cartesian/axis_ids' ) ;
44var scatterSubTypes = require ( '../../traces/scatter/subtypes' ) ;
55var Registry = require ( '../../registry' ) ;
6+ var isUnifiedHover = require ( '../fx/helpers' ) . isUnifiedHover ;
67
78var createModeBar = require ( './modebar' ) ;
89var modeBarButtons = require ( './buttons' ) ;
@@ -66,25 +67,6 @@ var DRAW_MODES = [
6667 'eraseshape'
6768] ;
6869
69- var HOVER_MODES = [
70- 'hoverCompareCartesian' ,
71- 'hoverClosestCartesian' ,
72- 'hoverClosestGl2d' ,
73- 'hoverClosest3d' ,
74- 'hoverClosestGeo' ,
75- 'hoverClosestPie' ,
76- 'toggleHover'
77- ] ;
78-
79- var SPIKE_MODES = [
80- 'toggleSpikelines'
81- ] ;
82-
83- var EXTRA_MODES = [ ]
84- . concat ( DRAW_MODES )
85- . concat ( HOVER_MODES )
86- . concat ( SPIKE_MODES ) ;
87-
8870// logic behind which buttons are displayed by default
8971function getButtonGroups ( gd ) {
9072 var fullLayout = gd . _fullLayout ;
@@ -104,6 +86,7 @@ function getButtonGroups(gd) {
10486 var hasPolar = fullLayout . _has ( 'polar' ) ;
10587 var hasSankey = fullLayout . _has ( 'sankey' ) ;
10688 var allAxesFixed = areAllAxesFixed ( fullLayout ) ;
89+ var hasUnifiedHoverLabel = isUnifiedHover ( fullLayout . hovermode ) ;
10790
10891 var groups = [ ] ;
10992
@@ -128,23 +111,45 @@ function getButtonGroups(gd) {
128111 addGroup ( commonGroup ) ;
129112
130113 var zoomGroup = [ ] ;
114+ var hoverGroup = [ ] ;
131115 var resetGroup = [ ] ;
132116 var dragModeGroup = [ ] ;
133117
134118 if ( ( hasCartesian || hasGL2D || hasPie || hasFunnelarea || hasTernary ) + hasGeo + hasGL3D + hasMapbox + hasPolar > 1 ) {
135119 // graphs with more than one plot types get 'union buttons'
136- // which reset the view across all subplots.
120+ // which reset the view or toggle hover labels across all subplots.
121+ hoverGroup = [ 'toggleHover' ] ;
137122 resetGroup = [ 'resetViews' ] ;
138123 } else if ( hasGeo ) {
139124 zoomGroup = [ 'zoomInGeo' , 'zoomOutGeo' ] ;
125+ hoverGroup = [ 'hoverClosestGeo' ] ;
140126 resetGroup = [ 'resetGeo' ] ;
141127 } else if ( hasGL3D ) {
128+ hoverGroup = [ 'hoverClosest3d' ] ;
142129 resetGroup = [ 'resetCameraDefault3d' , 'resetCameraLastSave3d' ] ;
143130 } else if ( hasMapbox ) {
144131 zoomGroup = [ 'zoomInMapbox' , 'zoomOutMapbox' ] ;
132+ hoverGroup = [ 'toggleHover' ] ;
145133 resetGroup = [ 'resetViewMapbox' ] ;
134+ } else if ( hasGL2D ) {
135+ hoverGroup = [ 'hoverClosestGl2d' ] ;
136+ } else if ( hasPie ) {
137+ hoverGroup = [ 'hoverClosestPie' ] ;
146138 } else if ( hasSankey ) {
139+ hoverGroup = [ 'hoverClosestCartesian' , 'hoverCompareCartesian' ] ;
147140 resetGroup = [ 'resetViewSankey' ] ;
141+ } else { // hasPolar, hasTernary
142+ // always show at least one hover icon.
143+ hoverGroup = [ 'toggleHover' ] ;
144+ }
145+ // if we have cartesian, allow switching between closest and compare
146+ // regardless of what other types are on the plot, since they'll all
147+ // just treat any truthy hovermode as 'closest'
148+ if ( hasCartesian ) {
149+ hoverGroup = [ 'toggleSpikelines' , 'hoverClosestCartesian' , 'hoverCompareCartesian' ] ;
150+ }
151+ if ( hasNoHover ( fullData ) || hasUnifiedHoverLabel ) {
152+ hoverGroup = [ ] ;
148153 }
149154
150155 if ( ( hasCartesian || hasGL2D ) && ! allAxesFixed ) {
@@ -165,20 +170,40 @@ function getButtonGroups(gd) {
165170 dragModeGroup . push ( 'select2d' , 'lasso2d' ) ;
166171 }
167172
168- // accept pre-defined buttons as string
173+ var enabledHoverGroup = [ ] ;
174+ var enableHover = function ( a ) {
175+ // return if already added
176+ if ( enabledHoverGroup . indexOf ( a ) !== - 1 ) return ;
177+ // should be in hoverGroup
178+ if ( hoverGroup . indexOf ( a ) !== - 1 ) {
179+ enabledHoverGroup . push ( a ) ;
180+ }
181+ } ;
169182 if ( Array . isArray ( buttonsToAdd ) ) {
170183 var newList = [ ] ;
171184 for ( var i = 0 ; i < buttonsToAdd . length ; i ++ ) {
172185 var b = buttonsToAdd [ i ] ;
173186 if ( typeof b === 'string' ) {
174- if ( EXTRA_MODES . indexOf ( b ) !== - 1 ) {
187+ if ( DRAW_MODES . indexOf ( b ) !== - 1 ) {
188+ // accept pre-defined drag modes i.e. shape drawing features as string
175189 if (
176- DRAW_MODES . indexOf ( b ) === - 1 ||
177190 fullLayout . _has ( 'mapbox' ) || // draw shapes in paper coordinate (could be improved in future to support data coordinate, when there is no pitch)
178191 fullLayout . _has ( 'cartesian' ) // draw shapes in data coordinate
179192 ) {
180193 dragModeGroup . push ( b ) ;
181194 }
195+ } else if ( b === 'toggleSpikelines' ) {
196+ enableHover ( 'toggleSpikelines' ) ;
197+ } else if ( b === 'toggleHover' ) {
198+ enableHover ( 'toggleHover' ) ;
199+ } else if ( b === 'hoverCompare' ) {
200+ enableHover ( 'hoverCompareCartesian' ) ;
201+ } else if ( b === 'hoverClosest' ) {
202+ enableHover ( 'hoverClosestCartesian' ) ;
203+ enableHover ( 'hoverClosestGeo' ) ;
204+ enableHover ( 'hoverClosest3d' ) ;
205+ enableHover ( 'hoverClosestGl2d' ) ;
206+ enableHover ( 'hoverClosestPie' ) ;
182207 }
183208 } else newList . push ( b ) ;
184209 }
@@ -187,6 +212,7 @@ function getButtonGroups(gd) {
187212
188213 addGroup ( dragModeGroup ) ;
189214 addGroup ( zoomGroup . concat ( resetGroup ) ) ;
215+ addGroup ( enabledHoverGroup ) ;
190216
191217 return appendButtonsToGroups ( groups , buttonsToAdd ) ;
192218}
@@ -235,6 +261,14 @@ function isSelectable(fullData) {
235261 return selectable ;
236262}
237263
264+ // check whether all trace are 'noHover'
265+ function hasNoHover ( fullData ) {
266+ for ( var i = 0 ; i < fullData . length ; i ++ ) {
267+ if ( ! Registry . traceIs ( fullData [ i ] , 'noHover' ) ) return false ;
268+ }
269+ return true ;
270+ }
271+
238272function appendButtonsToGroups ( groups , buttons ) {
239273 if ( buttons . length ) {
240274 if ( Array . isArray ( buttons [ 0 ] ) ) {
0 commit comments