@@ -25,6 +25,7 @@ var styleOne = require('../../traces/pie/style_one');
25
25
26
26
var legend = module . exports = { } ;
27
27
28
+ var constants = require ( './constants' ) ;
28
29
legend . layoutAttributes = require ( './attributes' ) ;
29
30
30
31
legend . supplyLayoutDefaults = function ( layoutIn , layoutOut , fullData ) {
@@ -294,12 +295,18 @@ legend.texts = function(context, td, d, i, traces){
294
295
text . enter ( ) . append ( 'text' ) . classed ( 'legendtext' , true ) ;
295
296
text . attr ( {
296
297
x : 40 ,
297
- y : 0
298
+ y : 0 ,
299
+ 'data-unformatted' : name
300
+ } )
301
+ . style ( {
302
+ 'text-anchor' : 'start' ,
303
+ '-webkit-user-select' : 'none' ,
304
+ '-moz-user-select' : 'none' ,
305
+ '-ms-user-select' : 'none' ,
306
+ 'user-select' : 'none'
298
307
} )
299
- . style ( 'text-anchor' , 'start' )
300
308
. call ( Drawing . font , fullLayout . legend . font )
301
- . text ( name )
302
- . attr ( { 'data-unformatted' : name } ) ;
309
+ . text ( name ) ;
303
310
304
311
function textLayout ( s ) {
305
312
Plotly . util . convertToTspans ( s , function ( ) {
@@ -464,9 +471,11 @@ legend.draw = function(td) {
464
471
var scrollBar = legendsvg . selectAll ( 'rect.scrollbar' )
465
472
. data ( [ 0 ] ) ;
466
473
scrollBar . enter ( ) . append ( 'rect' )
467
- . attr ( 'class' , 'scrollbar' )
468
- . attr ( 'rx' , 20 )
469
- . attr ( 'ry' , 2 )
474
+ . attr ( {
475
+ 'class' : 'scrollbar' ,
476
+ 'rx' : 20 ,
477
+ 'ry' : 2
478
+ } )
470
479
. call ( Color . fill , '#808BA4' ) ;
471
480
472
481
var groups = scrollBox . selectAll ( 'g.groups' )
@@ -546,6 +555,78 @@ legend.draw = function(td) {
546
555
// Position and size the legend
547
556
legend . repositionLegend ( td , traces ) ;
548
557
558
+ // Scroll section must be executed after repositionLegend.
559
+ // It requires the legend width, height, x and y to position the scrollbox
560
+ // and these values are mutated in repositionLegend.
561
+ var gs = fullLayout . _size ,
562
+ lx = gs . l + gs . w * opts . x ,
563
+ ly = gs . t + gs . h * ( 1 - opts . y ) ;
564
+
565
+ // Deal with scrolling
566
+ var plotHeight = fullLayout . height - fullLayout . margin . b ,
567
+ scrollPosition = scrollBox . attr ( 'viewBox' ) ? scrollBox . attr ( 'viewBox' ) . split ( ' ' ) [ 1 ] : 0 ,
568
+ scrollheight = Math . min ( plotHeight - ly , opts . height ) ;
569
+
570
+ bg . style ( { width : opts . width , height : scrollheight } ) ;
571
+ scrollBox . attr ( 'viewBox' , '0 ' + scrollPosition + ' ' + opts . width + ' ' + scrollheight ) ;
572
+
573
+ legendsvg . call ( Drawing . setRect , lx , ly , opts . width , scrollheight ) ;
574
+
575
+ if ( td . firstRender && opts . height - scrollheight > 0 && ! td . _context . staticPlot ) {
576
+
577
+ legendsvg . node ( ) . addEventListener ( 'wheel' , function ( e ) {
578
+ e . preventDefault ( ) ;
579
+ scrollHandler ( Math . round ( e . deltaY / 15 ) ) ;
580
+ } ) ;
581
+
582
+ scrollBar . node ( ) . addEventListener ( 'mousedown' , function ( e ) {
583
+ e . preventDefault ( ) ;
584
+
585
+ function mMove ( e ) {
586
+ if ( e . buttons === 1 ) {
587
+ scrollHandler ( e . movementY ) ;
588
+ }
589
+ }
590
+
591
+ function mUp ( ) {
592
+ scrollBar . node ( ) . removeEventListener ( 'mousemove' , mMove ) ;
593
+ window . removeEventListener ( 'mouseup' , mUp ) ;
594
+ }
595
+
596
+ window . addEventListener ( 'mousemove' , mMove ) ;
597
+ window . addEventListener ( 'mouseup' , mUp ) ;
598
+ } ) ;
599
+
600
+ // Move scrollbar to starting position on the first render
601
+ scrollBar . call (
602
+ Drawing . setRect ,
603
+ opts . width - ( constants . scrollBarWidth + constants . scrollBarMargin ) ,
604
+ constants . scrollBarMargin ,
605
+ constants . scrollBarWidth ,
606
+ constants . scrollBarHeight
607
+ ) ;
608
+ }
609
+
610
+ function scrollHandler ( delta ) {
611
+
612
+ // Scale movement to simulate native scroll performance
613
+ var viewBox = scrollBox . attr ( 'viewBox' ) . split ( ' ' ) ,
614
+ scrollBarTrack = scrollheight - constants . scrollBarHeight - 2 * constants . scrollBarMargin ,
615
+ scrollBoxY = Lib . constrain ( + viewBox [ 1 ] + delta , 0 , Math . max ( opts . height - scrollheight , 0 ) ) ,
616
+ scrollBarY = scrollBoxY / ( opts . height - scrollheight ) * scrollBarTrack + constants . scrollBarMargin ;
617
+
618
+ viewBox [ 1 ] = scrollBoxY ;
619
+
620
+ scrollBox . attr ( 'viewBox' , viewBox . join ( ' ' ) ) ;
621
+ scrollBar . call (
622
+ Drawing . setRect ,
623
+ opts . width - ( constants . scrollBarWidth + constants . scrollBarMargin ) ,
624
+ scrollBarY ,
625
+ constants . scrollBarWidth ,
626
+ constants . scrollBarHeight
627
+ ) ;
628
+ }
629
+
549
630
if ( td . _context . editable ) {
550
631
var xf ,
551
632
yf ,
@@ -579,7 +660,7 @@ legend.draw = function(td) {
579
660
} ,
580
661
doneFn : function ( dragged ) {
581
662
Fx . setCursor ( legendsvg ) ;
582
- if ( dragged && xf !== undefined && yf !== undefined ) {
663
+ if ( dragged && xf !== undefined && yf !== undefined ) {
583
664
Plotly . relayout ( td , { 'legend.x' : xf , 'legend.y' : yf } ) ;
584
665
}
585
666
}
@@ -591,12 +672,10 @@ legend.repositionLegend = function(td, traces){
591
672
var fullLayout = td . _fullLayout ,
592
673
gs = fullLayout . _size ,
593
674
opts = fullLayout . legend ,
594
- borderwidth = opts . borderwidth ,
675
+ borderwidth = opts . borderwidth ;
595
676
596
- // add the legend elements, keeping track of the
597
- // legend size (in px) as we go
598
- legendwidth = 0 ,
599
- legendheight = 0 ;
677
+ opts . width = 0 ,
678
+ opts . height = 0 ,
600
679
601
680
traces . each ( function ( d ) {
602
681
var trace = d [ 0 ] . trace ,
@@ -605,7 +684,7 @@ legend.repositionLegend = function(td, traces){
605
684
text = g . selectAll ( '.legendtext' ) ,
606
685
tspans = g . selectAll ( '.legendtext>tspan' ) ,
607
686
tHeight = opts . font . size * 1.3 ,
608
- tLines = tspans [ 0 ] . length || 1 ,
687
+ tLines = tspans [ 0 ] . length || 1 ,
609
688
tWidth = text . node ( ) && Drawing . bBox ( text . node ( ) ) . width ,
610
689
mathjaxGroup = g . select ( 'g[class*=math-group]' ) ,
611
690
textY ,
@@ -620,12 +699,12 @@ legend.repositionLegend = function(td, traces){
620
699
var mathjaxBB = Drawing . bBox ( mathjaxGroup . node ( ) ) ;
621
700
tHeight = mathjaxBB . height ;
622
701
tWidth = mathjaxBB . width ;
623
- mathjaxGroup . attr ( 'transform' , 'translate(0,' + ( tHeight / 4 ) + ')' ) ;
702
+ mathjaxGroup . attr ( 'transform' , 'translate(0,' + ( tHeight / 4 ) + ')' ) ;
624
703
}
625
704
else {
626
705
// approximation to height offset to center the font
627
706
// to avoid getBoundingClientRect
628
- textY = tHeight * ( 0.3 + ( 1 - tLines ) / 2 ) ;
707
+ textY = tHeight * ( 0.3 + ( 1 - tLines ) / 2 ) ;
629
708
text . attr ( 'y' , textY ) ;
630
709
tspans . attr ( 'y' , textY ) ;
631
710
}
@@ -634,22 +713,23 @@ legend.repositionLegend = function(td, traces){
634
713
635
714
g . attr ( 'transform' ,
636
715
'translate(' + borderwidth + ',' +
637
- ( 5 + borderwidth + legendheight + tHeightFull / 2 ) +
716
+ ( 5 + borderwidth + opts . height + tHeightFull / 2 ) +
638
717
')'
639
718
) ;
640
719
bg . attr ( { x : 0 , y : - tHeightFull / 2 , height : tHeightFull } ) ;
641
720
642
- legendheight += tHeightFull ;
643
- legendwidth = Math . max ( legendwidth , tWidth || 0 ) ;
721
+ opts . height += tHeightFull ;
722
+ opts . width = Math . max ( opts . width , tWidth || 0 ) ;
644
723
} ) ;
645
724
646
- if ( isGrouped ( opts ) ) legendheight += ( opts . _lgroupsLength - 1 ) * opts . tracegroupgap ;
647
725
648
- traces . selectAll ( '.legendtoggle' )
649
- . attr ( 'width' , ( td . _context . editable ? 0 : legendwidth ) + 40 ) ;
726
+ opts . width += 45 + borderwidth * 2 ;
727
+ opts . height += 10 + borderwidth * 2 ;
728
+
729
+ if ( isGrouped ( opts ) ) opts . height += ( opts . _lgroupsLength - 1 ) * opts . tracegroupgap ;
650
730
651
- legendwidth += 45 + borderwidth * 2 ;
652
- legendheight += 10 + borderwidth * 2 ;
731
+ traces . selectAll ( '.legendtoggle' )
732
+ . attr ( 'width' , ( td . _context . editable ? 0 : opts . width ) + 40 ) ;
653
733
654
734
// now position the legend. for both x,y the positions are recorded as
655
735
// fractions of the plot area (left, bottom = 0,0). Outside the plot
@@ -661,83 +741,38 @@ legend.repositionLegend = function(td, traces){
661
741
ly = gs . t + gs . h * ( 1 - opts . y ) ;
662
742
663
743
var xanchor = 'left' ;
664
- if ( opts . xanchor === 'right' || ( opts . xanchor === 'auto' && opts . x >= 2 / 3 ) ) {
665
- lx -= legendwidth ;
744
+ if ( opts . xanchor === 'right' || ( opts . xanchor === 'auto' && opts . x >= 2 / 3 ) ) {
745
+ lx -= opts . width ;
666
746
xanchor = 'right' ;
667
747
}
668
- else if ( opts . xanchor === 'center' || ( opts . xanchor === 'auto' && opts . x > 1 / 3 ) ) {
669
- lx -= legendwidth / 2 ;
748
+ else if ( opts . xanchor === 'center' || ( opts . xanchor === 'auto' && opts . x > 1 / 3 ) ) {
749
+ lx -= opts . width / 2 ;
670
750
xanchor = 'center' ;
671
751
}
672
752
673
753
var yanchor = 'top' ;
674
- if ( opts . yanchor === 'bottom' || ( opts . yanchor === 'auto' && opts . y <= 1 / 3 ) ) {
675
- ly -= legendheight ;
754
+ if ( opts . yanchor === 'bottom' || ( opts . yanchor === 'auto' && opts . y <= 1 / 3 ) ) {
755
+ ly -= opts . width ;
676
756
yanchor = 'bottom' ;
677
757
}
678
- else if ( opts . yanchor === 'middle' || ( opts . yanchor === 'auto' && opts . y < 2 / 3 ) ) {
679
- ly -= legendheight / 2 ;
758
+ else if ( opts . yanchor === 'middle' || ( opts . yanchor === 'auto' && opts . y < 2 / 3 ) ) {
759
+ ly -= opts . height / 2 ;
680
760
yanchor = 'middle' ;
681
761
}
682
762
683
763
// make sure we're only getting full pixels
684
- legendwidth = Math . ceil ( legendwidth ) ;
685
- legendheight = Math . ceil ( legendheight ) ;
764
+ opts . width = Math . ceil ( opts . width ) ;
765
+ opts . height = Math . ceil ( opts . height ) ;
686
766
lx = Math . round ( lx ) ;
687
767
ly = Math . round ( ly ) ;
688
768
689
-
690
- var legendsvg = fullLayout . _infolayer . selectAll ( 'svg.legend' ) ,
691
- scrollBox = fullLayout . _infolayer . selectAll ( 'svg.legend .scrollbox' ) ,
692
- scrollBar = fullLayout . _infolayer . selectAll ( 'svg.legend .scrollbar' ) ,
693
- bg = fullLayout . _infolayer . selectAll ( 'svg.legend .bg' ) ;
694
-
695
- var plotHeight = fullLayout . height - fullLayout . margin . t - fullLayout . margin . b ,
696
- scrollheight = Math . min ( plotHeight - ly , legendheight ) ,
697
- scrollPosition = scrollBox . attr ( 'viewBox' ) ? scrollBox . attr ( 'viewBox' ) . split ( ' ' ) [ 1 ] : 0 ;
698
-
699
- legendsvg . node ( ) . addEventListener ( 'wheel' , scrollHandler ) ;
700
- legendsvg . call ( Drawing . setRect , lx , ly , legendwidth , scrollheight ) ;
701
-
702
- bg . style ( { width : legendwidth , height : scrollheight } ) ;
703
-
704
- scrollBox . attr ( 'viewBox' , '0 ' + scrollPosition + ' ' + legendwidth + ' ' + scrollheight ) ;
705
-
706
- if ( td . firstRender ) scrollBar . call ( Drawing . setRect , legendwidth - 6 , 10 , 4 , 20 ) ;
707
-
708
- function scrollHandler ( e ) {
709
- e . preventDefault ( ) ;
710
-
711
- // Scale movement to simulate native scroll performance
712
- var scrollDiff = e . deltaY / 25 ,
713
- viewBox = scrollBox . attr ( 'viewBox' ) . split ( ' ' ) ;
714
-
715
- var scrollBoxY = constrain ( 0 , Math . max ( legendheight - scrollheight , 0 ) , + viewBox [ 1 ] + scrollDiff ) ,
716
- scrollBarY = scrollBoxY / legendheight * ( scrollheight ) + 10 ;
717
-
718
- viewBox [ 1 ] = scrollBoxY ;
719
-
720
- scrollBox . attr ( 'viewBox' , viewBox . join ( ' ' ) ) ;
721
- scrollBar . call ( Drawing . setRect , legendwidth - 6 , scrollBarY , 4 , 20 ) ;
722
- }
723
-
724
- function constrain ( min , max , c ) {
725
- if ( c <= max && c >= min ) {
726
- return c ;
727
- } else if ( c > max ) {
728
- return max ;
729
- } else {
730
- return min ;
731
- }
732
- }
733
-
734
769
// lastly check if the margin auto-expand has changed
735
770
Plots . autoMargin ( td , 'legend' , {
736
771
x : opts . x ,
737
772
y : opts . y ,
738
- l : legendwidth * ( { right :1 , center :0.5 } [ xanchor ] || 0 ) ,
739
- r : legendwidth * ( { left :1 , center :0.5 } [ xanchor ] || 0 ) ,
740
- b : legendheight * ( { top :1 , middle :0.5 } [ yanchor ] || 0 ) ,
741
- t : legendheight * ( { bottom :1 , middle :0.5 } [ yanchor ] || 0 )
773
+ l : opts . width * ( { right :1 , center :0.5 } [ xanchor ] || 0 ) ,
774
+ r : opts . width * ( { left :1 , center :0.5 } [ xanchor ] || 0 ) ,
775
+ b : opts . height * ( { top :1 , middle :0.5 } [ yanchor ] || 0 ) ,
776
+ t : opts . height * ( { bottom :1 , middle :0.5 } [ yanchor ] || 0 )
742
777
} ) ;
743
778
} ;
0 commit comments