Skip to content

Commit 5f7eedf

Browse files
committed
Refactor autorange calculation for multi-axis shapes
1 parent 4a571aa commit 5f7eedf

2 files changed

Lines changed: 55 additions & 9 deletions

File tree

src/components/shapes/calc_autorange.js

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,21 @@ module.exports = function calcAutorange(gd) {
2121
var xRefType = Axes.getRefType(shape.xref);
2222
var yRefType = Axes.getRefType(shape.yref);
2323

24-
// paper and axis domain referenced shapes don't affect autorange
25-
// TODO: implement autorange calculation for array ref shapes
26-
if(xRefType !== 'array' && shape.xref !== 'paper' && xRefType !== 'domain') {
24+
if(xRefType === 'array') {
25+
calcArrayRefAutorange(gd, shape, 'x');
26+
} else if(shape.xref !== 'paper' && xRefType !== 'domain') {
27+
// paper and axis domain referenced shapes don't affect autorange
2728
ax = Axes.getFromId(gd, shape.xref);
28-
2929
bounds = shapeBounds(ax, shape, constants.paramIsX);
3030
if(bounds) {
3131
shape._extremes[ax._id] = Axes.findExtremes(ax, bounds, calcXPaddingOptions(shape));
3232
}
3333
}
3434

35-
// TODO: implement autorange calculation for array ref shapes
36-
if(yRefType !== 'array' && shape.yref !== 'paper' && yRefType !== 'domain') {
35+
if(yRefType === 'array') {
36+
calcArrayRefAutorange(gd, shape, 'y');
37+
} else if(shape.yref !== 'paper' && yRefType !== 'domain') {
3738
ax = Axes.getFromId(gd, shape.yref);
38-
3939
bounds = shapeBounds(ax, shape, constants.paramIsY);
4040
if(bounds) {
4141
shape._extremes[ax._id] = Axes.findExtremes(ax, bounds, calcYPaddingOptions(shape));
@@ -44,6 +44,50 @@ module.exports = function calcAutorange(gd) {
4444
}
4545
};
4646

47+
function calcArrayRefAutorange(gd, shape, dim) {
48+
var refs = shape[dim + 'ref'];
49+
var paramsToUse = dim === 'x' ? constants.paramIsX : constants.paramIsY;
50+
var paddingOpts = dim === 'x' ? calcXPaddingOptions(shape) : calcYPaddingOptions(shape);
51+
52+
function addToAxisGroup(ref, val) {
53+
if(ref === 'paper' || Axes.getRefType(ref) === 'domain') return;
54+
if(!axisGroups[ref]) axisGroups[ref] = [];
55+
axisGroups[ref].push(val);
56+
}
57+
58+
// group coordinates by axis reference so we can calculate the extremes for each axis
59+
var axisGroups = {};
60+
if(shape.type === 'path' && shape.path) {
61+
var segments = shape.path.match(constants.segmentRE) || [];
62+
var refIndex = 0;
63+
for(var i = 0; i < segments.length; i++) {
64+
var segment = segments[i];
65+
var command = segment.charAt(0);
66+
var drawnIndex = paramsToUse[command].drawn;
67+
68+
if(drawnIndex === undefined) continue;
69+
70+
var params = segment.slice(1).match(constants.paramRE);
71+
if(params && params.length > drawnIndex) {
72+
addToAxisGroup(refs[refIndex], params[drawnIndex]);
73+
refIndex++;
74+
}
75+
}
76+
} else {
77+
addToAxisGroup(refs[0], shape[dim + '0']);
78+
addToAxisGroup(refs[1], shape[dim + '1']);
79+
}
80+
81+
// For each axis, convert coordinates to data values then calculate extremes
82+
for(var axId in axisGroups) {
83+
var ax = Axes.getFromId(gd, axId);
84+
if(!ax) continue;
85+
var convertVal = (ax.type === 'category' || ax.type === 'multicategory') ? ax.r2c : ax.d2c;
86+
if(ax.type === 'date') convertVal = helpers.decodeDate(convertVal);
87+
shape._extremes[ax._id] = Axes.findExtremes(ax, axisGroups[axId].map(convertVal), paddingOpts);
88+
}
89+
}
90+
4791
function calcXPaddingOptions(shape) {
4892
return calcPaddingOptions(shape.line.width, shape.xsizemode, shape.x0, shape.x1, shape.path, false);
4993
}

src/components/shapes/draw.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,13 @@ function drawOne(gd, index) {
9191
// TODO: use d3 idioms instead of deleting and redrawing every time
9292
if(!options._input || options.visible !== true) return;
9393

94+
var isMultiAxisShape = Array.isArray(options.xref) || Array.isArray(options.yref);
95+
9496
if(options.layer === 'above') {
9597
drawShape(gd._fullLayout._shapeUpperLayer);
96-
} else if(options.xref === 'paper' || options.yref === 'paper') {
98+
} else if(options.xref.includes('paper') || options.yref.includes('paper')) {
9799
drawShape(gd._fullLayout._shapeLowerLayer);
98-
} else if(options.layer === 'between') {
100+
} else if(options.layer === 'between' && !isMultiAxisShape) {
99101
drawShape(plotinfo.shapelayerBetween);
100102
} else {
101103
if(plotinfo._hadPlotinfo) {

0 commit comments

Comments
 (0)