@@ -1687,19 +1687,13 @@ axes.doTicksSingle = function(gd, arg, skipTitle) {
16871687 vals = vals . filter ( ax . _tickFilter ) ;
16881688 }
16891689
1690- // remove zero lines, grid lines, and inside ticks if they're within
1691- // 1 pixel of the end
1690+ // Remove zero lines, grid lines, and inside ticks if they're within
1691+ // 1 pixel of the end.
16921692 // The key case here is removing zero lines when the axis bound is zero.
1693- function clipEnds ( d ) {
1694- var p = ax . l2p ( d . x ) ;
1695- return ( p > 1 && p < ax . _length - 1 ) ;
1696- }
1697- var valsClipped = vals . filter ( clipEnds ) ;
1698-
1699- // don't clip angular values
1700- if ( isAngular ( ax ) ) {
1701- valsClipped = vals ;
1702- }
1693+ // Don't clip angular values.
1694+ var valsClipped = ax . _valsClipped = isAngular ( ax ) ?
1695+ vals :
1696+ vals . filter ( function ( d ) { return clipEnds ( ax , d . x ) ; } ) ;
17031697
17041698 function drawTicks ( container , tickpath ) {
17051699 var ticks = container . selectAll ( 'path.' + tcls )
@@ -2142,69 +2136,17 @@ axes.doTicksSingle = function(gd, arg, skipTitle) {
21422136 } ) ;
21432137 }
21442138
2145- function traceHasBarsOrFill ( trace , subplot ) {
2146- if ( trace . visible !== true || trace . xaxis + trace . yaxis !== subplot ) return false ;
2147- if ( Registry . traceIs ( trace , 'bar' ) && trace . orientation === { x : 'h' , y : 'v' } [ axLetter ] ) return true ;
2148- return trace . fill && trace . fill . charAt ( trace . fill . length - 1 ) === axLetter ;
2149- }
2150-
2151- function lineNearZero ( ax2 , position ) {
2152- if ( ! ax2 . showline || ! ax2 . linewidth ) return false ;
2153- var tolerance = Math . max ( ( ax2 . linewidth + ax . zerolinewidth ) / 2 , 1 ) ;
2154-
2155- function closeEnough ( pos2 ) {
2156- return typeof pos2 === 'number' && Math . abs ( pos2 - position ) < tolerance ;
2157- }
2158-
2159- if ( closeEnough ( ax2 . _mainLinePosition ) || closeEnough ( ax2 . _mainMirrorPosition ) ) {
2160- return true ;
2161- }
2162- var linePositions = ax2 . _linepositions || { } ;
2163- for ( var k in linePositions ) {
2164- if ( closeEnough ( linePositions [ k ] [ 0 ] ) || closeEnough ( linePositions [ k ] [ 1 ] ) ) {
2165- return true ;
2166- }
2167- }
2168- }
2169-
2170- function anyCounterAxLineAtZero ( counterAxis , rng ) {
2171- var mainCounterAxis = counterAxis . _mainAxis ;
2172- if ( ! mainCounterAxis ) return ;
2173-
2174- var zeroPosition = ax . _offset + (
2175- ( ( Math . abs ( rng [ 0 ] ) < Math . abs ( rng [ 1 ] ) ) === ( axLetter === 'x' ) ) ?
2176- 0 : ax . _length
2177- ) ;
2178-
2179- var plotinfo = fullLayout . _plots [ counterAxis . _mainSubplot ] ;
2180- if ( ! ( plotinfo . mainplotinfo || plotinfo ) . overlays . length ) {
2181- return lineNearZero ( counterAxis , zeroPosition ) ;
2182- }
2183-
2184- var counterLetterAxes = axes . list ( gd , counterLetter ) ;
2185- for ( var i = 0 ; i < counterLetterAxes . length ; i ++ ) {
2186- var counterAxis2 = counterLetterAxes [ i ] ;
2187- if (
2188- counterAxis2 . _mainAxis === mainCounterAxis &&
2189- lineNearZero ( counterAxis2 , zeroPosition )
2190- ) {
2191- return true ;
2192- }
2193- }
2194- }
2195-
2196- function drawGrid ( plotinfo , counteraxis , subplot ) {
2139+ function drawGrid ( plotinfo , counteraxis ) {
21972140 if ( fullLayout . _hasOnlyLargeSploms ) return ;
21982141
21992142 var gridcontainer = plotinfo . gridlayer . selectAll ( '.' + axid ) ;
22002143 var zlcontainer = plotinfo . zerolinelayer ;
2201- var gridvals = plotinfo [ 'hidegrid' + axLetter ] ? [ ] : valsClipped ;
22022144 var gridpath = ax . _gridpath || ( ( axLetter === 'x' ?
22032145 ( 'M0,' + counteraxis . _offset + 'v' ) :
22042146 ( 'M' + counteraxis . _offset + ',0h' )
22052147 ) + counteraxis . _length ) ;
22062148 var grid = gridcontainer . selectAll ( 'path.' + gcls )
2207- . data ( ( ax . showgrid === false ) ? [ ] : gridvals , datafn ) ;
2149+ . data ( ( ax . showgrid === false ) ? [ ] : valsClipped , datafn ) ;
22082150 grid . enter ( ) . append ( 'path' ) . classed ( gcls , 1 )
22092151 . classed ( 'crisp' , 1 )
22102152 . attr ( 'd' , gridpath )
@@ -2222,24 +2164,8 @@ axes.doTicksSingle = function(gd, arg, skipTitle) {
22222164
22232165 // zero line
22242166 if ( zlcontainer ) {
2225- var hasBarsOrFill = false ;
2226- for ( var i = 0 ; i < gd . _fullData . length ; i ++ ) {
2227- if ( traceHasBarsOrFill ( gd . _fullData [ i ] , subplot ) ) {
2228- hasBarsOrFill = true ;
2229- break ;
2230- }
2231- }
2232- var rng = Lib . simpleMap ( ax . range , ax . r2l ) ;
22332167 var zlData = { x : 0 , id : axid } ;
2234-
2235- var showZl = ( rng [ 0 ] * rng [ 1 ] <= 0 ) && ax . zeroline &&
2236- ( ax . type === 'linear' || ax . type === '-' ) && gridvals . length &&
2237- (
2238- hasBarsOrFill ||
2239- clipEnds ( zlData ) ||
2240- ! anyCounterAxLineAtZero ( counteraxis , rng )
2241- ) ;
2242-
2168+ var showZl = axes . shouldShowZeroLine ( gd , ax , counteraxis ) ;
22432169 var zl = zlcontainer . selectAll ( 'path.' + zcls )
22442170 . data ( showZl ? [ zlData ] : [ ] ) ;
22452171 zl . enter ( ) . append ( 'path' ) . classed ( zcls , 1 ) . classed ( 'zl' , 1 )
@@ -2327,6 +2253,96 @@ axes.doTicksSingle = function(gd, arg, skipTitle) {
23272253 }
23282254} ;
23292255
2256+ axes . shouldShowZeroLine = function ( gd , ax , counterAxis ) {
2257+ var rng = Lib . simpleMap ( ax . range , ax . r2l ) ;
2258+ return (
2259+ ( rng [ 0 ] * rng [ 1 ] <= 0 ) &&
2260+ ax . zeroline &&
2261+ ( ax . type === 'linear' || ax . type === '-' ) &&
2262+ ax . _valsClipped . length &&
2263+ (
2264+ clipEnds ( ax , 0 ) ||
2265+ ! anyCounterAxLineAtZero ( gd , ax , counterAxis , rng ) ||
2266+ hasBarsOrFill ( gd , ax )
2267+ )
2268+ ) ;
2269+ } ;
2270+
2271+ function clipEnds ( ax , l ) {
2272+ var p = ax . l2p ( l ) ;
2273+ return ( p > 1 && p < ax . _length - 1 ) ;
2274+ }
2275+
2276+ function anyCounterAxLineAtZero ( gd , ax , counterAxis , rng ) {
2277+ var mainCounterAxis = counterAxis . _mainAxis ;
2278+ if ( ! mainCounterAxis ) return ;
2279+
2280+ var fullLayout = gd . _fullLayout ;
2281+ var axLetter = ax . _id . charAt ( 0 ) ;
2282+ var counterLetter = axes . counterLetter ( ax . _id ) ;
2283+
2284+ var zeroPosition = ax . _offset + (
2285+ ( ( Math . abs ( rng [ 0 ] ) < Math . abs ( rng [ 1 ] ) ) === ( axLetter === 'x' ) ) ?
2286+ 0 : ax . _length
2287+ ) ;
2288+
2289+ function lineNearZero ( ax2 ) {
2290+ if ( ! ax2 . showline || ! ax2 . linewidth ) return false ;
2291+ var tolerance = Math . max ( ( ax2 . linewidth + ax . zerolinewidth ) / 2 , 1 ) ;
2292+
2293+ function closeEnough ( pos2 ) {
2294+ return typeof pos2 === 'number' && Math . abs ( pos2 - zeroPosition ) < tolerance ;
2295+ }
2296+
2297+ if ( closeEnough ( ax2 . _mainLinePosition ) || closeEnough ( ax2 . _mainMirrorPosition ) ) {
2298+ return true ;
2299+ }
2300+ var linePositions = ax2 . _linepositions || { } ;
2301+ for ( var k in linePositions ) {
2302+ if ( closeEnough ( linePositions [ k ] [ 0 ] ) || closeEnough ( linePositions [ k ] [ 1 ] ) ) {
2303+ return true ;
2304+ }
2305+ }
2306+ }
2307+
2308+ var plotinfo = fullLayout . _plots [ counterAxis . _mainSubplot ] ;
2309+ if ( ! ( plotinfo . mainplotinfo || plotinfo ) . overlays . length ) {
2310+ return lineNearZero ( counterAxis , zeroPosition ) ;
2311+ }
2312+
2313+ var counterLetterAxes = axes . list ( gd , counterLetter ) ;
2314+ for ( var i = 0 ; i < counterLetterAxes . length ; i ++ ) {
2315+ var counterAxis2 = counterLetterAxes [ i ] ;
2316+ if (
2317+ counterAxis2 . _mainAxis === mainCounterAxis &&
2318+ lineNearZero ( counterAxis2 , zeroPosition )
2319+ ) {
2320+ return true ;
2321+ }
2322+ }
2323+ }
2324+
2325+ function hasBarsOrFill ( gd , ax ) {
2326+ var fullData = gd . _fullData ;
2327+ var subplot = ax . _mainSubplot ;
2328+ var axLetter = ax . _id . charAt ( 0 ) ;
2329+
2330+ for ( var i = 0 ; i < fullData . length ; i ++ ) {
2331+ var trace = fullData [ i ] ;
2332+
2333+ if ( trace . visible === true &&
2334+ ( trace . xaxis + trace . yaxis ) === subplot &&
2335+ (
2336+ Registry . traceIs ( trace , 'bar' ) && trace . orientation === { x : 'h' , y : 'v' } [ axLetter ] ||
2337+ trace . fill && trace . fill . charAt ( trace . fill . length - 1 ) === axLetter
2338+ )
2339+ ) {
2340+ return true ;
2341+ }
2342+ }
2343+ return false ;
2344+ }
2345+
23302346/**
23312347 * Find all margin pushers for 2D axes and reserve them for later use
23322348 * Both label and rangeslider automargin calculations happen later so
0 commit comments