Skip to content

Commit c50e962

Browse files
committed
fix #3600 - skip automargin pushes that lead to negative plot area
1 parent c1ad7d0 commit c50e962

File tree

2 files changed

+90
-12
lines changed

2 files changed

+90
-12
lines changed

src/plots/plots.js

+10-12
Original file line numberDiff line numberDiff line change
@@ -1841,6 +1841,8 @@ plots.doAutoMargin = function(gd) {
18411841
var mr = margin.r;
18421842
var mt = margin.t;
18431843
var mb = margin.b;
1844+
var width = fullLayout.width;
1845+
var height = fullLayout.height;
18441846
var pushMargin = fullLayout._pushmargin;
18451847
var pushMarginIds = fullLayout._pushmarginIds;
18461848

@@ -1876,11 +1878,9 @@ plots.doAutoMargin = function(gd) {
18761878
var pr = pushMargin[k2].r.size;
18771879

18781880
if(fr > fl) {
1879-
var newl = (pl * fr +
1880-
(pr - fullLayout.width) * fl) / (fr - fl);
1881-
var newr = (pr * (1 - fl) +
1882-
(pl - fullLayout.width) * (1 - fr)) / (fr - fl);
1883-
if(newl >= 0 && newr >= 0 && newl + newr > ml + mr) {
1881+
var newl = (pl * fr + (pr - width) * fl) / (fr - fl);
1882+
var newr = (pr * (1 - fl) + (pl - width) * (1 - fr)) / (fr - fl);
1883+
if(newl >= 0 && newr >= 0 && width - (newl + newr) > 0 && newl + newr > ml + mr) {
18841884
ml = newl;
18851885
mr = newr;
18861886
}
@@ -1892,11 +1892,9 @@ plots.doAutoMargin = function(gd) {
18921892
var pt = pushMargin[k2].t.size;
18931893

18941894
if(ft > fb) {
1895-
var newb = (pb * ft +
1896-
(pt - fullLayout.height) * fb) / (ft - fb);
1897-
var newt = (pt * (1 - fb) +
1898-
(pb - fullLayout.height) * (1 - ft)) / (ft - fb);
1899-
if(newb >= 0 && newt >= 0 && newb + newt > mb + mt) {
1895+
var newb = (pb * ft + (pt - height) * fb) / (ft - fb);
1896+
var newt = (pt * (1 - fb) + (pb - height) * (1 - ft)) / (ft - fb);
1897+
if(newb >= 0 && newt >= 0 && height - (newt + newb) > 0 && newb + newt > mb + mt) {
19001898
mb = newb;
19011899
mt = newt;
19021900
}
@@ -1911,8 +1909,8 @@ plots.doAutoMargin = function(gd) {
19111909
gs.t = Math.round(mt);
19121910
gs.b = Math.round(mb);
19131911
gs.p = Math.round(margin.pad);
1914-
gs.w = Math.round(fullLayout.width) - gs.l - gs.r;
1915-
gs.h = Math.round(fullLayout.height) - gs.t - gs.b;
1912+
gs.w = Math.round(width) - gs.l - gs.r;
1913+
gs.h = Math.round(height) - gs.t - gs.b;
19161914

19171915
// if things changed and we're not already redrawing, trigger a redraw
19181916
if(!fullLayout._replotting &&

test/jasmine/tests/axes_test.js

+80
Original file line numberDiff line numberDiff line change
@@ -3383,6 +3383,86 @@ describe('Test axes', function() {
33833383
.catch(failTest)
33843384
.then(done);
33853385
});
3386+
3387+
it('should not lead to negative plot area heights', function(done) {
3388+
function _assert(msg, exp) {
3389+
var gs = gd._fullLayout._size;
3390+
expect(gs.h).toBeGreaterThan(0, msg + '- positive height');
3391+
expect(gs.b).toBeGreaterThan(exp.bottomLowerBound, msg + ' - margin bottom');
3392+
expect(gs.b + gs.h + gs.t).toBeWithin(exp.totalHeight, 1.5, msg + ' - total height');
3393+
}
3394+
3395+
Plotly.plot(gd, [{
3396+
x: ['loooooong label 1', 'loooooong label 2'],
3397+
y: [1, 2]
3398+
}], {
3399+
xaxis: {automargin: true, tickangle: 90},
3400+
width: 500,
3401+
height: 500
3402+
})
3403+
.then(function() {
3404+
_assert('base', {
3405+
bottomLowerBound: 80,
3406+
totalHeight: 500
3407+
});
3408+
})
3409+
.then(function() { return Plotly.relayout(gd, 'height', 100); })
3410+
.then(function() {
3411+
_assert('after relayout to *small* height', {
3412+
bottomLowerBound: 30,
3413+
totalHeight: 100
3414+
});
3415+
})
3416+
.then(function() { return Plotly.relayout(gd, 'height', 800); })
3417+
.then(function() {
3418+
_assert('after relayout to *big* height', {
3419+
bottomLowerBound: 80,
3420+
totalHeight: 800
3421+
});
3422+
})
3423+
.catch(failTest)
3424+
.then(done);
3425+
});
3426+
3427+
it('should not lead to negative plot area widths', function(done) {
3428+
function _assert(msg, exp) {
3429+
var gs = gd._fullLayout._size;
3430+
expect(gs.w).toBeGreaterThan(0, msg + '- positive width');
3431+
expect(gs.l).toBeGreaterThan(exp.leftLowerBound, msg + ' - margin left');
3432+
expect(gs.l + gs.w + gs.r).toBeWithin(exp.totalWidth, 1.5, msg + ' - total width');
3433+
}
3434+
3435+
Plotly.plot(gd, [{
3436+
y: ['loooooong label 1', 'loooooong label 2'],
3437+
x: [1, 2]
3438+
}], {
3439+
yaxis: {automargin: true},
3440+
width: 500,
3441+
height: 500
3442+
})
3443+
.then(function() {
3444+
_assert('base', {
3445+
leftLowerBound: 80,
3446+
totalWidth: 500
3447+
});
3448+
})
3449+
.then(function() { return Plotly.relayout(gd, 'width', 100); })
3450+
.then(function() {
3451+
_assert('after relayout to *small* width', {
3452+
leftLowerBound: 30,
3453+
totalWidth: 100
3454+
});
3455+
})
3456+
.then(function() { return Plotly.relayout(gd, 'width', 1000); })
3457+
.then(function() {
3458+
_assert('after relayout to *big* width', {
3459+
leftLowerBound: 80,
3460+
totalWidth: 1000
3461+
});
3462+
})
3463+
.catch(failTest)
3464+
.then(done);
3465+
});
33863466
});
33873467

33883468
describe('zeroline visibility logic', function() {

0 commit comments

Comments
 (0)