diff --git a/src/plot_api/edit_types.js b/src/plot_api/edit_types.js index 91c59ba4c7a..24701a9a443 100644 --- a/src/plot_api/edit_types.js +++ b/src/plot_api/edit_types.js @@ -35,7 +35,7 @@ var layoutOpts = { valType: 'flaglist', extras: ['none'], flags: [ - 'calc', 'calcIfAutorange', 'plot', 'legend', 'ticks', + 'calc', 'calcIfAutorange', 'plot', 'legend', 'ticks', 'margins', 'layoutstyle', 'modebar', 'camera', 'arraydraw' ], description: [ @@ -47,6 +47,7 @@ var layoutOpts = { '*plot* calls `Plotly.plot` but without first clearing `gd.calcdata`.', '*legend* only redraws the legend.', '*ticks* only redraws axis ticks, labels, and gridlines.', + '*margins* recomputes ticklabel automargins.', '*layoutstyle* reapplies global and SVG cartesian axis styles.', '*modebar* just updates the modebar.', '*camera* just updates the camera settings for gl3d scenes.', diff --git a/src/plot_api/helpers.js b/src/plot_api/helpers.js index 38a5d715dd5..d4f44af785a 100644 --- a/src/plot_api/helpers.js +++ b/src/plot_api/helpers.js @@ -561,3 +561,12 @@ exports.clearAxisTypes = function(gd, traces, layoutUpdate) { } } }; + +exports.clearAxisAutomargins = function(gd) { + var keys = Object.keys(gd._fullLayout._pushmargin); + for(var i = 0; i < keys.length; i++) { + if(keys[i].indexOf('automargin') !== -1) { + delete gd._fullLayout._pushmargin[keys[i]]; + } + } +}; diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index c52bdc44cd5..db10ce3b1fb 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -1742,6 +1742,7 @@ Plotly.relayout = function relayout(gd, astr, val) { // clear calcdata if required if(flags.calc) gd.calcdata = undefined; + if(flags.margins) helpers.clearAxisAutomargins(gd); // fill in redraw sequence @@ -2182,6 +2183,7 @@ Plotly.update = function update(gd, traceUpdate, layoutUpdate, _traces) { // clear calcdata and/or axis types if required if(restyleFlags.clearCalc || relayoutFlags.calc) gd.calcdata = undefined; if(restyleFlags.clearAxisTypes) helpers.clearAxisTypes(gd, traces, layoutUpdate); + if(relayoutFlags.margins) helpers.clearAxisAutomargins(gd); // fill in redraw sequence var seq = []; @@ -2309,6 +2311,7 @@ Plotly.react = function(gd, data, layout, config) { // clear calcdata if required if(restyleFlags.calc || relayoutFlags.calc) gd.calcdata = undefined; + if(relayoutFlags.margins) helpers.clearAxisAutomargins(gd); // Note: what restyle/relayout use impliedEdits and clearAxisTypes for // must be handled by the user when using Plotly.react. diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index d884633bc75..4e1556f119e 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -11,6 +11,7 @@ var d3 = require('d3'); var isNumeric = require('fast-isnumeric'); +var Plots = require('../../plots/plots'); var Registry = require('../../registry'); var Lib = require('../../lib'); @@ -2217,10 +2218,40 @@ axes.doTicks = function(gd, axid, skipTitle) { } } + function doAutoMargins() { + if(!ax.automargin) { return; } + if(axLetter !== 'x' && axLetter !== 'y') { return; } + + var s = ax.side[0]; + var push = {x: 0, y: 0, r: 0, l: 0, t: 0, b: 0}; + + if(axLetter === 'x') { + push.y = (ax.anchor === 'free' ? ax.position : + ax._anchorAxis.domain[s === 't' ? 1 : 0]); + push[s] += ax._boundingBox.height; + } + else { + push.x = (ax.anchor === 'free' ? ax.position : + ax._anchorAxis.domain[s === 'r' ? 1 : 0]); + push[s] += ax._boundingBox.width; + } + + if(ax.title !== fullLayout._dfltTitle[axLetter]) { + push[s] += ax.titlefont.size; + } + + var pushKey = ax._name + '.automargin'; + var prevPush = fullLayout._pushmargin[pushKey]; + if(!prevPush || prevPush[s].size < push[s]) { + Plots.autoMargin(gd, pushKey, push); + } + } + var done = Lib.syncOrAsync([ allLabelsReady, fixLabelOverlaps, - calcBoundingBox + calcBoundingBox, + doAutoMargins ]); if(done && done.then) gd._promises.push(done); return done; diff --git a/src/plots/cartesian/axis_defaults.js b/src/plots/cartesian/axis_defaults.js index 6cc66906ebf..3610f101ce2 100644 --- a/src/plots/cartesian/axis_defaults.js +++ b/src/plots/cartesian/axis_defaults.js @@ -88,5 +88,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, if(containerOut.showline || containerOut.ticks) coerce('mirror'); + if(options.automargin) coerce('automargin'); + return containerOut; }; diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index 64783e015ea..4d7dfe34d8a 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -42,11 +42,11 @@ module.exports = { title: { valType: 'string', role: 'info', - editType: 'ticks', + editType: 'ticks+margins', description: 'Sets the title of this axis.' }, titlefont: fontAttrs({ - editType: 'ticks', + editType: 'ticks+margins', description: [ 'Sets this axis\' title font.' ].join(' ') @@ -100,10 +100,10 @@ module.exports = { valType: 'info_array', role: 'info', items: [ - {valType: 'any', editType: 'plot', impliedEdits: {'^autorange': false}}, - {valType: 'any', editType: 'plot', impliedEdits: {'^autorange': false}} + {valType: 'any', editType: 'plot+margins', impliedEdits: {'^autorange': false}}, + {valType: 'any', editType: 'plot+margins', impliedEdits: {'^autorange': false}} ], - editType: 'plot', + editType: 'plot+margins', impliedEdits: {'autorange': false}, description: [ 'Sets the range of this axis.', @@ -198,7 +198,7 @@ module.exports = { valType: 'enumerated', values: ['auto', 'linear', 'array'], role: 'info', - editType: 'ticks', + editType: 'ticks+margins', impliedEdits: {tick0: undefined, dtick: undefined}, description: [ 'Sets the tick mode for this axis.', @@ -216,7 +216,7 @@ module.exports = { min: 0, dflt: 0, role: 'style', - editType: 'ticks', + editType: 'ticks+margins', description: [ 'Specifies the maximum number of ticks for the particular axis.', 'The actual number of ticks will be chosen automatically to be', @@ -227,7 +227,7 @@ module.exports = { tick0: { valType: 'any', role: 'style', - editType: 'ticks', + editType: 'ticks+margins', impliedEdits: {tickmode: 'linear'}, description: [ 'Sets the placement of the first tick on this axis.', @@ -243,7 +243,7 @@ module.exports = { dtick: { valType: 'any', role: 'style', - editType: 'ticks', + editType: 'ticks+margins', impliedEdits: {tickmode: 'linear'}, description: [ 'Sets the step in-between ticks on this axis. Use with `tick0`.', @@ -269,7 +269,7 @@ module.exports = { }, tickvals: { valType: 'data_array', - editType: 'ticks', + editType: 'ticks+margins', description: [ 'Sets the values at which ticks on this axis appear.', 'Only has an effect if `tickmode` is set to *array*.', @@ -278,7 +278,7 @@ module.exports = { }, ticktext: { valType: 'data_array', - editType: 'ticks', + editType: 'ticks+margins', description: [ 'Sets the text displayed at the ticks position via `tickvals`.', 'Only has an effect if `tickmode` is set to *array*.', @@ -289,7 +289,7 @@ module.exports = { valType: 'enumerated', values: ['outside', 'inside', ''], role: 'style', - editType: 'ticks', + editType: 'ticks+margins', description: [ 'Determines whether ticks are drawn or not.', 'If **, this axis\' ticks are not drawn.', @@ -341,9 +341,19 @@ module.exports = { valType: 'boolean', dflt: true, role: 'style', - editType: 'ticks', + editType: 'ticks+margins', description: 'Determines whether or not the tick labels are drawn.' }, + automargin: { + valType: 'boolean', + dflt: false, + role: 'style', + editType: 'ticks+margins', + description: [ + 'Determines whether long tick labels automatically grow the figure', + 'margins.' + ].join(' ') + }, showspikes: { valType: 'boolean', dflt: false, @@ -396,14 +406,14 @@ module.exports = { description: 'Determines whether spikelines are stuck to the cursor or to the closest datapoints.' }, tickfont: fontAttrs({ - editType: 'ticks', + editType: 'ticks+margins', description: 'Sets the tick font.' }), tickangle: { valType: 'angle', dflt: 'auto', role: 'style', - editType: 'ticks', + editType: 'ticks+margins', description: [ 'Sets the angle of the tick labels with respect to the horizontal.', 'For example, a `tickangle` of -90 draws the tick labels', @@ -414,7 +424,7 @@ module.exports = { valType: 'string', dflt: '', role: 'style', - editType: 'ticks', + editType: 'ticks+margins', description: 'Sets a tick label prefix.' }, showtickprefix: { @@ -422,7 +432,7 @@ module.exports = { values: ['all', 'first', 'last', 'none'], dflt: 'all', role: 'style', - editType: 'ticks', + editType: 'ticks+margins', description: [ 'If *all*, all tick labels are displayed with a prefix.', 'If *first*, only the first tick is displayed with a prefix.', @@ -434,7 +444,7 @@ module.exports = { valType: 'string', dflt: '', role: 'style', - editType: 'ticks', + editType: 'ticks+margins', description: 'Sets a tick label suffix.' }, showticksuffix: { @@ -442,7 +452,7 @@ module.exports = { values: ['all', 'first', 'last', 'none'], dflt: 'all', role: 'style', - editType: 'ticks', + editType: 'ticks+margins', description: 'Same as `showtickprefix` but for tick suffixes.' }, showexponent: { @@ -450,7 +460,7 @@ module.exports = { values: ['all', 'first', 'last', 'none'], dflt: 'all', role: 'style', - editType: 'ticks', + editType: 'ticks+margins', description: [ 'If *all*, all exponents are shown besides their significands.', 'If *first*, only the exponent of the first tick is shown.', @@ -463,7 +473,7 @@ module.exports = { values: ['none', 'e', 'E', 'power', 'SI', 'B'], dflt: 'B', role: 'style', - editType: 'ticks', + editType: 'ticks+margins', description: [ 'Determines a formatting rule for the tick exponents.', 'For example, consider the number 1,000,000,000.', @@ -479,7 +489,7 @@ module.exports = { valType: 'boolean', dflt: false, role: 'style', - editType: 'ticks', + editType: 'ticks+margins', description: [ 'If "true", even 4-digit integers are separated' ].join(' ') @@ -488,7 +498,7 @@ module.exports = { valType: 'string', dflt: '', role: 'style', - editType: 'ticks', + editType: 'ticks+margins', description: [ 'Sets the tick label formatting rule using d3 formatting mini-languages', 'which are very similar to those in Python. For numbers, see:', @@ -507,10 +517,10 @@ module.exports = { valType: 'info_array', role: 'info', items: [ - {valType: 'any', editType: 'ticks'}, - {valType: 'any', editType: 'ticks'} + {valType: 'any', editType: 'ticks+margins'}, + {valType: 'any', editType: 'ticks+margins'} ], - editType: 'ticks', + editType: 'ticks+margins', description: [ 'range [*min*, *max*], where *min*, *max* - dtick values', 'which describe some zoom level, it is possible to omit *min*', @@ -521,12 +531,12 @@ module.exports = { valType: 'string', dflt: '', role: 'style', - editType: 'ticks', + editType: 'ticks+margins', description: [ 'string - dtickformat for described zoom level, the same as *tickformat*' ].join(' ') }, - editType: 'ticks' + editType: 'ticks+margins' }, hoverformat: { valType: 'string', @@ -628,7 +638,7 @@ module.exports = { constants.idRegex.y.toString() ], role: 'info', - editType: 'plot', + editType: 'plot+margins', description: [ 'If set to an opposite-letter axis id (e.g. `x2`, `y`), this axis is bound to', 'the corresponding opposite-letter axis.', @@ -641,7 +651,7 @@ module.exports = { valType: 'enumerated', values: ['top', 'bottom', 'left', 'right'], role: 'info', - editType: 'plot', + editType: 'plot+margins', description: [ 'Determines whether a x (y) axis is positioned', 'at the *bottom* (*left*) or *top* (*right*)', @@ -685,11 +695,11 @@ module.exports = { valType: 'info_array', role: 'info', items: [ - {valType: 'number', min: 0, max: 1, editType: 'plot'}, - {valType: 'number', min: 0, max: 1, editType: 'plot'} + {valType: 'number', min: 0, max: 1, editType: 'plot+margins'}, + {valType: 'number', min: 0, max: 1, editType: 'plot+margins'} ], dflt: [0, 1], - editType: 'plot', + editType: 'plot+margins', description: [ 'Sets the domain of this axis (in plot fraction).' ].join(' ') @@ -700,7 +710,7 @@ module.exports = { max: 1, dflt: 0, role: 'style', - editType: 'plot', + editType: 'plot+margins', description: [ 'Sets the position of this axis in the plotting space', '(in normalized coordinates).', @@ -744,7 +754,7 @@ module.exports = { autotick: { valType: 'boolean', role: 'info', - editType: 'ticks', + editType: 'ticks+margins', description: [ 'Obsolete.', 'Set `tickmode` to *auto* for old `autotick` *true* behavior.', diff --git a/src/plots/cartesian/layout_defaults.js b/src/plots/cartesian/layout_defaults.js index 54cedf70d16..adb92edd49a 100644 --- a/src/plots/cartesian/layout_defaults.js +++ b/src/plots/cartesian/layout_defaults.js @@ -138,6 +138,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { data: fullData, bgColor: bgColor, calendar: layoutOut.calendar, + automargin: true, cheateronly: axLetter === 'x' && xaCheater[axName] && !xaNonCheater[axName] }; diff --git a/src/plots/polar/polar.js b/src/plots/polar/polar.js index 7db125ce6bc..0c6c9b70713 100644 --- a/src/plots/polar/polar.js +++ b/src/plots/polar/polar.js @@ -286,7 +286,10 @@ proto.updateRadialAxis = function(fullLayout, polarLayout) { position: 0, // dummy truthy value to make Axes.doTicks draw the grid - _counteraxis: true + _counteraxis: true, + + // don't use automargins routine for labels + automargin: false }); setScale(ax, radialLayout, fullLayout); @@ -410,7 +413,10 @@ proto.updateAngularAxis = function(fullLayout, polarLayout) { position: 0, // dummy truthy value to make Axes.doTicks draw the grid - _counteraxis: true + _counteraxis: true, + + // don't use automargins routine for labels + automargin: false }); // Set the angular range in degrees to make auto-tick computation cleaner, diff --git a/src/plots/ternary/ternary.js b/src/plots/ternary/ternary.js index 2b0f2ab0169..6814d46fc3d 100644 --- a/src/plots/ternary/ternary.js +++ b/src/plots/ternary/ternary.js @@ -261,7 +261,8 @@ proto.adjustLayout = function(ternaryLayout, graphSize) { _pos: 0, // _this.xaxis.domain[0] * graphSize.w, _id: 'y', _length: w, - _gridpath: 'M0,0l' + h + ',-' + (w / 2) + _gridpath: 'M0,0l' + h + ',-' + (w / 2), + automargin: false // don't use automargins routine for labels }); setConvert(aaxis, _this.graphDiv._fullLayout); aaxis.setScale(); @@ -280,7 +281,8 @@ proto.adjustLayout = function(ternaryLayout, graphSize) { _pos: 0, // (1 - yDomain0) * graphSize.h, _id: 'x', _length: w, - _gridpath: 'M0,0l-' + (w / 2) + ',-' + h + _gridpath: 'M0,0l-' + (w / 2) + ',-' + h, + automargin: false // don't use automargins routine for labels }); setConvert(baxis, _this.graphDiv._fullLayout); baxis.setScale(); @@ -301,7 +303,8 @@ proto.adjustLayout = function(ternaryLayout, graphSize) { _pos: 0, // _this.xaxis.domain[1] * graphSize.w, _id: 'y', _length: w, - _gridpath: 'M0,0l-' + h + ',' + (w / 2) + _gridpath: 'M0,0l-' + h + ',' + (w / 2), + automargin: false // don't use automargins routine for labels }); setConvert(caxis, _this.graphDiv._fullLayout); caxis.setScale(); diff --git a/test/image/baselines/long_axis_labels.png b/test/image/baselines/long_axis_labels.png new file mode 100644 index 00000000000..7c5c5605654 Binary files /dev/null and b/test/image/baselines/long_axis_labels.png differ diff --git a/test/image/mocks/long_axis_labels.json b/test/image/mocks/long_axis_labels.json new file mode 100644 index 00000000000..d15ac453546 --- /dev/null +++ b/test/image/mocks/long_axis_labels.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "type": "scatter", + "name": "loooooong x", + "x": [ + "short label 1", + "loooooong label 1", + "short label 2", + "loooooong label 2", + "short label 3", + "loooooong label 3", + "short label 4", + "loooooongloooooongloooooong label 4", + "short label 5", + "loooooong label 5" + ], + "y": [ + "short label 1", + "loooooong label 1", + "short label 2", + "loooooong label 2", + "short label 3", + "loooooong label 3", + "short label 4", + "loooooong label 4", + "short label 5", + "loooooong label 5" + ] + }, + { + "yaxis": "y2", + "type": "scatter", + "name": "loooooong y", + "x": ["looooooooooooonger"], + "y": ["loooooooo"] + } + ], + "layout": { + "xaxis": { + "title": "X Axis Title", + "titlefont": { "size": 80 }, + "automargin": true + }, + "yaxis": { + "title": "Y Axis Title", + "titlefont": { "size": 40 }, + "ticklen": 50, + "automargin": true + }, + "yaxis2": { + "title": "Y2 Axis Title", + "overlaying": "y", + "side": "right", + "titlefont": { "size": 40 }, + "automargin": true + } + } +} diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index b3e74a8c9bf..77006d1a1fe 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -2564,6 +2564,178 @@ describe('Test axes', function() { }); }); }); + + describe('automargin', function() { + var data = [{ + x: [ + 'short label 1', 'loooooong label 1', + 'short label 2', 'loooooong label 2', + 'short label 3', 'loooooong label 3', + 'short label 4', 'loooooongloooooongloooooong label 4', + 'short label 5', 'loooooong label 5' + ], + y: [ + 'short label 1', 'loooooong label 1', + 'short label 2', 'loooooong label 2', + 'short label 3', 'loooooong label 3', + 'short label 4', 'loooooong label 4', + 'short label 5', 'loooooong label 5' + ] + }], + gd, initialSize, previousSize, savedBottom; + + beforeEach(function() { + gd = createGraphDiv(); + }); + + afterEach(destroyGraphDiv); + + it('should grow and shrink margins', function(done) { + + Plotly.plot(gd, data) + .then(function() { + initialSize = Lib.extendDeep({}, gd._fullLayout._size); + expect(gd._fullLayout.xaxis._lastangle).toBe(30); + }) + .then(function() { + previousSize = Lib.extendDeep({}, gd._fullLayout._size); + return Plotly.relayout(gd, {'yaxis.automargin': true}); + }) + .then(function() { + var size = gd._fullLayout._size; + expect(size.l).toBeGreaterThan(previousSize.l); + expect(size.r).toBe(previousSize.r); + expect(size.b).toBe(previousSize.b); + expect(size.t).toBe(previousSize.t); + }) + .then(function() { + previousSize = Lib.extendDeep({}, gd._fullLayout._size); + return Plotly.relayout(gd, {'xaxis.automargin': true}); + }) + .then(function() { + var size = gd._fullLayout._size; + expect(size.l).toBe(previousSize.l); + expect(size.r).toBe(previousSize.r); + expect(size.b).toBeGreaterThan(previousSize.b); + expect(size.t).toBe(previousSize.t); + }) + .then(function() { + previousSize = Lib.extendDeep({}, gd._fullLayout._size); + savedBottom = previousSize.b; + return Plotly.relayout(gd, {'xaxis.tickangle': 45}); + }) + .then(function() { + var size = gd._fullLayout._size; + expect(size.l).toBe(previousSize.l); + expect(size.r).toBe(previousSize.r); + expect(size.b).toBeGreaterThan(previousSize.b); + expect(size.t).toBe(previousSize.t); + }) + .then(function() { + previousSize = Lib.extendDeep({}, gd._fullLayout._size); + return Plotly.relayout(gd, {'xaxis.tickangle': 30}); + }) + .then(function() { + var size = gd._fullLayout._size; + expect(size.l).toBe(previousSize.l); + expect(size.r).toBe(previousSize.r); + expect(size.b).toBe(savedBottom); + expect(size.t).toBe(previousSize.t); + }) + .then(function() { + previousSize = Lib.extendDeep({}, gd._fullLayout._size); + return Plotly.relayout(gd, {'yaxis.ticklen': 30}); + }) + .then(function() { + var size = gd._fullLayout._size; + expect(size.l).toBeGreaterThan(previousSize.l); + expect(size.r).toBe(previousSize.r); + expect(size.b).toBe(previousSize.b); + expect(size.t).toBe(previousSize.t); + }) + .then(function() { + previousSize = Lib.extendDeep({}, gd._fullLayout._size); + return Plotly.relayout(gd, {'yaxis.titlefont.size': 30}); + }) + .then(function() { + var size = gd._fullLayout._size; + expect(size).toEqual(previousSize); + }) + .then(function() { + previousSize = Lib.extendDeep({}, gd._fullLayout._size); + return Plotly.relayout(gd, {'yaxis.title': 'hello'}); + }) + .then(function() { + var size = gd._fullLayout._size; + expect(size.l).toBeGreaterThan(previousSize.l); + expect(size.r).toBe(previousSize.r); + expect(size.b).toBe(previousSize.b); + expect(size.t).toBe(previousSize.t); + }) + .then(function() { + previousSize = Lib.extendDeep({}, gd._fullLayout._size); + return Plotly.relayout(gd, { 'yaxis.anchor': 'free' }); + }) + .then(function() { + var size = gd._fullLayout._size; + expect(size.l).toBe(previousSize.l); + expect(size.r).toBe(previousSize.r); + expect(size.b).toBe(previousSize.b); + expect(size.t).toBe(previousSize.t); + }) + .then(function() { + previousSize = Lib.extendDeep({}, gd._fullLayout._size); + return Plotly.relayout(gd, { 'yaxis.position': 0.1}); + }) + .then(function() { + var size = gd._fullLayout._size; + expect(size.l).toBeLessThan(previousSize.l, 'axis moved right'); + expect(size.r).toBe(previousSize.r); + expect(size.b).toBe(previousSize.b); + expect(size.t).toBe(previousSize.t); + }) + .then(function() { + previousSize = Lib.extendDeep({}, gd._fullLayout._size); + return Plotly.relayout(gd, { 'yaxis.anchor': 'x' }); + }) + .then(function() { + var size = gd._fullLayout._size; + expect(size.l).toBeGreaterThan(previousSize.l, 'axis snapped back'); + expect(size.r).toBe(previousSize.r); + expect(size.b).toBe(previousSize.b); + expect(size.t).toBe(previousSize.t); + }) + .then(function() { + previousSize = Lib.extendDeep({}, gd._fullLayout._size); + return Plotly.relayout(gd, { + 'yaxis.side': 'right', + 'xaxis.side': 'top' + }); + }) + .then(function() { + var size = gd._fullLayout._size; + // left to right and bottom to top + expect(size.l).toBe(initialSize.r); + expect(size.r).toBe(previousSize.l); + expect(size.b).toBe(initialSize.b); + expect(size.t).toBe(previousSize.b); + }) + .then(function() { + return Plotly.relayout(gd, { + 'xaxis.automargin': false, + 'yaxis.automargin': false + }); + }) + .then(function() { + var size = gd._fullLayout._size; + // back to the defaults + expect(size).toEqual(initialSize); + }) + .catch(failTest) + .then(done); + + }); + }); }); function getZoomInButton(gd) {