Skip to content

Commit e182686

Browse files
authored
Merge pull request #5550 from plotly/hide-gridlines-inside-ticklabels
Hide gridlines and ticks overlapping inside ticklabels
2 parents dbf9364 + e683b07 commit e182686

12 files changed

+117
-23
lines changed

src/plots/cartesian/axes.js

+106-16
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ var ONESEC = constants.ONESEC;
3434
var MINUS_SIGN = constants.MINUS_SIGN;
3535
var BADNUM = constants.BADNUM;
3636

37+
var ZERO_PATH = { K: 'zeroline' };
38+
var GRID_PATH = { K: 'gridline', L: 'path' };
39+
var TICK_PATH = { K: 'tick', L: 'path' };
40+
var TICK_TEXT = { K: 'tick', L: 'text' };
41+
3742
var alignmentConstants = require('../../constants/alignment');
3843
var MID_SHIFT = alignmentConstants.MID_SHIFT;
3944
var CAP_SHIFT = alignmentConstants.CAP_SHIFT;
@@ -1449,7 +1454,7 @@ function formatDate(ax, out, hover, extraPrecision) {
14491454
ax._prevDateHead = headStr;
14501455
dateStr += '<br>' + headStr;
14511456
} else {
1452-
var isInside = (ax.ticklabelposition || '').indexOf('inside') !== -1;
1457+
var isInside = insideTicklabelposition(ax);
14531458
var side = ax._realSide || ax.side; // polar mocks the side of the radial axis
14541459
if(
14551460
(!isInside && side === 'top') ||
@@ -2180,6 +2185,7 @@ axes.drawOne = function(gd, ax, opts) {
21802185
return axes.drawLabels(gd, ax, {
21812186
vals: vals,
21822187
layer: mainAxLayer,
2188+
plotinfo: plotinfo,
21832189
transFn: transTickLabelFn,
21842190
labelFns: axes.makeLabelFns(ax, mainLinePosition)
21852191
});
@@ -2798,7 +2804,10 @@ axes.drawTicks = function(gd, ax, opts) {
27982804
.classed('crisp', opts.crisp !== false)
27992805
.call(Color.stroke, ax.tickcolor)
28002806
.style('stroke-width', Drawing.crispRound(gd, ax.tickwidth, 1) + 'px')
2801-
.attr('d', opts.path);
2807+
.attr('d', opts.path)
2808+
.style('display', null); // visible
2809+
2810+
hideCounterAxisInsideTickLabels(ax, [TICK_PATH]);
28022811

28032812
ticks.attr('transform', opts.transFn);
28042813
};
@@ -2861,7 +2870,10 @@ axes.drawGrid = function(gd, ax, opts) {
28612870
grid.attr('transform', opts.transFn)
28622871
.attr('d', opts.path)
28632872
.call(Color.stroke, ax.gridcolor || '#ddd')
2864-
.style('stroke-width', ax._gw + 'px');
2873+
.style('stroke-width', ax._gw + 'px')
2874+
.style('display', null); // visible
2875+
2876+
hideCounterAxisInsideTickLabels(ax, [GRID_PATH]);
28652877

28662878
if(typeof opts.path === 'function') grid.attr('d', opts.path);
28672879
};
@@ -2910,7 +2922,10 @@ axes.drawZeroLine = function(gd, ax, opts) {
29102922
zl.attr('transform', opts.transFn)
29112923
.attr('d', opts.path)
29122924
.call(Color.stroke, ax.zerolinecolor || Color.defaultLine)
2913-
.style('stroke-width', Drawing.crispRound(gd, ax.zerolinewidth, ax._gw || 1) + 'px');
2925+
.style('stroke-width', Drawing.crispRound(gd, ax.zerolinewidth, ax._gw || 1) + 'px')
2926+
.style('display', null); // visible
2927+
2928+
hideCounterAxisInsideTickLabels(ax, [ZERO_PATH]);
29142929
};
29152930

29162931
/**
@@ -2983,7 +2998,10 @@ axes.drawLabels = function(gd, ax, opts) {
29832998
// sync label: just position it now.
29842999
positionLabels(thisLabel, tickAngle);
29853000
}
2986-
});
3001+
})
3002+
.style('display', null); // visible
3003+
3004+
hideCounterAxisInsideTickLabels(ax, [TICK_TEXT]);
29873005

29883006
tickLabels.exit().remove();
29893007

@@ -2995,7 +3013,7 @@ axes.drawLabels = function(gd, ax, opts) {
29953013
}
29963014

29973015
function positionLabels(s, angle) {
2998-
var isInside = (ax.ticklabelposition || '').indexOf('inside') !== -1;
3016+
var isInside = insideTicklabelposition(ax);
29993017

30003018
s.each(function(d) {
30013019
var thisLabel = d3.select(this);
@@ -3025,8 +3043,7 @@ axes.drawLabels = function(gd, ax, opts) {
30253043
});
30263044

30273045
if(isInside) {
3028-
// ensure visible
3029-
thisText.style({ opacity: 100 });
3046+
thisText.style('opacity', 0); // visible
30303047

30313048
if(ax._hideOutOfRangeInsideTickLabels) {
30323049
ax._hideOutOfRangeInsideTickLabels();
@@ -3040,9 +3057,8 @@ axes.drawLabels = function(gd, ax, opts) {
30403057
});
30413058
}
30423059

3043-
ax._hideOutOfRangeInsideTickLabels = undefined;
3044-
if((ax.ticklabelposition || '').indexOf('inside') !== -1) {
3045-
ax._hideOutOfRangeInsideTickLabels = function() {
3060+
ax._hideOutOfRangeInsideTickLabels = function() {
3061+
if(insideTicklabelposition(ax)) {
30463062
var rl = Lib.simpleMap(ax.range, ax.r2l);
30473063

30483064
// hide inside tick labels that go outside axis end points
@@ -3052,8 +3068,12 @@ axes.drawLabels = function(gd, ax, opts) {
30523068
var min = Math.min(p0, p1) + ax._offset;
30533069
var max = Math.max(p0, p1) + ax._offset;
30543070

3071+
var side = ax.side;
30553072
var isX = ax._id.charAt(0) === 'x';
30563073

3074+
var visibleLabelMin = Infinity;
3075+
var visibleLabelMax = -Infinity;
3076+
30573077
tickLabels.each(function(d) {
30583078
var thisLabel = d3.select(this);
30593079
var mathjaxGroup = thisLabel.select('.text-math-group');
@@ -3068,11 +3088,69 @@ axes.drawLabels = function(gd, ax, opts) {
30683088
if(bb.bottom > max) hide = true;
30693089
else if(bb.top + (ax.tickangle ? 0 : d.fontSize / 4) < min) hide = true;
30703090
}
3071-
if(hide) thisLabel.select('text').style({ opacity: 0 });
3091+
3092+
var t = thisLabel.select('text');
3093+
if(hide) {
3094+
t.style('opacity', 0); // hidden
3095+
} else {
3096+
t.style('opacity', 1); // visible
3097+
3098+
if(side === 'bottom' || side === 'right') {
3099+
visibleLabelMin = Math.min(visibleLabelMin, isX ? bb.top : bb.left);
3100+
} else {
3101+
visibleLabelMin = -Infinity;
3102+
}
3103+
3104+
if(side === 'top' || side === 'left') {
3105+
visibleLabelMax = Math.max(visibleLabelMax, isX ? bb.bottom : bb.right);
3106+
} else {
3107+
visibleLabelMax = Infinity;
3108+
}
3109+
}
30723110
} // TODO: hide mathjax?
30733111
});
3074-
};
3075-
}
3112+
3113+
if(ax._anchorAxis) {
3114+
ax._anchorAxis._visibleLabelMin = visibleLabelMin;
3115+
ax._anchorAxis._visibleLabelMax = visibleLabelMax;
3116+
}
3117+
}
3118+
};
3119+
3120+
ax._hideCounterAxisInsideTickLabels = function(partialOpts) {
3121+
if(insideTicklabelposition(ax._anchorAxis || {})) {
3122+
(partialOpts || [
3123+
ZERO_PATH,
3124+
GRID_PATH,
3125+
TICK_PATH,
3126+
TICK_TEXT
3127+
]).forEach(function(e) {
3128+
var isTickText = e.K === 'tick' && e.L === 'text';
3129+
if(isTickText && ax.ticklabelmode === 'period') return;
3130+
3131+
var sel;
3132+
if(e.K === ZERO_PATH.K) sel = opts.plotinfo.zerolinelayer.selectAll('.' + ax._id + 'zl');
3133+
else if(e.K === GRID_PATH.K) sel = opts.plotinfo.gridlayer.selectAll('.' + ax._id);
3134+
else sel = opts.plotinfo[ax._id.charAt(0) + 'axislayer'];
3135+
3136+
sel.each(function() {
3137+
var w = d3.select(this);
3138+
if(e.L) w = w.selectAll(e.L);
3139+
3140+
w.each(function(d) {
3141+
var q = ax.l2p(d.x) + ax._offset;
3142+
3143+
var t = d3.select(this);
3144+
if(q < ax._visibleLabelMax && q > ax._visibleLabelMin) {
3145+
t.style('display', 'none'); // hidden
3146+
} else if(e.K === 'tick') {
3147+
t.style('display', null); // visible
3148+
}
3149+
});
3150+
});
3151+
});
3152+
}
3153+
};
30763154

30773155
// make sure all labels are correctly positioned at their base angle
30783156
// the positionLabels call above is only for newly drawn labels.
@@ -3201,7 +3279,7 @@ axes.drawLabels = function(gd, ax, opts) {
32013279
var anchorAx = ax._anchorAxis;
32023280
if(
32033281
anchorAx && anchorAx.autorange &&
3204-
(ax.ticklabelposition || '').indexOf('inside') !== -1 &&
3282+
insideTicklabelposition(ax) &&
32053283
!isLinked(fullLayout, ax._id)
32063284
) {
32073285
if(!fullLayout._insideTickLabelsAutorange) {
@@ -3350,7 +3428,7 @@ function drawTitle(gd, ax) {
33503428
if(ax.title.hasOwnProperty('standoff')) {
33513429
titleStandoff = ax._depth + ax.title.standoff + approxTitleDepth(ax);
33523430
} else {
3353-
var isInside = (ax.ticklabelposition || '').indexOf('inside') !== -1;
3431+
var isInside = insideTicklabelposition(ax);
33543432

33553433
if(ax.type === 'multicategory') {
33563434
titleStandoff = ax._depth;
@@ -3708,3 +3786,15 @@ function moveOutsideBreak(v, ax) {
37083786
}
37093787
return v;
37103788
}
3789+
3790+
function insideTicklabelposition(ax) {
3791+
return ((ax.ticklabelposition || '').indexOf('inside') !== -1);
3792+
}
3793+
3794+
function hideCounterAxisInsideTickLabels(ax, opts) {
3795+
if(insideTicklabelposition(ax._anchorAxis || {})) {
3796+
if(ax._hideCounterAxisInsideTickLabels) {
3797+
ax._hideCounterAxisInsideTickLabels(opts);
3798+
}
3799+
}
3800+
}

src/plots/plots.js

+11-7
Original file line numberDiff line numberDiff line change
@@ -2076,17 +2076,21 @@ plots.doAutoMargin = function(gd) {
20762076
}
20772077
}
20782078

2079-
hideOutOfRangeInsideTickLabels(gd);
2079+
hideInsideTickLabels(gd);
20802080
};
20812081

2082-
function hideOutOfRangeInsideTickLabels(gd) {
2082+
function hideInsideTickLabels(gd) {
20832083
var axList = axisIDs.list(gd, '', true);
2084-
for(var i = 0; i < axList.length; i++) {
2085-
var ax = axList[i];
20862084

2087-
var hideFn = ax._hideOutOfRangeInsideTickLabels;
2088-
if(hideFn) hideFn();
2089-
}
2085+
[
2086+
'_hideOutOfRangeInsideTickLabels',
2087+
'_hideCounterAxisInsideTickLabels'
2088+
].forEach(function(k) {
2089+
for(var i = 0; i < axList.length; i++) {
2090+
var hideFn = axList[i][k];
2091+
if(hideFn) hideFn();
2092+
}
2093+
});
20902094
}
20912095

20922096
var marginKeys = ['l', 'r', 't', 'b', 'p', 'w', 'h'];
Loading
-4.59 KB
Loading
-3.57 KB
Loading
-772 Bytes
Loading
-639 Bytes
Loading
-10.6 KB
Loading
-366 Bytes
Loading
-1.58 KB
Loading
-3.76 KB
Loading
-1.16 KB
Loading

0 commit comments

Comments
 (0)