@@ -59,6 +59,8 @@ function handleAnnotationDefaults(annIn, fullLayout) {
59
59
coerce ( 'arrowwidth' , ( ( borderOpacity && borderWidth ) || 1 ) * 2 ) ;
60
60
coerce ( 'ax' ) ;
61
61
coerce ( 'ay' ) ;
62
+ coerce ( 'axref' ) ;
63
+ coerce ( 'ayref' ) ;
62
64
63
65
// if you have one part of arrow length you should have both
64
66
Lib . noneOrAll ( annIn , annOut , [ 'ax' , 'ay' ] ) ;
@@ -76,6 +78,10 @@ function handleAnnotationDefaults(annIn, fullLayout) {
76
78
// xref, yref
77
79
var axRef = Axes . coerceRef ( annIn , annOut , tdMock , axLetter ) ;
78
80
81
+ //todo: should be refactored in conjunction with Axes
82
+ // axref, ayref
83
+ var aaxRef = Axes . coerceARef ( annIn , annOut , tdMock , axLetter ) ;
84
+
79
85
// x, y
80
86
var defaultPosition = 0.5 ;
81
87
if ( axRef !== 'paper' ) {
@@ -89,6 +95,11 @@ function handleAnnotationDefaults(annIn, fullLayout) {
89
95
if ( ax . type === 'date' ) {
90
96
newval = Lib . dateTime2ms ( annIn [ axLetter ] ) ;
91
97
if ( newval !== false ) annIn [ axLetter ] = newval ;
98
+
99
+ if ( aaxRef === axRef ) {
100
+ var newvalB = Lib . dateTime2ms ( annIn [ 'a' + axLetter ] ) ;
101
+ if ( newvalB !== false ) annIn [ 'a' + axLetter ] = newvalB ;
102
+ }
92
103
}
93
104
else if ( ( ax . _categories || [ ] ) . length ) {
94
105
newval = ax . _categories . indexOf ( annIn [ axLetter ] ) ;
@@ -419,8 +430,8 @@ annotations.draw = function(gd, index, opt, value) {
419
430
420
431
var annotationIsOffscreen = false ;
421
432
[ 'x' , 'y' ] . forEach ( function ( axLetter ) {
422
- var ax = Axes . getFromId ( gd ,
423
- options [ axLetter + 'ref' ] || axLetter ) ,
433
+ var axRef = options [ axLetter + 'ref' ] || axLetter ,
434
+ ax = Axes . getFromId ( gd , axRef ) ,
424
435
dimAngle = ( textangle + ( axLetter === 'x' ? 0 : 90 ) ) * Math . PI / 180 ,
425
436
annSize = outerwidth * Math . abs ( Math . cos ( dimAngle ) ) +
426
437
outerheight * Math . abs ( Math . sin ( dimAngle ) ) ,
@@ -435,8 +446,16 @@ annotations.draw = function(gd, index, opt, value) {
435
446
// anyway to get its bounding box)
436
447
if ( ! ax . autorange && ( ( options [ axLetter ] - ax . range [ 0 ] ) *
437
448
( options [ axLetter ] - ax . range [ 1 ] ) > 0 ) ) {
438
- annotationIsOffscreen = true ;
439
- return ;
449
+ if ( options [ 'a' + axLetter + 'ref' ] === axRef ) {
450
+ if ( ( options [ 'a' + axLetter ] - ax . range [ 0 ] ) *
451
+ ( options [ 'a' + axLetter ] - ax . range [ 1 ] ) > 0 ) {
452
+ annotationIsOffscreen = true ;
453
+ }
454
+ } else {
455
+ annotationIsOffscreen = true ;
456
+ }
457
+
458
+ if ( annotationIsOffscreen ) return ;
440
459
}
441
460
annPosPx [ axLetter ] = ax . _offset + ax . l2p ( options [ axLetter ] ) ;
442
461
alignPosition = 0.5 ;
@@ -450,13 +469,17 @@ annotations.draw = function(gd, index, opt, value) {
450
469
}
451
470
452
471
var alignShift = 0 ;
453
- if ( options . showarrow ) {
454
- alignShift = options [ 'a' + axLetter ] ;
455
- }
456
- else {
457
- alignShift = annSize * shiftFraction ( alignPosition , anchor ) ;
472
+ if ( options [ 'a' + axLetter + 'ref' ] === axRef ) {
473
+ annPosPx [ 'aa' + axLetter ] = ax . _offset + ax . l2p ( options [ 'a' + axLetter ] ) ;
474
+ } else {
475
+ if ( options . showarrow ) {
476
+ alignShift = options [ 'a' + axLetter ] ;
477
+ }
478
+ else {
479
+ alignShift = annSize * shiftFraction ( alignPosition , anchor ) ;
480
+ }
481
+ annPosPx [ axLetter ] += alignShift ;
458
482
}
459
- annPosPx [ axLetter ] += alignShift ;
460
483
461
484
// save the current axis type for later log/linear changes
462
485
options [ '_' + axLetter + 'type' ] = ax && ax . type ;
@@ -476,8 +499,21 @@ annotations.draw = function(gd, index, opt, value) {
476
499
// make sure the arrowhead (if there is one)
477
500
// and the annotation center are visible
478
501
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 ) ;
502
+ if ( options . axref === options . xref ) {
503
+ //we don't want to constrain if the tail is absolute
504
+ //or the slope (which is meaningful) will change.
505
+ arrowX = annPosPx . x ;
506
+ } else {
507
+ arrowX = Lib . constrain ( annPosPx . x - options . ax , 1 , fullLayout . width - 1 ) ;
508
+ }
509
+
510
+ if ( options . ayref === options . yref ) {
511
+ //we don't want to constrain if the tail is absolute
512
+ //or the slope (which is meaningful) will change.
513
+ arrowY = annPosPx . y ;
514
+ } else {
515
+ arrowY = Lib . constrain ( annPosPx . y - options . ay , 1 , fullLayout . height - 1 ) ;
516
+ }
481
517
}
482
518
annPosPx . x = Lib . constrain ( annPosPx . x , 1 , fullLayout . width - 1 ) ;
483
519
annPosPx . y = Lib . constrain ( annPosPx . y , 1 , fullLayout . height - 1 ) ;
@@ -496,8 +532,19 @@ annotations.draw = function(gd, index, opt, value) {
496
532
annbg . call ( Drawing . setRect , borderwidth / 2 , borderwidth / 2 ,
497
533
outerwidth - borderwidth , outerheight - borderwidth ) ;
498
534
499
- var annX = Math . round ( annPosPx . x - outerwidth / 2 ) ,
535
+ var annX = 0 , annY = 0 ;
536
+ if ( options . axref === options . xref ) {
537
+ annX = Math . round ( annPosPx . aax - outerwidth / 2 ) ;
538
+ } else {
539
+ annX = Math . round ( annPosPx . x - outerwidth / 2 ) ;
540
+ }
541
+
542
+ if ( options . ayref === options . yref ) {
543
+ annY = Math . round ( annPosPx . aay - outerheight / 2 ) ;
544
+ } else {
500
545
annY = Math . round ( annPosPx . y - outerheight / 2 ) ;
546
+ }
547
+
501
548
ann . call ( Lib . setTranslate , annX , annY ) ;
502
549
503
550
var annbase = 'annotations[' + index + ']' ;
@@ -515,11 +562,22 @@ annotations.draw = function(gd, index, opt, value) {
515
562
// looks like there may be a cross-browser solution, see
516
563
// http://stackoverflow.com/questions/5364980/
517
564
// how-to-get-the-width-of-an-svg-tspan-element
518
- var arrowX0 = annPosPx . x + dx ,
519
- arrowY0 = annPosPx . y + dy ,
565
+ var arrowX0 , arrowY0 ;
566
+
567
+ if ( options . axref === options . xref ) {
568
+ arrowX0 = annPosPx . aax + dx ;
569
+ } else {
570
+ arrowX0 = annPosPx . x + dx ;
571
+ }
572
+
573
+ if ( options . ayref === options . yref ) {
574
+ arrowY0 = annPosPx . aay + dy ;
575
+ } else {
576
+ arrowY0 = annPosPx . y + dy ;
577
+ }
520
578
521
579
// create transform matrix and related functions
522
- transform =
580
+ var transform =
523
581
Lib . rotationXYMatrix ( textangle , arrowX0 , arrowY0 ) ,
524
582
applyTransform = Lib . apply2DTransform ( transform ) ,
525
583
applyTransform2 = Lib . apply2DTransform2 ( transform ) ,
@@ -618,6 +676,18 @@ annotations.draw = function(gd, index, opt, value) {
618
676
( options . y + dy / ya . _m ) :
619
677
( 1 - ( ( arrowY + dy - gs . t ) / gs . h ) ) ;
620
678
679
+ if ( options . axref === options . xref ) {
680
+ update [ annbase + '.ax' ] = xa ?
681
+ ( options . ax + dx / xa . _m ) :
682
+ ( ( arrowX + dx - gs . l ) / gs . w ) ;
683
+ }
684
+
685
+ if ( options . ayref === options . yref ) {
686
+ update [ annbase + '.ay' ] = ya ?
687
+ ( options . ay + dy / ya . _m ) :
688
+ ( 1 - ( ( arrowY + dy - gs . t ) / gs . h ) ) ;
689
+ }
690
+
621
691
anng . attr ( {
622
692
transform : 'rotate(' + textangle + ',' +
623
693
xcenter + ',' + ycenter + ')'
@@ -660,8 +730,18 @@ annotations.draw = function(gd, index, opt, value) {
660
730
ann . call ( Lib . setTranslate , x0 + dx , y0 + dy ) ;
661
731
var csr = 'pointer' ;
662
732
if ( options . showarrow ) {
663
- update [ annbase + '.ax' ] = options . ax + dx ;
664
- update [ annbase + '.ay' ] = options . ay + dy ;
733
+ if ( options . axref === options . xref ) {
734
+ update [ annbase + '.ax' ] = xa . p2l ( xa . l2p ( options . ax ) + dx ) ;
735
+ } else {
736
+ update [ annbase + '.ax' ] = options . ax + dx ;
737
+ }
738
+
739
+ if ( options . ayref === options . yref ) {
740
+ update [ annbase + '.ay' ] = ya . p2l ( ya . l2p ( options . ay ) + dy ) ;
741
+ } else {
742
+ update [ annbase + '.ay' ] = options . ay + dy ;
743
+ }
744
+
665
745
drawArrow ( dx , dy ) ;
666
746
}
667
747
else {
0 commit comments