diff --git a/src/components/colorbar/draw.js b/src/components/colorbar/draw.js index b7eef65140c..c76324ca067 100644 --- a/src/components/colorbar/draw.js +++ b/src/components/colorbar/draw.js @@ -185,11 +185,10 @@ module.exports = function draw(gd, id) { } // Prepare the Plotly axis object - handleAxisDefaults(cbAxisIn, cbAxisOut, coerce, axisOptions); + handleAxisDefaults(cbAxisIn, cbAxisOut, coerce, axisOptions, fullLayout); handleAxisPositionDefaults(cbAxisIn, cbAxisOut, coerce, axisOptions); cbAxisOut._id = 'y' + id; - cbAxisOut._gd = gd; // position can't go in through supplyDefaults // because that restricts it to [0,1] diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index e805637d037..b8aad370b5a 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -133,12 +133,14 @@ Plotly.plot = function(gd, data, layout, config) { Plots.supplyDefaults(gd); + var fullLayout = gd._fullLayout; + // Polar plots if(data && data[0] && data[0].r) return plotPolar(gd, data, layout); // so we don't try to re-call Plotly.plot from inside // legend and colorbar, if margins changed - gd._replotting = true; + fullLayout._replotting = true; // make or remake the framework if we need to if(graphWasEmpty) makePlotFramework(gd); @@ -152,7 +154,6 @@ Plotly.plot = function(gd, data, layout, config) { // save initial axis range once per graph if(graphWasEmpty) Plotly.Axes.saveRangeInitial(gd); - var fullLayout = gd._fullLayout; // prepare the data and find the autorange @@ -321,13 +322,13 @@ Plotly.plot = function(gd, data, layout, config) { Plots.addLinks(gd); // Mark the first render as complete - gd._replotting = false; + fullLayout._replotting = false; return Plots.previousPromises(gd); } // An initial paint must be completed before these components can be - // correctly sized and the whole plot re-margined. gd._replotting must + // correctly sized and the whole plot re-margined. fullLayout._replotting must // be set to false before these will work properly. function finalDraw() { Registry.getComponentMethod('shapes', 'draw')(gd); diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index c66c7e77216..48b4962bd07 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -49,7 +49,8 @@ exports.lsInner = function(gd) { xa = Plotly.Axes.getFromId(gd, subplot, 'x'), ya = Plotly.Axes.getFromId(gd, subplot, 'y'); - xa.setScale(); // this may already be done... not sure + // reset scale in case the margins have changed + xa.setScale(); ya.setScale(); if(plotinfo.bg) { diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 1157b32169b..e77bc52831e 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -328,14 +328,10 @@ axes.doAutoRange = function(ax) { // doAutoRange will get called on fullLayout, // but we want to report its results back to layout - var axIn = ax._gd.layout[ax._name]; - if(!axIn) ax._gd.layout[ax._name] = axIn = {}; - - if(axIn !== ax) { - axIn.range = ax.range.slice(); - axIn.autorange = ax.autorange; - } + var axIn = ax._input; + axIn.range = ax.range.slice(); + axIn.autorange = ax.autorange; } }; @@ -1137,7 +1133,7 @@ axes.tickText = function(ax, x, hover) { }; function tickTextObj(ax, x, text) { - var tf = ax.tickfont || ax._gd._fullLayout.font; + var tf = ax.tickfont || {}; return { x: x, @@ -1347,7 +1343,7 @@ function numFormat(v, ax, fmtoverride, hover) { if(dp) v = v.substr(0, dp + tickRound).replace(/\.?0+$/, ''); } // insert appropriate decimal point and thousands separator - v = Lib.numSeparate(v, ax._gd._fullLayout.separators, separatethousands); + v = Lib.numSeparate(v, ax._separators, separatethousands); } // add exponent diff --git a/src/plots/cartesian/axis_defaults.js b/src/plots/cartesian/axis_defaults.js index 0ab7517bd5c..1ed0a669392 100644 --- a/src/plots/cartesian/axis_defaults.js +++ b/src/plots/cartesian/axis_defaults.js @@ -39,7 +39,7 @@ var autoType = require('./axis_autotype'); * data: the plot data to use in choosing auto type * bgColor: the plot background color, to calculate default gridline colors */ -module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, options) { +module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, options, layoutOut) { var letter = options.letter, font = options.font || {}, defaultTitle = 'Click to enter ' + @@ -78,7 +78,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, handleCalendarDefaults(containerIn, containerOut, 'calendar', options.calendar); } - setConvert(containerOut); + setConvert(containerOut, layoutOut); var dfltColor = coerce('color'); // if axis.color was provided, use it for fonts too; otherwise, diff --git a/src/plots/cartesian/index.js b/src/plots/cartesian/index.js index c50444ed68d..4c91f281e10 100644 --- a/src/plots/cartesian/index.js +++ b/src/plots/cartesian/index.js @@ -12,7 +12,8 @@ var d3 = require('d3'); var Lib = require('../../lib'); var Plots = require('../plots'); -var Axes = require('./axes'); + +var axisIds = require('./axis_ids'); var constants = require('./constants'); exports.name = 'cartesian'; @@ -166,7 +167,7 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) if(hadCartesian && !hasCartesian) { var subplotLayers = oldFullLayout._cartesianlayer.selectAll('.subplot'); - var axIds = Axes.listIds({ _fullLayout: oldFullLayout }); + var axIds = axisIds.listIds({ _fullLayout: oldFullLayout }); subplotLayers.call(purgeSubplotLayers, oldFullLayout); oldFullLayout._defs.selectAll('.axesclip').remove(); @@ -241,13 +242,13 @@ function makeSubplotData(gd) { // dimension that this one overlays to be an overlaid subplot, // the main plot must exist make sure we're not trying to // overlay on an axis that's already overlaying another - var xa2 = Axes.getFromId(gd, xa.overlaying) || xa; + var xa2 = axisIds.getFromId(gd, xa.overlaying) || xa; if(xa2 !== xa && xa2.overlaying) { xa2 = xa; xa.overlaying = false; } - var ya2 = Axes.getFromId(gd, ya.overlaying) || ya; + var ya2 = axisIds.getFromId(gd, ya.overlaying) || ya; if(ya2 !== ya && ya2.overlaying) { ya2 = ya; ya.overlaying = false; diff --git a/src/plots/cartesian/layout_defaults.js b/src/plots/cartesian/layout_defaults.js index 3594499ffdc..6b6cb4ee3d0 100644 --- a/src/plots/cartesian/layout_defaults.js +++ b/src/plots/cartesian/layout_defaults.js @@ -115,17 +115,43 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { var bgColor = Color.combine(plot_bgcolor, layoutOut.paper_bgcolor); - var axLayoutIn, axLayoutOut; + var axName, axLayoutIn, axLayoutOut; function coerce(attr, dflt) { return Lib.coerce(axLayoutIn, axLayoutOut, layoutAttributes, attr, dflt); } - axesList.forEach(function(axName) { - var axLetter = axName.charAt(0); + function getCounterAxes(axLetter) { + var list = {x: yaList, y: xaList}[axLetter]; + return Lib.simpleMap(list, axisIds.name2id); + } + + function getOverlayableAxes(axLetter, axName) { + var list = {x: xaList, y: yaList}[axLetter]; + var out = []; - axLayoutIn = layoutIn[axName] || {}; - axLayoutOut = {}; + for(var j = 0; j < list.length; j++) { + var axName2 = list[j]; + + if(axName2 !== axName && !(layoutIn[axName2] || {}).overlaying) { + out.push(axisIds.name2id(axName2)); + } + } + + return out; + } + + for(i = 0; i < axesList.length; i++) { + axName = axesList[i]; + + if(!Lib.isPlainObject(layoutIn[axName])) { + layoutIn[axName] = {}; + } + + axLayoutIn = layoutIn[axName]; + axLayoutOut = layoutOut[axName] = {}; + + var axLetter = axName.charAt(0); var defaultOptions = { letter: axLetter, @@ -142,29 +168,21 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { var positioningOptions = { letter: axLetter, - counterAxes: {x: yaList, y: xaList}[axLetter].map(axisIds.name2id), - overlayableAxes: {x: xaList, y: yaList}[axLetter].filter(function(axName2) { - return axName2 !== axName && !(layoutIn[axName2] || {}).overlaying; - }).map(axisIds.name2id) + counterAxes: getCounterAxes(axLetter), + overlayableAxes: getOverlayableAxes(axLetter, axName) }; handlePositionDefaults(axLayoutIn, axLayoutOut, coerce, positioningOptions); - layoutOut[axName] = axLayoutOut; - - // so we don't have to repeat autotype unnecessarily, - // copy an autotype back to layoutIn - if(!layoutIn[axName] && axLayoutIn.type !== '-') { - layoutIn[axName] = {type: axLayoutIn.type}; - } - - }); + axLayoutOut._input = axLayoutIn; + } // quick second pass for range slider and selector defaults var rangeSliderDefaults = Registry.getComponentMethod('rangeslider', 'handleDefaults'), rangeSelectorDefaults = Registry.getComponentMethod('rangeselector', 'handleDefaults'); - xaList.forEach(function(axName) { + for(i = 0; i < xaList.length; i++) { + axName = xaList[i]; axLayoutIn = layoutIn[axName]; axLayoutOut = layoutOut[axName]; @@ -181,9 +199,10 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { } coerce('fixedrange'); - }); + } - yaList.forEach(function(axName) { + for(i = 0; i < yaList.length; i++) { + axName = yaList[i]; axLayoutIn = layoutIn[axName]; axLayoutOut = layoutOut[axName]; @@ -196,5 +215,5 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { ); coerce('fixedrange', fixedRangeDflt); - }); + } }; diff --git a/src/plots/cartesian/set_convert.js b/src/plots/cartesian/set_convert.js index e6036bd8ef9..903864504e8 100644 --- a/src/plots/cartesian/set_convert.js +++ b/src/plots/cartesian/set_convert.js @@ -61,7 +61,8 @@ function num(v) { * also clears the autorange bounds ._min and ._max * and the autotick constraints ._minDtick, ._forceTick0 */ -module.exports = function setConvert(ax) { +module.exports = function setConvert(ax, fullLayout) { + fullLayout = fullLayout || {}; // clipMult: how many axis lengths past the edge do we render? // for panning, 1-2 would suffice, but for zooming more is nice. @@ -319,7 +320,7 @@ module.exports = function setConvert(ax) { // set scaling to pixels ax.setScale = function(usePrivateRange) { - var gs = ax._gd._fullLayout._size, + var gs = fullLayout._size, axLetter = ax._id.charAt(0); // TODO cleaner way to handle this case @@ -328,7 +329,7 @@ module.exports = function setConvert(ax) { // make sure we have a domain (pull it in from the axis // this one is overlaying if necessary) if(ax.overlaying) { - var ax2 = axisIds.getFromId(ax._gd, ax.overlaying); + var ax2 = axisIds.getFromId({ _fullLayout: fullLayout }, ax.overlaying); ax.domain = ax2.domain; } @@ -360,7 +361,7 @@ module.exports = function setConvert(ax) { Lib.notifier( 'Something went wrong with axis scaling', 'long'); - ax._gd._replotting = false; + fullLayout._replotting = false; throw new Error('axis scaling'); } }; @@ -417,6 +418,10 @@ module.exports = function setConvert(ax) { ax._min = []; ax._max = []; + // copy ref to fullLayout.separators so that + // methods in Axes can use it w/o having to pass fullLayout + ax._separators = fullLayout.separators; + // and for bar charts and box plots: reset forced minimum tick spacing delete ax._minDtick; delete ax._forceTick0; diff --git a/src/plots/geo/geo.js b/src/plots/geo/geo.js index 72f5b016b7d..56dd3ce42cc 100644 --- a/src/plots/geo/geo.js +++ b/src/plots/geo/geo.js @@ -465,10 +465,9 @@ function createMockAxis(fullLayout) { var mockAxis = { type: 'linear', showexponent: 'all', - exponentformat: Axes.layoutAttributes.exponentformat.dflt, - _gd: { _fullLayout: fullLayout } + exponentformat: Axes.layoutAttributes.exponentformat.dflt }; - Axes.setConvert(mockAxis); + Axes.setConvert(mockAxis, fullLayout); return mockAxis; } diff --git a/src/plots/gl3d/index.js b/src/plots/gl3d/index.js index 6e42343abc0..66cc89996fc 100644 --- a/src/plots/gl3d/index.js +++ b/src/plots/gl3d/index.js @@ -14,9 +14,6 @@ var Plots = require('../plots'); var Lib = require('../../lib'); var xmlnsNamespaces = require('../../constants/xmlns_namespaces'); -var axesNames = ['xaxis', 'yaxis', 'zaxis']; - - exports.name = 'gl3d'; exports.attr = 'scene'; @@ -45,8 +42,6 @@ exports.plot = function plotGl3d(gd) { scene = sceneLayout._scene; if(!scene) { - initAxes(gd, sceneLayout); - scene = new Scene({ id: sceneId, graphDiv: gd, @@ -118,13 +113,3 @@ exports.cleanId = function cleanId(id) { return 'scene' + sceneNum; }; - -exports.setConvert = require('./set_convert'); - -function initAxes(gd, sceneLayout) { - for(var j = 0; j < 3; ++j) { - var axisName = axesNames[j]; - - sceneLayout[axisName]._gd = gd; - } -} diff --git a/src/plots/gl3d/scene.js b/src/plots/gl3d/scene.js index 013075e5e64..0373a665a19 100644 --- a/src/plots/gl3d/scene.js +++ b/src/plots/gl3d/scene.js @@ -22,7 +22,6 @@ var showNoWebGlMsg = require('../../lib/show_no_webgl_msg'); var createCamera = require('./camera'); var project = require('./project'); -var setConvert = require('./set_convert'); var createAxesOptions = require('./layout/convert'); var createSpikeOptions = require('./layout/spikes'); var computeTickMarks = require('./layout/tick_marks'); @@ -339,6 +338,7 @@ proto.plot = function(sceneData, fullLayout, layout) { this.glplot.snapToData = true; // Update layout + this.fullLayout = fullLayout; this.fullSceneLayout = fullSceneLayout; this.glplotLayout = fullSceneLayout; @@ -353,10 +353,7 @@ proto.plot = function(sceneData, fullLayout, layout) { this.glplot.update({}); // Update axes functions BEFORE updating traces - for(i = 0; i < 3; ++i) { - axis = fullSceneLayout[axisProperties[i]]; - setConvert(axis); - } + this.setConvert(axis); // Convert scene data if(!sceneData) sceneData = []; @@ -708,4 +705,11 @@ proto.toImage = function(format) { return dataURL; }; +proto.setConvert = function() { + for(var i = 0; i < 3; ++i) { + var ax = this.fullSceneLayout[axisProperties[i]]; + Axes.setConvert(ax, this.fullLayout); + } +}; + module.exports = Scene; diff --git a/src/plots/gl3d/set_convert.js b/src/plots/gl3d/set_convert.js deleted file mode 100644 index d19caa8f713..00000000000 --- a/src/plots/gl3d/set_convert.js +++ /dev/null @@ -1,19 +0,0 @@ -/** -* Copyright 2012-2017, Plotly, Inc. -* All rights reserved. -* -* This source code is licensed under the MIT license found in the -* LICENSE file in the root directory of this source tree. -*/ - - -'use strict'; - -var Lib = require('../../lib'); -var Axes = require('../cartesian/axes'); - - -module.exports = function setConvert(containerOut) { - Axes.setConvert(containerOut); - containerOut.setScale = Lib.noop; -}; diff --git a/src/plots/plots.js b/src/plots/plots.js index cd5ca7a212d..87fb69e66b2 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -491,12 +491,10 @@ plots.supplyDefaults = function(gd) { // TODO may return a promise plots.doAutoMargin(gd); - // can't quite figure out how to get rid of this... each axis needs - // a reference back to the DOM object for just a few purposes + // set scale after auto margin routine var axList = Plotly.Axes.list(gd); for(i = 0; i < axList.length; i++) { var ax = axList[i]; - ax._gd = gd; ax.setScale(); } @@ -1127,7 +1125,6 @@ plots.purge = function(gd) { delete gd._testref; delete gd._promises; delete gd._redrawTimer; - delete gd._replotting; delete gd.firstscatter; delete gd.hmlumcount; delete gd.hmpixcount; @@ -1208,7 +1205,7 @@ plots.autoMargin = function(gd, id, o) { }; } - if(!gd._replotting) plots.doAutoMargin(gd); + if(!fullLayout._replotting) plots.doAutoMargin(gd); } }; @@ -1301,7 +1298,7 @@ plots.doAutoMargin = function(gd) { gs.h = Math.round(fullLayout.height) - gs.t - gs.b; // if things changed and we're not already redrawing, trigger a redraw - if(!gd._replotting && oldmargins !== '{}' && + if(!fullLayout._replotting && oldmargins !== '{}' && oldmargins !== JSON.stringify(fullLayout._size)) { return Plotly.plot(gd); } diff --git a/src/plots/ternary/ternary.js b/src/plots/ternary/ternary.js index 547e427af99..2c53f6f4a17 100644 --- a/src/plots/ternary/ternary.js +++ b/src/plots/ternary/ternary.js @@ -176,10 +176,9 @@ proto.adjustLayout = function(ternaryLayout, graphSize) { xDomainCenter - xDomainFinal / 2, xDomainCenter + xDomainFinal / 2 ], - _id: 'x', - _gd: _this.graphDiv + _id: 'x' }; - setConvert(_this.xaxis); + setConvert(_this.xaxis, _this.graphDiv._fullLayout); _this.xaxis.setScale(); _this.yaxis = { @@ -189,10 +188,9 @@ proto.adjustLayout = function(ternaryLayout, graphSize) { yDomainCenter - yDomainFinal / 2, yDomainCenter + yDomainFinal / 2 ], - _id: 'y', - _gd: _this.graphDiv + _id: 'y' }; - setConvert(_this.yaxis); + setConvert(_this.yaxis, _this.graphDiv._fullLayout); _this.yaxis.setScale(); // set up the modified axes for tick drawing @@ -212,12 +210,12 @@ proto.adjustLayout = function(ternaryLayout, graphSize) { _axislayer: _this.layers.aaxis, _gridlayer: _this.layers.agrid, _pos: 0, // _this.xaxis.domain[0] * graphSize.w, - _gd: _this.graphDiv, _id: 'y', _length: w, _gridpath: 'M0,0l' + h + ',-' + (w / 2) }); - setConvert(aaxis); + setConvert(aaxis, _this.graphDiv._fullLayout); + aaxis.setScale(); // baxis goes across the bottom (backward). We can set it up as an x axis // without any enclosing transformation. @@ -230,12 +228,12 @@ proto.adjustLayout = function(ternaryLayout, graphSize) { _gridlayer: _this.layers.bgrid, _counteraxis: _this.aaxis, _pos: 0, // (1 - yDomain0) * graphSize.h, - _gd: _this.graphDiv, _id: 'x', _length: w, _gridpath: 'M0,0l-' + (w / 2) + ',-' + h }); - setConvert(baxis); + setConvert(baxis, _this.graphDiv._fullLayout); + baxis.setScale(); aaxis._counteraxis = baxis; // caxis goes down the right side. Set it up as a y axis, with @@ -250,12 +248,12 @@ proto.adjustLayout = function(ternaryLayout, graphSize) { _gridlayer: _this.layers.cgrid, _counteraxis: _this.baxis, _pos: 0, // _this.xaxis.domain[1] * graphSize.w, - _gd: _this.graphDiv, _id: 'y', _length: w, _gridpath: 'M0,0l-' + h + ',' + (w / 2) }); - setConvert(caxis); + setConvert(caxis, _this.graphDiv._fullLayout); + caxis.setScale(); var triangleClip = 'M' + x0 + ',' + (y0 + h) + 'h' + w + 'l-' + (w / 2) + ',-' + h + 'Z'; _this.clipDef.select('path').attr('d', triangleClip); diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index 656a3284135..6f82ef2b067 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -1485,9 +1485,8 @@ describe('Test axes', function() { describe('calcTicks and tickText', function() { function mockCalc(ax) { - Axes.setConvert(ax); ax.tickfont = {}; - ax._gd = {_fullLayout: {separators: '.,'}}; + Axes.setConvert(ax, {separators: '.,'}); return Axes.calcTicks(ax).map(function(v) { return v.text; }); } diff --git a/test/jasmine/tests/plots_test.js b/test/jasmine/tests/plots_test.js index 0e702ec5b89..b2bd10f5cca 100644 --- a/test/jasmine/tests/plots_test.js +++ b/test/jasmine/tests/plots_test.js @@ -418,7 +418,6 @@ describe('Test Plots', function() { expect(gd._testref).toBeUndefined(); expect(gd._promises).toBeUndefined(); expect(gd._redrawTimer).toBeUndefined(); - expect(gd._replotting).toBeUndefined(); expect(gd.firstscatter).toBeUndefined(); expect(gd.hmlumcount).toBeUndefined(); expect(gd.hmpixcount).toBeUndefined();