@@ -41,9 +41,9 @@ module.exports = function draw(gd) {
4141
4242 if ( ! gd . _legendMouseDownTime ) gd . _legendMouseDownTime = 0 ;
4343
44- var opts = fullLayout . legend ,
45- legendData = fullLayout . showlegend && getLegendData ( gd . calcdata , opts ) ,
46- hiddenSlices = fullLayout . hiddenlabels || [ ] ;
44+ var opts = fullLayout . legend ;
45+ var legendData = fullLayout . showlegend && getLegendData ( gd . calcdata , opts ) ;
46+ var hiddenSlices = fullLayout . hiddenlabels || [ ] ;
4747
4848 if ( ! fullLayout . showlegend || ! legendData . length ) {
4949 fullLayout . _infolayer . selectAll ( '.legend' ) . remove ( ) ;
@@ -53,6 +53,17 @@ module.exports = function draw(gd) {
5353 return ;
5454 }
5555
56+ var maxLength = 0 ;
57+ for ( var i = 0 ; i < legendData . length ; i ++ ) {
58+ for ( var j = 0 ; j < legendData [ i ] . length ; j ++ ) {
59+ var item = legendData [ i ] [ j ] [ 0 ] ;
60+ var trace = item . trace ;
61+ var isPie = Registry . traceIs ( trace , 'pie' ) ;
62+ var name = isPie ? item . label : trace . name ;
63+ maxLength = Math . max ( maxLength , name && name . length || 0 ) ;
64+ }
65+ }
66+
5667 var firstRender = false ;
5768 var legend = Lib . ensureSingle ( fullLayout . _infolayer , 'g' , 'legend' , function ( s ) {
5869 s . attr ( 'pointer-events' , 'all' ) ;
@@ -108,7 +119,7 @@ module.exports = function draw(gd) {
108119 } )
109120 . each ( function ( ) {
110121 d3 . select ( this )
111- . call ( drawTexts , gd )
122+ . call ( drawTexts , gd , maxLength )
112123 . call ( setupTraceToggle , gd ) ;
113124 } ) ;
114125
@@ -352,38 +363,35 @@ module.exports = function draw(gd) {
352363 }
353364} ;
354365
355- function drawTexts ( g , gd ) {
356- var legendItem = g . data ( ) [ 0 ] [ 0 ] ,
357- fullLayout = gd . _fullLayout ,
358- trace = legendItem . trace ,
359- isPie = Registry . traceIs ( trace , 'pie' ) ,
360- traceIndex = trace . index ,
361- name = isPie ? legendItem . label : trace . name ;
366+ function drawTexts ( g , gd , maxLength ) {
367+ var legendItem = g . data ( ) [ 0 ] [ 0 ] ;
368+ var fullLayout = gd . _fullLayout ;
369+ var trace = legendItem . trace ;
370+ var isPie = Registry . traceIs ( trace , 'pie' ) ;
371+ var traceIndex = trace . index ;
372+ var name = isPie ? legendItem . label : trace . name ;
373+ var isEditable = gd . _context . edits . legendText && ! isPie ;
362374
363- var text = Lib . ensureSingle ( g , 'text' , 'legendtext' ) ;
375+ var textEl = Lib . ensureSingle ( g , 'text' , 'legendtext' ) ;
364376
365- text . attr ( 'text-anchor' , 'start' )
377+ textEl . attr ( 'text-anchor' , 'start' )
366378 . classed ( 'user-select-none' , true )
367379 . call ( Drawing . font , fullLayout . legend . font )
368- . text ( name ) ;
380+ . text ( isEditable ? ensureLength ( name , maxLength ) : name ) ;
369381
370382 function textLayout ( s ) {
371383 svgTextUtils . convertToTspans ( s , gd , function ( ) {
372384 computeTextDimensions ( g , gd ) ;
373385 } ) ;
374386 }
375387
376- if ( gd . _context . edits . legendText && ! isPie ) {
377- text . call ( svgTextUtils . makeEditable , { gd : gd } )
388+ if ( isEditable ) {
389+ textEl . call ( svgTextUtils . makeEditable , { gd : gd , text : name } )
378390 . call ( textLayout )
379- . on ( 'edit' , function ( text ) {
380- this . text ( text )
391+ . on ( 'edit' , function ( newName ) {
392+ this . text ( ensureLength ( newName , maxLength ) )
381393 . call ( textLayout ) ;
382394
383- var origText = text ;
384-
385- if ( ! this . text ( ) ) text = ' \u0020\u0020 ' ;
386-
387395 var fullInput = legendItem . trace . _fullInput || { } ;
388396 var update = { } ;
389397
@@ -393,24 +401,35 @@ function drawTexts(g, gd) {
393401
394402 var kcont = Lib . keyedContainer ( fullInput , 'transforms[' + index + '].styles' , 'target' , 'value.name' ) ;
395403
396- if ( origText === '' ) {
397- kcont . remove ( legendItem . trace . _group ) ;
398- } else {
399- kcont . set ( legendItem . trace . _group , text ) ;
400- }
404+ kcont . set ( legendItem . trace . _group , newName ) ;
401405
402406 update = kcont . constructUpdate ( ) ;
403407 } else {
404- update . name = text ;
408+ update . name = newName ;
405409 }
406410
407411 return Registry . call ( 'restyle' , gd , update , traceIndex ) ;
408412 } ) ;
409413 } else {
410- textLayout ( text ) ;
414+ textLayout ( textEl ) ;
411415 }
412416}
413417
418+ /*
419+ * Make sure we have a reasonably clickable region.
420+ * If this string is missing or very short, pad it with spaces out to at least
421+ * 4 characters, up to the max length of other labels, on the assumption that
422+ * most characters are wider than spaces so a string of spaces will usually be
423+ * no wider than the real labels.
424+ */
425+ function ensureLength ( str , maxLength ) {
426+ var targetLength = Math . max ( 4 , maxLength ) ;
427+ if ( str && str . trim ( ) . length >= targetLength / 2 ) return str ;
428+ str = str || '' ;
429+ for ( var i = targetLength - str . length ; i > 0 ; i -- ) str += ' ' ;
430+ return str ;
431+ }
432+
414433function setupTraceToggle ( g , gd ) {
415434 var newMouseDownTime ,
416435 numClicks = 1 ;
0 commit comments