Skip to content

Commit 8a310b3

Browse files
authored
Merge pull request #1431 from plotly/axes-ref-cleanup
Axes ref cleanup
2 parents 954da8a + 9612549 commit 8a310b3

File tree

16 files changed

+95
-111
lines changed

16 files changed

+95
-111
lines changed

src/components/colorbar/draw.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,10 @@ module.exports = function draw(gd, id) {
185185
}
186186

187187
// Prepare the Plotly axis object
188-
handleAxisDefaults(cbAxisIn, cbAxisOut, coerce, axisOptions);
188+
handleAxisDefaults(cbAxisIn, cbAxisOut, coerce, axisOptions, fullLayout);
189189
handleAxisPositionDefaults(cbAxisIn, cbAxisOut, coerce, axisOptions);
190190

191191
cbAxisOut._id = 'y' + id;
192-
cbAxisOut._gd = gd;
193192

194193
// position can't go in through supplyDefaults
195194
// because that restricts it to [0,1]

src/plot_api/plot_api.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ Plotly.plot = function(gd, data, layout, config) {
133133

134134
Plots.supplyDefaults(gd);
135135

136+
var fullLayout = gd._fullLayout;
137+
136138
// Polar plots
137139
if(data && data[0] && data[0].r) return plotPolar(gd, data, layout);
138140

139141
// so we don't try to re-call Plotly.plot from inside
140142
// legend and colorbar, if margins changed
141-
gd._replotting = true;
143+
fullLayout._replotting = true;
142144

143145
// make or remake the framework if we need to
144146
if(graphWasEmpty) makePlotFramework(gd);
@@ -152,7 +154,6 @@ Plotly.plot = function(gd, data, layout, config) {
152154
// save initial axis range once per graph
153155
if(graphWasEmpty) Plotly.Axes.saveRangeInitial(gd);
154156

155-
var fullLayout = gd._fullLayout;
156157

157158
// prepare the data and find the autorange
158159

@@ -321,13 +322,13 @@ Plotly.plot = function(gd, data, layout, config) {
321322
Plots.addLinks(gd);
322323

323324
// Mark the first render as complete
324-
gd._replotting = false;
325+
fullLayout._replotting = false;
325326

326327
return Plots.previousPromises(gd);
327328
}
328329

329330
// An initial paint must be completed before these components can be
330-
// correctly sized and the whole plot re-margined. gd._replotting must
331+
// correctly sized and the whole plot re-margined. fullLayout._replotting must
331332
// be set to false before these will work properly.
332333
function finalDraw() {
333334
Registry.getComponentMethod('shapes', 'draw')(gd);

src/plot_api/subroutines.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ exports.lsInner = function(gd) {
4949
xa = Plotly.Axes.getFromId(gd, subplot, 'x'),
5050
ya = Plotly.Axes.getFromId(gd, subplot, 'y');
5151

52-
xa.setScale(); // this may already be done... not sure
52+
// reset scale in case the margins have changed
53+
xa.setScale();
5354
ya.setScale();
5455

5556
if(plotinfo.bg) {

src/plots/cartesian/axes.js

+5-9
Original file line numberDiff line numberDiff line change
@@ -328,14 +328,10 @@ axes.doAutoRange = function(ax) {
328328

329329
// doAutoRange will get called on fullLayout,
330330
// but we want to report its results back to layout
331-
var axIn = ax._gd.layout[ax._name];
332331

333-
if(!axIn) ax._gd.layout[ax._name] = axIn = {};
334-
335-
if(axIn !== ax) {
336-
axIn.range = ax.range.slice();
337-
axIn.autorange = ax.autorange;
338-
}
332+
var axIn = ax._input;
333+
axIn.range = ax.range.slice();
334+
axIn.autorange = ax.autorange;
339335
}
340336
};
341337

@@ -1137,7 +1133,7 @@ axes.tickText = function(ax, x, hover) {
11371133
};
11381134

11391135
function tickTextObj(ax, x, text) {
1140-
var tf = ax.tickfont || ax._gd._fullLayout.font;
1136+
var tf = ax.tickfont || {};
11411137

11421138
return {
11431139
x: x,
@@ -1347,7 +1343,7 @@ function numFormat(v, ax, fmtoverride, hover) {
13471343
if(dp) v = v.substr(0, dp + tickRound).replace(/\.?0+$/, '');
13481344
}
13491345
// insert appropriate decimal point and thousands separator
1350-
v = Lib.numSeparate(v, ax._gd._fullLayout.separators, separatethousands);
1346+
v = Lib.numSeparate(v, ax._separators, separatethousands);
13511347
}
13521348

13531349
// add exponent

src/plots/cartesian/axis_defaults.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ var autoType = require('./axis_autotype');
3939
* data: the plot data to use in choosing auto type
4040
* bgColor: the plot background color, to calculate default gridline colors
4141
*/
42-
module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, options) {
42+
module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, options, layoutOut) {
4343
var letter = options.letter,
4444
font = options.font || {},
4545
defaultTitle = 'Click to enter ' +
@@ -78,7 +78,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,
7878
handleCalendarDefaults(containerIn, containerOut, 'calendar', options.calendar);
7979
}
8080

81-
setConvert(containerOut);
81+
setConvert(containerOut, layoutOut);
8282

8383
var dfltColor = coerce('color');
8484
// if axis.color was provided, use it for fonts too; otherwise,

src/plots/cartesian/index.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
var d3 = require('d3');
1313
var Lib = require('../../lib');
1414
var Plots = require('../plots');
15-
var Axes = require('./axes');
15+
16+
var axisIds = require('./axis_ids');
1617
var constants = require('./constants');
1718

1819
exports.name = 'cartesian';
@@ -166,7 +167,7 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout)
166167

167168
if(hadCartesian && !hasCartesian) {
168169
var subplotLayers = oldFullLayout._cartesianlayer.selectAll('.subplot');
169-
var axIds = Axes.listIds({ _fullLayout: oldFullLayout });
170+
var axIds = axisIds.listIds({ _fullLayout: oldFullLayout });
170171

171172
subplotLayers.call(purgeSubplotLayers, oldFullLayout);
172173
oldFullLayout._defs.selectAll('.axesclip').remove();
@@ -241,13 +242,13 @@ function makeSubplotData(gd) {
241242
// dimension that this one overlays to be an overlaid subplot,
242243
// the main plot must exist make sure we're not trying to
243244
// overlay on an axis that's already overlaying another
244-
var xa2 = Axes.getFromId(gd, xa.overlaying) || xa;
245+
var xa2 = axisIds.getFromId(gd, xa.overlaying) || xa;
245246
if(xa2 !== xa && xa2.overlaying) {
246247
xa2 = xa;
247248
xa.overlaying = false;
248249
}
249250

250-
var ya2 = Axes.getFromId(gd, ya.overlaying) || ya;
251+
var ya2 = axisIds.getFromId(gd, ya.overlaying) || ya;
251252
if(ya2 !== ya && ya2.overlaying) {
252253
ya2 = ya;
253254
ya.overlaying = false;

src/plots/cartesian/layout_defaults.js

+41-22
Original file line numberDiff line numberDiff line change
@@ -115,17 +115,43 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
115115

116116
var bgColor = Color.combine(plot_bgcolor, layoutOut.paper_bgcolor);
117117

118-
var axLayoutIn, axLayoutOut;
118+
var axName, axLayoutIn, axLayoutOut;
119119

120120
function coerce(attr, dflt) {
121121
return Lib.coerce(axLayoutIn, axLayoutOut, layoutAttributes, attr, dflt);
122122
}
123123

124-
axesList.forEach(function(axName) {
125-
var axLetter = axName.charAt(0);
124+
function getCounterAxes(axLetter) {
125+
var list = {x: yaList, y: xaList}[axLetter];
126+
return Lib.simpleMap(list, axisIds.name2id);
127+
}
128+
129+
function getOverlayableAxes(axLetter, axName) {
130+
var list = {x: xaList, y: yaList}[axLetter];
131+
var out = [];
126132

127-
axLayoutIn = layoutIn[axName] || {};
128-
axLayoutOut = {};
133+
for(var j = 0; j < list.length; j++) {
134+
var axName2 = list[j];
135+
136+
if(axName2 !== axName && !(layoutIn[axName2] || {}).overlaying) {
137+
out.push(axisIds.name2id(axName2));
138+
}
139+
}
140+
141+
return out;
142+
}
143+
144+
for(i = 0; i < axesList.length; i++) {
145+
axName = axesList[i];
146+
147+
if(!Lib.isPlainObject(layoutIn[axName])) {
148+
layoutIn[axName] = {};
149+
}
150+
151+
axLayoutIn = layoutIn[axName];
152+
axLayoutOut = layoutOut[axName] = {};
153+
154+
var axLetter = axName.charAt(0);
129155

130156
var defaultOptions = {
131157
letter: axLetter,
@@ -142,29 +168,21 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
142168

143169
var positioningOptions = {
144170
letter: axLetter,
145-
counterAxes: {x: yaList, y: xaList}[axLetter].map(axisIds.name2id),
146-
overlayableAxes: {x: xaList, y: yaList}[axLetter].filter(function(axName2) {
147-
return axName2 !== axName && !(layoutIn[axName2] || {}).overlaying;
148-
}).map(axisIds.name2id)
171+
counterAxes: getCounterAxes(axLetter),
172+
overlayableAxes: getOverlayableAxes(axLetter, axName)
149173
};
150174

151175
handlePositionDefaults(axLayoutIn, axLayoutOut, coerce, positioningOptions);
152176

153-
layoutOut[axName] = axLayoutOut;
154-
155-
// so we don't have to repeat autotype unnecessarily,
156-
// copy an autotype back to layoutIn
157-
if(!layoutIn[axName] && axLayoutIn.type !== '-') {
158-
layoutIn[axName] = {type: axLayoutIn.type};
159-
}
160-
161-
});
177+
axLayoutOut._input = axLayoutIn;
178+
}
162179

163180
// quick second pass for range slider and selector defaults
164181
var rangeSliderDefaults = Registry.getComponentMethod('rangeslider', 'handleDefaults'),
165182
rangeSelectorDefaults = Registry.getComponentMethod('rangeselector', 'handleDefaults');
166183

167-
xaList.forEach(function(axName) {
184+
for(i = 0; i < xaList.length; i++) {
185+
axName = xaList[i];
168186
axLayoutIn = layoutIn[axName];
169187
axLayoutOut = layoutOut[axName];
170188

@@ -181,9 +199,10 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
181199
}
182200

183201
coerce('fixedrange');
184-
});
202+
}
185203

186-
yaList.forEach(function(axName) {
204+
for(i = 0; i < yaList.length; i++) {
205+
axName = yaList[i];
187206
axLayoutIn = layoutIn[axName];
188207
axLayoutOut = layoutOut[axName];
189208

@@ -196,5 +215,5 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
196215
);
197216

198217
coerce('fixedrange', fixedRangeDflt);
199-
});
218+
}
200219
};

src/plots/cartesian/set_convert.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ function num(v) {
6161
* also clears the autorange bounds ._min and ._max
6262
* and the autotick constraints ._minDtick, ._forceTick0
6363
*/
64-
module.exports = function setConvert(ax) {
64+
module.exports = function setConvert(ax, fullLayout) {
65+
fullLayout = fullLayout || {};
6566

6667
// clipMult: how many axis lengths past the edge do we render?
6768
// for panning, 1-2 would suffice, but for zooming more is nice.
@@ -319,7 +320,7 @@ module.exports = function setConvert(ax) {
319320

320321
// set scaling to pixels
321322
ax.setScale = function(usePrivateRange) {
322-
var gs = ax._gd._fullLayout._size,
323+
var gs = fullLayout._size,
323324
axLetter = ax._id.charAt(0);
324325

325326
// TODO cleaner way to handle this case
@@ -328,7 +329,7 @@ module.exports = function setConvert(ax) {
328329
// make sure we have a domain (pull it in from the axis
329330
// this one is overlaying if necessary)
330331
if(ax.overlaying) {
331-
var ax2 = axisIds.getFromId(ax._gd, ax.overlaying);
332+
var ax2 = axisIds.getFromId({ _fullLayout: fullLayout }, ax.overlaying);
332333
ax.domain = ax2.domain;
333334
}
334335

@@ -360,7 +361,7 @@ module.exports = function setConvert(ax) {
360361
Lib.notifier(
361362
'Something went wrong with axis scaling',
362363
'long');
363-
ax._gd._replotting = false;
364+
fullLayout._replotting = false;
364365
throw new Error('axis scaling');
365366
}
366367
};
@@ -417,6 +418,10 @@ module.exports = function setConvert(ax) {
417418
ax._min = [];
418419
ax._max = [];
419420

421+
// copy ref to fullLayout.separators so that
422+
// methods in Axes can use it w/o having to pass fullLayout
423+
ax._separators = fullLayout.separators;
424+
420425
// and for bar charts and box plots: reset forced minimum tick spacing
421426
delete ax._minDtick;
422427
delete ax._forceTick0;

src/plots/geo/geo.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -465,10 +465,9 @@ function createMockAxis(fullLayout) {
465465
var mockAxis = {
466466
type: 'linear',
467467
showexponent: 'all',
468-
exponentformat: Axes.layoutAttributes.exponentformat.dflt,
469-
_gd: { _fullLayout: fullLayout }
468+
exponentformat: Axes.layoutAttributes.exponentformat.dflt
470469
};
471470

472-
Axes.setConvert(mockAxis);
471+
Axes.setConvert(mockAxis, fullLayout);
473472
return mockAxis;
474473
}

src/plots/gl3d/index.js

-15
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ var Plots = require('../plots');
1414
var Lib = require('../../lib');
1515
var xmlnsNamespaces = require('../../constants/xmlns_namespaces');
1616

17-
var axesNames = ['xaxis', 'yaxis', 'zaxis'];
18-
19-
2017
exports.name = 'gl3d';
2118

2219
exports.attr = 'scene';
@@ -45,8 +42,6 @@ exports.plot = function plotGl3d(gd) {
4542
scene = sceneLayout._scene;
4643

4744
if(!scene) {
48-
initAxes(gd, sceneLayout);
49-
5045
scene = new Scene({
5146
id: sceneId,
5247
graphDiv: gd,
@@ -118,13 +113,3 @@ exports.cleanId = function cleanId(id) {
118113

119114
return 'scene' + sceneNum;
120115
};
121-
122-
exports.setConvert = require('./set_convert');
123-
124-
function initAxes(gd, sceneLayout) {
125-
for(var j = 0; j < 3; ++j) {
126-
var axisName = axesNames[j];
127-
128-
sceneLayout[axisName]._gd = gd;
129-
}
130-
}

src/plots/gl3d/scene.js

+9-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ var showNoWebGlMsg = require('../../lib/show_no_webgl_msg');
2222

2323
var createCamera = require('./camera');
2424
var project = require('./project');
25-
var setConvert = require('./set_convert');
2625
var createAxesOptions = require('./layout/convert');
2726
var createSpikeOptions = require('./layout/spikes');
2827
var computeTickMarks = require('./layout/tick_marks');
@@ -339,6 +338,7 @@ proto.plot = function(sceneData, fullLayout, layout) {
339338
this.glplot.snapToData = true;
340339

341340
// Update layout
341+
this.fullLayout = fullLayout;
342342
this.fullSceneLayout = fullSceneLayout;
343343

344344
this.glplotLayout = fullSceneLayout;
@@ -353,10 +353,7 @@ proto.plot = function(sceneData, fullLayout, layout) {
353353
this.glplot.update({});
354354

355355
// Update axes functions BEFORE updating traces
356-
for(i = 0; i < 3; ++i) {
357-
axis = fullSceneLayout[axisProperties[i]];
358-
setConvert(axis);
359-
}
356+
this.setConvert(axis);
360357

361358
// Convert scene data
362359
if(!sceneData) sceneData = [];
@@ -708,4 +705,11 @@ proto.toImage = function(format) {
708705
return dataURL;
709706
};
710707

708+
proto.setConvert = function() {
709+
for(var i = 0; i < 3; ++i) {
710+
var ax = this.fullSceneLayout[axisProperties[i]];
711+
Axes.setConvert(ax, this.fullLayout);
712+
}
713+
};
714+
711715
module.exports = Scene;

0 commit comments

Comments
 (0)