Skip to content

Commit 3a2c547

Browse files
committed
autosize: remove internal option 'initial'
* Moved initial call to `plotAutoSize` into `Plots.supplyDefaults(gd)`. * Replaced `{ autosize: 'initial' }` with the flag `gd._fullLayout._initialAutoSizeIsDone`. * `{ autosize: false }` the values of width and height undefined in `gd.layout` will be autosized only once. * `{ autosize: true }` only autosizes the values of width and height undefined in `gd.layout`. Fixes plotly#537
1 parent f1415f8 commit 3a2c547

File tree

3 files changed

+145
-123
lines changed

3 files changed

+145
-123
lines changed

src/plot_api/plot_api.js

+15-105
Original file line numberDiff line numberDiff line change
@@ -414,10 +414,6 @@ function plotPolar(gd, data, layout) {
414414
if(layout) gd.layout = layout;
415415
Plotly.micropolar.manager.fillLayout(gd);
416416

417-
if(gd._fullLayout.autosize === 'initial' && gd._context.autosizable) {
418-
plotAutoSize(gd, {});
419-
gd._fullLayout.autosize = layout.autosize = true;
420-
}
421417
// resize canvas
422418
paperDiv.style({
423419
width: gd._fullLayout.width + 'px',
@@ -2158,8 +2154,6 @@ Plotly.relayout = function relayout(gd, astr, val) {
21582154
return (fullLayout[axName] || {}).autorange;
21592155
}
21602156

2161-
var hw = ['height', 'width'];
2162-
21632157
// alter gd.layout
21642158
for(var ai in aobj) {
21652159
var p = Lib.nestedProperty(layout, ai),
@@ -2182,14 +2176,8 @@ Plotly.relayout = function relayout(gd, astr, val) {
21822176
// op and has no flag.
21832177
undoit[ai] = (pleaf === 'reverse') ? vi : p.get();
21842178

2185-
// check autosize or autorange vs size and range
2186-
if(hw.indexOf(ai) !== -1) {
2187-
doextra('autosize', false);
2188-
}
2189-
else if(ai === 'autosize') {
2190-
doextra(hw, undefined);
2191-
}
2192-
else if(pleafPlus.match(/^[xyz]axis[0-9]*\.range(\[[0|1]\])?$/)) {
2179+
// check autorange vs range
2180+
if(pleafPlus.match(/^[xyz]axis[0-9]*\.range(\[[0|1]\])?$/)) {
21932181
doextra(ptrunk + '.autorange', false);
21942182
}
21952183
else if(pleafPlus.match(/^[xyz]axis[0-9]*\.autorange$/)) {
@@ -2367,11 +2355,20 @@ Plotly.relayout = function relayout(gd, astr, val) {
23672355
Queue.add(gd, relayout, [gd, undoit], relayout, [gd, redoit]);
23682356
}
23692357

2370-
// calculate autosizing - if size hasn't changed,
2371-
// will remove h&w so we don't need to redraw
2372-
if(aobj.autosize) aobj = plotAutoSize(gd, aobj);
2358+
var oldWidth = gd._fullLayout.width,
2359+
oldHeight = gd._fullLayout.height;
23732360

2374-
if(aobj.height || aobj.width || aobj.autosize) docalc = true;
2361+
// coerce the updated layout
2362+
Plots.supplyDefaults(gd);
2363+
2364+
// calculate autosizing
2365+
if(gd.layout.autosize) Plots.plotAutoSize(gd, gd.layout, gd._fullLayout);
2366+
2367+
// avoid unnecessary redraws
2368+
var changed = aobj.height || aobj.width ||
2369+
(gd._fullLayout.width !== oldWidth) ||
2370+
(gd._fullLayout.height !== oldHeight);
2371+
if(changed) docalc = true;
23752372

23762373
// redraw
23772374
// first check if there's still anything to do
@@ -2392,7 +2389,6 @@ Plotly.relayout = function relayout(gd, astr, val) {
23922389
}
23932390
else if(ak.length) {
23942391
// if we didn't need to redraw entirely, just do the needed parts
2395-
Plots.supplyDefaults(gd);
23962392
fullLayout = gd._fullLayout;
23972393

23982394
if(dolegend) {
@@ -2501,85 +2497,6 @@ Plotly.purge = function purge(gd) {
25012497
return gd;
25022498
};
25032499

2504-
/**
2505-
* Reduce all reserved margin objects to a single required margin reservation.
2506-
*
2507-
* @param {Object} margins
2508-
* @returns {{left: number, right: number, bottom: number, top: number}}
2509-
*/
2510-
function calculateReservedMargins(margins) {
2511-
var resultingMargin = {left: 0, right: 0, bottom: 0, top: 0},
2512-
marginName;
2513-
2514-
if(margins) {
2515-
for(marginName in margins) {
2516-
if(margins.hasOwnProperty(marginName)) {
2517-
resultingMargin.left += margins[marginName].left || 0;
2518-
resultingMargin.right += margins[marginName].right || 0;
2519-
resultingMargin.bottom += margins[marginName].bottom || 0;
2520-
resultingMargin.top += margins[marginName].top || 0;
2521-
}
2522-
}
2523-
}
2524-
return resultingMargin;
2525-
}
2526-
2527-
function plotAutoSize(gd, aobj) {
2528-
var fullLayout = gd._fullLayout,
2529-
context = gd._context,
2530-
computedStyle;
2531-
2532-
var newHeight, newWidth;
2533-
2534-
gd.emit('plotly_autosize');
2535-
2536-
// embedded in an iframe - just take the full iframe size
2537-
// if we get to this point, with no aspect ratio restrictions
2538-
if(gd._context.fillFrame) {
2539-
newWidth = window.innerWidth;
2540-
newHeight = window.innerHeight;
2541-
2542-
// somehow we get a few extra px height sometimes...
2543-
// just hide it
2544-
document.body.style.overflow = 'hidden';
2545-
}
2546-
else if(isNumeric(context.frameMargins) && context.frameMargins > 0) {
2547-
var reservedMargins = calculateReservedMargins(gd._boundingBoxMargins),
2548-
reservedWidth = reservedMargins.left + reservedMargins.right,
2549-
reservedHeight = reservedMargins.bottom + reservedMargins.top,
2550-
gdBB = fullLayout._container.node().getBoundingClientRect(),
2551-
factor = 1 - 2 * context.frameMargins;
2552-
2553-
newWidth = Math.round(factor * (gdBB.width - reservedWidth));
2554-
newHeight = Math.round(factor * (gdBB.height - reservedHeight));
2555-
}
2556-
else {
2557-
// plotly.js - let the developers do what they want, either
2558-
// provide height and width for the container div,
2559-
// specify size in layout, or take the defaults,
2560-
// but don't enforce any ratio restrictions
2561-
computedStyle = window.getComputedStyle(gd);
2562-
newHeight = parseFloat(computedStyle.height) || fullLayout.height;
2563-
newWidth = parseFloat(computedStyle.width) || fullLayout.width;
2564-
}
2565-
2566-
if(Math.abs(fullLayout.width - newWidth) > 1 ||
2567-
Math.abs(fullLayout.height - newHeight) > 1) {
2568-
fullLayout.height = gd.layout.height = newHeight;
2569-
fullLayout.width = gd.layout.width = newWidth;
2570-
}
2571-
// if there's no size change, update layout but
2572-
// delete the autosize attr so we don't redraw
2573-
else {
2574-
delete(aobj.autosize);
2575-
fullLayout.autosize = gd.layout.autosize = true;
2576-
}
2577-
2578-
Plots.sanitizeMargins(fullLayout);
2579-
2580-
return aobj;
2581-
}
2582-
25832500
// -------------------------------------------------------
25842501
// makePlotFramework: Create the plot container and axes
25852502
// -------------------------------------------------------
@@ -2599,13 +2516,6 @@ function makePlotFramework(gd) {
25992516
.classed('svg-container', true)
26002517
.style('position', 'relative');
26012518

2602-
// Initial autosize
2603-
if(fullLayout.autosize === 'initial') {
2604-
plotAutoSize(gd, {});
2605-
fullLayout.autosize = true;
2606-
gd.layout.autosize = true;
2607-
}
2608-
26092519
// Make the graph containers
26102520
// start fresh each time we get here, so we know the order comes out
26112521
// right, rather than enter/exit which can muck up the order

src/plots/layout_attributes.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,16 @@ module.exports = {
4747
autosize: {
4848
valType: 'enumerated',
4949
role: 'info',
50-
// TODO: better handling of 'initial'
51-
values: [true, false, 'initial'],
50+
values: [false, true],
51+
dflt: false,
5252
description: [
53-
'Determines whether or not the dimensions of the figure are',
54-
'computed as a function of the display size.'
53+
'Determines whether or not a layout width or height',
54+
'that has been left undefined by the user',
55+
'is initialized on each relayout.',
56+
57+
'Note that, regardless of this attribute,',
58+
'an undefined layout width or height',
59+
'is always initialized on the first call to plot.'
5560
].join(' ')
5661
},
5762
width: {

src/plots/plots.js

+121-14
Original file line numberDiff line numberDiff line change
@@ -287,17 +287,26 @@ plots.resize = function(gd) {
287287
if(gd._redrawTimer) clearTimeout(gd._redrawTimer);
288288

289289
gd._redrawTimer = setTimeout(function() {
290-
if((gd._fullLayout || {}).autosize) {
291-
// autosizing doesn't count as a change that needs saving
292-
var oldchanged = gd.changed;
290+
// return if there is nothing to resize
291+
if(gd.layout.width && gd.layout.height) {
292+
resolve(gd);
293+
return;
294+
}
295+
296+
delete gd._fullLayout._initialAutoSizeIsDone;
297+
if(!gd.layout.width) delete (gd._fullLayout || {}).width;
298+
if(!gd.layout.height) delete (gd._fullLayout || {}).height;
293299

294-
// nor should it be included in the undo queue
295-
gd.autoplay = true;
300+
// autosizing doesn't count as a change that needs saving
301+
var oldchanged = gd.changed;
296302

297-
Plotly.relayout(gd, { autosize: true });
303+
// nor should it be included in the undo queue
304+
gd.autoplay = true;
305+
306+
Plotly.plot(gd).then(function() {
298307
gd.changed = oldchanged;
299308
resolve(gd);
300-
}
309+
});
301310
}, 100);
302311
});
303312
};
@@ -455,7 +464,7 @@ plots.sendDataToCloud = function(gd) {
455464
plots.supplyDefaults = function(gd) {
456465
var oldFullLayout = gd._fullLayout || {},
457466
newFullLayout = gd._fullLayout = {},
458-
newLayout = gd.layout || {};
467+
layout = gd.layout || {};
459468

460469
var oldFullData = gd._fullData || [],
461470
newFullData = gd._fullData = [],
@@ -468,7 +477,27 @@ plots.supplyDefaults = function(gd) {
468477

469478
// first fill in what we can of layout without looking at data
470479
// because fullData needs a few things from layout
471-
plots.supplyLayoutGlobalDefaults(newLayout, newFullLayout);
480+
481+
if(oldFullLayout._initialAutoSizeIsDone) {
482+
// coerce the updated layout while preserving width and height
483+
var oldWidth = oldFullLayout.width,
484+
oldHeight = oldFullLayout.height;
485+
486+
plots.supplyLayoutGlobalDefaults(layout, newFullLayout);
487+
488+
if(!layout.width) newFullLayout.width = oldWidth;
489+
if(!layout.height) newFullLayout.height = oldHeight;
490+
}
491+
else {
492+
// coerce the updated layout and autosize if needed
493+
plots.supplyLayoutGlobalDefaults(layout, newFullLayout);
494+
495+
if(!layout.width || !layout.height) {
496+
plots.plotAutoSize(gd, layout, newFullLayout);
497+
}
498+
}
499+
500+
newFullLayout._initialAutoSizeIsDone = true;
472501

473502
// keep track of how many traces are inputted
474503
newFullLayout._dataLength = newData.length;
@@ -505,7 +534,7 @@ plots.supplyDefaults = function(gd) {
505534
}
506535

507536
// finally, fill in the pieces of layout that may need to look at data
508-
plots.supplyLayoutModuleDefaults(newLayout, newFullLayout, newFullData);
537+
plots.supplyLayoutModuleDefaults(layout, newFullLayout, newFullData);
509538

510539
// TODO remove in v2.0.0
511540
// add has-plot-type refs to fullLayout for backward compatibility
@@ -522,6 +551,7 @@ plots.supplyDefaults = function(gd) {
522551
// relink functions and _ attributes to promote consistency between plots
523552
relinkPrivateKeys(newFullLayout, oldFullLayout);
524553

554+
// TODO may return a promise
525555
plots.doAutoMargin(gd);
526556

527557
// can't quite figure out how to get rid of this... each axis needs
@@ -730,11 +760,9 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) {
730760
color: globalFont.color
731761
});
732762

733-
var autosize = coerce('autosize',
734-
(layoutIn.width && layoutIn.height) ? false : 'initial');
763+
coerce('autosize');
735764
coerce('width');
736765
coerce('height');
737-
738766
coerce('margin.l');
739767
coerce('margin.r');
740768
coerce('margin.t');
@@ -743,7 +771,7 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) {
743771
coerce('margin.autoexpand');
744772

745773
// called in plotAutoSize otherwise
746-
if(autosize !== 'initial') plots.sanitizeMargins(layoutOut);
774+
if(layoutOut.width && layoutOut.height) plots.sanitizeMargins(layoutOut);
747775

748776
coerce('paper_bgcolor');
749777

@@ -752,6 +780,85 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) {
752780
coerce('smith');
753781
};
754782

783+
plots.plotAutoSize = function plotAutoSize(gd, layout, fullLayout) {
784+
var context = gd._context || {},
785+
frameMargins = context.frameMargins,
786+
newWidth,
787+
newHeight;
788+
789+
if(typeof gd.emit === 'function') gd.emit('plotly_autosize');
790+
791+
// embedded in an iframe - just take the full iframe size
792+
// if we get to this point, with no aspect ratio restrictions
793+
if(context.fillFrame) {
794+
newWidth = window.innerWidth;
795+
newHeight = window.innerHeight;
796+
797+
// somehow we get a few extra px height sometimes...
798+
// just hide it
799+
document.body.style.overflow = 'hidden';
800+
}
801+
else if(isNumeric(frameMargins) && frameMargins > 0) {
802+
var reservedMargins = calculateReservedMargins(gd._boundingBoxMargins),
803+
reservedWidth = reservedMargins.left + reservedMargins.right,
804+
reservedHeight = reservedMargins.bottom + reservedMargins.top,
805+
gdBB = fullLayout._container.node().getBoundingClientRect(),
806+
factor = 1 - 2 * frameMargins;
807+
808+
newWidth = Math.round(factor * (gdBB.width - reservedWidth));
809+
newHeight = Math.round(factor * (gdBB.height - reservedHeight));
810+
}
811+
else {
812+
// plotly.js - let the developers do what they want, either
813+
// provide height and width for the container div,
814+
// specify size in layout, or take the defaults,
815+
// but don't enforce any ratio restrictions
816+
var computedStyle;
817+
try {
818+
computedStyle = window.getComputedStyle(gd);
819+
} catch(err) {
820+
computedStyle = {};
821+
}
822+
newWidth = parseFloat(computedStyle.width) || fullLayout.width;
823+
newHeight = parseFloat(computedStyle.height) || fullLayout.height;
824+
}
825+
826+
var widthHasChanged = !layout.width &&
827+
(Math.abs(fullLayout.width - newWidth) > 1),
828+
heightHasChanged = !layout.height &&
829+
(Math.abs(fullLayout.height - newHeight) > 1);
830+
831+
if(heightHasChanged || widthHasChanged) {
832+
if(widthHasChanged) fullLayout.width = newWidth;
833+
if(heightHasChanged) fullLayout.height = newHeight;
834+
835+
plots.sanitizeMargins(fullLayout);
836+
}
837+
};
838+
839+
/**
840+
* Reduce all reserved margin objects to a single required margin reservation.
841+
*
842+
* @param {Object} margins
843+
* @returns {{left: number, right: number, bottom: number, top: number}}
844+
*/
845+
function calculateReservedMargins(margins) {
846+
var resultingMargin = {left: 0, right: 0, bottom: 0, top: 0},
847+
marginName;
848+
849+
if(margins) {
850+
for(marginName in margins) {
851+
if(margins.hasOwnProperty(marginName)) {
852+
resultingMargin.left += margins[marginName].left || 0;
853+
resultingMargin.right += margins[marginName].right || 0;
854+
resultingMargin.bottom += margins[marginName].bottom || 0;
855+
resultingMargin.top += margins[marginName].top || 0;
856+
}
857+
}
858+
}
859+
return resultingMargin;
860+
}
861+
755862
plots.supplyLayoutModuleDefaults = function(layoutIn, layoutOut, fullData) {
756863
var i, _module;
757864

0 commit comments

Comments
 (0)