@@ -73,6 +73,31 @@ function drawOne(gd, index) {
73
73
drawRaw ( gd , options , index , false , xa , ya ) ;
74
74
}
75
75
76
+ // Convert pixels to the coordinates relevant for the axis referred to. For
77
+ // example, for paper it would convert to a value normalized by the dimension of
78
+ // the plot.
79
+ // axDomainRef: if true and axa defined, draws relative to axis domain,
80
+ // otherwise draws relative to data (if axa defined) or paper (if not).
81
+ function shiftPosition ( axa , dAx , axLetter , gs , options ) {
82
+ var optAx = options [ axLetter ] ;
83
+ var axRef = options [ axLetter + 'ref' ] ;
84
+ var vertical = axLetter . indexOf ( 'y' ) !== - 1 ;
85
+ var axDomainRef = Axes . getRefType ( axRef ) === 'domain' ;
86
+ var gsDim = vertical ? gs . h : gs . w ;
87
+ if ( axa ) {
88
+ if ( axDomainRef ) {
89
+ // here optAx normalized to length of axis (e.g., normally in range
90
+ // 0 to 1). But dAx is in pixels. So we normalize dAx to length of
91
+ // axis before doing the math.
92
+ return optAx + ( vertical ? - dAx : dAx ) / axa . _length ;
93
+ } else {
94
+ return axa . p2r ( axa . r2p ( optAx ) + dAx ) ;
95
+ }
96
+ } else {
97
+ return optAx + ( vertical ? - dAx : dAx ) / gsDim ;
98
+ }
99
+ }
100
+
76
101
/**
77
102
* drawRaw: draw a single annotation, potentially with modifications
78
103
*
@@ -296,13 +321,14 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
296
321
var alignPosition ;
297
322
var autoAlignFraction ;
298
323
var textShift ;
324
+ var axRefType = Axes . getRefType ( axRef ) ;
299
325
300
326
/*
301
327
* calculate the *primary* pixel position
302
328
* which is the arrowhead if there is one,
303
329
* otherwise the text anchor point
304
330
*/
305
- if ( ax ) {
331
+ if ( ax && ( axRefType !== 'domain' ) ) {
306
332
// check if annotation is off screen, to bypass DOM manipulations
307
333
var posFraction = ax . r2fraction ( options [ axLetter ] ) ;
308
334
if ( posFraction < 0 || posFraction > 1 ) {
@@ -318,12 +344,17 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
318
344
basePx = ax . _offset + ax . r2p ( options [ axLetter ] ) ;
319
345
autoAlignFraction = 0.5 ;
320
346
} else {
347
+ var axRefTypeEqDomain = axRefType === 'domain' ;
321
348
if ( axLetter === 'x' ) {
322
349
alignPosition = options [ axLetter ] ;
323
- basePx = gs . l + gs . w * alignPosition ;
350
+ basePx = axRefTypeEqDomain ?
351
+ ax . _offset + ax . _length * alignPosition :
352
+ basePx = gs . l + gs . w * alignPosition ;
324
353
} else {
325
354
alignPosition = 1 - options [ axLetter ] ;
326
- basePx = gs . t + gs . h * alignPosition ;
355
+ basePx = axRefTypeEqDomain ?
356
+ ax . _offset + ax . _length * alignPosition :
357
+ basePx = gs . t + gs . h * alignPosition ;
327
358
}
328
359
autoAlignFraction = options . showarrow ? 0.5 : alignPosition ;
329
360
}
@@ -340,8 +371,29 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
340
371
annSizeFromHeight * shiftFraction ( 0.5 , options . yanchor ) ;
341
372
342
373
if ( tailRef === axRef ) {
343
- posPx . tail = ax . _offset + ax . r2p ( arrowLength ) ;
344
- // tail is data-referenced: autorange pads the text in px from the tail
374
+ // In the case tailRefType is 'domain' or 'paper', the arrow's
375
+ // position is set absolutely, which is consistent with how
376
+ // it behaves when its position is set in data ('range')
377
+ // coordinates.
378
+ var tailRefType = Axes . getRefType ( tailRef ) ;
379
+ if ( tailRefType === 'domain' ) {
380
+ if ( axLetter === 'y' ) {
381
+ arrowLength = 1 - arrowLength ;
382
+ }
383
+ posPx . tail = ax . _offset + ax . _length * arrowLength ;
384
+ } else if ( tailRefType === 'paper' ) {
385
+ if ( axLetter === 'y' ) {
386
+ arrowLength = 1 - arrowLength ;
387
+ posPx . tail = gs . t + gs . h * arrowLength ;
388
+ } else {
389
+ posPx . tail = gs . l + gs . w * arrowLength ;
390
+ }
391
+ } else {
392
+ // assumed tailRef is range or paper referenced
393
+ posPx . tail = ax . _offset + ax . r2p ( arrowLength ) ;
394
+ }
395
+ // tail is range- or domain-referenced: autorange pads the
396
+ // text in px from the tail
345
397
textPadShift = textShift ;
346
398
} else {
347
399
posPx . tail = basePx + arrowLength ;
@@ -562,19 +614,20 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
562
614
var ycenter = annxy0 [ 1 ] + dy ;
563
615
annTextGroupInner . call ( Drawing . setTranslate , xcenter , ycenter ) ;
564
616
565
- modifyItem ( 'x' , xa ?
566
- xa . p2r ( xa . r2p ( options . x ) + dx ) :
567
- ( options . x + ( dx / gs . w ) ) ) ;
568
- modifyItem ( 'y' , ya ?
569
- ya . p2r ( ya . r2p ( options . y ) + dy ) :
570
- ( options . y - ( dy / gs . h ) ) ) ;
617
+ modifyItem ( 'x' ,
618
+ shiftPosition ( xa , dx , 'x' , gs , options ) ) ;
619
+ modifyItem ( 'y' ,
620
+ shiftPosition ( ya , dy , 'y' , gs , options ) ) ;
571
621
622
+ // for these 2 calls to shiftPosition, it is assumed xa, ya are
623
+ // defined, so gsDim will not be used, but we put it in
624
+ // anyways for consistency
572
625
if ( options . axref === options . xref ) {
573
- modifyItem ( 'ax' , xa . p2r ( xa . r2p ( options . ax ) + dx ) ) ;
626
+ modifyItem ( 'ax' , shiftPosition ( xa , dx , 'ax' , gs , options ) ) ;
574
627
}
575
628
576
629
if ( options . ayref === options . yref ) {
577
- modifyItem ( 'ay' , ya . p2r ( ya . r2p ( options . ay ) + dy ) ) ;
630
+ modifyItem ( 'ay' , shiftPosition ( ya , dy , 'ay' , gs , options ) ) ;
578
631
}
579
632
580
633
arrowGroup . attr ( 'transform' , 'translate(' + dx + ',' + dy + ')' ) ;
@@ -609,14 +662,17 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
609
662
moveFn : function ( dx , dy ) {
610
663
var csr = 'pointer' ;
611
664
if ( options . showarrow ) {
665
+ // for these 2 calls to shiftPosition, it is assumed xa, ya are
666
+ // defined, so gsDim will not be used, but we put it in
667
+ // anyways for consistency
612
668
if ( options . axref === options . xref ) {
613
- modifyItem ( 'ax' , xa . p2r ( xa . r2p ( options . ax ) + dx ) ) ;
669
+ modifyItem ( 'ax' , shiftPosition ( xa , dx , 'ax' , gs , options ) ) ;
614
670
} else {
615
671
modifyItem ( 'ax' , options . ax + dx ) ;
616
672
}
617
673
618
674
if ( options . ayref === options . yref ) {
619
- modifyItem ( 'ay' , ya . p2r ( ya . r2p ( options . ay ) + dy ) ) ;
675
+ modifyItem ( 'ay' , shiftPosition ( ya , dy , 'ay' , gs . w , options ) ) ;
620
676
} else {
621
677
modifyItem ( 'ay' , options . ay + dy ) ;
622
678
}
@@ -625,7 +681,9 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
625
681
} else if ( ! subplotId ) {
626
682
var xUpdate , yUpdate ;
627
683
if ( xa ) {
628
- xUpdate = xa . p2r ( xa . r2p ( options . x ) + dx ) ;
684
+ // shiftPosition will not execute code where xa was
685
+ // undefined, so we use to calculate xUpdate too
686
+ xUpdate = shiftPosition ( xa , dx , 'x' , gs , options ) ;
629
687
} else {
630
688
var widthFraction = options . _xsize / gs . w ;
631
689
var xLeft = options . x + ( options . _xshift - options . xshift ) / gs . w - widthFraction / 2 ;
@@ -635,7 +693,9 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
635
693
}
636
694
637
695
if ( ya ) {
638
- yUpdate = ya . p2r ( ya . r2p ( options . y ) + dy ) ;
696
+ // shiftPosition will not execute code where ya was
697
+ // undefined, so we use to calculate yUpdate too
698
+ yUpdate = shiftPosition ( ya , dy , 'y' , gs , options ) ;
639
699
} else {
640
700
var heightFraction = options . _ysize / gs . h ;
641
701
var yBottom = options . y - ( options . _yshift + options . yshift ) / gs . h - heightFraction / 2 ;
0 commit comments