@@ -42,9 +42,9 @@ module.exports = function draw(gd) {
42
42
43
43
if ( ! gd . _legendMouseDownTime ) gd . _legendMouseDownTime = 0 ;
44
44
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 || [ ] ;
48
48
49
49
if ( ! fullLayout . showlegend || ! legendData . length ) {
50
50
fullLayout . _infolayer . selectAll ( '.legend' ) . remove ( ) ;
@@ -54,6 +54,17 @@ module.exports = function draw(gd) {
54
54
return ;
55
55
}
56
56
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
+
57
68
var firstRender = false ;
58
69
var legend = Lib . ensureSingle ( fullLayout . _infolayer , 'g' , 'legend' , function ( s ) {
59
70
s . attr ( 'pointer-events' , 'all' ) ;
@@ -109,7 +120,7 @@ module.exports = function draw(gd) {
109
120
} )
110
121
. each ( function ( ) {
111
122
d3 . select ( this )
112
- . call ( drawTexts , gd )
123
+ . call ( drawTexts , gd , maxLength )
113
124
. call ( setupTraceToggle , gd ) ;
114
125
} ) ;
115
126
@@ -377,38 +388,35 @@ function clickOrDoubleClick(gd, legend, clickedTrace, numClicks, evt) {
377
388
}
378
389
}
379
390
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 ;
387
399
388
- var text = Lib . ensureSingle ( g , 'text' , 'legendtext' ) ;
400
+ var textEl = Lib . ensureSingle ( g , 'text' , 'legendtext' ) ;
389
401
390
- text . attr ( 'text-anchor' , 'start' )
402
+ textEl . attr ( 'text-anchor' , 'start' )
391
403
. classed ( 'user-select-none' , true )
392
404
. call ( Drawing . font , fullLayout . legend . font )
393
- . text ( name ) ;
405
+ . text ( isEditable ? ensureLength ( name , maxLength ) : name ) ;
394
406
395
407
function textLayout ( s ) {
396
408
svgTextUtils . convertToTspans ( s , gd , function ( ) {
397
409
computeTextDimensions ( g , gd ) ;
398
410
} ) ;
399
411
}
400
412
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 } )
403
415
. call ( textLayout )
404
- . on ( 'edit' , function ( text ) {
405
- this . text ( text )
416
+ . on ( 'edit' , function ( newName ) {
417
+ this . text ( ensureLength ( newName , maxLength ) )
406
418
. call ( textLayout ) ;
407
419
408
- var origText = text ;
409
-
410
- if ( ! this . text ( ) ) text = ' \u0020\u0020 ' ;
411
-
412
420
var fullInput = legendItem . trace . _fullInput || { } ;
413
421
var update = { } ;
414
422
@@ -418,24 +426,35 @@ function drawTexts(g, gd) {
418
426
419
427
var kcont = Lib . keyedContainer ( fullInput , 'transforms[' + index + '].styles' , 'target' , 'value.name' ) ;
420
428
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 ) ;
426
430
427
431
update = kcont . constructUpdate ( ) ;
428
432
} else {
429
- update . name = text ;
433
+ update . name = newName ;
430
434
}
431
435
432
436
return Registry . call ( 'restyle' , gd , update , traceIndex ) ;
433
437
} ) ;
434
438
} else {
435
- textLayout ( text ) ;
439
+ textLayout ( textEl ) ;
436
440
}
437
441
}
438
442
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
+
439
458
function setupTraceToggle ( g , gd ) {
440
459
var newMouseDownTime ,
441
460
numClicks = 1 ;
0 commit comments