@@ -272,136 +272,197 @@ function appendBarText(gd, bar, calcTrace, i, x0, x1, y0, y1) {
272
272
}
273
273
}
274
274
275
- // compute translate transform
275
+ // set text transform
276
276
var transform ;
277
277
if ( textPosition === 'outside' ) {
278
278
transform = getTransformToMoveOutsideBar ( x0 , x1 , y0 , y1 , textBB ,
279
279
trace . orientation ) ;
280
280
}
281
281
else {
282
- transform = getTransformToMoveInsideBar ( x0 , x1 , y0 , y1 , textBB ) ;
282
+ transform = getTransformToMoveInsideBar ( x0 , x1 , y0 , y1 , textBB ,
283
+ trace . orientation ) ;
283
284
}
284
285
285
286
textSelection . attr ( 'transform' , transform ) ;
286
287
}
287
288
288
- function getTransformToMoveInsideBar ( x0 , x1 , y0 , y1 , textBB ) {
289
+ function getTransformToMoveInsideBar ( x0 , x1 , y0 , y1 , textBB , orientation ) {
289
290
// compute text and target positions
290
- var barWidth = Math . abs ( x1 - x0 ) ,
291
- barHeight = Math . abs ( y1 - y0 ) ,
292
- textWidth = textBB . width ,
291
+ var textWidth = textBB . width ,
293
292
textHeight = textBB . height ,
294
- barX = ( x0 + x1 ) / 2 ,
295
- barY = ( y0 + y1 ) / 2 ,
296
293
textX = ( textBB . left + textBB . right ) / 2 ,
297
- textY = ( textBB . top + textBB . bottom ) / 2 ;
298
-
299
- // apply 3px target padding
300
- var targetWidth = barWidth - 2 * TEXTPAD ,
301
- targetHeight = barHeight - 2 * TEXTPAD ;
302
-
303
- return getTransform (
304
- textX , textY , textWidth , textHeight ,
305
- barX , barY , targetWidth , targetHeight ) ;
306
- }
294
+ textY = ( textBB . top + textBB . bottom ) / 2 ,
295
+ barWidth = Math . abs ( x1 - x0 ) - 2 * TEXTPAD ,
296
+ barHeight = Math . abs ( y1 - y0 ) - 2 * TEXTPAD ,
297
+ targetWidth ,
298
+ targetHeight ,
299
+ targetX ,
300
+ targetY ;
301
+
302
+ // compute rotation and scale
303
+ var needsRotating ,
304
+ scale ;
305
+
306
+ if ( textWidth <= barWidth && textHeight <= barHeight ) {
307
+ // no scale or rotation is required
308
+ needsRotating = false ;
309
+ scale = 1 ;
310
+ }
311
+ else if ( textWidth <= barHeight && textHeight <= barWidth ) {
312
+ // only rotation is required
313
+ needsRotating = true ;
314
+ scale = 1 ;
315
+ }
316
+ else if ( ( textWidth < textHeight ) === ( barWidth < barHeight ) ) {
317
+ // only scale is required
318
+ needsRotating = false ;
319
+ scale = Math . min ( barWidth / textWidth , barHeight / textHeight ) ;
320
+ }
321
+ else {
322
+ // both scale and rotation are required
323
+ needsRotating = true ;
324
+ scale = Math . min ( barHeight / textWidth , barWidth / textHeight ) ;
325
+ }
307
326
308
- function getTransformToMoveOutsideBar ( x0 , x1 , y0 , y1 , textBB , orientation ) {
309
327
// compute text and target positions
310
- var textWidth = textBB . width ,
311
- textHeight = textBB . height ,
312
- textX = ( textBB . left + textBB . right ) / 2 ,
313
- textY = ( textBB . top + textBB . bottom ) / 2 ;
328
+ if ( needsRotating ) {
329
+ targetWidth = scale * textHeight ;
330
+ targetHeight = scale * textWidth ;
331
+ }
332
+ else {
333
+ targetWidth = scale * textWidth ;
334
+ targetHeight = scale * textHeight ;
335
+ }
314
336
315
- var targetWidth , targetHeight ,
316
- targetX , targetY ;
317
337
if ( orientation === 'h' ) {
318
338
if ( x1 < x0 ) {
319
339
// bar end is on the left hand side
320
- targetWidth = textWidth + 2 * TEXTPAD ; // padding included
321
- targetHeight = Math . abs ( y1 - y0 ) - 2 * TEXTPAD ;
322
- targetX = x1 - targetWidth / 2 ;
340
+ targetX = x1 + TEXTPAD + targetWidth / 2 ;
323
341
targetY = ( y0 + y1 ) / 2 ;
324
342
}
325
343
else {
326
- targetWidth = textWidth + 2 * TEXTPAD ; // padding included
327
- targetHeight = Math . abs ( y1 - y0 ) - 2 * TEXTPAD ;
328
- targetX = x1 + targetWidth / 2 ;
344
+ targetX = x1 - TEXTPAD - targetWidth / 2 ;
329
345
targetY = ( y0 + y1 ) / 2 ;
330
346
}
331
347
}
332
348
else {
333
349
if ( y1 > y0 ) {
334
350
// bar end is on the bottom
335
- targetWidth = Math . abs ( x1 - x0 ) ;
336
- targetHeight = 2 + textHeight ; // padding included
337
351
targetX = ( x0 + x1 ) / 2 ;
338
- targetY = y1 + targetHeight / 2 ;
352
+ targetY = y1 - TEXTPAD - targetHeight / 2 ;
339
353
}
340
354
else {
341
- targetWidth = Math . abs ( x1 - x0 ) ;
342
- targetHeight = 2 + textHeight ; // padding included
343
355
targetX = ( x0 + x1 ) / 2 ;
344
- targetY = y1 - targetHeight / 2 ;
356
+ targetY = y1 + TEXTPAD + targetHeight / 2 ;
345
357
}
346
358
}
347
359
348
- return getTransform (
349
- textX , textY , textWidth , textHeight ,
350
- targetX , targetY , targetWidth , targetHeight ) ;
360
+ return getTransform ( textX , textY , targetX , targetY , scale , needsRotating ) ;
351
361
}
352
362
353
- /**
354
- * Compute SVG transform to move a text box into a target box
355
- *
356
- * @param {number } textX X pixel coord of the text box center
357
- * @param {number } textY Y pixel coord of the text box center
358
- * @param {number } textWidth text box width
359
- * @param {number } textHeight text box height
360
- * @param {number } targetX X pixel coord of the target box center
361
- * @param {number } targetY Y pixel coord of the target box center
362
- * @param {number } targetWidth target box width
363
- * @param {number } targetHeight target box height
364
- *
365
- * @returns {string } SVG transform
366
- */
367
- function getTransform (
368
- textX , textY , textWidth , textHeight ,
369
- targetX , targetY , targetWidth , targetHeight ) {
370
-
371
- // compute translate transform
372
- var translateX = targetX - textX ,
373
- translateY = targetY - textY ,
374
- translate = 'translate(' + translateX + ' ' + translateY + ')' ;
375
-
376
- // if bar text doesn't fit, compute rotate and scale transforms
377
- var doesntFit = ( textWidth > targetWidth || textHeight > targetHeight ) ,
378
- rotate , scale , scaleX , scaleY ;
379
-
380
- if ( doesntFit ) {
381
- var textIsHorizontal = ( textWidth > textHeight ) ,
382
- targetIsHorizontal = ( targetWidth > targetHeight ) ;
383
- if ( textIsHorizontal !== targetIsHorizontal ) {
384
- rotate = 'rotate(-90 ' + textX + ' ' + textY + ')' ;
385
- scaleX = targetWidth / textHeight ;
386
- scaleY = targetHeight / textWidth ;
363
+ function getTransformToMoveOutsideBar ( x0 , x1 , y0 , y1 , textBB , orientation ) {
364
+ // In order to handle both orientations with the same algorithm,
365
+ // *textWidth* is defined as the text length in the direction of *barWidth*.
366
+ var barWidth ,
367
+ textWidth ,
368
+ textHeight ;
369
+ if ( orientation === 'h' ) {
370
+ barWidth = Math . abs ( y1 - y0 ) - 2 * TEXTPAD ;
371
+ textWidth = textBB . height ;
372
+ textHeight = textBB . width ;
373
+ }
374
+ else {
375
+ barWidth = Math . abs ( x1 - x0 ) - 2 * TEXTPAD ;
376
+ textWidth = textBB . width ;
377
+ textHeight = textBB . height ;
378
+ }
379
+
380
+ // compute rotation and scale
381
+ var needsRotating ,
382
+ scale ;
383
+ if ( textWidth <= barWidth ) {
384
+ // no scale or rotation
385
+ needsRotating = false ;
386
+ scale = 1 ;
387
+ }
388
+ else if ( textHeight <= textWidth ) {
389
+ // only scale
390
+ // (don't rotate to prevent having text perpendicular to the bar)
391
+ needsRotating = false ;
392
+ scale = barWidth / textWidth ;
393
+ }
394
+ else if ( textHeight <= barWidth ) {
395
+ // only rotation
396
+ needsRotating = true ;
397
+ scale = 1 ;
398
+ }
399
+ else {
400
+ // both scale and rotation
401
+ // (rotation prevents having text perpendicular to the bar)
402
+ needsRotating = true ;
403
+ scale = barWidth / textHeight ;
404
+ }
405
+
406
+ // compute text and target positions
407
+ var textX = ( textBB . left + textBB . right ) / 2 ,
408
+ textY = ( textBB . top + textBB . bottom ) / 2 ,
409
+ targetWidth ,
410
+ targetHeight ,
411
+ targetX ,
412
+ targetY ;
413
+ if ( needsRotating ) {
414
+ targetWidth = scale * textBB . height ;
415
+ targetHeight = scale * textBB . width ;
416
+ }
417
+ else {
418
+ targetWidth = scale * textBB . width ;
419
+ targetHeight = scale * textBB . height ;
420
+ }
421
+
422
+ if ( orientation === 'h' ) {
423
+ if ( x1 < x0 ) {
424
+ // bar end is on the left hand side
425
+ targetX = x1 - TEXTPAD - targetWidth / 2 ;
426
+ targetY = ( y0 + y1 ) / 2 ;
387
427
}
388
428
else {
389
- scaleX = targetWidth / textWidth ;
390
- scaleY = targetHeight / textHeight ;
429
+ targetX = x1 + TEXTPAD + targetWidth / 2 ;
430
+ targetY = ( y0 + y1 ) / 2 ;
391
431
}
432
+ }
433
+ else {
434
+ if ( y1 > y0 ) {
435
+ // bar end is on the bottom
436
+ targetX = ( x0 + x1 ) / 2 ;
437
+ targetY = y1 + TEXTPAD + targetHeight / 2 ;
438
+ }
439
+ else {
440
+ targetX = ( x0 + x1 ) / 2 ;
441
+ targetY = y1 - TEXTPAD - targetHeight / 2 ;
442
+ }
443
+ }
392
444
393
- if ( scaleX > 1 ) scaleX = 1 ;
394
- if ( scaleY > 1 ) scaleY = 1 ;
445
+ return getTransform ( textX , textY , targetX , targetY , scale , needsRotating ) ;
446
+ }
395
447
396
- if ( scaleX !== 1 || scaleY !== 1 ) {
397
- scale = 'scale(' + scaleX + ' ' + scaleY + ')' ;
398
- }
448
+ function getTransform ( textX , textY , targetX , targetY , scale , needsRotating ) {
449
+ var transformScale ,
450
+ transformRotate ,
451
+ transformTranslate ;
452
+
453
+ if ( scale < 1 ) transformScale = 'scale(' + scale + ') ' ;
454
+ else {
455
+ scale = 1 ;
456
+ transformScale = '' ;
399
457
}
400
458
401
- // compute transform
402
- var transform = translate ;
403
- if ( scale ) transform += ' ' + scale ;
404
- if ( rotate ) transform += ' ' + rotate ;
459
+ transformRotate = ( needsRotating ) ?
460
+ 'rotate(-90 ' + textX + ' ' + textY + ') ' : '' ;
461
+
462
+ // Note that scaling also affects the center of the text box
463
+ var translateX = ( targetX - scale * textX ) ,
464
+ translateY = ( targetY - scale * textY ) ;
465
+ transformTranslate = 'translate(' + translateX + ' ' + translateY + ')' ;
405
466
406
- return transform ;
467
+ return transformTranslate + transformScale + transformRotate ;
407
468
}
0 commit comments