@@ -42,9 +42,9 @@ module.exports = function draw(gd) {
4242
4343 if ( ! gd . _legendMouseDownTime ) gd . _legendMouseDownTime = 0 ;
4444
45- var opts = fullLayout . legend ,
46- legendData = fullLayout . showlegend && getLegendData ( gd . calcdata , opts ) ,
47- hiddenSlices = fullLayout . hiddenlabels || [ ] ;
45+ var opts = fullLayout . legend ;
46+ var legendData = fullLayout . showlegend && getLegendData ( gd . calcdata , opts ) ;
47+ var hiddenSlices = fullLayout . hiddenlabels || [ ] ;
4848
4949 if ( ! fullLayout . showlegend || ! legendData . length ) {
5050 fullLayout . _infolayer . selectAll ( '.legend' ) . remove ( ) ;
@@ -54,6 +54,17 @@ module.exports = function draw(gd) {
5454 return ;
5555 }
5656
57+ var maxLength = 0 ;
58+ for ( var i = 0 ; i < legendData . length ; i ++ ) {
59+ for ( var j = 0 ; j < legendData [ i ] . length ; j ++ ) {
60+ var item = legendData [ i ] [ j ] [ 0 ] ;
61+ var trace = item . trace ;
62+ var isPie = Registry . traceIs ( trace , 'pie' ) ;
63+ var name = isPie ? item . label : trace . name ;
64+ maxLength = Math . max ( maxLength , name && name . length || 0 ) ;
65+ }
66+ }
67+
5768 var firstRender = false ;
5869 var legend = Lib . ensureSingle ( fullLayout . _infolayer , 'g' , 'legend' , function ( s ) {
5970 s . attr ( 'pointer-events' , 'all' ) ;
@@ -109,7 +120,7 @@ module.exports = function draw(gd) {
109120 } )
110121 . each ( function ( ) {
111122 d3 . select ( this )
112- . call ( drawTexts , gd )
123+ . call ( drawTexts , gd , maxLength )
113124 . call ( setupTraceToggle , gd ) ;
114125 } ) ;
115126
@@ -377,38 +388,35 @@ function clickOrDoubleClick(gd, legend, clickedTrace, numClicks, evt) {
377388 }
378389}
379390
380- function drawTexts ( g , gd ) {
381- var legendItem = g . data ( ) [ 0 ] [ 0 ] ,
382- fullLayout = gd . _fullLayout ,
383- trace = legendItem . trace ,
384- isPie = Registry . traceIs ( trace , 'pie' ) ,
385- traceIndex = trace . index ,
386- name = isPie ? legendItem . label : trace . name ;
391+ function drawTexts ( g , gd , maxLength ) {
392+ var legendItem = g . data ( ) [ 0 ] [ 0 ] ;
393+ var fullLayout = gd . _fullLayout ;
394+ var trace = legendItem . trace ;
395+ var isPie = Registry . traceIs ( trace , 'pie' ) ;
396+ var traceIndex = trace . index ;
397+ var name = isPie ? legendItem . label : trace . name ;
398+ var isEditable = gd . _context . edits . legendText && ! isPie ;
387399
388- var text = Lib . ensureSingle ( g , 'text' , 'legendtext' ) ;
400+ var textEl = Lib . ensureSingle ( g , 'text' , 'legendtext' ) ;
389401
390- text . attr ( 'text-anchor' , 'start' )
402+ textEl . attr ( 'text-anchor' , 'start' )
391403 . classed ( 'user-select-none' , true )
392404 . call ( Drawing . font , fullLayout . legend . font )
393- . text ( name ) ;
405+ . text ( isEditable ? ensureLength ( name , maxLength ) : name ) ;
394406
395407 function textLayout ( s ) {
396408 svgTextUtils . convertToTspans ( s , gd , function ( ) {
397409 computeTextDimensions ( g , gd ) ;
398410 } ) ;
399411 }
400412
401- if ( gd . _context . edits . legendText && ! isPie ) {
402- text . call ( svgTextUtils . makeEditable , { gd : gd } )
413+ if ( isEditable ) {
414+ textEl . call ( svgTextUtils . makeEditable , { gd : gd , text : name } )
403415 . call ( textLayout )
404- . on ( 'edit' , function ( text ) {
405- this . text ( text )
416+ . on ( 'edit' , function ( newName ) {
417+ this . text ( ensureLength ( newName , maxLength ) )
406418 . call ( textLayout ) ;
407419
408- var origText = text ;
409-
410- if ( ! this . text ( ) ) text = ' \u0020\u0020 ' ;
411-
412420 var fullInput = legendItem . trace . _fullInput || { } ;
413421 var update = { } ;
414422
@@ -418,24 +426,35 @@ function drawTexts(g, gd) {
418426
419427 var kcont = Lib . keyedContainer ( fullInput , 'transforms[' + index + '].styles' , 'target' , 'value.name' ) ;
420428
421- if ( origText === '' ) {
422- kcont . remove ( legendItem . trace . _group ) ;
423- } else {
424- kcont . set ( legendItem . trace . _group , text ) ;
425- }
429+ kcont . set ( legendItem . trace . _group , newName ) ;
426430
427431 update = kcont . constructUpdate ( ) ;
428432 } else {
429- update . name = text ;
433+ update . name = newName ;
430434 }
431435
432436 return Registry . call ( 'restyle' , gd , update , traceIndex ) ;
433437 } ) ;
434438 } else {
435- textLayout ( text ) ;
439+ textLayout ( textEl ) ;
436440 }
437441}
438442
443+ /*
444+ * Make sure we have a reasonably clickable region.
445+ * If this string is missing or very short, pad it with spaces out to at least
446+ * 4 characters, up to the max length of other labels, on the assumption that
447+ * most characters are wider than spaces so a string of spaces will usually be
448+ * no wider than the real labels.
449+ */
450+ function ensureLength ( str , maxLength ) {
451+ var targetLength = Math . max ( 4 , maxLength ) ;
452+ if ( str && str . trim ( ) . length >= targetLength / 2 ) return str ;
453+ str = str || '' ;
454+ for ( var i = targetLength - str . length ; i > 0 ; i -- ) str += ' ' ;
455+ return str ;
456+ }
457+
439458function setupTraceToggle ( g , gd ) {
440459 var newMouseDownTime ,
441460 numClicks = 1 ;
0 commit comments