Skip to content

Commit 637e6c9

Browse files
committed
pull out should-have-zeroline logic from doTicks
- in the process, pull out clipEnds, anyCounterAxLineAtZero and hasBarsOrFill - attach 'clipped' grid values to ax._valsClipped
1 parent e545415 commit 637e6c9

File tree

1 file changed

+99
-82
lines changed

1 file changed

+99
-82
lines changed

src/plots/cartesian/axes.js

Lines changed: 99 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)