@@ -101,35 +101,8 @@ module.exports = function draw(gd) {
101
101
var lx = gs . l + gs . w * opts . x - FROM_TL [ getXanchor ( opts ) ] * opts . _width ;
102
102
var ly = gs . t + gs . h * ( 1 - opts . y ) - FROM_TL [ getYanchor ( opts ) ] * opts . _effHeight ;
103
103
104
-
105
- // Make sure the legend left and right sides are visible
106
- var legendWidth = opts . _width ;
107
- var legendWidthMax = gs . w ;
108
-
109
- if ( legendWidth > legendWidthMax ) {
110
- lx = gs . l ;
111
- legendWidth = legendWidthMax ;
112
- } else {
113
- if ( lx + legendWidth > fullLayout . width ) lx = fullLayout . width - legendWidth ;
114
- if ( lx < 0 ) lx = 0 ;
115
- legendWidth = Math . min ( fullLayout . width - lx , opts . _width ) ;
116
- }
117
-
118
-
119
- // Make sure the legend top and bottom are visible
120
- // (legends with a scroll bar are not allowed to stretch beyond the extended
121
- // margins)
122
- var legendHeight = opts . _height ;
123
- var legendHeightMax = gs . h ;
124
-
125
- if ( legendHeight > legendHeightMax ) {
126
- ly = gs . t ;
127
- legendHeight = legendHeightMax ;
128
- } else {
129
- if ( ly + legendHeight > fullLayout . height ) ly = fullLayout . height - legendHeight ;
130
- if ( ly < 0 ) ly = 0 ;
131
- legendHeight = Math . min ( fullLayout . height - ly , opts . _height ) ;
132
- }
104
+ lx = Lib . constrain ( lx , 0 , fullLayout . width - opts . _width ) ;
105
+ ly = Lib . constrain ( ly , 0 , fullLayout . height - opts . _effHeight ) ;
133
106
134
107
// Set size and position of all the elements that make up a legend:
135
108
// legend, background and border, scroll box and scroll bar
@@ -139,20 +112,20 @@ module.exports = function draw(gd) {
139
112
scrollBar . on ( '.drag' , null ) ;
140
113
legend . on ( 'wheel' , null ) ;
141
114
142
- if ( opts . _height <= legendHeight || gd . _context . staticPlot ) {
115
+ if ( opts . _height <= opts . _maxHeight || gd . _context . staticPlot ) {
143
116
// if scrollbar should not be shown.
144
117
bg . attr ( {
145
- width : legendWidth - bw ,
146
- height : legendHeight - bw ,
118
+ width : opts . _width - bw ,
119
+ height : opts . _effHeight - bw ,
147
120
x : bw / 2 ,
148
121
y : bw / 2
149
122
} ) ;
150
123
151
124
Drawing . setTranslate ( scrollBox , 0 , 0 ) ;
152
125
153
126
clipPath . select ( 'rect' ) . attr ( {
154
- width : legendWidth - 2 * bw ,
155
- height : legendHeight - 2 * bw ,
127
+ width : opts . _width - 2 * bw ,
128
+ height : opts . _effHeight - 2 * bw ,
156
129
x : bw ,
157
130
y : bw
158
131
} ) ;
@@ -163,33 +136,33 @@ module.exports = function draw(gd) {
163
136
delete opts . _scrollY ;
164
137
} else {
165
138
var scrollBarHeight = Math . max ( constants . scrollBarMinHeight ,
166
- legendHeight * legendHeight / opts . _height ) ;
167
- var scrollBarYMax = legendHeight -
139
+ opts . _effHeight * opts . _effHeight / opts . _height ) ;
140
+ var scrollBarYMax = opts . _effHeight -
168
141
scrollBarHeight -
169
142
2 * constants . scrollBarMargin ;
170
- var scrollBoxYMax = opts . _height - legendHeight ;
143
+ var scrollBoxYMax = opts . _height - opts . _effHeight ;
171
144
var scrollRatio = scrollBarYMax / scrollBoxYMax ;
172
145
173
146
var scrollBoxY = Math . min ( opts . _scrollY || 0 , scrollBoxYMax ) ;
174
147
175
148
// increase the background and clip-path width
176
149
// by the scrollbar width and margin
177
150
bg . attr ( {
178
- width : legendWidth -
151
+ width : opts . _width -
179
152
2 * bw +
180
153
constants . scrollBarWidth +
181
154
constants . scrollBarMargin ,
182
- height : legendHeight - bw ,
155
+ height : opts . _effHeight - bw ,
183
156
x : bw / 2 ,
184
157
y : bw / 2
185
158
} ) ;
186
159
187
160
clipPath . select ( 'rect' ) . attr ( {
188
- width : legendWidth -
161
+ width : opts . _width -
189
162
2 * bw +
190
163
constants . scrollBarWidth +
191
164
constants . scrollBarMargin ,
192
- height : legendHeight - 2 * bw ,
165
+ height : opts . _effHeight - 2 * bw ,
193
166
x : bw ,
194
167
y : bw + scrollBoxY
195
168
} ) ;
@@ -235,7 +208,7 @@ module.exports = function draw(gd) {
235
208
236
209
Drawing . setRect (
237
210
scrollBar ,
238
- legendWidth ,
211
+ opts . _width ,
239
212
constants . scrollBarMargin + scrollBoxY * scrollRatio ,
240
213
constants . scrollBarWidth ,
241
214
scrollBarHeight
@@ -474,9 +447,20 @@ function computeTextDimensions(g, gd) {
474
447
legendItem . width = width ;
475
448
}
476
449
450
+ /*
451
+ * Computes in fullLayout.legend:
452
+ *
453
+ * - _height: legend height including items past scrollbox height
454
+ * - _maxHeight: maximum legend height before scrollbox is required
455
+ * - _effHeight: legend height w/ or w/o scrollbox
456
+ *
457
+ * - _width: legend width
458
+ * - _maxWidth (for orientation:h only): maximum width before starting new row
459
+ */
477
460
function computeLegendDimensions ( gd , groups , traces ) {
478
461
var fullLayout = gd . _fullLayout ;
479
462
var opts = fullLayout . legend ;
463
+ var gs = fullLayout . _size ;
480
464
var isVertical = helpers . isVertical ( opts ) ;
481
465
var isGrouped = helpers . isGrouped ( opts ) ;
482
466
@@ -486,7 +470,16 @@ function computeLegendDimensions(gd, groups, traces) {
486
470
var itemGap = constants . itemGap ;
487
471
var endPad = 2 * ( bw + itemGap ) ;
488
472
489
- opts . _maxWidth = fullLayout . _size . w ;
473
+ var yanchor = getYanchor ( opts ) ;
474
+ var isBelowPlotArea = opts . y < 0 || ( opts . y === 0 && yanchor === 'top' ) ;
475
+ var isAbovePlotArea = opts . y > 1 || ( opts . y === 1 && yanchor === 'bottom' ) ;
476
+
477
+ // - if below/above plot area, give it the maximum potential margin-push value
478
+ // - otherwise, extend the height of the plot area
479
+ opts . _maxHeight = Math . max (
480
+ ( isBelowPlotArea || isAbovePlotArea ) ? fullLayout . height / 2 : gs . h ,
481
+ 30
482
+ ) ;
490
483
491
484
var toggleRectWidth = 0 ;
492
485
opts . _width = 0 ;
@@ -511,6 +504,20 @@ function computeLegendDimensions(gd, groups, traces) {
511
504
opts . _height += ( opts . _lgroupsLength - 1 ) * opts . tracegroupgap ;
512
505
}
513
506
} else {
507
+ var xanchor = getXanchor ( opts ) ;
508
+ var isLeftOfPlotArea = opts . x < 0 || ( opts . x === 0 && xanchor === 'right' ) ;
509
+ var isRightOfPlotArea = opts . x > 1 || ( opts . x === 1 && xanchor === 'left' ) ;
510
+ var isBeyondPlotAreaX = isAbovePlotArea || isBelowPlotArea ;
511
+ var hw = fullLayout . width / 2 ;
512
+
513
+ // - if placed within x-margins, extend the width of the plot area
514
+ // - else if below/above plot area and anchored in the margin, extend to opposite margin,
515
+ // - otherwise give it the maximum potential margin-push value
516
+ opts . _maxWidth = Math . max (
517
+ isLeftOfPlotArea ? ( ( isBeyondPlotAreaX && xanchor === 'left' ) ? gs . l + gs . w : hw ) :
518
+ isRightOfPlotArea ? ( ( isBeyondPlotAreaX && yanchor === 'right' ) ? gs . r + gs . w : hw ) :
519
+ gs . w ,
520
+ 2 * textGap ) ;
514
521
var maxItemWidth = 0 ;
515
522
var combinedItemWidth = 0 ;
516
523
traces . each ( function ( d ) {
@@ -604,6 +611,8 @@ function computeLegendDimensions(gd, groups, traces) {
604
611
opts . _width = Math . ceil ( opts . _width ) ;
605
612
opts . _height = Math . ceil ( opts . _height ) ;
606
613
614
+ opts . _effHeight = Math . min ( opts . _height , opts . _maxHeight ) ;
615
+
607
616
var edits = gd . _context . edits ;
608
617
var isEditable = edits . legendText || edits . legendPosition ;
609
618
traces . each ( function ( d ) {
@@ -627,8 +636,8 @@ function expandMargin(gd) {
627
636
y : opts . y ,
628
637
l : opts . _width * ( FROM_TL [ xanchor ] ) ,
629
638
r : opts . _width * ( FROM_BR [ xanchor ] ) ,
630
- b : opts . _height * ( FROM_BR [ yanchor ] ) ,
631
- t : opts . _height * ( FROM_TL [ yanchor ] )
639
+ b : opts . _effHeight * ( FROM_BR [ yanchor ] ) ,
640
+ t : opts . _effHeight * ( FROM_TL [ yanchor ] )
632
641
} ) ;
633
642
}
634
643
0 commit comments