@@ -59,6 +59,8 @@ function handleAnnotationDefaults(annIn, fullLayout) {
5959 coerce ( 'arrowwidth' , ( ( borderOpacity && borderWidth ) || 1 ) * 2 ) ;
6060 coerce ( 'ax' ) ;
6161 coerce ( 'ay' ) ;
62+ coerce ( 'axref' ) ;
63+ coerce ( 'ayref' ) ;
6264
6365 // if you have one part of arrow length you should have both
6466 Lib . noneOrAll ( annIn , annOut , [ 'ax' , 'ay' ] ) ;
@@ -76,6 +78,10 @@ function handleAnnotationDefaults(annIn, fullLayout) {
7678 // xref, yref
7779 var axRef = Axes . coerceRef ( annIn , annOut , tdMock , axLetter ) ;
7880
81+ //todo: should be refactored in conjunction with Axes
82+ // axref, ayref
83+ var aaxRef = Axes . coerceARef ( annIn , annOut , tdMock , axLetter ) ;
84+
7985 // x, y
8086 var defaultPosition = 0.5 ;
8187 if ( axRef !== 'paper' ) {
@@ -89,6 +95,11 @@ function handleAnnotationDefaults(annIn, fullLayout) {
8995 if ( ax . type === 'date' ) {
9096 newval = Lib . dateTime2ms ( annIn [ axLetter ] ) ;
9197 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+ }
92103 }
93104 else if ( ( ax . _categories || [ ] ) . length ) {
94105 newval = ax . _categories . indexOf ( annIn [ axLetter ] ) ;
@@ -419,8 +430,8 @@ annotations.draw = function(gd, index, opt, value) {
419430
420431 var annotationIsOffscreen = false ;
421432 [ '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 ) ,
424435 dimAngle = ( textangle + ( axLetter === 'x' ? 0 : 90 ) ) * Math . PI / 180 ,
425436 annSize = outerwidth * Math . abs ( Math . cos ( dimAngle ) ) +
426437 outerheight * Math . abs ( Math . sin ( dimAngle ) ) ,
@@ -435,8 +446,16 @@ annotations.draw = function(gd, index, opt, value) {
435446 // anyway to get its bounding box)
436447 if ( ! ax . autorange && ( ( options [ axLetter ] - ax . range [ 0 ] ) *
437448 ( 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 ;
440459 }
441460 annPosPx [ axLetter ] = ax . _offset + ax . l2p ( options [ axLetter ] ) ;
442461 alignPosition = 0.5 ;
@@ -450,13 +469,17 @@ annotations.draw = function(gd, index, opt, value) {
450469 }
451470
452471 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 ;
458482 }
459- annPosPx [ axLetter ] += alignShift ;
460483
461484 // save the current axis type for later log/linear changes
462485 options [ '_' + axLetter + 'type' ] = ax && ax . type ;
@@ -476,8 +499,21 @@ annotations.draw = function(gd, index, opt, value) {
476499 // make sure the arrowhead (if there is one)
477500 // and the annotation center are visible
478501 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+ }
481517 }
482518 annPosPx . x = Lib . constrain ( annPosPx . x , 1 , fullLayout . width - 1 ) ;
483519 annPosPx . y = Lib . constrain ( annPosPx . y , 1 , fullLayout . height - 1 ) ;
@@ -496,8 +532,19 @@ annotations.draw = function(gd, index, opt, value) {
496532 annbg . call ( Drawing . setRect , borderwidth / 2 , borderwidth / 2 ,
497533 outerwidth - borderwidth , outerheight - borderwidth ) ;
498534
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 {
500545 annY = Math . round ( annPosPx . y - outerheight / 2 ) ;
546+ }
547+
501548 ann . call ( Lib . setTranslate , annX , annY ) ;
502549
503550 var annbase = 'annotations[' + index + ']' ;
@@ -515,11 +562,22 @@ annotations.draw = function(gd, index, opt, value) {
515562 // looks like there may be a cross-browser solution, see
516563 // http://stackoverflow.com/questions/5364980/
517564 // 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+ }
520578
521579 // create transform matrix and related functions
522- transform =
580+ var transform =
523581 Lib . rotationXYMatrix ( textangle , arrowX0 , arrowY0 ) ,
524582 applyTransform = Lib . apply2DTransform ( transform ) ,
525583 applyTransform2 = Lib . apply2DTransform2 ( transform ) ,
@@ -618,6 +676,18 @@ annotations.draw = function(gd, index, opt, value) {
618676 ( options . y + dy / ya . _m ) :
619677 ( 1 - ( ( arrowY + dy - gs . t ) / gs . h ) ) ;
620678
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+
621691 anng . attr ( {
622692 transform : 'rotate(' + textangle + ',' +
623693 xcenter + ',' + ycenter + ')'
@@ -660,8 +730,18 @@ annotations.draw = function(gd, index, opt, value) {
660730 ann . call ( Lib . setTranslate , x0 + dx , y0 + dy ) ;
661731 var csr = 'pointer' ;
662732 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+
665745 drawArrow ( dx , dy ) ;
666746 }
667747 else {
0 commit comments