@@ -24,32 +24,61 @@ var helpers = require('./helpers');
2424
2525var MAIN_TITLE = 1 ;
2626
27+ var LEGEND_PATTERN = / ^ l e g e n d [ 0 - 9 ] * $ / ;
28+
2729module . exports = function draw ( gd , opts ) {
28- if ( ! opts ) opts = gd . _fullLayout . legend || { } ;
29- return _draw ( gd , opts ) ;
30+ if ( opts ) {
31+ drawOne ( gd , opts ) ;
32+ } else {
33+ var fullLayout = gd . _fullLayout ;
34+ var newLegends = fullLayout . _legends ;
35+
36+ // remove old legends that won't stay on the graph
37+ var oldLegends = fullLayout . _infolayer . selectAll ( '[class^="legend"]' ) ;
38+
39+ oldLegends . each ( function ( ) {
40+ var el = d3 . select ( this ) ;
41+ var classes = el . attr ( 'class' ) ;
42+ var cls = classes . split ( ' ' ) [ 0 ] ;
43+ if ( cls . match ( LEGEND_PATTERN ) && newLegends . indexOf ( cls ) === - 1 ) {
44+ el . remove ( ) ;
45+ }
46+ } ) ;
47+
48+ // draw/update new legends
49+ for ( var i = 0 ; i < newLegends . length ; i ++ ) {
50+ var legendId = newLegends [ i ] ;
51+ var legendObj = gd . _fullLayout [ legendId ] ;
52+ drawOne ( gd , legendObj ) ;
53+ }
54+ }
3055} ;
3156
32- function _draw ( gd , legendObj ) {
57+ function drawOne ( gd , opts ) {
58+ var legendObj = opts || { } ;
59+
3360 var fullLayout = gd . _fullLayout ;
34- var clipId = 'legend' + fullLayout . _uid ;
35- var layer ;
61+ var legendId = getId ( legendObj ) ;
62+
63+ var clipId , layer ;
3664
3765 var inHover = legendObj . _inHover ;
3866 if ( inHover ) {
3967 layer = legendObj . layer ;
40- clipId + = '- hover' ;
68+ clipId = 'hover' ;
4169 } else {
4270 layer = fullLayout . _infolayer ;
71+ clipId = legendId ;
4372 }
44-
4573 if ( ! layer ) return ;
74+ clipId += fullLayout . _uid ;
4675
4776 if ( ! gd . _legendMouseDownTime ) gd . _legendMouseDownTime = 0 ;
4877
4978 var legendData ;
5079 if ( ! inHover ) {
5180 if ( ! gd . calcdata ) return ;
52- legendData = fullLayout . showlegend && getLegendData ( gd . calcdata , legendObj ) ;
81+ legendData = fullLayout . showlegend && getLegendData ( gd . calcdata , legendObj , fullLayout . _legends . length > 1 ) ;
5382 } else {
5483 if ( ! legendObj . entries ) return ;
5584 legendData = getLegendData ( legendObj . entries , legendObj ) ;
@@ -58,12 +87,12 @@ function _draw(gd, legendObj) {
5887 var hiddenSlices = fullLayout . hiddenlabels || [ ] ;
5988
6089 if ( ! inHover && ( ! fullLayout . showlegend || ! legendData . length ) ) {
61- layer . selectAll ( '.legend' ) . remove ( ) ;
90+ layer . selectAll ( '.' + legendId ) . remove ( ) ;
6291 fullLayout . _topdefs . select ( '#' + clipId ) . remove ( ) ;
63- return Plots . autoMargin ( gd , 'legend' ) ;
92+ return Plots . autoMargin ( gd , legendId ) ;
6493 }
6594
66- var legend = Lib . ensureSingle ( layer , 'g' , 'legend' , function ( s ) {
95+ var legend = Lib . ensureSingle ( layer , 'g' , legendId , function ( s ) {
6796 if ( ! inHover ) s . attr ( 'pointer-events' , 'all' ) ;
6897 } ) ;
6998
@@ -84,14 +113,14 @@ function _draw(gd, legendObj) {
84113 legendObj . _titleWidth = 0 ;
85114 legendObj . _titleHeight = 0 ;
86115 if ( title . text ) {
87- var titleEl = Lib . ensureSingle ( scrollBox , 'text' , 'legendtitletext ') ;
116+ var titleEl = Lib . ensureSingle ( scrollBox , 'text' , legendId + 'titletext ') ;
88117 titleEl . attr ( 'text-anchor' , 'start' )
89118 . call ( Drawing . font , title . font )
90119 . text ( title . text ) ;
91120
92121 textLayout ( titleEl , scrollBox , gd , legendObj , MAIN_TITLE ) ; // handle mathjax or multi-line text and compute title height
93122 } else {
94- scrollBox . selectAll ( '.legendtitletext ' ) . remove ( ) ;
123+ scrollBox . selectAll ( '.' + legendId + 'titletext ') . remove ( ) ;
95124 }
96125
97126 var scrollBar = Lib . ensureSingle ( legend , 'rect' , 'scrollbar' , function ( s ) {
@@ -117,7 +146,7 @@ function _draw(gd, legendObj) {
117146 } )
118147 . each ( function ( ) { d3 . select ( this ) . call ( drawTexts , gd , legendObj ) ; } )
119148 . call ( style , gd , legendObj )
120- . each ( function ( ) { if ( ! inHover ) d3 . select ( this ) . call ( setupTraceToggle , gd ) ; } ) ;
149+ . each ( function ( ) { if ( ! inHover ) d3 . select ( this ) . call ( setupTraceToggle , gd , legendId ) ; } ) ;
121150
122151 Lib . syncOrAsync ( [
123152 Plots . previousPromises ,
@@ -127,7 +156,7 @@ function _draw(gd, legendObj) {
127156 var bw = legendObj . borderwidth ;
128157
129158 if ( ! inHover ) {
130- var expMargin = expandMargin ( gd ) ;
159+ var expMargin = expandMargin ( gd , legendId ) ;
131160
132161 // IF expandMargin return a Promise (which is truthy),
133162 // we're under a doAutoMargin redraw, so we don't have to
@@ -145,10 +174,10 @@ function _draw(gd, legendObj) {
145174 ly = Lib . constrain ( ly , 0 , fullLayout . height - legendObj . _effHeight ) ;
146175
147176 if ( lx !== lx0 ) {
148- Lib . log ( 'Constrain legend .x to make legend fit inside graph' ) ;
177+ Lib . log ( 'Constrain ' + legendId + ' .x to make legend fit inside graph') ;
149178 }
150179 if ( ly !== ly0 ) {
151- Lib . log ( 'Constrain legend .y to make legend fit inside graph' ) ;
180+ Lib . log ( 'Constrain ' + legendId + ' .y to make legend fit inside graph') ;
152181 }
153182 }
154183
@@ -294,7 +323,7 @@ function _draw(gd, legendObj) {
294323 }
295324
296325 function scrollHandler ( scrollBoxY , scrollBarHeight , scrollRatio ) {
297- legendObj . _scrollY = gd . _fullLayout . legend . _scrollY = scrollBoxY ;
326+ legendObj . _scrollY = gd . _fullLayout [ legendId ] . _scrollY = scrollBoxY ;
298327 Drawing . setTranslate ( scrollBox , 0 , - scrollBoxY ) ;
299328
300329 Drawing . setRect (
@@ -330,11 +359,14 @@ function _draw(gd, legendObj) {
330359 } ,
331360 doneFn : function ( ) {
332361 if ( xf !== undefined && yf !== undefined ) {
333- Registry . call ( '_guiRelayout' , gd , { 'legend.x' : xf , 'legend.y' : yf } ) ;
362+ var obj = { } ;
363+ obj [ legendId + '.x' ] = xf ;
364+ obj [ legendId + '.y' ] = yf ;
365+ Registry . call ( '_guiRelayout' , gd , obj ) ;
334366 }
335367 } ,
336368 clickFn : function ( numClicks , e ) {
337- var clickedTrace = layer . selectAll ( 'g.traces' ) . filter ( function ( ) {
369+ var clickedTrace = groups . selectAll ( 'g.traces' ) . filter ( function ( ) {
338370 var bbox = this . getBoundingClientRect ( ) ;
339371 return (
340372 e . clientX >= bbox . left && e . clientX <= bbox . right &&
@@ -402,6 +434,7 @@ function clickOrDoubleClick(gd, legend, legendItem, numClicks, evt) {
402434}
403435
404436function drawTexts ( g , gd , legendObj ) {
437+ var legendId = getId ( legendObj ) ;
405438 var legendItem = g . data ( ) [ 0 ] [ 0 ] ;
406439 var trace = legendItem . trace ;
407440 var isPieLike = Registry . traceIs ( trace , 'pie-like' ) ;
@@ -424,7 +457,7 @@ function drawTexts(g, gd, legendObj) {
424457 }
425458 }
426459
427- var textEl = Lib . ensureSingle ( g , 'text' , 'legendtext ') ;
460+ var textEl = Lib . ensureSingle ( g , 'text' , legendId + 'text ') ;
428461
429462 textEl . attr ( 'text-anchor' , 'start' )
430463 . call ( Drawing . font , font )
@@ -478,12 +511,12 @@ function ensureLength(str, maxLength) {
478511 return str ;
479512}
480513
481- function setupTraceToggle ( g , gd ) {
514+ function setupTraceToggle ( g , gd , legendId ) {
482515 var doubleClickDelay = gd . _context . doubleClickDelay ;
483516 var newMouseDownTime ;
484517 var numClicks = 1 ;
485518
486- var traceToggle = Lib . ensureSingle ( g , 'rect' , 'legendtoggle ', function ( s ) {
519+ var traceToggle = Lib . ensureSingle ( g , 'rect' , legendId + 'toggle ', function ( s ) {
487520 if ( ! gd . _context . staticPlot ) {
488521 s . style ( 'cursor' , 'pointer' ) . attr ( 'pointer-events' , 'all' ) ;
489522 }
@@ -505,7 +538,7 @@ function setupTraceToggle(g, gd) {
505538 } ) ;
506539 traceToggle . on ( 'mouseup' , function ( ) {
507540 if ( gd . _dragged || gd . _editing ) return ;
508- var legend = gd . _fullLayout . legend ;
541+ var legend = gd . _fullLayout [ legendId ] ;
509542
510543 if ( ( new Date ( ) ) . getTime ( ) - gd . _legendMouseDownTime > doubleClickDelay ) {
511544 numClicks = Math . max ( numClicks - 1 , 1 ) ;
@@ -531,7 +564,11 @@ function computeTextDimensions(g, gd, legendObj, aTitle) {
531564
532565 var mathjaxGroup = g . select ( 'g[class*=math-group]' ) ;
533566 var mathjaxNode = mathjaxGroup . node ( ) ;
534- if ( ! legendObj ) legendObj = gd . _fullLayout . legend ;
567+
568+ var legendId = getId ( legendObj ) ;
569+ if ( ! legendObj ) {
570+ legendObj = gd . _fullLayout [ legendId ] ;
571+ }
535572 var bw = legendObj . borderwidth ;
536573 var font ;
537574 if ( aTitle === MAIN_TITLE ) {
@@ -556,9 +593,12 @@ function computeTextDimensions(g, gd, legendObj, aTitle) {
556593 Drawing . setTranslate ( mathjaxGroup , 0 , height * 0.25 ) ;
557594 }
558595 } else {
559- var textEl = g . select ( aTitle === MAIN_TITLE ?
560- '.legendtitletext' : '.legendtext'
561- ) ;
596+ var cls = '.' + legendId + (
597+ aTitle === MAIN_TITLE ? 'title' : ''
598+ ) + 'text' ;
599+
600+ var textEl = g . select ( cls ) ;
601+
562602 var textLines = svgTextUtils . lineCount ( textEl ) ;
563603 var textNode = textEl . node ( ) ;
564604
@@ -619,7 +659,7 @@ function getTitleSize(legendObj) {
619659}
620660
621661/*
622- * Computes in fullLayout.legend :
662+ * Computes in fullLayout[legendId] :
623663 *
624664 * - _height: legend height including items past scrollbox height
625665 * - _maxHeight: maximum legend height before scrollbox is required
@@ -630,7 +670,10 @@ function getTitleSize(legendObj) {
630670 */
631671function computeLegendDimensions ( gd , groups , traces , legendObj ) {
632672 var fullLayout = gd . _fullLayout ;
633- if ( ! legendObj ) legendObj = fullLayout . legend ;
673+ var legendId = getId ( legendObj ) ;
674+ if ( ! legendObj ) {
675+ legendObj = fullLayout [ legendId ] ;
676+ }
634677 var gs = fullLayout . _size ;
635678
636679 var isVertical = helpers . isVertical ( legendObj ) ;
@@ -818,7 +861,7 @@ function computeLegendDimensions(gd, groups, traces, legendObj) {
818861 var edits = gd . _context . edits ;
819862 var isEditable = edits . legendText || edits . legendPosition ;
820863 traces . each ( function ( d ) {
821- var traceToggle = d3 . select ( this ) . select ( '.legendtoggle ' ) ;
864+ var traceToggle = d3 . select ( this ) . select ( '.' + legendId + 'toggle ') ;
822865 var h = d [ 0 ] . height ;
823866 var legendgroup = d [ 0 ] . trace . legendgroup ;
824867 var traceWidth = getTraceWidth ( d , legendObj , textGap ) ;
@@ -833,13 +876,13 @@ function computeLegendDimensions(gd, groups, traces, legendObj) {
833876 } ) ;
834877}
835878
836- function expandMargin ( gd ) {
879+ function expandMargin ( gd , legendId ) {
837880 var fullLayout = gd . _fullLayout ;
838- var legendObj = fullLayout . legend ;
881+ var legendObj = fullLayout [ legendId ] ;
839882 var xanchor = getXanchor ( legendObj ) ;
840883 var yanchor = getYanchor ( legendObj ) ;
841884
842- return Plots . autoMargin ( gd , 'legend' , {
885+ return Plots . autoMargin ( gd , legendId , {
843886 x : legendObj . x ,
844887 y : legendObj . y ,
845888 l : legendObj . _width * ( FROM_TL [ xanchor ] ) ,
@@ -860,3 +903,7 @@ function getYanchor(legendObj) {
860903 Lib . isMiddleAnchor ( legendObj ) ? 'middle' :
861904 'top' ;
862905}
906+
907+ function getId ( legendObj ) {
908+ return legendObj . _id || 'legend' ;
909+ }
0 commit comments