@@ -98,12 +98,8 @@ module.exports = function draw(gd) {
98
98
var gs = fullLayout . _size ;
99
99
var bw = opts . borderwidth ;
100
100
101
- var lx = gs . l + gs . w * opts . x ;
102
- if ( Lib . isRightAnchor ( opts ) ) {
103
- lx -= opts . _width ;
104
- } else if ( Lib . isCenterAnchor ( opts ) ) {
105
- lx -= opts . _width / 2 ;
106
- }
101
+ var lx = gs . l + gs . w * opts . x - FROM_TL [ getXanchor ( opts ) ] * opts . _width ;
102
+ var ly = gs . t + gs . h * ( 1 - opts . y ) - FROM_TL [ getYanchor ( opts ) ] * opts . _effHeight ;
107
103
108
104
109
105
// Make sure the legend left and right sides are visible
@@ -119,12 +115,6 @@ module.exports = function draw(gd) {
119
115
legendWidth = Math . min ( fullLayout . width - lx , opts . _width ) ;
120
116
}
121
117
122
- var ly = gs . t + gs . h * ( 1 - opts . y ) ;
123
- if ( Lib . isBottomAnchor ( opts ) ) {
124
- ly -= opts . _height ;
125
- } else if ( Lib . isMiddleAnchor ( opts ) ) {
126
- ly -= opts . _height / 2 ;
127
- }
128
118
129
119
// Make sure the legend top and bottom are visible
130
120
// (legends with a scroll bar are not allowed to stretch beyond the extended
@@ -487,6 +477,7 @@ function computeTextDimensions(g, gd) {
487
477
function computeLegendDimensions ( gd , groups , traces ) {
488
478
var fullLayout = gd . _fullLayout ;
489
479
var opts = fullLayout . legend ;
480
+ var isVertical = helpers . isVertical ( opts ) ;
490
481
var isGrouped = helpers . isGrouped ( opts ) ;
491
482
492
483
var bw = opts . borderwidth ;
@@ -495,172 +486,141 @@ function computeLegendDimensions(gd, groups, traces) {
495
486
var itemGap = constants . itemGap ;
496
487
var endPad = 2 * ( bw + itemGap ) ;
497
488
498
- var extraWidth = 0 ;
489
+ opts . _maxWidth = fullLayout . _size . w ;
490
+
491
+ var toggleRectWidth = 0 ;
499
492
opts . _width = 0 ;
500
493
opts . _height = 0 ;
501
494
502
- if ( helpers . isVertical ( opts ) ) {
503
- if ( isGrouped ) {
504
- groups . each ( function ( d , i ) {
505
- Drawing . setTranslate ( this , 0 , i * opts . tracegroupgap ) ;
506
- } ) ;
507
- }
508
-
495
+ if ( isVertical ) {
509
496
traces . each ( function ( d ) {
510
497
var h = d [ 0 ] . height ;
511
498
Drawing . setTranslate ( this , bw , itemGap + bw + opts . _height + h / 2 ) ;
512
499
opts . _height += h ;
513
500
opts . _width = Math . max ( opts . _width , d [ 0 ] . width ) ;
514
501
} ) ;
515
502
503
+ toggleRectWidth = textGap + opts . _width ;
516
504
opts . _width += itemGap + textGap + bw2 ;
517
505
opts . _height += endPad ;
518
506
519
507
if ( isGrouped ) {
508
+ groups . each ( function ( d , i ) {
509
+ Drawing . setTranslate ( this , 0 , i * opts . tracegroupgap ) ;
510
+ } ) ;
520
511
opts . _height += ( opts . _lgroupsLength - 1 ) * opts . tracegroupgap ;
521
512
}
513
+ } else {
514
+ var maxItemWidth = 0 ;
515
+ var combinedItemWidth = 0 ;
516
+ traces . each ( function ( d ) {
517
+ var w = d [ 0 ] . width + textGap ;
518
+ maxItemWidth = Math . max ( maxItemWidth , w ) ;
519
+ combinedItemWidth += w ;
520
+ } ) ;
522
521
523
- extraWidth = textGap ;
524
- } else if ( isGrouped ) {
525
- var maxHeight = 0 ;
526
- var maxWidth = 0 ;
527
- var maxItems = 0 ;
528
- var groupData = groups . data ( ) ;
529
- var i ;
530
-
531
- for ( i = 0 ; i < groupData . length ; i ++ ) {
532
- var group = groupData [ i ] ;
533
- var groupWidths = group . map ( function ( d ) { return d [ 0 ] . width ; } ) ;
534
- var groupHeight = group . reduce ( function ( a , b ) { return a + b [ 0 ] . height ; } , 0 ) ;
535
- maxWidth = Math . max ( maxWidth , Lib . aggNums ( Math . max , null , groupWidths ) ) ;
536
- maxHeight = Math . max ( maxHeight , groupHeight ) ;
537
- maxItems = Math . max ( maxItems , group . length ) ;
538
- }
539
-
540
- maxWidth += itemGap + textGap ;
522
+ if ( isGrouped ) {
523
+ var groupData = groups . data ( ) ;
524
+ var i ;
541
525
542
- var groupXOffsets = [ opts . _width ] ;
543
- var groupYOffsets = [ ] ;
544
- var rowNum = 0 ;
545
- for ( i = 0 ; i < groupData . length ; i ++ ) {
546
- if ( fullLayout . _size . w < ( bw + opts . _width + itemGap + maxWidth ) ) {
547
- groupXOffsets [ groupXOffsets . length - 1 ] = groupXOffsets [ 0 ] ;
548
- opts . _width = maxWidth ;
549
- rowNum ++ ;
550
- } else {
551
- opts . _width += maxWidth + bw ;
526
+ var maxGroupHeight = 0 ;
527
+ for ( i = 0 ; i < groupData . length ; i ++ ) {
528
+ var groupHeight = groupData [ i ] . reduce ( function ( a , b ) { return a + b [ 0 ] . height ; } , 0 ) ;
529
+ maxGroupHeight = Math . max ( maxGroupHeight , groupHeight ) ;
552
530
}
553
531
554
- var rowYOffset = ( rowNum * maxHeight ) ;
555
- rowYOffset += rowNum > 0 ? opts . tracegroupgap : 0 ;
532
+ var groupXOffsets = [ opts . _width ] ;
533
+ var groupYOffsets = [ ] ;
534
+ var rowNum = 0 ;
535
+ for ( i = 0 ; i < groupData . length ; i ++ ) {
536
+ if ( ( opts . _width + itemGap + maxItemWidth + bw ) > opts . _maxWidth ) {
537
+ groupXOffsets [ groupXOffsets . length - 1 ] = groupXOffsets [ 0 ] ;
538
+ opts . _width = maxItemWidth + itemGap ;
539
+ rowNum ++ ;
540
+ } else {
541
+ opts . _width += maxItemWidth + itemGap ;
542
+ }
556
543
557
- groupYOffsets . push ( rowYOffset ) ;
558
- groupXOffsets . push ( opts . _width ) ;
559
- }
544
+ groupXOffsets . push ( opts . _width ) ;
545
+ groupYOffsets . push ( rowNum * maxGroupHeight + ( rowNum > 0 ? opts . tracegroupgap : 0 ) ) ;
546
+ }
560
547
561
- groups . each ( function ( d , i ) {
562
- Drawing . setTranslate ( this , groupXOffsets [ i ] , groupYOffsets [ i ] ) ;
563
- } ) ;
548
+ groups . each ( function ( d , i ) {
549
+ Drawing . setTranslate ( this , groupXOffsets [ i ] , groupYOffsets [ i ] ) ;
550
+ } ) ;
564
551
565
- groups . each ( function ( ) {
566
- var group = d3 . select ( this ) ;
567
- var groupTraces = group . selectAll ( 'g.traces' ) ;
568
- var groupHeight = 0 ;
552
+ groups . each ( function ( ) {
553
+ var group = d3 . select ( this ) ;
554
+ var groupTraces = group . selectAll ( 'g.traces' ) ;
555
+ var groupHeight = 0 ;
569
556
570
- groupTraces . each ( function ( d ) {
571
- var h = d [ 0 ] . height ;
572
- Drawing . setTranslate ( this , 0 , itemGap + bw + groupHeight + h / 2 ) ;
573
- groupHeight += h ;
557
+ groupTraces . each ( function ( d ) {
558
+ var h = d [ 0 ] . height ;
559
+ Drawing . setTranslate ( this , 0 , itemGap + bw + groupHeight + h / 2 ) ;
560
+ groupHeight += h ;
561
+ } ) ;
574
562
} ) ;
575
- } ) ;
576
563
577
- var maxYLegend = groupYOffsets [ groupYOffsets . length - 1 ] + maxHeight ;
578
- opts . _height = maxYLegend + endPad ;
564
+ opts . _height = groupYOffsets [ groupYOffsets . length - 1 ] + maxGroupHeight + endPad ;
565
+ opts . _width = Math . max . apply ( null , groupXOffsets ) + maxItemWidth + textGap + bw2 ;
566
+ toggleRectWidth = maxItemWidth ;
567
+ } else {
568
+ var oneRowLegend = ( combinedItemWidth + bw2 + ( traces . size ( ) - 1 ) * itemGap ) < opts . _maxWidth ;
579
569
580
- var maxOffset = Math . max . apply ( null , groupXOffsets ) ;
581
- opts . _width = maxOffset + maxWidth + textGap + bw2 ;
582
- } else {
583
- var rowHeight = 0 ;
584
- var maxTraceHeight = 0 ;
585
- var maxTraceWidth = 0 ;
586
- var offsetX = 0 ;
587
- var fullTracesWidth = 0 ;
570
+ var maxRowWidth = 0 ;
571
+ var maxItemHeightInRow = 0 ;
572
+ var offsetX = 0 ;
573
+ var offsetY = 0 ;
574
+ traces . each ( function ( d ) {
575
+ var h = d [ 0 ] . height ;
576
+ var next = ( oneRowLegend ? textGap + d [ 0 ] . width : maxItemWidth ) + itemGap ;
577
+
578
+ if ( ( next + bw + offsetX ) > opts . _maxWidth ) {
579
+ maxRowWidth = Math . max ( maxRowWidth , offsetX ) ;
580
+ offsetX = 0 ;
581
+ offsetY += maxItemHeightInRow ;
582
+ opts . _height += maxItemHeightInRow ;
583
+ maxItemHeightInRow = 0 ;
584
+ }
588
585
589
- // calculate largest width for traces and use for width of all legend items
590
- traces . each ( function ( d ) {
591
- maxTraceWidth = Math . max ( maxTraceWidth , textGap + d [ 0 ] . width ) ;
592
- fullTracesWidth += textGap + d [ 0 ] . width + itemGap ;
593
- } ) ;
586
+ Drawing . setTranslate ( this , bw + offsetX , itemGap + bw + h / 2 + offsetY ) ;
594
587
595
- // check if legend fits in one row
596
- var oneRowLegend = fullLayout . _size . w > bw + fullTracesWidth - itemGap ;
588
+ offsetX += next ;
589
+ maxItemHeightInRow = Math . max ( maxItemHeightInRow , h ) ;
590
+ } ) ;
597
591
598
- traces . each ( function ( d ) {
599
- var h = d [ 0 ] . height ;
600
- var traceWidth = oneRowLegend ? textGap + d [ 0 ] . width : maxTraceWidth ;
601
-
602
- if ( ( bw + offsetX + itemGap + traceWidth ) > fullLayout . _size . w ) {
603
- offsetX = 0 ;
604
- rowHeight += maxTraceHeight ;
605
- opts . _height += maxTraceHeight ;
606
- // reset for next row
607
- maxTraceHeight = 0 ;
592
+ if ( oneRowLegend ) {
593
+ opts . _width = offsetX + bw2 ;
594
+ opts . _height = maxItemHeightInRow + endPad ;
595
+ toggleRectWidth = null ;
596
+ } else {
597
+ opts . _width = Math . max ( maxRowWidth , offsetX ) + bw ;
598
+ opts . _height += maxItemHeightInRow + endPad ;
599
+ toggleRectWidth = maxItemWidth ;
608
600
}
609
-
610
- Drawing . setTranslate ( this , bw + offsetX , itemGap + bw + h / 2 + rowHeight ) ;
611
- opts . _width += itemGap + traceWidth ;
612
-
613
- // keep track of tallest trace in group
614
- offsetX += itemGap + traceWidth ;
615
- maxTraceHeight = Math . max ( maxTraceHeight , h ) ;
616
- } ) ;
617
-
618
- if ( oneRowLegend ) {
619
- opts . _height = maxTraceHeight ;
620
- } else {
621
- opts . _height += maxTraceHeight ;
622
601
}
623
-
624
- opts . _width += bw2 ;
625
- opts . _height += endPad ;
626
602
}
627
603
628
604
opts . _width = Math . ceil ( opts . _width ) ;
629
605
opts . _height = Math . ceil ( opts . _height ) ;
630
606
631
- var isEditable = (
632
- gd . _context . edits . legendText ||
633
- gd . _context . edits . legendPosition
634
- ) ;
635
-
607
+ var edits = gd . _context . edits ;
608
+ var isEditable = edits . legendText || edits . legendPosition ;
636
609
traces . each ( function ( d ) {
610
+ var traceToggle = d3 . select ( this ) . select ( '.legendtoggle' ) ;
637
611
var h = d [ 0 ] . height ;
638
- Drawing . setRect ( d3 . select ( this ) . select ( '.legendtoggle' ) ,
639
- 0 ,
640
- - h / 2 ,
641
- ( isEditable ? 0 : opts . _width ) + extraWidth ,
642
- h
643
- ) ;
612
+ var w = isEditable ? textGap : ( toggleRectWidth || ( textGap + d [ 0 ] . width ) ) ;
613
+ if ( ! isVertical ) w += itemGap / 2 ;
614
+ Drawing . setRect ( traceToggle , 0 , - h / 2 , w , h ) ;
644
615
} ) ;
645
616
}
646
617
647
618
function expandMargin ( gd ) {
648
619
var fullLayout = gd . _fullLayout ;
649
620
var opts = fullLayout . legend ;
621
+ var xanchor = getXanchor ( opts ) ;
622
+ var yanchor = getYanchor ( opts ) ;
650
623
651
- var xanchor = 'left' ;
652
- if ( Lib . isRightAnchor ( opts ) ) {
653
- xanchor = 'right' ;
654
- } else if ( Lib . isCenterAnchor ( opts ) ) {
655
- xanchor = 'center' ;
656
- }
657
-
658
- var yanchor = 'top' ;
659
- if ( Lib . isBottomAnchor ( opts ) ) {
660
- yanchor = 'bottom' ;
661
- } else if ( Lib . isMiddleAnchor ( opts ) ) {
662
- yanchor = 'middle' ;
663
- }
664
624
665
625
Plots . autoMargin ( gd , 'legend' , {
666
626
x : opts . x ,
@@ -671,3 +631,15 @@ function expandMargin(gd) {
671
631
t : opts . _height * ( FROM_TL [ yanchor ] )
672
632
} ) ;
673
633
}
634
+
635
+ function getXanchor ( opts ) {
636
+ return Lib . isRightAnchor ( opts ) ? 'right' :
637
+ Lib . isCenterAnchor ( opts ) ? 'center' :
638
+ 'left' ;
639
+ }
640
+
641
+ function getYanchor ( opts ) {
642
+ return Lib . isBottomAnchor ( opts ) ? 'bottom' :
643
+ Lib . isMiddleAnchor ( opts ) ? 'middle' :
644
+ 'top' ;
645
+ }
0 commit comments