Skip to content

Commit f7baf5d

Browse files
authored
Merge pull request #5287 from plotly/match-scale-aj
rework matching & scaleanchor so they work together
2 parents 6a0ecd2 + aaf33d3 commit f7baf5d

30 files changed

+919
-416
lines changed

src/plot_api/plot_api.js

+14-16
Original file line numberDiff line numberDiff line change
@@ -2055,7 +2055,7 @@ function _relayout(gd, aobj) {
20552055
// we're editing the (auto)range of, so we can tell the others constrained
20562056
// to scale with them that it's OK for them to shrink
20572057
var rangesAltered = {};
2058-
var axId;
2058+
var axId, ax;
20592059

20602060
function recordAlteredAxis(pleafPlus) {
20612061
var axId = Axes.name2id(pleafPlus.split('.')[0]);
@@ -2145,7 +2145,7 @@ function _relayout(gd, aobj) {
21452145
// previously we did this for log <-> not-log, but now only do it
21462146
// for log <-> linear
21472147
if(pleaf === 'type') {
2148-
var ax = parentIn;
2148+
ax = parentIn;
21492149
var toLog = parentFull.type === 'linear' && vi === 'log';
21502150
var fromLog = parentFull.type === 'log' && vi === 'linear';
21512151

@@ -2283,21 +2283,19 @@ function _relayout(gd, aobj) {
22832283
}
22842284

22852285
// figure out if we need to recalculate axis constraints
2286-
var constraints = fullLayout._axisConstraintGroups || [];
22872286
for(axId in rangesAltered) {
2288-
for(i = 0; i < constraints.length; i++) {
2289-
var group = constraints[i];
2290-
if(group[axId]) {
2291-
// Always recalc if we're changing constrained ranges.
2292-
// Otherwise it's possible to violate the constraints by
2293-
// specifying arbitrary ranges for all axes in the group.
2294-
// this way some ranges may expand beyond what's specified,
2295-
// as they do at first draw, to satisfy the constraints.
2296-
flags.calc = true;
2297-
for(var groupAxId in group) {
2298-
if(!rangesAltered[groupAxId]) {
2299-
Axes.getFromId(gd, groupAxId)._constraintShrinkable = true;
2300-
}
2287+
ax = Axes.getFromId(gd, axId);
2288+
var group = ax && ax._constraintGroup;
2289+
if(group) {
2290+
// Always recalc if we're changing constrained ranges.
2291+
// Otherwise it's possible to violate the constraints by
2292+
// specifying arbitrary ranges for all axes in the group.
2293+
// this way some ranges may expand beyond what's specified,
2294+
// as they do at first draw, to satisfy the constraints.
2295+
flags.calc = true;
2296+
for(var groupAxId in group) {
2297+
if(!rangesAltered[groupAxId]) {
2298+
Axes.getFromId(gd, groupAxId)._constraintShrinkable = true;
23012299
}
23022300
}
23032301
}

src/plot_api/subroutines.js

+19-42
Original file line numberDiff line numberDiff line change
@@ -667,57 +667,34 @@ exports.redrawReglTraces = function(gd) {
667667
};
668668

669669
exports.doAutoRangeAndConstraints = function(gd) {
670-
var fullLayout = gd._fullLayout;
671670
var axList = Axes.list(gd, '', true);
672-
var matchGroups = fullLayout._axisMatchGroups || [];
673-
var axLookup = {};
674671
var ax;
675-
var axRng;
672+
673+
var autoRangeDone = {};
676674

677675
for(var i = 0; i < axList.length; i++) {
678676
ax = axList[i];
679-
cleanAxisConstraints(gd, ax);
680-
doAutoRange(gd, ax);
681-
axLookup[ax._id] = 1;
682-
}
683-
684-
enforceAxisConstraints(gd);
685-
686-
groupLoop:
687-
for(var j = 0; j < matchGroups.length; j++) {
688-
var group = matchGroups[j];
689-
var rng = null;
690-
var id;
691-
692-
for(id in group) {
693-
ax = Axes.getFromId(gd, id);
694-
695-
// skip over 'missing' axes which do not pass through doAutoRange
696-
if(!axLookup[ax._id]) continue;
697-
// if one axis has autorange false, we're done
698-
if(ax.autorange === false) continue groupLoop;
699-
700-
axRng = Lib.simpleMap(ax.range, ax.r2l);
701-
if(rng) {
702-
if(rng[0] < rng[1]) {
703-
rng[0] = Math.min(rng[0], axRng[0]);
704-
rng[1] = Math.max(rng[1], axRng[1]);
705-
} else {
706-
rng[0] = Math.max(rng[0], axRng[0]);
707-
rng[1] = Math.min(rng[1], axRng[1]);
677+
if(!autoRangeDone[ax._id]) {
678+
autoRangeDone[ax._id] = 1;
679+
cleanAxisConstraints(gd, ax);
680+
doAutoRange(gd, ax);
681+
682+
// For matching axes, just propagate this autorange to the group.
683+
// The extra arg to doAutoRange avoids recalculating the range,
684+
// since doAutoRange by itself accounts for all matching axes. but
685+
// there are other side-effects of doAutoRange that we still want.
686+
var matchGroup = ax._matchGroup;
687+
if(matchGroup) {
688+
for(var id2 in matchGroup) {
689+
var ax2 = Axes.getFromId(gd, id2);
690+
doAutoRange(gd, ax2, ax.range);
691+
autoRangeDone[id2] = 1;
708692
}
709-
} else {
710-
rng = axRng;
711693
}
712694
}
713-
714-
for(id in group) {
715-
ax = Axes.getFromId(gd, id);
716-
ax.range = Lib.simpleMap(rng, ax.l2r);
717-
ax._input.range = ax.range.slice();
718-
ax.setScale();
719-
}
720695
}
696+
697+
enforceAxisConstraints(gd);
721698
};
722699

723700
// An initial paint must be completed before these components can be

src/plots/cartesian/autorange.js

+25-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ var Lib = require('../../lib');
1414
var FP_SAFE = require('../../constants/numerical').FP_SAFE;
1515
var Registry = require('../../registry');
1616

17+
var getFromId = require('./axis_ids').getFromId;
18+
1719
module.exports = {
1820
getAutoRange: getAutoRange,
1921
makePadFn: makePadFn,
@@ -213,7 +215,7 @@ function makePadFn(ax) {
213215
return function getPad(pt) { return pt.pad + (pt.extrapad ? extrappad : 0); };
214216
}
215217

216-
function concatExtremes(gd, ax) {
218+
function concatExtremes(gd, ax, noMatch) {
217219
var axId = ax._id;
218220
var fullData = gd._fullData;
219221
var fullLayout = gd._fullLayout;
@@ -242,14 +244,34 @@ function concatExtremes(gd, ax) {
242244
_concat(fullLayout.annotations || [], ax._annIndices || []);
243245
_concat(fullLayout.shapes || [], ax._shapeIndices || []);
244246

247+
// Include the extremes from other matched axes with this one
248+
if(ax._matchGroup && !noMatch) {
249+
for(var axId2 in ax._matchGroup) {
250+
if(axId2 !== ax._id) {
251+
var ax2 = getFromId(gd, axId2);
252+
var extremes2 = concatExtremes(gd, ax2, true);
253+
// convert padding on the second axis to the first with lenRatio
254+
var lenRatio = ax._length / ax2._length;
255+
for(j = 0; j < extremes2.min.length; j++) {
256+
d = extremes2.min[j];
257+
collapseMinArray(minArray, d.val, d.pad * lenRatio, {extrapad: d.extrapad});
258+
}
259+
for(j = 0; j < extremes2.max.length; j++) {
260+
d = extremes2.max[j];
261+
collapseMaxArray(maxArray, d.val, d.pad * lenRatio, {extrapad: d.extrapad});
262+
}
263+
}
264+
}
265+
}
266+
245267
return {min: minArray, max: maxArray};
246268
}
247269

248-
function doAutoRange(gd, ax) {
270+
function doAutoRange(gd, ax, presetRange) {
249271
ax.setScale();
250272

251273
if(ax.autorange) {
252-
ax.range = getAutoRange(gd, ax);
274+
ax.range = presetRange ? presetRange.slice() : getAutoRange(gd, ax);
253275

254276
ax._r = ax.range.slice();
255277
ax._rl = Lib.simpleMap(ax._r, ax.r2l);

src/plots/cartesian/axis_ids.js

-10
Original file line numberDiff line numberDiff line change
@@ -123,16 +123,6 @@ exports.idSort = function(id1, id2) {
123123
return +(id1.substr(1) || 1) - +(id2.substr(1) || 1);
124124
};
125125

126-
exports.getAxisGroup = function getAxisGroup(fullLayout, axId) {
127-
var matchGroups = fullLayout._axisMatchGroups;
128-
129-
for(var i = 0; i < matchGroups.length; i++) {
130-
var group = matchGroups[i];
131-
if(group[axId]) return 'g' + i;
132-
}
133-
return axId;
134-
};
135-
136126
/*
137127
* An axis reference (e.g., the contents at the 'xref' key of an object) might
138128
* have extra information appended. Extract the axis ID only.

0 commit comments

Comments
 (0)