@@ -41,9 +41,9 @@ module.exports = function draw(gd) {
41
41
42
42
if ( ! gd . _legendMouseDownTime ) gd . _legendMouseDownTime = 0 ;
43
43
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 || [ ] ;
47
47
48
48
if ( ! fullLayout . showlegend || ! legendData . length ) {
49
49
fullLayout . _infolayer . selectAll ( '.legend' ) . remove ( ) ;
@@ -53,6 +53,17 @@ module.exports = function draw(gd) {
53
53
return ;
54
54
}
55
55
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
+
56
67
var firstRender = false ;
57
68
var legend = Lib . ensureSingle ( fullLayout . _infolayer , 'g' , 'legend' , function ( s ) {
58
69
s . attr ( 'pointer-events' , 'all' ) ;
@@ -108,7 +119,7 @@ module.exports = function draw(gd) {
108
119
} )
109
120
. each ( function ( ) {
110
121
d3 . select ( this )
111
- . call ( drawTexts , gd )
122
+ . call ( drawTexts , gd , maxLength )
112
123
. call ( setupTraceToggle , gd ) ;
113
124
} ) ;
114
125
@@ -352,38 +363,35 @@ module.exports = function draw(gd) {
352
363
}
353
364
} ;
354
365
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 ;
362
374
363
- var text = Lib . ensureSingle ( g , 'text' , 'legendtext' ) ;
375
+ var textEl = Lib . ensureSingle ( g , 'text' , 'legendtext' ) ;
364
376
365
- text . attr ( 'text-anchor' , 'start' )
377
+ textEl . attr ( 'text-anchor' , 'start' )
366
378
. classed ( 'user-select-none' , true )
367
379
. call ( Drawing . font , fullLayout . legend . font )
368
- . text ( name ) ;
380
+ . text ( isEditable ? ensureLength ( name , maxLength ) : name ) ;
369
381
370
382
function textLayout ( s ) {
371
383
svgTextUtils . convertToTspans ( s , gd , function ( ) {
372
384
computeTextDimensions ( g , gd ) ;
373
385
} ) ;
374
386
}
375
387
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 } )
378
390
. call ( textLayout )
379
- . on ( 'edit' , function ( text ) {
380
- this . text ( text )
391
+ . on ( 'edit' , function ( newName ) {
392
+ this . text ( ensureLength ( newName , maxLength ) )
381
393
. call ( textLayout ) ;
382
394
383
- var origText = text ;
384
-
385
- if ( ! this . text ( ) ) text = ' \u0020\u0020 ' ;
386
-
387
395
var fullInput = legendItem . trace . _fullInput || { } ;
388
396
var update = { } ;
389
397
@@ -393,24 +401,35 @@ function drawTexts(g, gd) {
393
401
394
402
var kcont = Lib . keyedContainer ( fullInput , 'transforms[' + index + '].styles' , 'target' , 'value.name' ) ;
395
403
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 ) ;
401
405
402
406
update = kcont . constructUpdate ( ) ;
403
407
} else {
404
- update . name = text ;
408
+ update . name = newName ;
405
409
}
406
410
407
411
return Registry . call ( 'restyle' , gd , update , traceIndex ) ;
408
412
} ) ;
409
413
} else {
410
- textLayout ( text ) ;
414
+ textLayout ( textEl ) ;
411
415
}
412
416
}
413
417
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
+
414
433
function setupTraceToggle ( g , gd ) {
415
434
var newMouseDownTime ,
416
435
numClicks = 1 ;
0 commit comments