@@ -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,58 +2136,7 @@ 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 ) ;
@@ -2204,7 +2147,7 @@ axes.doTicksSingle = function(gd, arg, skipTitle) {
22042147 ( 'M' + counteraxis . _offset + ',0h' )
22052148 ) + counteraxis . _length ) ;
22062149 var grid = gridcontainer . selectAll ( 'path.' + gcls )
2207- . data ( ( ax . showgrid === false ) ? [ ] : gridvals , datafn ) ;
2150+ . data ( ( ax . showgrid === false ) ? [ ] : valsClipped , datafn ) ;
22082151 grid . enter ( ) . append ( 'path' ) . classed ( gcls , 1 )
22092152 . classed ( 'crisp' , 1 )
22102153 . attr ( 'd' , gridpath )
@@ -2222,24 +2165,8 @@ axes.doTicksSingle = function(gd, arg, skipTitle) {
22222165
22232166 // zero line
22242167 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 ) ;
22332168 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-
2169+ var showZl = axes . shouldShowZeroLine ( gd , ax , counteraxis ) ;
22432170 var zl = zlcontainer . selectAll ( 'path.' + zcls )
22442171 . data ( showZl ? [ zlData ] : [ ] ) ;
22452172 zl . enter ( ) . append ( 'path' ) . classed ( zcls , 1 ) . classed ( 'zl' , 1 )
@@ -2327,6 +2254,96 @@ axes.doTicksSingle = function(gd, arg, skipTitle) {
23272254 }
23282255} ;
23292256
2257+ axes . shouldShowZeroLine = function ( gd , ax , counterAxis ) {
2258+ var rng = Lib . simpleMap ( ax . range , ax . r2l ) ;
2259+ return (
2260+ ( rng [ 0 ] * rng [ 1 ] <= 0 ) &&
2261+ ax . zeroline &&
2262+ ( ax . type === 'linear' || ax . type === '-' ) &&
2263+ ax . _valsClipped . length &&
2264+ (
2265+ clipEnds ( ax , 0 ) ||
2266+ ! anyCounterAxLineAtZero ( gd , ax , counterAxis , rng ) ||
2267+ hasBarsOrFill ( gd , ax )
2268+ )
2269+ ) ;
2270+ } ;
2271+
2272+ function clipEnds ( ax , l ) {
2273+ var p = ax . l2p ( l ) ;
2274+ return ( p > 1 && p < ax . _length - 1 ) ;
2275+ }
2276+
2277+ function anyCounterAxLineAtZero ( gd , ax , counterAxis , rng ) {
2278+ var mainCounterAxis = counterAxis . _mainAxis ;
2279+ if ( ! mainCounterAxis ) return ;
2280+
2281+ var fullLayout = gd . _fullLayout ;
2282+ var axLetter = ax . _id . charAt ( 0 ) ;
2283+ var counterLetter = axes . counterLetter ( ax . _id ) ;
2284+
2285+ var zeroPosition = ax . _offset + (
2286+ ( ( Math . abs ( rng [ 0 ] ) < Math . abs ( rng [ 1 ] ) ) === ( axLetter === 'x' ) ) ?
2287+ 0 : ax . _length
2288+ ) ;
2289+
2290+ function lineNearZero ( ax2 ) {
2291+ if ( ! ax2 . showline || ! ax2 . linewidth ) return false ;
2292+ var tolerance = Math . max ( ( ax2 . linewidth + ax . zerolinewidth ) / 2 , 1 ) ;
2293+
2294+ function closeEnough ( pos2 ) {
2295+ return typeof pos2 === 'number' && Math . abs ( pos2 - zeroPosition ) < tolerance ;
2296+ }
2297+
2298+ if ( closeEnough ( ax2 . _mainLinePosition ) || closeEnough ( ax2 . _mainMirrorPosition ) ) {
2299+ return true ;
2300+ }
2301+ var linePositions = ax2 . _linepositions || { } ;
2302+ for ( var k in linePositions ) {
2303+ if ( closeEnough ( linePositions [ k ] [ 0 ] ) || closeEnough ( linePositions [ k ] [ 1 ] ) ) {
2304+ return true ;
2305+ }
2306+ }
2307+ }
2308+
2309+ var plotinfo = fullLayout . _plots [ counterAxis . _mainSubplot ] ;
2310+ if ( ! ( plotinfo . mainplotinfo || plotinfo ) . overlays . length ) {
2311+ return lineNearZero ( counterAxis , zeroPosition ) ;
2312+ }
2313+
2314+ var counterLetterAxes = axes . list ( gd , counterLetter ) ;
2315+ for ( var i = 0 ; i < counterLetterAxes . length ; i ++ ) {
2316+ var counterAxis2 = counterLetterAxes [ i ] ;
2317+ if (
2318+ counterAxis2 . _mainAxis === mainCounterAxis &&
2319+ lineNearZero ( counterAxis2 , zeroPosition )
2320+ ) {
2321+ return true ;
2322+ }
2323+ }
2324+ }
2325+
2326+ function hasBarsOrFill ( gd , ax ) {
2327+ var fullData = gd . _fullData ;
2328+ var subplot = ax . _mainSubplot ;
2329+ var axLetter = ax . _id . charAt ( 0 ) ;
2330+
2331+ for ( var i = 0 ; i < fullData . length ; i ++ ) {
2332+ var trace = fullData [ i ] ;
2333+
2334+ if ( trace . visible === true &&
2335+ ( trace . xaxis + trace . yaxis ) === subplot &&
2336+ (
2337+ Registry . traceIs ( trace , 'bar' ) && trace . orientation === { x : 'h' , y : 'v' } [ axLetter ] ||
2338+ trace . fill && trace . fill . charAt ( trace . fill . length - 1 ) === axLetter
2339+ )
2340+ ) {
2341+ return true ;
2342+ }
2343+ }
2344+ return false ;
2345+ }
2346+
23302347/**
23312348 * Find all margin pushers for 2D axes and reserve them for later use
23322349 * Both label and rangeslider automargin calculations happen later so
0 commit comments