@@ -96,13 +96,17 @@ module.exports = function draw(gd) {
9696
9797 // remove exiting header, remove dropped buttons and reset margins
9898 if ( headerGroups . enter ( ) . size ( ) ) {
99- foldDropdownMenu ( gButton , scrollBox ) ;
99+ gButton
100+ . call ( removeAllButtons )
101+ . attr ( constants . menuIndexAttrName , '-1' ) ;
100102 }
101103
102104 headerGroups . exit ( ) . each ( function ( menuOpts ) {
103105 d3 . select ( this ) . remove ( ) ;
104106
105- foldDropdownMenu ( gButton , scrollBox ) ;
107+ gButton
108+ . call ( removeAllButtons )
109+ . attr ( constants . menuIndexAttrName , '-1' ) ;
106110
107111 Plots . autoMargin ( gd , constants . autoMarginIdRoot + menuOpts . _index ) ;
108112 } ) ;
@@ -119,12 +123,12 @@ module.exports = function draw(gd) {
119123 if ( menuOpts . type === 'dropdown' ) {
120124 drawHeader ( gd , gHeader , gButton , scrollBox , menuOpts ) ;
121125
122- // update dropdown buttons if this menu is active
126+ // if this menu is active, update the dropdown container
123127 if ( isActive ( gButton , menuOpts ) ) {
124- unfoldDropdownMenu ( gd , gHeader , gButton , scrollBox , menuOpts ) ;
128+ drawButtons ( gd , gHeader , gButton , scrollBox , menuOpts ) ;
125129 }
126130 } else {
127- drawButtons ( gd , gHeader , null , scrollBox , menuOpts ) ;
131+ drawButtons ( gd , gHeader , null , null , menuOpts ) ;
128132 }
129133
130134 } ) ;
@@ -163,86 +167,22 @@ function isActive(gButton, menuOpts) {
163167 return + gButton . attr ( constants . menuIndexAttrName ) === menuOpts . _index ;
164168}
165169
166- function unfoldDropdownMenu ( gd , gHeader , gButton , scrollBox , menuOpts ) {
167- // enable the scrollbox
168- var direction = menuOpts . direction ,
169- isUp = ( direction === 'up' ) ,
170- isDown = ( direction === 'down' ) ,
171- isLeft = ( direction === 'left' ) ,
172- isRight = ( direction === 'right' ) ,
173- isVertical = ( isUp || isDown ) ;
174-
175- var x0 , y0 ;
176- if ( isDown ) {
177- x0 = 0 ;
178- y0 = menuOpts . headerHeight + constants . gapButtonHeader ;
179- }
180- else if ( isUp ) {
181- x0 = 0 ;
182- y0 = menuOpts . headerHeight + constants . gapButton - menuOpts . openHeight ;
183- }
184- else if ( isRight ) {
185- x0 = menuOpts . headerWidth + constants . gapButtonHeader ;
186- y0 = 0 ;
187- }
188- else if ( isLeft ) {
189- x0 = menuOpts . headerWidth + constants . gapButton - menuOpts . openWidth ;
190- y0 = 0 ;
191- }
192-
193- var position = {
194- l : menuOpts . lx + menuOpts . borderwidth + x0 + menuOpts . pad . l ,
195- t : menuOpts . ly + menuOpts . borderwidth + y0 + menuOpts . pad . t ,
196- w : Math . max ( menuOpts . openWidth , menuOpts . headerWidth ) ,
197- h : menuOpts . openHeight
198- } ;
199-
200- var active = menuOpts . active ,
201- translateX , translateY ,
202- i ;
203- if ( isVertical ) {
204- translateY = 0 ;
205- for ( i = 0 ; i < active ; i ++ ) {
206- translateY += menuOpts . heights [ i ] + constants . gapButton ;
207- }
208- }
209- else {
210- translateX = 0 ;
211- for ( i = 0 ; i < active ; i ++ ) {
212- translateX += menuOpts . widths [ i ] + constants . gapButton ;
213- }
214- }
215-
216- scrollBox . enable ( position , translateX , translateY ) ;
217-
218- // store index of active menu (-1 means dropdown menu is folded)
219- gButton . attr ( constants . menuIndexAttrName , menuOpts . _index ) ;
220-
221- drawButtons ( gd , gHeader , gButton , scrollBox , menuOpts ) ;
222- }
223-
224- function foldDropdownMenu ( gButton , scrollBox ) {
225- scrollBox . disable ( ) ;
226-
227- // -1 means dropdown menu is folded
228- gButton
229- . attr ( constants . menuIndexAttrName , '-1' )
230- . call ( removeAllButtons ) ;
231- }
232-
233170function setActive ( gd , menuOpts , buttonOpts , gHeader , gButton , scrollBox , buttonIndex , isSilentUpdate ) {
234171 // update 'active' attribute in menuOpts
235172 menuOpts . _input . active = menuOpts . active = buttonIndex ;
236173
237- if ( menuOpts . type === 'dropdown' ) {
174+ if ( menuOpts . type === 'buttons' ) {
175+ drawButtons ( gd , gHeader , null , null , menuOpts ) ;
176+ }
177+ else if ( menuOpts . type === 'dropdown' ) {
238178 // fold up buttons and redraw header
239179 gButton . attr ( constants . menuIndexAttrName , '-1' ) ;
240180
241181 drawHeader ( gd , gHeader , gButton , scrollBox , menuOpts ) ;
242- }
243182
244- if ( ! isSilentUpdate || menuOpts . type === 'buttons' ) {
245- drawButtons ( gd , gHeader , gButton , scrollBox , menuOpts ) ;
183+ if ( ! isSilentUpdate ) {
184+ drawButtons ( gd , gHeader , gButton , scrollBox , menuOpts ) ;
185+ }
246186 }
247187}
248188
@@ -283,18 +223,19 @@ function drawHeader(gd, gHeader, gButton, scrollBox, menuOpts) {
283223 } ) ;
284224
285225 header . on ( 'click' , function ( ) {
286- if ( isFolded ( gButton ) ) {
287- unfoldDropdownMenu ( gd , gHeader , gButton , scrollBox , menuOpts ) ;
288- }
289- else if ( isActive ( gButton , menuOpts ) ) {
290- foldDropdownMenu ( gButton , scrollBox ) ;
291- }
292- else {
293- // the dropdown menu is unfolded,
294- // but the clicked header is not the active header
295- foldDropdownMenu ( gButton , scrollBox ) ;
296- unfoldDropdownMenu ( gd , gHeader , gButton , scrollBox , menuOpts ) ;
297- }
226+ gButton . call ( removeAllButtons ) ;
227+
228+
229+ // if this menu is active, fold the dropdown container
230+ // otherwise, make this menu active
231+ gButton . attr (
232+ constants . menuIndexAttrName ,
233+ isActive ( gButton , menuOpts ) ?
234+ - 1 :
235+ String ( menuOpts . _index )
236+ ) ;
237+
238+ drawButtons ( gd , gHeader , gButton , scrollBox , menuOpts ) ;
298239 } ) ;
299240
300241 header . on ( 'mouseover' , function ( ) {
@@ -339,20 +280,11 @@ function drawButtons(gd, gHeader, gButton, scrollBox, menuOpts) {
339280
340281 exit . transition ( )
341282 . attr ( 'opacity' , '0' )
342- . remove ( )
343- . each ( 'end' , function ( ) {
344- // remove the scrollbox, if all the buttons have been removed
345- if ( gButton . selectAll ( 'g.' + klass ) . size ( ) === 0 ) {
346- foldDropdownMenu ( gButton , scrollBox ) ;
347- }
348- } ) ;
283+ . remove ( ) ;
349284 } else {
350285 exit . remove ( ) ;
351286 }
352287
353- // if folding a dropdown menu, don't draw the buttons
354- if ( ! buttons . size ( ) ) return ;
355-
356288 var x0 = 0 ;
357289 var y0 = 0 ;
358290
@@ -411,6 +343,107 @@ function drawButtons(gd, gHeader, gButton, scrollBox, menuOpts) {
411343 } ) ;
412344
413345 buttons . call ( styleButtons , menuOpts ) ;
346+
347+ if ( scrollBox ) {
348+ if ( buttons . size ( ) ) {
349+ drawScrollBox ( gd , gHeader , gButton , scrollBox , menuOpts ) ;
350+ }
351+ else {
352+ hideScrollBox ( scrollBox ) ;
353+ }
354+ }
355+ }
356+
357+ function drawScrollBox ( gd , gHeader , gButton , scrollBox , menuOpts ) {
358+ // enable the scrollbox
359+ var direction = menuOpts . direction ,
360+ isUp = ( direction === 'up' ) ,
361+ isDown = ( direction === 'down' ) ,
362+ isLeft = ( direction === 'left' ) ,
363+ isRight = ( direction === 'right' ) ,
364+ isVertical = ( isUp || isDown ) ;
365+
366+ var x0 , y0 ;
367+ if ( isDown ) {
368+ x0 = 0 ;
369+ y0 = menuOpts . headerHeight + constants . gapButtonHeader ;
370+ }
371+ else if ( isUp ) {
372+ x0 = 0 ;
373+ y0 = menuOpts . headerHeight + constants . gapButton - menuOpts . openHeight ;
374+ }
375+ else if ( isRight ) {
376+ x0 = menuOpts . headerWidth + constants . gapButtonHeader ;
377+ y0 = 0 ;
378+ }
379+ else if ( isLeft ) {
380+ x0 = menuOpts . headerWidth + constants . gapButton - menuOpts . openWidth ;
381+ y0 = 0 ;
382+ }
383+
384+ var position = {
385+ l : menuOpts . lx + menuOpts . borderwidth + x0 + menuOpts . pad . l ,
386+ t : menuOpts . ly + menuOpts . borderwidth + y0 + menuOpts . pad . t ,
387+ w : Math . max ( menuOpts . openWidth , menuOpts . headerWidth ) ,
388+ h : menuOpts . openHeight
389+ } ;
390+
391+ var active = menuOpts . active ,
392+ translateX , translateY ,
393+ i ;
394+ if ( isVertical ) {
395+ translateY = 0 ;
396+ for ( i = 0 ; i < active ; i ++ ) {
397+ translateY += menuOpts . heights [ i ] + constants . gapButton ;
398+ }
399+ }
400+ else {
401+ translateX = 0 ;
402+ for ( i = 0 ; i < active ; i ++ ) {
403+ translateX += menuOpts . widths [ i ] + constants . gapButton ;
404+ }
405+ }
406+
407+ scrollBox . enable ( position , translateX , translateY ) ;
408+
409+ if ( scrollBox . hbar ) {
410+ scrollBox . hbar
411+ . attr ( 'opacity' , '0' )
412+ . transition ( )
413+ . attr ( 'opacity' , '1' ) ;
414+ }
415+
416+ if ( scrollBox . vbar ) {
417+ scrollBox . vbar
418+ . attr ( 'opacity' , '0' )
419+ . transition ( )
420+ . attr ( 'opacity' , '1' ) ;
421+ }
422+ }
423+
424+ function hideScrollBox ( scrollBox ) {
425+ var hasHBar = ! ! scrollBox . hbar ,
426+ hasVBar = ! ! scrollBox . vbar ;
427+
428+ if ( hasHBar ) {
429+ scrollBox . hbar
430+ . transition ( )
431+ . attr ( 'opacity' , '0' )
432+ . each ( 'end' , function ( ) {
433+ hasHBar = false ;
434+ if ( ! hasVBar ) scrollBox . disable ( ) ;
435+ } ) ;
436+ }
437+
438+ if ( hasVBar ) {
439+ scrollBox . vbar
440+ . transition ( )
441+ . attr ( 'opacity' , '0' )
442+ . each ( 'end' , function ( ) {
443+ hasVBar = false ;
444+ if ( ! hasHBar ) scrollBox . disable ( ) ;
445+ } ) ;
446+ }
414447}
415448
416449function drawItem ( item , menuOpts , itemOpts ) {
0 commit comments