@@ -1632,7 +1632,7 @@ axes.doTicks = function(gd, axid, skipTitle) {
16321632 // set scaling to pixels
16331633 ax . setScale ( ) ;
16341634
1635- var axletter = axid . charAt ( 0 ) ,
1635+ var axLetter = axid . charAt ( 0 ) ,
16361636 counterLetter = axes . counterLetter ( axid ) ,
16371637 vals = axes . calcTicks ( ax ) ,
16381638 datafn = function ( d ) { return [ d . text , d . x , ax . mirror ] . join ( '_' ) ; } ,
@@ -1646,7 +1646,7 @@ axes.doTicks = function(gd, axid, skipTitle) {
16461646 gridWidth = Drawing . crispRound ( gd , ax . gridwidth , 1 ) ,
16471647 zeroLineWidth = Drawing . crispRound ( gd , ax . zerolinewidth , gridWidth ) ,
16481648 tickWidth = Drawing . crispRound ( gd , ax . tickwidth , 1 ) ,
1649- sides , transfn , tickpathfn ,
1649+ sides , transfn , tickpathfn , subplots ,
16501650 i ;
16511651
16521652 if ( ax . _counterangle && ax . ticks === 'outside' ) {
@@ -1656,7 +1656,7 @@ axes.doTicks = function(gd, axid, skipTitle) {
16561656 }
16571657
16581658 // positioning arguments for x vs y axes
1659- if ( axletter === 'x' ) {
1659+ if ( axLetter === 'x' ) {
16601660 sides = [ 'bottom' , 'top' ] ;
16611661 transfn = function ( d ) {
16621662 return 'translate(' + ax . l2p ( d . x ) + ',0)' ;
@@ -1669,7 +1669,7 @@ axes.doTicks = function(gd, axid, skipTitle) {
16691669 else return 'M0,' + shift + 'v' + len ;
16701670 } ;
16711671 }
1672- else if ( axletter === 'y' ) {
1672+ else if ( axLetter === 'y' ) {
16731673 sides = [ 'left' , 'right' ] ;
16741674 transfn = function ( d ) {
16751675 return 'translate(0,' + ax . l2p ( d . x ) + ')' ;
@@ -1690,7 +1690,7 @@ axes.doTicks = function(gd, axid, skipTitle) {
16901690 // which direction do the side[0], side[1], and free ticks go?
16911691 // then we flip if outside XOR y axis
16921692 ticksign = [ - 1 , 1 , axside === sides [ 1 ] ? 1 : - 1 ] ;
1693- if ( ( ax . ticks !== 'inside' ) === ( axletter === 'x' ) ) {
1693+ if ( ( ax . ticks !== 'inside' ) === ( axLetter === 'x' ) ) {
16941694 ticksign = ticksign . map ( function ( v ) { return - v ; } ) ;
16951695 }
16961696
@@ -1724,12 +1724,12 @@ axes.doTicks = function(gd, axid, skipTitle) {
17241724 var tickLabels = container . selectAll ( 'g.' + tcls ) . data ( vals , datafn ) ;
17251725 if ( ! ax . showticklabels || ! isNumeric ( position ) ) {
17261726 tickLabels . remove ( ) ;
1727- drawAxTitle ( axid ) ;
1727+ drawAxTitle ( ) ;
17281728 return ;
17291729 }
17301730
17311731 var labelx , labely , labelanchor , labelpos0 , flipit ;
1732- if ( axletter === 'x' ) {
1732+ if ( axLetter === 'x' ) {
17331733 flipit = ( axside === 'bottom' ) ? 1 : - 1 ;
17341734 labelx = function ( d ) { return d . dx + labelShift * flipit ; } ;
17351735 labelpos0 = position + ( labelStandoff + pad ) * flipit ;
@@ -1845,7 +1845,7 @@ axes.doTicks = function(gd, axid, skipTitle) {
18451845 // check for auto-angling if x labels overlap
18461846 // don't auto-angle at all for log axes with
18471847 // base and digit format
1848- if ( axletter === 'x' && ! isNumeric ( ax . tickangle ) &&
1848+ if ( axLetter === 'x' && ! isNumeric ( ax . tickangle ) &&
18491849 ( ax . type !== 'log' || String ( ax . dtick ) . charAt ( 0 ) !== 'D' ) ) {
18501850 var lbbArray = [ ] ;
18511851 tickLabels . each ( function ( d ) {
@@ -1890,12 +1890,59 @@ axes.doTicks = function(gd, axid, skipTitle) {
18901890 // (so it can move out of the way if needed)
18911891 // TODO: separate out scoot so we don't need to do
18921892 // a full redraw of the title (mostly relevant for MathJax)
1893- drawAxTitle ( axid ) ;
1893+ drawAxTitle ( ) ;
18941894 return axid + ' done' ;
18951895 }
18961896
18971897 function calcBoundingBox ( ) {
1898- ax . _boundingBox = container . node ( ) . getBoundingClientRect ( ) ;
1898+ var bBox = container . node ( ) . getBoundingClientRect ( ) ;
1899+ var gdBB = gd . getBoundingClientRect ( ) ;
1900+
1901+ /*
1902+ * the way we're going to use this, the positioning that matters
1903+ * is relative to the origin of gd. This is important particularly
1904+ * if gd is scrollable, and may have been scrolled between the time
1905+ * we calculate this and the time we use it
1906+ */
1907+ var bbFinal = ax . _boundingBox = {
1908+ width : bBox . width ,
1909+ height : bBox . height ,
1910+ left : bBox . left - gdBB . left ,
1911+ right : bBox . right - gdBB . left ,
1912+ top : bBox . top - gdBB . top ,
1913+ bottom : bBox . bottom - gdBB . top
1914+ } ;
1915+
1916+ /*
1917+ * for spikelines: what's the full domain of positions in the
1918+ * opposite direction that are associated with this axis?
1919+ * This means any axes that we make a subplot with, plus the
1920+ * position of the axis itself if it's free.
1921+ */
1922+ if ( subplots ) {
1923+ var fullRange = ax . _counterSpan = [ Infinity , - Infinity ] ;
1924+
1925+ for ( i = 0 ; i < subplots . length ; i ++ ) {
1926+ var subplot = fullLayout . _plots [ subplots [ i ] ] ;
1927+ var counterAxis = subplot [ ( axLetter === 'x' ) ? 'yaxis' : 'xaxis' ] ;
1928+
1929+ extendRange ( fullRange , [
1930+ counterAxis . _offset ,
1931+ counterAxis . _offset + counterAxis . _length
1932+ ] ) ;
1933+ }
1934+
1935+ if ( ax . anchor === 'free' ) {
1936+ extendRange ( fullRange , ( axLetter === 'x' ) ?
1937+ [ ax . _boundingBox . bottom , ax . _boundingBox . top ] :
1938+ [ ax . _boundingBox . right , ax . _boundingBox . left ] ) ;
1939+ }
1940+ }
1941+
1942+ function extendRange ( range , newRange ) {
1943+ range [ 0 ] = Math . min ( range [ 0 ] , newRange [ 0 ] ) ;
1944+ range [ 1 ] = Math . max ( range [ 1 ] , newRange [ 1 ] ) ;
1945+ }
18991946 }
19001947
19011948 var done = Lib . syncOrAsync ( [
@@ -1907,7 +1954,7 @@ axes.doTicks = function(gd, axid, skipTitle) {
19071954 return done ;
19081955 }
19091956
1910- function drawAxTitle ( axid ) {
1957+ function drawAxTitle ( ) {
19111958 if ( skipTitle ) return ;
19121959
19131960 // now this only applies to regular cartesian axes; colorbars and
@@ -1978,16 +2025,16 @@ axes.doTicks = function(gd, axid, skipTitle) {
19782025
19792026 function traceHasBarsOrFill ( trace , subplot ) {
19802027 if ( trace . visible !== true || trace . xaxis + trace . yaxis !== subplot ) return false ;
1981- if ( Registry . traceIs ( trace , 'bar' ) && trace . orientation === { x : 'h' , y : 'v' } [ axletter ] ) return true ;
1982- return trace . fill && trace . fill . charAt ( trace . fill . length - 1 ) === axletter ;
2028+ if ( Registry . traceIs ( trace , 'bar' ) && trace . orientation === { x : 'h' , y : 'v' } [ axLetter ] ) return true ;
2029+ return trace . fill && trace . fill . charAt ( trace . fill . length - 1 ) === axLetter ;
19832030 }
19842031
19852032 function drawGrid ( plotinfo , counteraxis , subplot ) {
19862033 var gridcontainer = plotinfo . gridlayer ,
19872034 zlcontainer = plotinfo . zerolinelayer ,
1988- gridvals = plotinfo [ 'hidegrid' + axletter ] ? [ ] : valsClipped ,
2035+ gridvals = plotinfo [ 'hidegrid' + axLetter ] ? [ ] : valsClipped ,
19892036 gridpath = ax . _gridpath ||
1990- 'M0,0' + ( ( axletter === 'x' ) ? 'v' : 'h' ) + counteraxis . _length ,
2037+ 'M0,0' + ( ( axLetter === 'x' ) ? 'v' : 'h' ) + counteraxis . _length ,
19912038 grid = gridcontainer . selectAll ( 'path.' + gcls )
19922039 . data ( ( ax . showgrid === false ) ? [ ] : gridvals , datafn ) ;
19932040 grid . enter ( ) . append ( 'path' ) . classed ( gcls , 1 )
@@ -2041,12 +2088,13 @@ axes.doTicks = function(gd, axid, skipTitle) {
20412088 return drawLabels ( ax . _axislayer , ax . _pos ) ;
20422089 }
20432090 else {
2044- var alldone = axes . getSubplots ( gd , ax ) . map ( function ( subplot ) {
2091+ subplots = axes . getSubplots ( gd , ax ) ;
2092+ var alldone = subplots . map ( function ( subplot ) {
20452093 var plotinfo = fullLayout . _plots [ subplot ] ;
20462094
20472095 if ( ! fullLayout . _has ( 'cartesian' ) ) return ;
20482096
2049- var container = plotinfo [ axletter + 'axislayer' ] ,
2097+ var container = plotinfo [ axLetter + 'axislayer' ] ,
20502098
20512099 // [bottom or left, top or right, free, main]
20522100 linepositions = ax . _linepositions [ subplot ] || [ ] ,
0 commit comments