From f1415f82f6eb63761c9ef026e288ae29bfd4658a Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Wed, 25 May 2016 10:34:13 +0100 Subject: [PATCH 01/25] autosize: Remove unnecessary guard in plotAutoSize * Commit 5df675af (fix demo/outside legend bug and null data autoscale bug) introduced a guard in plotAutoSize to avoid calling layoutStyles while autosize is set to 'initial'. * Commit ee974d97 (autosizing in shareplots, autosize aspect ratio restrictions and ...) removed the call to layoutStyles but forgot to remove the guard. * This commit removes the guard. * Checked that all the jasmine and image tests still pass. --- src/plot_api/plot_api.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 2da62220350..e2fa366d13e 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -2570,8 +2570,7 @@ function plotAutoSize(gd, aobj) { } // if there's no size change, update layout but // delete the autosize attr so we don't redraw - // but can't call layoutStyles for initial autosize - else if(fullLayout.autosize !== 'initial') { + else { delete(aobj.autosize); fullLayout.autosize = gd.layout.autosize = true; } From 3a2c547bbe9dcebc61e18731c973927cbcf3cf28 Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Fri, 27 May 2016 19:10:37 +0100 Subject: [PATCH 02/25] 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 #537 --- src/plot_api/plot_api.js | 120 ++++------------------------- src/plots/layout_attributes.js | 13 +++- src/plots/plots.js | 135 +++++++++++++++++++++++++++++---- 3 files changed, 145 insertions(+), 123 deletions(-) diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index e2fa366d13e..8cfaa610bce 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -414,10 +414,6 @@ function plotPolar(gd, data, layout) { if(layout) gd.layout = layout; Plotly.micropolar.manager.fillLayout(gd); - if(gd._fullLayout.autosize === 'initial' && gd._context.autosizable) { - plotAutoSize(gd, {}); - gd._fullLayout.autosize = layout.autosize = true; - } // resize canvas paperDiv.style({ width: gd._fullLayout.width + 'px', @@ -2158,8 +2154,6 @@ Plotly.relayout = function relayout(gd, astr, val) { return (fullLayout[axName] || {}).autorange; } - var hw = ['height', 'width']; - // alter gd.layout for(var ai in aobj) { var p = Lib.nestedProperty(layout, ai), @@ -2182,14 +2176,8 @@ Plotly.relayout = function relayout(gd, astr, val) { // op and has no flag. undoit[ai] = (pleaf === 'reverse') ? vi : p.get(); - // check autosize or autorange vs size and range - if(hw.indexOf(ai) !== -1) { - doextra('autosize', false); - } - else if(ai === 'autosize') { - doextra(hw, undefined); - } - else if(pleafPlus.match(/^[xyz]axis[0-9]*\.range(\[[0|1]\])?$/)) { + // check autorange vs range + if(pleafPlus.match(/^[xyz]axis[0-9]*\.range(\[[0|1]\])?$/)) { doextra(ptrunk + '.autorange', false); } else if(pleafPlus.match(/^[xyz]axis[0-9]*\.autorange$/)) { @@ -2367,11 +2355,20 @@ Plotly.relayout = function relayout(gd, astr, val) { Queue.add(gd, relayout, [gd, undoit], relayout, [gd, redoit]); } - // calculate autosizing - if size hasn't changed, - // will remove h&w so we don't need to redraw - if(aobj.autosize) aobj = plotAutoSize(gd, aobj); + var oldWidth = gd._fullLayout.width, + oldHeight = gd._fullLayout.height; - if(aobj.height || aobj.width || aobj.autosize) docalc = true; + // coerce the updated layout + Plots.supplyDefaults(gd); + + // calculate autosizing + if(gd.layout.autosize) Plots.plotAutoSize(gd, gd.layout, gd._fullLayout); + + // avoid unnecessary redraws + var changed = aobj.height || aobj.width || + (gd._fullLayout.width !== oldWidth) || + (gd._fullLayout.height !== oldHeight); + if(changed) docalc = true; // redraw // first check if there's still anything to do @@ -2392,7 +2389,6 @@ Plotly.relayout = function relayout(gd, astr, val) { } else if(ak.length) { // if we didn't need to redraw entirely, just do the needed parts - Plots.supplyDefaults(gd); fullLayout = gd._fullLayout; if(dolegend) { @@ -2501,85 +2497,6 @@ Plotly.purge = function purge(gd) { return gd; }; -/** - * Reduce all reserved margin objects to a single required margin reservation. - * - * @param {Object} margins - * @returns {{left: number, right: number, bottom: number, top: number}} - */ -function calculateReservedMargins(margins) { - var resultingMargin = {left: 0, right: 0, bottom: 0, top: 0}, - marginName; - - if(margins) { - for(marginName in margins) { - if(margins.hasOwnProperty(marginName)) { - resultingMargin.left += margins[marginName].left || 0; - resultingMargin.right += margins[marginName].right || 0; - resultingMargin.bottom += margins[marginName].bottom || 0; - resultingMargin.top += margins[marginName].top || 0; - } - } - } - return resultingMargin; -} - -function plotAutoSize(gd, aobj) { - var fullLayout = gd._fullLayout, - context = gd._context, - computedStyle; - - var newHeight, newWidth; - - gd.emit('plotly_autosize'); - - // embedded in an iframe - just take the full iframe size - // if we get to this point, with no aspect ratio restrictions - if(gd._context.fillFrame) { - newWidth = window.innerWidth; - newHeight = window.innerHeight; - - // somehow we get a few extra px height sometimes... - // just hide it - document.body.style.overflow = 'hidden'; - } - else if(isNumeric(context.frameMargins) && context.frameMargins > 0) { - var reservedMargins = calculateReservedMargins(gd._boundingBoxMargins), - reservedWidth = reservedMargins.left + reservedMargins.right, - reservedHeight = reservedMargins.bottom + reservedMargins.top, - gdBB = fullLayout._container.node().getBoundingClientRect(), - factor = 1 - 2 * context.frameMargins; - - newWidth = Math.round(factor * (gdBB.width - reservedWidth)); - newHeight = Math.round(factor * (gdBB.height - reservedHeight)); - } - else { - // plotly.js - let the developers do what they want, either - // provide height and width for the container div, - // specify size in layout, or take the defaults, - // but don't enforce any ratio restrictions - computedStyle = window.getComputedStyle(gd); - newHeight = parseFloat(computedStyle.height) || fullLayout.height; - newWidth = parseFloat(computedStyle.width) || fullLayout.width; - } - - if(Math.abs(fullLayout.width - newWidth) > 1 || - Math.abs(fullLayout.height - newHeight) > 1) { - fullLayout.height = gd.layout.height = newHeight; - fullLayout.width = gd.layout.width = newWidth; - } - // if there's no size change, update layout but - // delete the autosize attr so we don't redraw - else { - delete(aobj.autosize); - fullLayout.autosize = gd.layout.autosize = true; - } - - Plots.sanitizeMargins(fullLayout); - - return aobj; -} - // ------------------------------------------------------- // makePlotFramework: Create the plot container and axes // ------------------------------------------------------- @@ -2599,13 +2516,6 @@ function makePlotFramework(gd) { .classed('svg-container', true) .style('position', 'relative'); - // Initial autosize - if(fullLayout.autosize === 'initial') { - plotAutoSize(gd, {}); - fullLayout.autosize = true; - gd.layout.autosize = true; - } - // Make the graph containers // start fresh each time we get here, so we know the order comes out // right, rather than enter/exit which can muck up the order diff --git a/src/plots/layout_attributes.js b/src/plots/layout_attributes.js index 06b4ab0913c..063ef3fff5a 100644 --- a/src/plots/layout_attributes.js +++ b/src/plots/layout_attributes.js @@ -47,11 +47,16 @@ module.exports = { autosize: { valType: 'enumerated', role: 'info', - // TODO: better handling of 'initial' - values: [true, false, 'initial'], + values: [false, true], + dflt: false, description: [ - 'Determines whether or not the dimensions of the figure are', - 'computed as a function of the display size.' + 'Determines whether or not a layout width or height', + 'that has been left undefined by the user', + 'is initialized on each relayout.', + + 'Note that, regardless of this attribute,', + 'an undefined layout width or height', + 'is always initialized on the first call to plot.' ].join(' ') }, width: { diff --git a/src/plots/plots.js b/src/plots/plots.js index 6a33c21fc53..502a181bc79 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -287,17 +287,26 @@ plots.resize = function(gd) { if(gd._redrawTimer) clearTimeout(gd._redrawTimer); gd._redrawTimer = setTimeout(function() { - if((gd._fullLayout || {}).autosize) { - // autosizing doesn't count as a change that needs saving - var oldchanged = gd.changed; + // return if there is nothing to resize + if(gd.layout.width && gd.layout.height) { + resolve(gd); + return; + } + + delete gd._fullLayout._initialAutoSizeIsDone; + if(!gd.layout.width) delete (gd._fullLayout || {}).width; + if(!gd.layout.height) delete (gd._fullLayout || {}).height; - // nor should it be included in the undo queue - gd.autoplay = true; + // autosizing doesn't count as a change that needs saving + var oldchanged = gd.changed; - Plotly.relayout(gd, { autosize: true }); + // nor should it be included in the undo queue + gd.autoplay = true; + + Plotly.plot(gd).then(function() { gd.changed = oldchanged; resolve(gd); - } + }); }, 100); }); }; @@ -455,7 +464,7 @@ plots.sendDataToCloud = function(gd) { plots.supplyDefaults = function(gd) { var oldFullLayout = gd._fullLayout || {}, newFullLayout = gd._fullLayout = {}, - newLayout = gd.layout || {}; + layout = gd.layout || {}; var oldFullData = gd._fullData || [], newFullData = gd._fullData = [], @@ -468,7 +477,27 @@ plots.supplyDefaults = function(gd) { // first fill in what we can of layout without looking at data // because fullData needs a few things from layout - plots.supplyLayoutGlobalDefaults(newLayout, newFullLayout); + + if(oldFullLayout._initialAutoSizeIsDone) { + // coerce the updated layout while preserving width and height + var oldWidth = oldFullLayout.width, + oldHeight = oldFullLayout.height; + + plots.supplyLayoutGlobalDefaults(layout, newFullLayout); + + if(!layout.width) newFullLayout.width = oldWidth; + if(!layout.height) newFullLayout.height = oldHeight; + } + else { + // coerce the updated layout and autosize if needed + plots.supplyLayoutGlobalDefaults(layout, newFullLayout); + + if(!layout.width || !layout.height) { + plots.plotAutoSize(gd, layout, newFullLayout); + } + } + + newFullLayout._initialAutoSizeIsDone = true; // keep track of how many traces are inputted newFullLayout._dataLength = newData.length; @@ -505,7 +534,7 @@ plots.supplyDefaults = function(gd) { } // finally, fill in the pieces of layout that may need to look at data - plots.supplyLayoutModuleDefaults(newLayout, newFullLayout, newFullData); + plots.supplyLayoutModuleDefaults(layout, newFullLayout, newFullData); // TODO remove in v2.0.0 // add has-plot-type refs to fullLayout for backward compatibility @@ -522,6 +551,7 @@ plots.supplyDefaults = function(gd) { // relink functions and _ attributes to promote consistency between plots relinkPrivateKeys(newFullLayout, oldFullLayout); + // TODO may return a promise plots.doAutoMargin(gd); // can't quite figure out how to get rid of this... each axis needs @@ -730,11 +760,9 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) { color: globalFont.color }); - var autosize = coerce('autosize', - (layoutIn.width && layoutIn.height) ? false : 'initial'); + coerce('autosize'); coerce('width'); coerce('height'); - coerce('margin.l'); coerce('margin.r'); coerce('margin.t'); @@ -743,7 +771,7 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) { coerce('margin.autoexpand'); // called in plotAutoSize otherwise - if(autosize !== 'initial') plots.sanitizeMargins(layoutOut); + if(layoutOut.width && layoutOut.height) plots.sanitizeMargins(layoutOut); coerce('paper_bgcolor'); @@ -752,6 +780,85 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) { coerce('smith'); }; +plots.plotAutoSize = function plotAutoSize(gd, layout, fullLayout) { + var context = gd._context || {}, + frameMargins = context.frameMargins, + newWidth, + newHeight; + + if(typeof gd.emit === 'function') gd.emit('plotly_autosize'); + + // embedded in an iframe - just take the full iframe size + // if we get to this point, with no aspect ratio restrictions + if(context.fillFrame) { + newWidth = window.innerWidth; + newHeight = window.innerHeight; + + // somehow we get a few extra px height sometimes... + // just hide it + document.body.style.overflow = 'hidden'; + } + else if(isNumeric(frameMargins) && frameMargins > 0) { + var reservedMargins = calculateReservedMargins(gd._boundingBoxMargins), + reservedWidth = reservedMargins.left + reservedMargins.right, + reservedHeight = reservedMargins.bottom + reservedMargins.top, + gdBB = fullLayout._container.node().getBoundingClientRect(), + factor = 1 - 2 * frameMargins; + + newWidth = Math.round(factor * (gdBB.width - reservedWidth)); + newHeight = Math.round(factor * (gdBB.height - reservedHeight)); + } + else { + // plotly.js - let the developers do what they want, either + // provide height and width for the container div, + // specify size in layout, or take the defaults, + // but don't enforce any ratio restrictions + var computedStyle; + try { + computedStyle = window.getComputedStyle(gd); + } catch(err) { + computedStyle = {}; + } + newWidth = parseFloat(computedStyle.width) || fullLayout.width; + newHeight = parseFloat(computedStyle.height) || fullLayout.height; + } + + var widthHasChanged = !layout.width && + (Math.abs(fullLayout.width - newWidth) > 1), + heightHasChanged = !layout.height && + (Math.abs(fullLayout.height - newHeight) > 1); + + if(heightHasChanged || widthHasChanged) { + if(widthHasChanged) fullLayout.width = newWidth; + if(heightHasChanged) fullLayout.height = newHeight; + + plots.sanitizeMargins(fullLayout); + } +}; + +/** + * Reduce all reserved margin objects to a single required margin reservation. + * + * @param {Object} margins + * @returns {{left: number, right: number, bottom: number, top: number}} + */ +function calculateReservedMargins(margins) { + var resultingMargin = {left: 0, right: 0, bottom: 0, top: 0}, + marginName; + + if(margins) { + for(marginName in margins) { + if(margins.hasOwnProperty(marginName)) { + resultingMargin.left += margins[marginName].left || 0; + resultingMargin.right += margins[marginName].right || 0; + resultingMargin.bottom += margins[marginName].bottom || 0; + resultingMargin.top += margins[marginName].top || 0; + } + } + } + return resultingMargin; +} + plots.supplyLayoutModuleDefaults = function(layoutIn, layoutOut, fullData) { var i, _module; From f9140b00d0402d17c3fbe601877aef73b44c942a Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Fri, 27 May 2016 19:28:14 +0100 Subject: [PATCH 03/25] autosize: update baseline image `ternary_simple` * Previous image didn't honour the width and height set in the layout. --- test/image/baselines/ternary_simple.png | Bin 41350 -> 37515 bytes test/image/mocks/ternary_simple.json | 3 +-- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/image/baselines/ternary_simple.png b/test/image/baselines/ternary_simple.png index c6d5869de4053376195a8a60b4176fc714004515..111ead3bf5fb92efec65a2dddccb2397034c7b42 100644 GIT binary patch literal 37515 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 literal 41350 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 Vd@Z5f$dv&IJYD@<);T3K0RT1e>ox!Y diff --git a/test/image/mocks/ternary_simple.json b/test/image/mocks/ternary_simple.json index ea1d78ff2a3..0f092db4a96 100644 --- a/test/image/mocks/ternary_simple.json +++ b/test/image/mocks/ternary_simple.json @@ -46,7 +46,6 @@ "bgcolor": "#eee" }, "height": 450, - "width": 700, - "autosize": true + "width": 700 } } From 206888b3d3a8fe2c42e5c9033577d845b2d66eaa Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Fri, 27 May 2016 19:30:43 +0100 Subject: [PATCH 04/25] test: make `toimage_test.js` stricter --- test/jasmine/tests/toimage_test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/jasmine/tests/toimage_test.js b/test/jasmine/tests/toimage_test.js index 32466c1266f..ac6ee12d1f1 100644 --- a/test/jasmine/tests/toimage_test.js +++ b/test/jasmine/tests/toimage_test.js @@ -70,6 +70,8 @@ describe('Plotly.toImage', function() { subplotMock.layout.width = 700; Plotly.plot(gd, subplotMock.data, subplotMock.layout).then(function(gd) { + expect(gd.layout.height).toBe(600); + expect(gd.layout.width).toBe(700); return Plotly.toImage(gd); }).then(function(url) { return new Promise(function(resolve) { From 9c2a0d96166f1aca13fc84cab48002106cfa1d72 Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Fri, 27 May 2016 20:01:12 +0100 Subject: [PATCH 05/25] test: add test for issue #537 * Added test to check `Plotly.newPlot` respects `layout.width` and `layout.height`. --- test/jasmine/tests/plot_api_test.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/jasmine/tests/plot_api_test.js b/test/jasmine/tests/plot_api_test.js index 7c92bbad4d0..618d35d076e 100644 --- a/test/jasmine/tests/plot_api_test.js +++ b/test/jasmine/tests/plot_api_test.js @@ -786,4 +786,29 @@ describe('Test plot api', function() { expect(gd.data[1].contours).toBeUndefined(); }); }); + + describe('Plotly.newPlot', function() { + var gd; + + beforeEach(function() { + gd = createGraphDiv(); + }); + + afterEach(destroyGraphDiv); + + it('should respect layout.width and layout.height', function(done) { + + // See issue https://github.com/plotly/plotly.js/issues/537 + var data = [{ + x: [1, 2], + y: [1, 2] + }]; + + Plotly.plot(gd, data).then(function() { + Plotly.newPlot(gd, data, { height: 50 }).then(function() { + expect(gd._fullLayout.height).toBe(50); + }).then(done); + }); + }); + }); }); From 53d4b90f39bb63f37789b15357cfaaff9ce63124 Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Wed, 1 Jun 2016 09:40:02 +0100 Subject: [PATCH 06/25] test: autosize sets size of main SVG --- test/jasmine/tests/plot_api_test.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/jasmine/tests/plot_api_test.js b/test/jasmine/tests/plot_api_test.js index 618d35d076e..3a34732fdb1 100644 --- a/test/jasmine/tests/plot_api_test.js +++ b/test/jasmine/tests/plot_api_test.js @@ -805,8 +805,14 @@ describe('Test plot api', function() { }]; Plotly.plot(gd, data).then(function() { - Plotly.newPlot(gd, data, { height: 50 }).then(function() { - expect(gd._fullLayout.height).toBe(50); + var height = 50; + + Plotly.newPlot(gd, data, { height: height }).then(function() { + var fullLayout = gd._fullLayout, + svg = document.getElementsByClassName('main-svg')[0]; + + expect(fullLayout.height).toBe(height); + expect(+svg.getAttribute('height')).toBe(height); }).then(done); }); }); From 61aa240d00808cc4f03c4c53e37b0c63e25439f1 Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Wed, 1 Jun 2016 10:33:45 +0100 Subject: [PATCH 07/25] test: supplyDefaults accepts plain objects --- test/jasmine/tests/plots_test.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/jasmine/tests/plots_test.js b/test/jasmine/tests/plots_test.js index 3d46f8bd298..2575a18e9c9 100644 --- a/test/jasmine/tests/plots_test.js +++ b/test/jasmine/tests/plots_test.js @@ -7,6 +7,24 @@ var destroyGraphDiv = require('../assets/destroy_graph_div'); describe('Test Plots', function() { 'use strict'; + describe('Plotly.supplyDefaults', function() { + it('should not throw an error when gd is a plain object', function() { + var height = 100, + gd = { + layout: { + height: height + } + }; + + Plots.supplyDefaults(gd); + expect(gd.layout.height).toBe(height); + expect(gd._fullLayout).toBeDefined(); + expect(gd._fullLayout.height).toBe(height); + expect(gd._fullLayout.width).toBe(Plots.layoutAttributes.width.dflt); + expect(gd._fullData).toBeDefined(); + }); + }); + describe('Plots.supplyLayoutGlobalDefaults should', function() { var layoutIn, layoutOut, From a334254704ab43d0a571e0755c54e6f55891f3eb Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Wed, 1 Jun 2016 14:51:49 +0100 Subject: [PATCH 08/25] autosize: supplyDefaults accepts plain objects * Fix bug in `plotAutoSize`, triggered when `autosize` and `frameMagins` are both enabled and `gd` is a plain object. * Ensure `autosize` doesn't set values of width and height smaller than the minimum defined in the corresponding layout attribute. --- src/plots/plots.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/plots/plots.js b/src/plots/plots.js index 502a181bc79..2593586234f 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -802,9 +802,18 @@ plots.plotAutoSize = function plotAutoSize(gd, layout, fullLayout) { var reservedMargins = calculateReservedMargins(gd._boundingBoxMargins), reservedWidth = reservedMargins.left + reservedMargins.right, reservedHeight = reservedMargins.bottom + reservedMargins.top, - gdBB = fullLayout._container.node().getBoundingClientRect(), factor = 1 - 2 * frameMargins; + var gdBB; + try { + gdBB = fullLayout._container.node().getBoundingClientRect(); + } catch(err) { + gdBB = { + width: fullLayout.width, + height: fullLayout.height + }; + } + newWidth = Math.round(factor * (gdBB.width - reservedWidth)); newHeight = Math.round(factor * (gdBB.height - reservedHeight)); } @@ -823,6 +832,11 @@ plots.plotAutoSize = function plotAutoSize(gd, layout, fullLayout) { newHeight = parseFloat(computedStyle.height) || fullLayout.height; } + var minWidth = plots.layoutAttributes.width.min, + minHeight = plots.layoutAttributes.height.min; + if(newWidth < minWidth) newWidth = minWidth; + if(newHeight < minHeight) newHeight = minHeight; + var widthHasChanged = !layout.width && (Math.abs(fullLayout.width - newWidth) > 1), heightHasChanged = !layout.height && From 7815efe28cee4e818168461fd8c4e8e84c110a3d Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Wed, 1 Jun 2016 14:58:15 +0100 Subject: [PATCH 09/25] test: autosize, fillFrame and frameMargins --- test/jasmine/tests/config_test.js | 115 ++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/test/jasmine/tests/config_test.js b/test/jasmine/tests/config_test.js index eeda25ab966..8a91cc5b804 100644 --- a/test/jasmine/tests/config_test.js +++ b/test/jasmine/tests/config_test.js @@ -5,6 +5,121 @@ var mouseEvent = require('../assets/mouse_event'); describe('config argument', function() { + describe('attribute autosize', function() { + var layoutWidth = 1111, + relayoutWidth = 555, + containerWidthBeforePlot = 888, + containerWidthBeforeRelayout = 666, + containerHeightBeforePlot = 543, + containerHeightBeforeRelayout = 321, + data = [], + gd; + + beforeEach(function() { + gd = createGraphDiv(); + }); + + afterEach(destroyGraphDiv); + + function checkLayoutSize(width, height) { + expect(gd._fullLayout.width).toBe(width); + expect(gd._fullLayout.height).toBe(height); + + var svg = document.getElementsByClassName('main-svg')[0]; + expect(+svg.getAttribute('width')).toBe(width); + expect(+svg.getAttribute('height')).toBe(height); + } + + function testAutosize(config, layoutHeight, relayoutHeight, done) { + var layout = { + autosize: config.autosizable, + width: layoutWidth + + }, + relayout = { + width: relayoutWidth + }; + + var container = document.getElementById('graph'); + container.style.width = containerWidthBeforePlot + 'px'; + container.style.height = containerHeightBeforePlot + 'px'; + + Plotly.plot(gd, data, layout, config).then(function() { + checkLayoutSize(layoutWidth, layoutHeight); + + container.style.width = containerWidthBeforeRelayout + 'px'; + container.style.height = containerHeightBeforeRelayout + 'px'; + + Plotly.relayout(gd, relayout).then(function() { + checkLayoutSize(relayoutWidth, relayoutHeight); + done(); + }); + }); + } + + it('should fill the frame when autosize: false, fillFrame: true, frameMargins: undefined', function(done) { + var config = { + autosizable: false, + fillFrame: true + }, + layoutHeight = window.innerHeight, + relayoutHeight = layoutHeight; + testAutosize(config, layoutHeight, relayoutHeight, done); + }); + + it('should fill the frame when autosize: true, fillFrame: true and frameMargins: undefined', function(done) { + var config = { + autosizable: true, + fillFrame: true + }, + layoutHeight = window.innerHeight, + relayoutHeight = window.innerHeight; + testAutosize(config, layoutHeight, relayoutHeight, done); + }); + + it('should fill the container when autosize: false, fillFrame: false and frameMargins: undefined', function(done) { + var config = { + autosizable: false, + fillFrame: false + }, + layoutHeight = containerHeightBeforePlot, + relayoutHeight = layoutHeight; + testAutosize(config, layoutHeight, relayoutHeight, done); + }); + + it('should fill the container when autosize: true, fillFrame: false and frameMargins: undefined', function(done) { + var config = { + autosizable: true, + fillFrame: false + }, + layoutHeight = containerHeightBeforePlot, + relayoutHeight = containerHeightBeforeRelayout; + testAutosize(config, layoutHeight, relayoutHeight, done); + }); + + it('should fill the container when autosize: false, fillFrame: false and frameMargins: 0.1', function(done) { + var config = { + autosizable: false, + fillFrame: false, + frameMargins: 0.1 + }, + layoutHeight = 360, + relayoutHeight = layoutHeight; + testAutosize(config, layoutHeight, relayoutHeight, done); + }); + + it('should fill the container when autosize: true, fillFrame: false and frameMargins: 0.1', function(done) { + var config = { + autosizable: true, + fillFrame: false, + frameMargins: 0.1 + }, + layoutHeight = 360, + relayoutHeight = 288; + testAutosize(config, layoutHeight, relayoutHeight, done); + }); + }); + describe('showLink attribute', function() { var gd; From 7e95d936c544a4f9d3aa3497da2f609dbe0b363a Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Wed, 1 Jun 2016 15:44:19 +0100 Subject: [PATCH 10/25] autosize: respect config.autosizable * Do not do the initial autosize if both config.autosizable and layout.autosize are false. --- src/plot_api/plot_config.js | 2 +- src/plots/plots.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plot_api/plot_config.js b/src/plot_api/plot_config.js index 6671d6790de..e1daa53ee08 100644 --- a/src/plot_api/plot_config.js +++ b/src/plot_api/plot_config.js @@ -25,7 +25,7 @@ module.exports = { // we can edit titles, move annotations, etc editable: false, - // plot will respect layout.autosize=true and infer its container size + // DO initial autosize autosizable: false, // if we DO autosize, do we fill the container or the screen? diff --git a/src/plots/plots.js b/src/plots/plots.js index 2593586234f..56c5132c2d0 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -492,9 +492,9 @@ plots.supplyDefaults = function(gd) { // coerce the updated layout and autosize if needed plots.supplyLayoutGlobalDefaults(layout, newFullLayout); - if(!layout.width || !layout.height) { - plots.plotAutoSize(gd, layout, newFullLayout); - } + var initialAutoSize = (!layout.width || !layout.height) && + (layout.autosize || gd._context.autosizable); + if(initialAutoSize) plots.plotAutoSize(gd, layout, newFullLayout); } newFullLayout._initialAutoSizeIsDone = true; From 370ad8b7205a90b8d26f5374e9d1a995457afba6 Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Wed, 1 Jun 2016 15:55:27 +0100 Subject: [PATCH 11/25] test: config.autosizable --- test/jasmine/tests/config_test.js | 57 +++++++++++++++++++------------ 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/test/jasmine/tests/config_test.js b/test/jasmine/tests/config_test.js index 8a91cc5b804..4a49c7c6284 100644 --- a/test/jasmine/tests/config_test.js +++ b/test/jasmine/tests/config_test.js @@ -1,11 +1,12 @@ var Plotly = require('@lib/index'); +var Plots = Plotly.Plots; var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var mouseEvent = require('../assets/mouse_event'); describe('config argument', function() { - describe('attribute autosize', function() { + describe('attribute layout.autosize', function() { var layoutWidth = 1111, relayoutWidth = 555, containerWidthBeforePlot = 888, @@ -30,9 +31,9 @@ describe('config argument', function() { expect(+svg.getAttribute('height')).toBe(height); } - function testAutosize(config, layoutHeight, relayoutHeight, done) { + function testAutosize(autosize, config, layoutHeight, relayoutHeight, done) { var layout = { - autosize: config.autosizable, + autosize: autosize, width: layoutWidth }, @@ -58,65 +59,79 @@ describe('config argument', function() { } it('should fill the frame when autosize: false, fillFrame: true, frameMargins: undefined', function(done) { - var config = { - autosizable: false, + var autosize = false, + config = { + autosizable: true, fillFrame: true }, layoutHeight = window.innerHeight, relayoutHeight = layoutHeight; - testAutosize(config, layoutHeight, relayoutHeight, done); + testAutosize(autosize, config, layoutHeight, relayoutHeight, done); }); it('should fill the frame when autosize: true, fillFrame: true and frameMargins: undefined', function(done) { - var config = { - autosizable: true, + var autosize = true, + config = { fillFrame: true }, layoutHeight = window.innerHeight, relayoutHeight = window.innerHeight; - testAutosize(config, layoutHeight, relayoutHeight, done); + testAutosize(autosize, config, layoutHeight, relayoutHeight, done); }); it('should fill the container when autosize: false, fillFrame: false and frameMargins: undefined', function(done) { - var config = { - autosizable: false, + var autosize = false, + config = { + autosizable: true, fillFrame: false }, layoutHeight = containerHeightBeforePlot, relayoutHeight = layoutHeight; - testAutosize(config, layoutHeight, relayoutHeight, done); + testAutosize(autosize, config, layoutHeight, relayoutHeight, done); }); it('should fill the container when autosize: true, fillFrame: false and frameMargins: undefined', function(done) { - var config = { - autosizable: true, + var autosize = true, + config = { fillFrame: false }, layoutHeight = containerHeightBeforePlot, relayoutHeight = containerHeightBeforeRelayout; - testAutosize(config, layoutHeight, relayoutHeight, done); + testAutosize(autosize, config, layoutHeight, relayoutHeight, done); }); it('should fill the container when autosize: false, fillFrame: false and frameMargins: 0.1', function(done) { - var config = { - autosizable: false, + var autosize = false, + config = { + autosizable: true, fillFrame: false, frameMargins: 0.1 }, layoutHeight = 360, relayoutHeight = layoutHeight; - testAutosize(config, layoutHeight, relayoutHeight, done); + testAutosize(autosize, config, layoutHeight, relayoutHeight, done); }); it('should fill the container when autosize: true, fillFrame: false and frameMargins: 0.1', function(done) { - var config = { - autosizable: true, + var autosize = true, + config = { fillFrame: false, frameMargins: 0.1 }, layoutHeight = 360, relayoutHeight = 288; - testAutosize(config, layoutHeight, relayoutHeight, done); + testAutosize(autosize, config, layoutHeight, relayoutHeight, done); + }); + + it('should respect attribute autosizable: false', function(done) { + var autosize = false, + config = { + autosizable: false, + fillFrame: true + }, + layoutHeight = Plots.layoutAttributes.height.dflt, + relayoutHeight = layoutHeight; + testAutosize(autosize, config, layoutHeight, relayoutHeight, done); }); }); From 46d7af5ae7e7bbefb25ee048cec603698b6af684 Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Wed, 1 Jun 2016 16:33:05 +0100 Subject: [PATCH 12/25] autosize: supplyDefaults accepts plain objects * Fix bug introduced in the commit for respecting `config.autosizable`. --- src/plots/plots.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plots/plots.js b/src/plots/plots.js index 56c5132c2d0..6eb5557b43d 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -492,8 +492,10 @@ plots.supplyDefaults = function(gd) { // coerce the updated layout and autosize if needed plots.supplyLayoutGlobalDefaults(layout, newFullLayout); - var initialAutoSize = (!layout.width || !layout.height) && - (layout.autosize || gd._context.autosizable); + var missingWidthOrHeight = (!layout.width || !layout.height), + autosize = layout.autosize, + autosizable = gd._context && gd._context.autosizable, + initialAutoSize = missingWidthOrHeight && (autosize || autosizable); if(initialAutoSize) plots.plotAutoSize(gd, layout, newFullLayout); } From 94f450a31d35a34e82600faa29662e42587c5daa Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Wed, 1 Jun 2016 16:36:21 +0100 Subject: [PATCH 13/25] test: account for default autosizable being false --- test/jasmine/tests/modebar_test.js | 1 + test/jasmine/tests/plots_test.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js index b8a5c460e12..a0a020c3c3c 100644 --- a/test/jasmine/tests/modebar_test.js +++ b/test/jasmine/tests/modebar_test.js @@ -643,6 +643,7 @@ describe('ModeBar', function() { }]; var mockLayout = { + autosize: true, xaxis: { anchor: 'y', domain: [0, 0.5], diff --git a/test/jasmine/tests/plots_test.js b/test/jasmine/tests/plots_test.js index 2575a18e9c9..f6c5e36e1fc 100644 --- a/test/jasmine/tests/plots_test.js +++ b/test/jasmine/tests/plots_test.js @@ -344,7 +344,7 @@ describe('Test Plots', function() { beforeEach(function(done) { gd = createGraphDiv(); - Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], {}) + Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], { autosize: true }) .then(function() { gd.style.width = '400px'; gd.style.height = '400px'; From 49bb2cfb8c54d20d6af8d5d56b48bc03e3bf00a3 Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Tue, 7 Jun 2016 11:26:32 +0100 Subject: [PATCH 14/25] autosize: use Lib.isPlotDiv(gd) --- src/plots/plots.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/plots/plots.js b/src/plots/plots.js index f43f3201796..4c29719f397 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -788,7 +788,7 @@ plots.plotAutoSize = function plotAutoSize(gd, layout, fullLayout) { newWidth, newHeight; - if(typeof gd.emit === 'function') gd.emit('plotly_autosize'); + if(Lib.isPlotDiv(gd)) gd.emit('plotly_autosize'); // embedded in an iframe - just take the full iframe size // if we get to this point, with no aspect ratio restrictions @@ -806,15 +806,11 @@ plots.plotAutoSize = function plotAutoSize(gd, layout, fullLayout) { reservedHeight = reservedMargins.bottom + reservedMargins.top, factor = 1 - 2 * frameMargins; - var gdBB; - try { - gdBB = fullLayout._container.node().getBoundingClientRect(); - } catch(err) { - gdBB = { + var gdBB = fullLayout._container && fullLayout._container.node ? + fullLayout._container.node().getBoundingClientRect() : { width: fullLayout.width, height: fullLayout.height }; - } newWidth = Math.round(factor * (gdBB.width - reservedWidth)); newHeight = Math.round(factor * (gdBB.height - reservedHeight)); From 0c316bab8f0d60ad812b0e0a4f81cfe958152d06 Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Tue, 7 Jun 2016 11:35:22 +0100 Subject: [PATCH 15/25] autosize: expand description of config.autosizable --- src/plot_api/plot_config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plot_api/plot_config.js b/src/plot_api/plot_config.js index 54765b7ad53..ee3b93ea6ce 100644 --- a/src/plot_api/plot_config.js +++ b/src/plot_api/plot_config.js @@ -26,7 +26,8 @@ module.exports = { // we can edit titles, move annotations, etc editable: false, - // DO initial autosize + // DO autosize once regardless of layout.autosize + // (use default width or height values otherwise) autosizable: false, // if we DO autosize, do we fill the container or the screen? From 3ed69b1490e2b45914920cabb3a2e3c3e222ca5c Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Tue, 7 Jun 2016 11:41:36 +0100 Subject: [PATCH 16/25] autosize: revert change of variable name --- src/plots/plots.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/plots/plots.js b/src/plots/plots.js index 4c29719f397..5d26606682d 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -464,7 +464,7 @@ plots.sendDataToCloud = function(gd) { plots.supplyDefaults = function(gd) { var oldFullLayout = gd._fullLayout || {}, newFullLayout = gd._fullLayout = {}, - layout = gd.layout || {}; + newLayout = gd.layout || {}; var oldFullData = gd._fullData || [], newFullData = gd._fullData = [], @@ -483,20 +483,20 @@ plots.supplyDefaults = function(gd) { var oldWidth = oldFullLayout.width, oldHeight = oldFullLayout.height; - plots.supplyLayoutGlobalDefaults(layout, newFullLayout); + plots.supplyLayoutGlobalDefaults(newLayout, newFullLayout); - if(!layout.width) newFullLayout.width = oldWidth; - if(!layout.height) newFullLayout.height = oldHeight; + if(!newLayout.width) newFullLayout.width = oldWidth; + if(!newLayout.height) newFullLayout.height = oldHeight; } else { // coerce the updated layout and autosize if needed - plots.supplyLayoutGlobalDefaults(layout, newFullLayout); + plots.supplyLayoutGlobalDefaults(newLayout, newFullLayout); - var missingWidthOrHeight = (!layout.width || !layout.height), - autosize = layout.autosize, + var missingWidthOrHeight = (!newLayout.width || !newLayout.height), + autosize = newLayout.autosize, autosizable = gd._context && gd._context.autosizable, initialAutoSize = missingWidthOrHeight && (autosize || autosizable); - if(initialAutoSize) plots.plotAutoSize(gd, layout, newFullLayout); + if(initialAutoSize) plots.plotAutoSize(gd, newLayout, newFullLayout); } newFullLayout._initialAutoSizeIsDone = true; @@ -536,7 +536,7 @@ plots.supplyDefaults = function(gd) { } // finally, fill in the pieces of layout that may need to look at data - plots.supplyLayoutModuleDefaults(layout, newFullLayout, newFullData); + plots.supplyLayoutModuleDefaults(newLayout, newFullLayout, newFullData); // TODO remove in v2.0.0 // add has-plot-type refs to fullLayout for backward compatibility From 862578ee48ab4b02a3b655728bc38bb708eca41d Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Tue, 7 Jun 2016 11:53:50 +0100 Subject: [PATCH 17/25] autosize: fix condition to call sanitizeMargins --- src/plots/plots.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plots/plots.js b/src/plots/plots.js index 5d26606682d..0792be69ca7 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -773,7 +773,7 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) { coerce('margin.autoexpand'); // called in plotAutoSize otherwise - if(layoutOut.width && layoutOut.height) plots.sanitizeMargins(layoutOut); + if(layoutIn.width && layoutIn.height) plots.sanitizeMargins(layoutOut); coerce('paper_bgcolor'); From 172d81dfad29a31ca06c745e08f9e602ac90628c Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Tue, 7 Jun 2016 12:37:01 +0100 Subject: [PATCH 18/25] autosize: restore backwards-compatibility with v1 * Initialise `layout.width` and `layout.height` if `autosize` is false. --- src/plots/plots.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plots/plots.js b/src/plots/plots.js index 0792be69ca7..b85279108b0 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -497,6 +497,12 @@ plots.supplyDefaults = function(gd) { autosizable = gd._context && gd._context.autosizable, initialAutoSize = missingWidthOrHeight && (autosize || autosizable); if(initialAutoSize) plots.plotAutoSize(gd, newLayout, newFullLayout); + + // for backwards-compatibility with Plotly v1.x.x + if(!autosize && missingWidthOrHeight) { + newLayout.width = newFullLayout.width; + newLayout.height = newFullLayout.height; + } } newFullLayout._initialAutoSizeIsDone = true; From 42a3ed0172e5ea27fe88a767b395bdd96af7f85d Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Tue, 7 Jun 2016 16:32:02 +0100 Subject: [PATCH 19/25] test: autosize is backwards-compatible --- test/jasmine/tests/config_test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/jasmine/tests/config_test.js b/test/jasmine/tests/config_test.js index 4a49c7c6284..f066d4a1f07 100644 --- a/test/jasmine/tests/config_test.js +++ b/test/jasmine/tests/config_test.js @@ -31,6 +31,11 @@ describe('config argument', function() { expect(+svg.getAttribute('height')).toBe(height); } + function compareLayoutAndFullLayout(gd) { + expect(gd.layout.width).toBe(gd._fullLayout.width); + expect(gd.layout.height).toBe(gd._fullLayout.height); + } + function testAutosize(autosize, config, layoutHeight, relayoutHeight, done) { var layout = { autosize: autosize, @@ -47,12 +52,14 @@ describe('config argument', function() { Plotly.plot(gd, data, layout, config).then(function() { checkLayoutSize(layoutWidth, layoutHeight); + if(!autosize) compareLayoutAndFullLayout(gd); container.style.width = containerWidthBeforeRelayout + 'px'; container.style.height = containerHeightBeforeRelayout + 'px'; Plotly.relayout(gd, relayout).then(function() { checkLayoutSize(relayoutWidth, relayoutHeight); + if(!autosize) compareLayoutAndFullLayout(gd); done(); }); }); From de69b3d97824500fcffc48e34423991db9ba95f2 Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Tue, 7 Jun 2016 18:01:28 +0100 Subject: [PATCH 20/25] test: supplyDefaults calls sanitizeMargins once --- test/jasmine/tests/plots_test.js | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/test/jasmine/tests/plots_test.js b/test/jasmine/tests/plots_test.js index f6c5e36e1fc..33226b1c1c3 100644 --- a/test/jasmine/tests/plots_test.js +++ b/test/jasmine/tests/plots_test.js @@ -8,6 +8,12 @@ describe('Test Plots', function() { 'use strict'; describe('Plotly.supplyDefaults', function() { + function testSanitizeMarginsHasBeenCalledOnlyOnce(gd) { + spyOn(Plots, 'sanitizeMargins').and.callThrough(); + Plots.supplyDefaults(gd); + expect(Plots.sanitizeMargins).toHaveBeenCalledTimes(1); + } + it('should not throw an error when gd is a plain object', function() { var height = 100, gd = { @@ -23,6 +29,39 @@ describe('Test Plots', function() { expect(gd._fullLayout.width).toBe(Plots.layoutAttributes.width.dflt); expect(gd._fullData).toBeDefined(); }); + + it('should call sanitizeMargins only once when both width and height are defined', function() { + var gd = { + layout: { + width: 100, + height: 100 + } + }; + + testSanitizeMarginsHasBeenCalledOnlyOnce(gd); + }); + + it('should call sanitizeMargins only once when autosize is false', function() { + var gd = { + layout: { + autosize: false, + height: 100 + } + }; + + testSanitizeMarginsHasBeenCalledOnlyOnce(gd); + }); + + it('should call sanitizeMargins only once when autosize is true', function() { + var gd = { + layout: { + autosize: true, + height: 100 + } + }; + + testSanitizeMarginsHasBeenCalledOnlyOnce(gd); + }); }); describe('Plots.supplyLayoutGlobalDefaults should', function() { From ada5323716cfb32e4e9daa6f22d19b40e5990a5c Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Tue, 7 Jun 2016 18:02:42 +0100 Subject: [PATCH 21/25] lib: ensure isPlotDiv accepts plain objects --- src/lib/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/index.js b/src/lib/index.js index 32f3f811a67..84a5a11d2e6 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -379,7 +379,9 @@ lib.getPlotDiv = function(el) { lib.isPlotDiv = function(el) { var el3 = d3.select(el); - return el3.size() && el3.classed('js-plotly-plot'); + return el3.node() instanceof HTMLElement && + el3.size() && + el3.classed('js-plotly-plot'); }; lib.removeElement = function(el) { From bc1a97033d09bb74c92f10362aa71f7ed0702398 Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Tue, 7 Jun 2016 18:06:54 +0100 Subject: [PATCH 22/25] test: Lib.isPlotLib accepts plain objects --- test/jasmine/tests/lib_test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/jasmine/tests/lib_test.js b/test/jasmine/tests/lib_test.js index b736d31a73e..223ce6c1d3a 100644 --- a/test/jasmine/tests/lib_test.js +++ b/test/jasmine/tests/lib_test.js @@ -1041,4 +1041,10 @@ describe('Test lib.js:', function() { }).toThrowError('Separator string required for formatting!'); }); }); + + describe('isPlotDiv', function() { + it('should work on plain objects', function() { + expect(Lib.isPlotDiv({})).toBe(false); + }); + }); }); From 6021c4387b93d685227143f24b77855c94d09b3e Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Tue, 7 Jun 2016 18:22:44 +0100 Subject: [PATCH 23/25] autosize: use Lib.isPlotDiv --- src/plots/plots.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/plots/plots.js b/src/plots/plots.js index b85279108b0..91174b5cb45 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -794,7 +794,9 @@ plots.plotAutoSize = function plotAutoSize(gd, layout, fullLayout) { newWidth, newHeight; - if(Lib.isPlotDiv(gd)) gd.emit('plotly_autosize'); + var isPlotDiv = Lib.isPlotDiv(gd); + + if(isPlotDiv) gd.emit('plotly_autosize'); // embedded in an iframe - just take the full iframe size // if we get to this point, with no aspect ratio restrictions @@ -826,12 +828,8 @@ plots.plotAutoSize = function plotAutoSize(gd, layout, fullLayout) { // provide height and width for the container div, // specify size in layout, or take the defaults, // but don't enforce any ratio restrictions - var computedStyle; - try { - computedStyle = window.getComputedStyle(gd); - } catch(err) { - computedStyle = {}; - } + var computedStyle = isPlotDiv ? window.getComputedStyle(gd) : {}; + newWidth = parseFloat(computedStyle.width) || fullLayout.width; newHeight = parseFloat(computedStyle.height) || fullLayout.height; } From e822ff72ac83b2953dfb2c43aee01035d7a72035 Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Tue, 7 Jun 2016 18:40:30 +0100 Subject: [PATCH 24/25] autosize: ensure sanitizeMargins is called once --- src/plots/plots.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plots/plots.js b/src/plots/plots.js index 91174b5cb45..29025dd999b 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -493,10 +493,11 @@ plots.supplyDefaults = function(gd) { plots.supplyLayoutGlobalDefaults(newLayout, newFullLayout); var missingWidthOrHeight = (!newLayout.width || !newLayout.height), - autosize = newLayout.autosize, + autosize = newFullLayout.autosize, autosizable = gd._context && gd._context.autosizable, initialAutoSize = missingWidthOrHeight && (autosize || autosizable); if(initialAutoSize) plots.plotAutoSize(gd, newLayout, newFullLayout); + else if(missingWidthOrHeight) plots.sanitizeMargins(gd); // for backwards-compatibility with Plotly v1.x.x if(!autosize && missingWidthOrHeight) { @@ -778,7 +779,6 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) { coerce('margin.pad'); coerce('margin.autoexpand'); - // called in plotAutoSize otherwise if(layoutIn.width && layoutIn.height) plots.sanitizeMargins(layoutOut); coerce('paper_bgcolor'); @@ -847,9 +847,9 @@ plots.plotAutoSize = function plotAutoSize(gd, layout, fullLayout) { if(heightHasChanged || widthHasChanged) { if(widthHasChanged) fullLayout.width = newWidth; if(heightHasChanged) fullLayout.height = newHeight; - - plots.sanitizeMargins(fullLayout); } + + plots.sanitizeMargins(fullLayout); }; /** From fbc01c3dc26b4bc3ba005cac87ce128f71fa9551 Mon Sep 17 00:00:00 2001 From: Nicolas Riesco Date: Thu, 9 Jun 2016 17:42:02 +0100 Subject: [PATCH 25/25] autosize: change attribute valType to boolean --- src/plots/layout_attributes.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plots/layout_attributes.js b/src/plots/layout_attributes.js index 063ef3fff5a..030f99eca75 100644 --- a/src/plots/layout_attributes.js +++ b/src/plots/layout_attributes.js @@ -45,9 +45,8 @@ module.exports = { description: 'Sets the title font.' }), autosize: { - valType: 'enumerated', + valType: 'boolean', role: 'info', - values: [false, true], dflt: false, description: [ 'Determines whether or not a layout width or height',