Skip to content

Commit 1dee68b

Browse files
authored
Merge pull request #4216 from plotly/automargin-max-number-of-redraws
More auto-margin fixes (some of them temporary)
2 parents 8b7c737 + 9a665db commit 1dee68b

File tree

4 files changed

+71
-16
lines changed

4 files changed

+71
-16
lines changed

src/plots/cartesian/axes.js

+37-15
Original file line numberDiff line numberDiff line change
@@ -1643,6 +1643,7 @@ axes.draw = function(gd, arg, opts) {
16431643
* - ax._anchorAxis
16441644
* - ax._subplotsWith
16451645
* - ax._counterDomainMin, ax._counterDomainMax (optionally, from linkSubplots)
1646+
* - ax._tickAngles (on redraw only, old value relinked during supplyDefaults)
16461647
* - ax._mainLinePosition (from lsInner)
16471648
* - ax._mainMirrorPosition
16481649
* - ax._linepositions
@@ -1684,6 +1685,8 @@ axes.drawOne = function(gd, ax, opts) {
16841685
// - stash tickLabels selection, so that drawTitle can use it to scoot title
16851686
ax._selections = {};
16861687
// stash tick angle (including the computed 'auto' values) per tick-label class
1688+
// linkup 'previous' tick angles on redraws
1689+
if(ax._tickAngles) ax._prevTickAngles = ax._tickAngles;
16871690
ax._tickAngles = {};
16881691
// measure [in px] between axis position and outward-most part of bounding box
16891692
// (touching either the tick label or ticks)
@@ -1897,12 +1900,12 @@ axes.drawOne = function(gd, ax, opts) {
18971900
if(llbbox.width > 0) {
18981901
var rExtra = llbbox.right - (ax._offset + ax._length);
18991902
if(rExtra > 0) {
1900-
push.x = 1;
1903+
push.xr = 1;
19011904
push.r = rExtra;
19021905
}
19031906
var lExtra = ax._offset - llbbox.left;
19041907
if(lExtra > 0) {
1905-
push.x = 0;
1908+
push.xl = 0;
19061909
push.l = lExtra;
19071910
}
19081911
}
@@ -1917,12 +1920,12 @@ axes.drawOne = function(gd, ax, opts) {
19171920
if(llbbox.height > 0) {
19181921
var bExtra = llbbox.bottom - (ax._offset + ax._length);
19191922
if(bExtra > 0) {
1920-
push.y = 0;
1923+
push.yb = 0;
19211924
push.b = bExtra;
19221925
}
19231926
var tExtra = ax._offset - llbbox.top;
19241927
if(tExtra > 0) {
1925-
push.y = 1;
1928+
push.yt = 1;
19261929
push.t = tExtra;
19271930
}
19281931
}
@@ -2400,6 +2403,7 @@ axes.drawZeroLine = function(gd, ax, opts) {
24002403
* - {number} tickangle
24012404
* - {object (optional)} _selections
24022405
* - {object} (optional)} _tickAngles
2406+
* - {object} (optional)} _prevTickAngles
24032407
* @param {object} opts
24042408
* - {array of object} vals (calcTicks output-like)
24052409
* - {d3 selection} layer
@@ -2416,13 +2420,14 @@ axes.drawZeroLine = function(gd, ax, opts) {
24162420
axes.drawLabels = function(gd, ax, opts) {
24172421
opts = opts || {};
24182422

2423+
var fullLayout = gd._fullLayout;
24192424
var axId = ax._id;
24202425
var axLetter = axId.charAt(0);
24212426
var cls = opts.cls || axId + 'tick';
24222427
var vals = opts.vals;
24232428
var labelFns = opts.labelFns;
24242429
var tickAngle = opts.secondary ? 0 : ax.tickangle;
2425-
var lastAngle = (ax._tickAngles || {})[cls];
2430+
var prevAngle = (ax._prevTickAngles || {})[cls];
24262431

24272432
var tickLabels = opts.layer.selectAll('g.' + cls)
24282433
.data(ax.showticklabels ? vals : [], tickDataFn);
@@ -2507,17 +2512,17 @@ axes.drawLabels = function(gd, ax, opts) {
25072512
// do this without waiting, using the last calculated angle to
25082513
// minimize flicker, then do it again when we know all labels are
25092514
// there, putting back the prescribed angle to check for overlaps.
2510-
positionLabels(tickLabels, lastAngle || tickAngle);
2515+
positionLabels(tickLabels, (prevAngle + 1) ? prevAngle : tickAngle);
25112516

25122517
function allLabelsReady() {
25132518
return labelsReady.length && Promise.all(labelsReady);
25142519
}
25152520

2521+
var autoangle = null;
2522+
25162523
function fixLabelOverlaps() {
25172524
positionLabels(tickLabels, tickAngle);
25182525

2519-
var autoangle = null;
2520-
25212526
// check for auto-angling if x labels overlap
25222527
// don't auto-angle at all for log axes with
25232528
// base and digit format
@@ -2584,19 +2589,36 @@ axes.drawLabels = function(gd, ax, opts) {
25842589
positionLabels(tickLabels, autoangle);
25852590
}
25862591
}
2587-
2588-
if(ax._tickAngles) {
2589-
ax._tickAngles[cls] = autoangle === null ?
2590-
(isNumeric(tickAngle) ? tickAngle : 0) :
2591-
autoangle;
2592-
}
25932592
}
25942593

25952594
if(ax._selections) {
25962595
ax._selections[cls] = tickLabels;
25972596
}
25982597

2599-
var done = Lib.syncOrAsync([allLabelsReady, fixLabelOverlaps]);
2598+
var seq = [allLabelsReady];
2599+
2600+
// N.B. during auto-margin redraws, if the axis fixed its label overlaps
2601+
// by rotating 90 degrees, do not attempt to re-fix its label overlaps
2602+
// as this can lead to infinite redraw loops!
2603+
if(ax.automargin && fullLayout._redrawFromAutoMarginCount && prevAngle === 90) {
2604+
autoangle = 90;
2605+
seq.push(function() {
2606+
positionLabels(tickLabels, prevAngle);
2607+
});
2608+
} else {
2609+
seq.push(fixLabelOverlaps);
2610+
}
2611+
2612+
// save current tick angle for future redraws
2613+
if(ax._tickAngles) {
2614+
seq.push(function() {
2615+
ax._tickAngles[cls] = autoangle === null ?
2616+
(isNumeric(tickAngle) ? tickAngle : 0) :
2617+
autoangle;
2618+
});
2619+
}
2620+
2621+
var done = Lib.syncOrAsync(seq);
26002622
if(done && done.then) gd._promises.push(done);
26012623
return done;
26022624
};

src/plots/plots.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -1960,7 +1960,19 @@ plots.doAutoMargin = function(gd) {
19601960
} else {
19611961
fullLayout._redrawFromAutoMarginCount = 1;
19621962
}
1963-
return Registry.call('plot', gd);
1963+
1964+
// Always allow at least one redraw and give each margin-push
1965+
// call 3 loops to converge. Of course, for most cases this way too many,
1966+
// but let's keep things on the safe side until we fix our
1967+
// auto-margin pipeline problems:
1968+
// https://github.com/plotly/plotly.js/issues/2704
1969+
var maxNumberOfRedraws = 3 * (1 + Object.keys(pushMarginIds).length);
1970+
1971+
if(fullLayout._redrawFromAutoMarginCount < maxNumberOfRedraws) {
1972+
return Registry.call('plot', gd);
1973+
} else {
1974+
Lib.warn('Too many auto-margin redraws.');
1975+
}
19641976
}
19651977
};
19661978

8.72 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"data": [
3+
{
4+
"type": "bar",
5+
"x": [ "Montreal", "Tofu Bowl", "Tropical Beaches" ],
6+
"y": [ 3, 1, 2 ]
7+
}
8+
],
9+
"layout": {
10+
"margin": {
11+
"l": 20,
12+
"r": 0,
13+
"b": 30,
14+
"t": 15
15+
},
16+
"xaxis": {
17+
"automargin": true
18+
},
19+
"width": 150
20+
}
21+
}

0 commit comments

Comments
 (0)