Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rework matching & scaleanchor so they work together #5287

Merged
merged 11 commits into from
Nov 21, 2020
30 changes: 14 additions & 16 deletions src/plot_api/plot_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2055,7 +2055,7 @@ function _relayout(gd, aobj) {
// we're editing the (auto)range of, so we can tell the others constrained
// to scale with them that it's OK for them to shrink
var rangesAltered = {};
var axId;
var axId, ax;

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

Expand Down Expand Up @@ -2283,21 +2283,19 @@ function _relayout(gd, aobj) {
}

// figure out if we need to recalculate axis constraints
var constraints = fullLayout._axisConstraintGroups || [];
for(axId in rangesAltered) {
for(i = 0; i < constraints.length; i++) {
var group = constraints[i];
if(group[axId]) {
// Always recalc if we're changing constrained ranges.
// Otherwise it's possible to violate the constraints by
// specifying arbitrary ranges for all axes in the group.
// this way some ranges may expand beyond what's specified,
// as they do at first draw, to satisfy the constraints.
flags.calc = true;
for(var groupAxId in group) {
if(!rangesAltered[groupAxId]) {
Axes.getFromId(gd, groupAxId)._constraintShrinkable = true;
}
ax = Axes.getFromId(gd, axId);
var group = ax && ax._constraintGroup;
if(group) {
// Always recalc if we're changing constrained ranges.
// Otherwise it's possible to violate the constraints by
// specifying arbitrary ranges for all axes in the group.
// this way some ranges may expand beyond what's specified,
// as they do at first draw, to satisfy the constraints.
flags.calc = true;
for(var groupAxId in group) {
if(!rangesAltered[groupAxId]) {
Axes.getFromId(gd, groupAxId)._constraintShrinkable = true;
}
}
}
Expand Down
61 changes: 19 additions & 42 deletions src/plot_api/subroutines.js
Original file line number Diff line number Diff line change
Expand Up @@ -667,57 +667,34 @@ exports.redrawReglTraces = function(gd) {
};

exports.doAutoRangeAndConstraints = function(gd) {
var fullLayout = gd._fullLayout;
var axList = Axes.list(gd, '', true);
var matchGroups = fullLayout._axisMatchGroups || [];
var axLookup = {};
var ax;
var axRng;

var autoRangeDone = {};

for(var i = 0; i < axList.length; i++) {
ax = axList[i];
cleanAxisConstraints(gd, ax);
doAutoRange(gd, ax);
axLookup[ax._id] = 1;
}

enforceAxisConstraints(gd);

groupLoop:
for(var j = 0; j < matchGroups.length; j++) {
var group = matchGroups[j];
var rng = null;
var id;

for(id in group) {
ax = Axes.getFromId(gd, id);

// skip over 'missing' axes which do not pass through doAutoRange
if(!axLookup[ax._id]) continue;
// if one axis has autorange false, we're done
if(ax.autorange === false) continue groupLoop;

axRng = Lib.simpleMap(ax.range, ax.r2l);
if(rng) {
if(rng[0] < rng[1]) {
rng[0] = Math.min(rng[0], axRng[0]);
rng[1] = Math.max(rng[1], axRng[1]);
} else {
rng[0] = Math.max(rng[0], axRng[0]);
rng[1] = Math.min(rng[1], axRng[1]);
if(!autoRangeDone[ax._id]) {
autoRangeDone[ax._id] = 1;
cleanAxisConstraints(gd, ax);
doAutoRange(gd, ax);

// For matching axes, just propagate this autorange to the group.
// The extra arg to doAutoRange avoids recalculating the range,
// since doAutoRange by itself accounts for all matching axes. but
// there are other side-effects of doAutoRange that we still want.
var matchGroup = ax._matchGroup;
if(matchGroup) {
for(var id2 in matchGroup) {
var ax2 = Axes.getFromId(gd, id2);
doAutoRange(gd, ax2, ax.range);
autoRangeDone[id2] = 1;
}
} else {
rng = axRng;
}
}

for(id in group) {
ax = Axes.getFromId(gd, id);
ax.range = Lib.simpleMap(rng, ax.l2r);
ax._input.range = ax.range.slice();
ax.setScale();
}
}

enforceAxisConstraints(gd);
};

// An initial paint must be completed before these components can be
Expand Down
28 changes: 25 additions & 3 deletions src/plots/cartesian/autorange.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ var Lib = require('../../lib');
var FP_SAFE = require('../../constants/numerical').FP_SAFE;
var Registry = require('../../registry');

var getFromId = require('./axis_ids').getFromId;

module.exports = {
getAutoRange: getAutoRange,
makePadFn: makePadFn,
Expand Down Expand Up @@ -213,7 +215,7 @@ function makePadFn(ax) {
return function getPad(pt) { return pt.pad + (pt.extrapad ? extrappad : 0); };
}

function concatExtremes(gd, ax) {
function concatExtremes(gd, ax, noMatch) {
var axId = ax._id;
var fullData = gd._fullData;
var fullLayout = gd._fullLayout;
Expand Down Expand Up @@ -242,14 +244,34 @@ function concatExtremes(gd, ax) {
_concat(fullLayout.annotations || [], ax._annIndices || []);
_concat(fullLayout.shapes || [], ax._shapeIndices || []);

// Include the extremes from other matched axes with this one
if(ax._matchGroup && !noMatch) {
for(var axId2 in ax._matchGroup) {
if(axId2 !== ax._id) {
var ax2 = getFromId(gd, axId2);
var extremes2 = concatExtremes(gd, ax2, true);
// convert padding on the second axis to the first with lenRatio
var lenRatio = ax._length / ax2._length;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously we calculated autorange for matched axes incorrectly: we just took the minimum and maximum of all the individually-calculated ranges. This is fine when there's no padding around the edges (pixel padding or the 5% "extrapad") but when we have either of these, the simple combination of results gives too little padding. So what I changed to instead is combining the extremes arrays (sets of min and max items each with its own padding) by converting pixel padding to its equivalent on one axis. Note that this is still compatible with constrain='domain' because, while it shrinks the axes' _length, it does so symmetrically across the whole matching group.

for(j = 0; j < extremes2.min.length; j++) {
d = extremes2.min[j];
collapseMinArray(minArray, d.val, d.pad * lenRatio, {extrapad: d.extrapad});
}
for(j = 0; j < extremes2.max.length; j++) {
d = extremes2.max[j];
collapseMaxArray(maxArray, d.val, d.pad * lenRatio, {extrapad: d.extrapad});
}
}
}
}

return {min: minArray, max: maxArray};
}

function doAutoRange(gd, ax) {
function doAutoRange(gd, ax, presetRange) {
ax.setScale();

if(ax.autorange) {
ax.range = getAutoRange(gd, ax);
ax.range = presetRange ? presetRange.slice() : getAutoRange(gd, ax);

ax._r = ax.range.slice();
ax._rl = Lib.simpleMap(ax._r, ax.r2l);
Expand Down
10 changes: 0 additions & 10 deletions src/plots/cartesian/axis_ids.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,6 @@ exports.idSort = function(id1, id2) {
return +(id1.substr(1) || 1) - +(id2.substr(1) || 1);
};

exports.getAxisGroup = function getAxisGroup(fullLayout, axId) {
var matchGroups = fullLayout._axisMatchGroups;

for(var i = 0; i < matchGroups.length; i++) {
var group = matchGroups[i];
if(group[axId]) return 'g' + i;
}
return axId;
};

/*
* An axis reference (e.g., the contents at the 'xref' key of an object) might
* have extra information appended. Extract the axis ID only.
Expand Down
Loading