@@ -20,33 +20,36 @@ var SHOWISOLATETIP = true;
2020exports . handleItemClick = function handleItemClick ( g , gd , legendObj , mode ) {
2121 var fullLayout = gd . _fullLayout ;
2222
23- if ( gd . _dragged || gd . _editing ) return ;
23+ if ( gd . _dragged || gd . _editing ) return ;
2424
2525 var legendItem = g . data ( ) [ 0 ] [ 0 ] ;
26- if ( legendItem . groupTitle && legendItem . noClick ) return ;
26+ if ( legendItem . groupTitle && legendItem . noClick ) return ;
2727
2828 var groupClick = legendObj . groupclick ;
2929
3030 // Show isolate tip on first single click when default behavior is active
31- if ( mode === 'toggle' && legendObj . itemdoubleclick === 'toggleothers' &&
32- SHOWISOLATETIP && gd . data && gd . _context . showTips
31+ if (
32+ mode === 'toggle' &&
33+ legendObj . itemdoubleclick === 'toggleothers' &&
34+ SHOWISOLATETIP &&
35+ gd . data &&
36+ gd . _context . showTips
3337 ) {
3438 Lib . notifier ( Lib . _ ( gd , 'Double-click on legend to isolate one trace' ) , 'long' , gd ) ;
3539 SHOWISOLATETIP = false ;
3640 }
3741
3842 var toggleGroup = groupClick === 'togglegroup' ;
3943
40- var hiddenSlices = fullLayout . hiddenlabels ?
41- fullLayout . hiddenlabels . slice ( ) :
42- [ ] ;
44+ var hiddenSlices = fullLayout . hiddenlabels ? fullLayout . hiddenlabels . slice ( ) : [ ] ;
4345
4446 var fullData = gd . _fullData ;
45- var shapesWithLegend = ( fullLayout . shapes || [ ] ) . filter ( function ( d ) { return d . showlegend ; } ) ;
46- var allLegendItems = fullData . concat ( shapesWithLegend ) ;
47+ // legendgroup membership matters even when showlegend is false, so togglegroup reaches hidden group peers.
48+ const shapesInLegend = ( fullLayout . shapes || [ ] ) . filter ( ( d ) => d . showlegend || d . legendgroup ) ;
49+ var allLegendItems = fullData . concat ( shapesInLegend ) ;
4750
4851 var fullTrace = legendItem . trace ;
49- if ( fullTrace . _isShape ) {
52+ if ( fullTrace . _isShape ) {
5053 fullTrace = fullTrace . _fullInput ;
5154 }
5255
@@ -61,11 +64,11 @@ exports.handleItemClick = function handleItemClick(g, gd, legendObj, mode) {
6164 function insertDataUpdate ( traceIndex , value ) {
6265 var attrIndex = dataIndices . indexOf ( traceIndex ) ;
6366 var valueArray = dataUpdate . visible ;
64- if ( ! valueArray ) {
67+ if ( ! valueArray ) {
6568 valueArray = dataUpdate . visible = [ ] ;
6669 }
6770
68- if ( dataIndices . indexOf ( traceIndex ) === - 1 ) {
71+ if ( dataIndices . indexOf ( traceIndex ) === - 1 ) {
6972 dataIndices . push ( traceIndex ) ;
7073 attrIndex = dataIndices . length - 1 ;
7174 }
@@ -75,7 +78,7 @@ exports.handleItemClick = function handleItemClick(g, gd, legendObj, mode) {
7578 return attrIndex ;
7679 }
7780
78- var updatedShapes = ( fullLayout . shapes || [ ] ) . map ( function ( d ) {
81+ var updatedShapes = ( fullLayout . shapes || [ ] ) . map ( function ( d ) {
7982 return d . _input ;
8083 } ) ;
8184
@@ -87,19 +90,19 @@ exports.handleItemClick = function handleItemClick(g, gd, legendObj, mode) {
8790 }
8891
8992 function setVisibility ( fullTrace , visibility ) {
90- if ( legendItem . groupTitle && ! toggleGroup ) return ;
93+ if ( legendItem . groupTitle && ! toggleGroup ) return ;
9194
9295 var fullInput = fullTrace . _fullInput || fullTrace ;
9396 var isShape = fullInput . _isShape ;
9497 var index = fullInput . index ;
95- if ( index === undefined ) index = fullInput . _index ;
98+ if ( index === undefined ) index = fullInput . _index ;
9699
97100 // false -> false (not possible since will not be visible in legend)
98101 // true -> legendonly
99102 // legendonly -> true
100103 var nextVisibility = fullInput . visible === false ? false : visibility ;
101104
102- if ( isShape ) {
105+ if ( isShape ) {
103106 insertShapesUpdate ( index , nextVisibility ) ;
104107 } else {
105108 insertDataUpdate ( index , nextVisibility ) ;
@@ -111,37 +114,37 @@ exports.handleItemClick = function handleItemClick(g, gd, legendObj, mode) {
111114 var fullInput = fullTrace . _fullInput ;
112115 var isShape = fullInput && fullInput . _isShape ;
113116
114- if ( ! isShape && Registry . traceIs ( fullTrace , 'pie-like' ) ) {
117+ if ( ! isShape && Registry . traceIs ( fullTrace , 'pie-like' ) ) {
115118 var thisLabel = legendItem . label ;
116119 var thisLabelIndex = hiddenSlices . indexOf ( thisLabel ) ;
117120
118- if ( mode === 'toggle' ) {
119- if ( thisLabelIndex === - 1 ) hiddenSlices . push ( thisLabel ) ;
121+ if ( mode === 'toggle' ) {
122+ if ( thisLabelIndex === - 1 ) hiddenSlices . push ( thisLabel ) ;
120123 else hiddenSlices . splice ( thisLabelIndex , 1 ) ;
121- } else if ( mode === 'toggleothers' ) {
124+ } else if ( mode === 'toggleothers' ) {
122125 var changed = thisLabelIndex !== - 1 ;
123126 var unhideList = [ ] ;
124- for ( i = 0 ; i < gd . calcdata . length ; i ++ ) {
127+ for ( i = 0 ; i < gd . calcdata . length ; i ++ ) {
125128 var cdi = gd . calcdata [ i ] ;
126- for ( j = 0 ; j < cdi . length ; j ++ ) {
129+ for ( j = 0 ; j < cdi . length ; j ++ ) {
127130 var d = cdi [ j ] ;
128131 var dLabel = d . label ;
129132
130133 // ensure we toggle slices that are in this legend)
131- if ( thisLegend === cdi [ 0 ] . trace . legend ) {
132- if ( thisLabel !== dLabel ) {
133- if ( hiddenSlices . indexOf ( dLabel ) === - 1 ) changed = true ;
134+ if ( thisLegend === cdi [ 0 ] . trace . legend ) {
135+ if ( thisLabel !== dLabel ) {
136+ if ( hiddenSlices . indexOf ( dLabel ) === - 1 ) changed = true ;
134137 pushUnique ( hiddenSlices , dLabel ) ;
135138 unhideList . push ( dLabel ) ;
136139 }
137140 }
138141 }
139142 }
140143
141- if ( ! changed ) {
142- for ( var q = 0 ; q < unhideList . length ; q ++ ) {
144+ if ( ! changed ) {
145+ for ( var q = 0 ; q < unhideList . length ; q ++ ) {
143146 var pos = hiddenSlices . indexOf ( unhideList [ q ] ) ;
144- if ( pos !== - 1 ) {
147+ if ( pos !== - 1 ) {
145148 hiddenSlices . splice ( pos , 1 ) ;
146149 }
147150 }
@@ -153,20 +156,20 @@ exports.handleItemClick = function handleItemClick(g, gd, legendObj, mode) {
153156 var hasLegendgroup = legendgroup && legendgroup . length ;
154157 var traceIndicesInGroup = [ ] ;
155158 var tracei ;
156- if ( hasLegendgroup ) {
157- for ( i = 0 ; i < allLegendItems . length ; i ++ ) {
159+ if ( hasLegendgroup ) {
160+ for ( i = 0 ; i < allLegendItems . length ; i ++ ) {
158161 tracei = allLegendItems [ i ] ;
159- if ( ! tracei . visible ) continue ;
160- if ( tracei . legendgroup === legendgroup ) {
162+ if ( ! tracei . visible ) continue ;
163+ if ( tracei . legendgroup === legendgroup ) {
161164 traceIndicesInGroup . push ( i ) ;
162165 }
163166 }
164167 }
165168
166- if ( mode === 'toggle' ) {
169+ if ( mode === 'toggle' ) {
167170 var nextVisibility ;
168171
169- switch ( fullTrace . visible ) {
172+ switch ( fullTrace . visible ) {
170173 case true :
171174 nextVisibility = 'legendonly' ;
172175 break ;
@@ -178,11 +181,11 @@ exports.handleItemClick = function handleItemClick(g, gd, legendObj, mode) {
178181 break ;
179182 }
180183
181- if ( hasLegendgroup ) {
182- if ( toggleGroup ) {
183- for ( i = 0 ; i < allLegendItems . length ; i ++ ) {
184+ if ( hasLegendgroup ) {
185+ if ( toggleGroup ) {
186+ for ( i = 0 ; i < allLegendItems . length ; i ++ ) {
184187 var item = allLegendItems [ i ] ;
185- if ( item . visible !== false && item . legendgroup === legendgroup ) {
188+ if ( item . visible !== false && item . legendgroup === legendgroup ) {
186189 setVisibility ( item , nextVisibility ) ;
187190 }
188191 }
@@ -192,58 +195,63 @@ exports.handleItemClick = function handleItemClick(g, gd, legendObj, mode) {
192195 } else {
193196 setVisibility ( fullTrace , nextVisibility ) ;
194197 }
195- } else if ( mode === 'toggleothers' ) {
198+ } else if ( mode === 'toggleothers' ) {
196199 // Compute the clicked index. expandedIndex does what we want for expanded traces
197200 // but also culls hidden traces. That means we have some work to do.
198201 var isClicked , isInGroup , notInLegend , otherState , _item ;
199202 var isIsolated = true ;
200- for ( i = 0 ; i < allLegendItems . length ; i ++ ) {
203+ for ( i = 0 ; i < allLegendItems . length ; i ++ ) {
201204 _item = allLegendItems [ i ] ;
202205 isClicked = _item === fullTrace ;
203206 notInLegend = _item . showlegend !== true ;
204- if ( isClicked || notInLegend ) continue ;
207+ if ( isClicked || notInLegend ) continue ;
205208
206- isInGroup = ( hasLegendgroup && _item . legendgroup === legendgroup ) ;
209+ isInGroup = hasLegendgroup && _item . legendgroup === legendgroup ;
207210
208- if ( ! isInGroup && _item . legend === thisLegend && _item . visible === true && ! Registry . traceIs ( _item , 'notLegendIsolatable' ) ) {
211+ if (
212+ ! isInGroup &&
213+ _item . legend === thisLegend &&
214+ _item . visible === true &&
215+ ! Registry . traceIs ( _item , 'notLegendIsolatable' )
216+ ) {
209217 isIsolated = false ;
210218 break ;
211219 }
212220 }
213221
214- for ( i = 0 ; i < allLegendItems . length ; i ++ ) {
222+ for ( i = 0 ; i < allLegendItems . length ; i ++ ) {
215223 _item = allLegendItems [ i ] ;
216224
217225 // False is sticky; we don't change it. Also ensure we don't change states of itmes in other legend
218- if ( _item . visible === false || _item . legend !== thisLegend ) continue ;
226+ if ( _item . visible === false || _item . legend !== thisLegend ) continue ;
219227
220- if ( Registry . traceIs ( _item , 'notLegendIsolatable' ) ) {
228+ if ( Registry . traceIs ( _item , 'notLegendIsolatable' ) ) {
221229 continue ;
222230 }
223231
224- switch ( fullTrace . visible ) {
232+ switch ( fullTrace . visible ) {
225233 case 'legendonly' :
226234 setVisibility ( _item , true ) ;
227235 break ;
228236 case true :
229237 otherState = isIsolated ? true : 'legendonly' ;
230238 isClicked = _item === fullTrace ;
231239 // N.B. consider traces that have a set legendgroup as toggleable
232- notInLegend = ( _item . showlegend !== true && ! _item . legendgroup ) ;
240+ notInLegend = _item . showlegend !== true && ! _item . legendgroup ;
233241 isInGroup = isClicked || ( hasLegendgroup && _item . legendgroup === legendgroup ) ;
234- setVisibility ( _item , ( isInGroup || notInLegend ) ? true : otherState ) ;
242+ setVisibility ( _item , isInGroup || notInLegend ? true : otherState ) ;
235243 break ;
236244 }
237245 }
238246 }
239247
240- for ( i = 0 ; i < carrs . length ; i ++ ) {
248+ for ( i = 0 ; i < carrs . length ; i ++ ) {
241249 kcont = carrs [ i ] ;
242- if ( ! kcont ) continue ;
250+ if ( ! kcont ) continue ;
243251 var update = kcont . constructUpdate ( ) ;
244252
245253 var updateKeys = Object . keys ( update ) ;
246- for ( j = 0 ; j < updateKeys . length ; j ++ ) {
254+ for ( j = 0 ; j < updateKeys . length ; j ++ ) {
247255 key = updateKeys [ j ] ;
248256 val = dataUpdate [ key ] = dataUpdate [ key ] || [ ] ;
249257 val [ carrIdx [ i ] ] = update [ key ] ;
@@ -255,18 +263,18 @@ exports.handleItemClick = function handleItemClick(g, gd, legendObj, mode) {
255263 // as updates and not accidentally reset to the default value. This fills
256264 // out sparse arrays with the required number of undefined values:
257265 keys = Object . keys ( dataUpdate ) ;
258- for ( i = 0 ; i < keys . length ; i ++ ) {
266+ for ( i = 0 ; i < keys . length ; i ++ ) {
259267 key = keys [ i ] ;
260- for ( j = 0 ; j < dataIndices . length ; j ++ ) {
268+ for ( j = 0 ; j < dataIndices . length ; j ++ ) {
261269 // Use hasOwnProperty to protect against falsy values:
262- if ( ! dataUpdate [ key ] . hasOwnProperty ( j ) ) {
270+ if ( ! dataUpdate [ key ] . hasOwnProperty ( j ) ) {
263271 dataUpdate [ key ] [ j ] = undefined ;
264272 }
265273 }
266274 }
267275
268- if ( shapesUpdated ) {
269- Registry . call ( '_guiUpdate' , gd , dataUpdate , { shapes : updatedShapes } , dataIndices ) ;
276+ if ( shapesUpdated ) {
277+ Registry . call ( '_guiUpdate' , gd , dataUpdate , { shapes : updatedShapes } , dataIndices ) ;
270278 } else {
271279 Registry . call ( '_guiRestyle' , gd , dataUpdate , dataIndices ) ;
272280 }
@@ -286,8 +294,8 @@ exports.handleTitleClick = function handleTitleClick(gd, legendObj, mode) {
286294 const fullLayout = gd . _fullLayout ;
287295 const fullData = gd . _fullData ;
288296 const legendId = helpers . getId ( legendObj ) ;
289- const shapesWithLegend = ( fullLayout . shapes || [ ] ) . filter ( function ( d ) { return d . showlegend ; } ) ;
290- const allLegendItems = fullData . concat ( shapesWithLegend ) ;
297+ const shapesInLegend = ( fullLayout . shapes || [ ] ) . filter ( ( d ) => d . showlegend || d . legendgroup ) ;
298+ const allLegendItems = fullData . concat ( shapesInLegend ) ;
291299
292300 function isInLegend ( item ) {
293301 return ( item . legend || 'legend' ) === legendId ;
@@ -296,17 +304,17 @@ exports.handleTitleClick = function handleTitleClick(gd, legendObj, mode) {
296304 var toggleThisLegend ;
297305 var toggleOtherLegends ;
298306
299- if ( mode === 'toggle' ) {
307+ if ( mode === 'toggle' ) {
300308 // If any item is visible in this legend, hide all. If all are hidden, show all
301- const anyVisibleHere = allLegendItems . some ( function ( item ) {
309+ const anyVisibleHere = allLegendItems . some ( function ( item ) {
302310 return isInLegend ( item ) && item . visible === true ;
303311 } ) ;
304312
305313 toggleThisLegend = ! anyVisibleHere ;
306314 toggleOtherLegends = false ;
307315 } else {
308316 // isolate this legend or set all legends to visible
309- const anyVisibleElsewhere = allLegendItems . some ( function ( item ) {
317+ const anyVisibleElsewhere = allLegendItems . some ( function ( item ) {
310318 return ! isInLegend ( item ) && item . visible === true && item . showlegend !== false ;
311319 } ) ;
312320
@@ -316,26 +324,28 @@ exports.handleTitleClick = function handleTitleClick(gd, legendObj, mode) {
316324
317325 const dataUpdate = { visible : [ ] } ;
318326 const dataIndices = [ ] ;
319- const updatedShapes = ( fullLayout . shapes || [ ] ) . map ( function ( d ) { return d . _input ; } ) ;
327+ const updatedShapes = ( fullLayout . shapes || [ ] ) . map ( function ( d ) {
328+ return d . _input ;
329+ } ) ;
320330 var shapesUpdated = false ;
321331
322- for ( var i = 0 ; i < allLegendItems . length ; i ++ ) {
332+ for ( var i = 0 ; i < allLegendItems . length ; i ++ ) {
323333 const item = allLegendItems [ i ] ;
324334 const inThisLegend = isInLegend ( item ) ;
325335
326336 // If item is not in this legend, skip if in toggle mode
327337 // or if item is not displayed in the legend
328- if ( ! inThisLegend ) {
329- const notDisplayed = ( item . showlegend !== true && ! item . legendgroup ) ;
330- if ( mode === 'toggle' || notDisplayed ) continue ;
338+ if ( ! inThisLegend ) {
339+ const notDisplayed = item . showlegend !== true && ! item . legendgroup ;
340+ if ( mode === 'toggle' || notDisplayed ) continue ;
331341 }
332342
333343 const shouldShow = inThisLegend ? toggleThisLegend : toggleOtherLegends ;
334344 const newVis = shouldShow ? true : 'legendonly' ;
335345
336346 // Only update if visibility would actually change
337- if ( ( item . visible !== false ) && ( item . visible !== newVis ) ) {
338- if ( item . _isShape ) {
347+ if ( item . visible !== false && item . visible !== newVis ) {
348+ if ( item . _isShape ) {
339349 updatedShapes [ item . _index ] . visible = newVis ;
340350 shapesUpdated = true ;
341351 } else {
@@ -345,9 +355,9 @@ exports.handleTitleClick = function handleTitleClick(gd, legendObj, mode) {
345355 }
346356 }
347357
348- if ( shapesUpdated ) {
349- Registry . call ( '_guiUpdate' , gd , dataUpdate , { shapes : updatedShapes } , dataIndices ) ;
350- } else if ( dataIndices . length ) {
358+ if ( shapesUpdated ) {
359+ Registry . call ( '_guiUpdate' , gd , dataUpdate , { shapes : updatedShapes } , dataIndices ) ;
360+ } else if ( dataIndices . length ) {
351361 Registry . call ( '_guiRestyle' , gd , dataUpdate , dataIndices ) ;
352362 }
353363} ;
0 commit comments