@@ -59,6 +59,7 @@ function handleAnnotationDefaults(annIn, fullLayout) {
59
59
coerce ( 'arrowwidth' , ( ( borderOpacity && borderWidth ) || 1 ) * 2 ) ;
60
60
coerce ( 'ax' ) ;
61
61
coerce ( 'ay' ) ;
62
+ coerce ( 'absolutetail' ) ;
62
63
63
64
// if you have one part of arrow length you should have both
64
65
Lib . noneOrAll ( annIn , annOut , [ 'ax' , 'ay' ] ) ;
@@ -89,6 +90,11 @@ function handleAnnotationDefaults(annIn, fullLayout) {
89
90
if ( ax . type === 'date' ) {
90
91
newval = Lib . dateTime2ms ( annIn [ axLetter ] ) ;
91
92
if ( newval !== false ) annIn [ axLetter ] = newval ;
93
+
94
+ if ( annIn . absolutetail ) {
95
+ var newvalB = Lib . dateTime2ms ( annIn [ 'a' + axLetter ] ) ;
96
+ if ( newvalB !== false ) annIn [ 'a' + axLetter ] = newvalB ;
97
+ }
92
98
}
93
99
else if ( ( ax . _categories || [ ] ) . length ) {
94
100
newval = ax . _categories . indexOf ( annIn [ axLetter ] ) ;
@@ -450,13 +456,17 @@ annotations.draw = function(gd, index, opt, value) {
450
456
}
451
457
452
458
var alignShift = 0 ;
453
- if ( options . showarrow ) {
454
- alignShift = options [ 'a' + axLetter ] ;
455
- }
456
- else {
457
- alignShift = annSize * shiftFraction ( alignPosition , anchor ) ;
459
+ if ( options . absolutetail ) {
460
+ annPosPx [ 'aa' + axLetter ] = ax . _offset + ax . l2p ( options [ 'a' + axLetter ] ) ;
461
+ } else {
462
+ if ( options . showarrow ) {
463
+ alignShift = options [ 'a' + axLetter ] ;
464
+ }
465
+ else {
466
+ alignShift = annSize * shiftFraction ( alignPosition , anchor ) ;
467
+ }
468
+ annPosPx [ axLetter ] += alignShift ;
458
469
}
459
- annPosPx [ axLetter ] += alignShift ;
460
470
461
471
// save the current axis type for later log/linear changes
462
472
options [ '_' + axLetter + 'type' ] = ax && ax . type ;
@@ -476,8 +486,13 @@ annotations.draw = function(gd, index, opt, value) {
476
486
// make sure the arrowhead (if there is one)
477
487
// and the annotation center are visible
478
488
if ( options . showarrow ) {
479
- arrowX = Lib . constrain ( annPosPx . x - options . ax , 1 , fullLayout . width - 1 ) ;
480
- arrowY = Lib . constrain ( annPosPx . y - options . ay , 1 , fullLayout . height - 1 ) ;
489
+ if ( options . absolutetail ) {
490
+ arrowX = Lib . constrain ( annPosPx . x , 1 , fullLayout . width - 1 ) ;
491
+ arrowY = Lib . constrain ( annPosPx . y , 1 , fullLayout . height - 1 ) ;
492
+ } else {
493
+ arrowX = Lib . constrain ( annPosPx . x - options . ax , 1 , fullLayout . width - 1 ) ;
494
+ arrowY = Lib . constrain ( annPosPx . y - options . ay , 1 , fullLayout . height - 1 ) ;
495
+ }
481
496
}
482
497
annPosPx . x = Lib . constrain ( annPosPx . x , 1 , fullLayout . width - 1 ) ;
483
498
annPosPx . y = Lib . constrain ( annPosPx . y , 1 , fullLayout . height - 1 ) ;
@@ -496,8 +511,15 @@ annotations.draw = function(gd, index, opt, value) {
496
511
annbg . call ( Drawing . setRect , borderwidth / 2 , borderwidth / 2 ,
497
512
outerwidth - borderwidth , outerheight - borderwidth ) ;
498
513
499
- var annX = Math . round ( annPosPx . x - outerwidth / 2 ) ,
514
+ var annX = 0 , annY = 0 ;
515
+ if ( options . absolutetail ) {
516
+ annX = Math . round ( annPosPx . aax - outerwidth / 2 ) ;
517
+ annY = Math . round ( annPosPx . aay - outerheight / 2 ) ;
518
+ } else {
519
+ annX = Math . round ( annPosPx . x - outerwidth / 2 ) ;
500
520
annY = Math . round ( annPosPx . y - outerheight / 2 ) ;
521
+ }
522
+
501
523
ann . call ( Lib . setTranslate , annX , annY ) ;
502
524
503
525
var annbase = 'annotations[' + index + ']' ;
@@ -515,11 +537,18 @@ annotations.draw = function(gd, index, opt, value) {
515
537
// looks like there may be a cross-browser solution, see
516
538
// http://stackoverflow.com/questions/5364980/
517
539
// how-to-get-the-width-of-an-svg-tspan-element
518
- var arrowX0 = annPosPx . x + dx ,
519
- arrowY0 = annPosPx . y + dy ,
540
+ var arrowX0 , arrowY0 ;
541
+
542
+ if ( options . absolutetail ) {
543
+ arrowX0 = annPosPx . aax + dx ;
544
+ arrowY0 = annPosPx . aay + dy ;
545
+ } else {
546
+ arrowX0 = annPosPx . x + dx ;
547
+ arrowY0 = annPosPx . y + dy ;
548
+ }
520
549
521
550
// create transform matrix and related functions
522
- transform =
551
+ var transform =
523
552
Lib . rotationXYMatrix ( textangle , arrowX0 , arrowY0 ) ,
524
553
applyTransform = Lib . apply2DTransform ( transform ) ,
525
554
applyTransform2 = Lib . apply2DTransform2 ( transform ) ,
@@ -618,6 +647,15 @@ annotations.draw = function(gd, index, opt, value) {
618
647
( options . y + dy / ya . _m ) :
619
648
( 1 - ( ( arrowY + dy - gs . t ) / gs . h ) ) ;
620
649
650
+ if ( options . absolutetail ) {
651
+ update [ annbase + '.ax' ] = xa ?
652
+ ( options . ax + dx / xa . _m ) :
653
+ ( ( arrowX + dx - gs . l ) / gs . w ) ;
654
+ update [ annbase + '.ay' ] = ya ?
655
+ ( options . ay + dy / ya . _m ) :
656
+ ( 1 - ( ( arrowY + dy - gs . t ) / gs . h ) ) ;
657
+ }
658
+
621
659
anng . attr ( {
622
660
transform : 'rotate(' + textangle + ',' +
623
661
xcenter + ',' + ycenter + ')'
@@ -660,8 +698,13 @@ annotations.draw = function(gd, index, opt, value) {
660
698
ann . call ( Lib . setTranslate , x0 + dx , y0 + dy ) ;
661
699
var csr = 'pointer' ;
662
700
if ( options . showarrow ) {
663
- update [ annbase + '.ax' ] = options . ax + dx ;
664
- update [ annbase + '.ay' ] = options . ay + dy ;
701
+ if ( options . absolutetail ) {
702
+ update [ annbase + '.ax' ] = xa . p2l ( xa . l2p ( options . ax ) + dx ) ;
703
+ update [ annbase + '.ay' ] = ya . p2l ( ya . l2p ( options . ay ) + dy ) ;
704
+ } else {
705
+ update [ annbase + '.ax' ] = options . ax + dx ;
706
+ update [ annbase + '.ay' ] = options . ay + dy ;
707
+ }
665
708
drawArrow ( dx , dy ) ;
666
709
}
667
710
else {
0 commit comments