Skip to content

Commit ef256db

Browse files
committed
generalize "update matched ax rng" logic
... so that it works when matching an overlaying axis
1 parent c290adf commit ef256db

File tree

2 files changed

+126
-51
lines changed

2 files changed

+126
-51
lines changed

src/plots/cartesian/dragbox.js

+53-50
Original file line numberDiff line numberDiff line change
@@ -413,10 +413,12 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
413413

414414
// TODO: edit linked axes in zoomAxRanges and in dragTail
415415
if(zoomMode === 'xy' || zoomMode === 'x') {
416-
zoomAxRanges(xaxes, box.l / pw, box.r / pw, updates, links.xaxes, matches.xaxes);
416+
zoomAxRanges(xaxes, box.l / pw, box.r / pw, updates, links.xaxes);
417+
updateMatchedAxRange('x', updates);
417418
}
418419
if(zoomMode === 'xy' || zoomMode === 'y') {
419-
zoomAxRanges(yaxes, (ph - box.b) / ph, (ph - box.t) / ph, updates, links.yaxes, matches.yaxes);
420+
zoomAxRanges(yaxes, (ph - box.b) / ph, (ph - box.t) / ph, updates, links.yaxes);
421+
updateMatchedAxRange('y', updates);
420422
}
421423

422424
removeZoombox(gd);
@@ -482,7 +484,7 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
482484
for(i = 0; i < xaxes.length; i++) {
483485
zoomWheelOneAxis(xaxes[i], xfrac, zoom);
484486
}
485-
updateMatchedAxes(matches.isSubplotConstrained ? yaxes : matches.xaxes, xaxes[0].range);
487+
updateMatchedAxRange('x');
486488

487489
scrollViewBox[2] *= zoom;
488490
scrollViewBox[0] += scrollViewBox[2] * xfrac * (1 / zoom - 1);
@@ -493,7 +495,7 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
493495
for(i = 0; i < yaxes.length; i++) {
494496
zoomWheelOneAxis(yaxes[i], yfrac, zoom);
495497
}
496-
updateMatchedAxes(matches.isSubplotConstrained ? xaxes : matches.yaxes, yaxes[0].range);
498+
updateMatchedAxRange('y');
497499

498500
scrollViewBox[3] *= zoom;
499501
scrollViewBox[1] += scrollViewBox[3] * (1 - yfrac) * (1 / zoom - 1);
@@ -529,19 +531,15 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
529531
// prevent axis drawing from monkeying with margins until we're done
530532
gd._fullLayout._replotting = true;
531533

532-
var matchedByXaxes;
533-
var matchesByYaxes;
534-
if(matches.isSubplotConstrained) {
535-
matchedByXaxes = yaxes;
536-
matchesByYaxes = xaxes;
537-
} else {
538-
matchedByXaxes = matches.xaxes;
539-
matchesByYaxes = matches.yaxes;
540-
}
541-
542534
if(xActive === 'ew' || yActive === 'ns') {
543-
if(xActive) dragAxList(xaxes, matchedByXaxes, dx);
544-
if(yActive) dragAxList(yaxes, matchesByYaxes, dy);
535+
if(xActive) {
536+
dragAxList(xaxes, dx);
537+
updateMatchedAxRange('x');
538+
}
539+
if(yActive) {
540+
dragAxList(yaxes, dy);
541+
updateMatchedAxRange('y');
542+
}
545543
updateSubplots([xActive ? -dx : 0, yActive ? -dy : 0, pw, ph]);
546544
ticksAndAnnotations();
547545
return;
@@ -614,12 +612,39 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
614612
}
615613
}
616614

617-
updateMatchedAxes(matchedByXaxes, xaxes[0].range);
618-
updateMatchedAxes(matchesByYaxes, yaxes[0].range);
615+
updateMatchedAxRange('x');
616+
updateMatchedAxRange('y');
619617
updateSubplots([x0, y0, pw - dx, ph - dy]);
620618
ticksAndAnnotations();
621619
}
622620

621+
function updateMatchedAxRange(axLetter, out) {
622+
var matchedAxes = matches.isSubplotConstrained ?
623+
{x: yaxes, y: xaxes}[axLetter] :
624+
matches[axLetter + 'axes'];
625+
626+
var constrainedAxes = matches.isSubplotConstrained ?
627+
{x: xaxes, y: yaxes}[axLetter] :
628+
[];
629+
630+
for(var i = 0; i < matchedAxes.length; i++) {
631+
var ax = matchedAxes[i];
632+
var axId = ax._id;
633+
var axId2 = matches.xLinks[axId] || matches.yLinks[axId];
634+
var ax2 = constrainedAxes[0] || xaHash[axId2] || yaHash[axId2];
635+
636+
if(ax2) {
637+
var rng = ax2.range;
638+
if(out) {
639+
out[ax._name + '.range[0]'] = rng[0];
640+
out[ax._name + '.range[1]'] = rng[1];
641+
} else {
642+
ax.range = rng;
643+
}
644+
}
645+
}
646+
}
647+
623648
// Draw ticks and annotations (and other components) when ranges change.
624649
// Also records the ranges that have changed for use by update at the end.
625650
function ticksAndAnnotations() {
@@ -947,18 +972,13 @@ function getEndText(ax, end) {
947972
}
948973
}
949974

950-
function zoomAxRanges(axList, r0Fraction, r1Fraction, updates, linkedAxes, matchedAxes) {
951-
var i,
952-
axi,
953-
axRangeLinear0,
954-
axRangeLinearSpan;
955-
956-
for(i = 0; i < axList.length; i++) {
957-
axi = axList[i];
975+
function zoomAxRanges(axList, r0Fraction, r1Fraction, updates, linkedAxes) {
976+
for(var i = 0; i < axList.length; i++) {
977+
var axi = axList[i];
958978
if(axi.fixedrange) continue;
959979

960-
axRangeLinear0 = axi._rl[0];
961-
axRangeLinearSpan = axi._rl[1] - axRangeLinear0;
980+
var axRangeLinear0 = axi._rl[0];
981+
var axRangeLinearSpan = axi._rl[1] - axRangeLinear0;
962982
axi.range = [
963983
axi.l2r(axRangeLinear0 + axRangeLinearSpan * r0Fraction),
964984
axi.l2r(axRangeLinear0 + axRangeLinearSpan * r1Fraction)
@@ -973,18 +993,9 @@ function zoomAxRanges(axList, r0Fraction, r1Fraction, updates, linkedAxes, match
973993
var linkedR0Fraction = (r0Fraction + (1 - r1Fraction)) / 2;
974994
zoomAxRanges(linkedAxes, linkedR0Fraction, 1 - linkedR0Fraction, updates, [], []);
975995
}
976-
977-
// TODO is picking the first ax always ok in general?
978-
// What if we're matching an overlaying axis?
979-
var rng = axList[0].range;
980-
for(i = 0; i < matchedAxes.length; i++) {
981-
axi = matchedAxes[i];
982-
updates[axi._name + '.range[0]'] = rng[0];
983-
updates[axi._name + '.range[1]'] = rng[1];
984-
}
985996
}
986997

987-
function dragAxList(axList, matchedAxes, pix) {
998+
function dragAxList(axList, pix) {
988999
for(var i = 0; i < axList.length; i++) {
9891000
var axi = axList[i];
9901001
if(!axi.fixedrange) {
@@ -994,16 +1005,6 @@ function dragAxList(axList, matchedAxes, pix) {
9941005
];
9951006
}
9961007
}
997-
998-
updateMatchedAxes(matchedAxes, axList[0].range);
999-
}
1000-
1001-
function updateMatchedAxes(matchedAxes, rng) {
1002-
// TODO is picking the first ax always ok in general?
1003-
// What if we're matching an overlaying axis?
1004-
for(var i = 0; i < matchedAxes.length; i++) {
1005-
matchedAxes[i].range = rng.slice();
1006-
}
10071008
}
10081009

10091010
// common transform for dragging one end of an axis
@@ -1133,7 +1134,7 @@ function calcLinks(gd, groups, xaHash, yaHash) {
11331134
// to match the changes in the dragged x axes
11341135
for(xLinkID in group) {
11351136
if(!(xLinkID.charAt(0) === 'x' ? xaHash : yaHash)[xLinkID]) {
1136-
xLinks[xLinkID] = 1;
1137+
xLinks[xLinkID] = xID;
11371138
}
11381139
}
11391140

@@ -1150,7 +1151,7 @@ function calcLinks(gd, groups, xaHash, yaHash) {
11501151
if(group[yID]) {
11511152
for(yLinkID in group) {
11521153
if(!(yLinkID.charAt(0) === 'x' ? xaHash : yaHash)[yLinkID]) {
1153-
yLinks[yLinkID] = 1;
1154+
yLinks[yLinkID] = yID;
11541155
}
11551156
}
11561157
}
@@ -1186,6 +1187,8 @@ function calcLinks(gd, groups, xaHash, yaHash) {
11861187
yaHash: yaHashLinked,
11871188
xaxes: xaxesLinked,
11881189
yaxes: yaxesLinked,
1190+
xLinks: xLinks,
1191+
yLinks: yLinks,
11891192
isSubplotConstrained: isSubplotConstrained
11901193
};
11911194
}

test/jasmine/tests/cartesian_interact_test.js

+73-1
Original file line numberDiff line numberDiff line change
@@ -710,10 +710,11 @@ describe('axis zoom/pan and main plot zoom', function() {
710710
exp.forEach(function(expi) {
711711
var axNames = expi[0];
712712
var rng = expi[1];
713+
var opts = expi[2] || {};
713714

714715
axNames.forEach(function(n) {
715716
var msgi = n + ' - ' + msg;
716-
expect(gd.layout[n].range).toBeCloseToArray(rng, TOL, msgi + ' |input');
717+
if(!opts.skipInput) expect(gd.layout[n].range).toBeCloseToArray(rng, TOL, msgi + ' |input');
717718
expect(gd._fullLayout[n].range).toBeCloseToArray(rng, TOL, msgi + ' |full');
718719
});
719720
});
@@ -1325,6 +1326,77 @@ describe('axis zoom/pan and main plot zoom', function() {
13251326
});
13261327
});
13271328
});
1329+
1330+
it('panning a matching overlaying axis', function(done) {
1331+
/*
1332+
* y | | y2 y3 |
1333+
* | | |
1334+
* | | o m |
1335+
* | | v a |
1336+
* | | e t |
1337+
* | | r c |
1338+
* | | l h |
1339+
* | | a e |
1340+
* | | y s |
1341+
* | | |
1342+
* ______________________ y y2 ____________________
1343+
*
1344+
* x x2
1345+
*/
1346+
var data = [
1347+
{ y: [1, 2, 1] },
1348+
{ y: [2, 1, 3, 4], yaxis: 'y2' },
1349+
{ y: [2, 3, -1, 5], xaxis: 'x2', yaxis: 'y3' }
1350+
];
1351+
1352+
var layout = {
1353+
xaxis: {domain: [0, 0.4]},
1354+
xaxis2: {anchor: 'y2', domain: [0.5, 1]},
1355+
yaxis2: {anchor: 'x', overlaying: 'y', side: 'right'},
1356+
yaxis3: {anchor: 'x2', matches: 'y2'},
1357+
width: 700,
1358+
height: 500,
1359+
dragmode: 'pan'
1360+
};
1361+
1362+
makePlot(data, layout).then(function() {
1363+
assertRanges('base', [
1364+
[['yaxis2', 'yaxis3'], [-1.422, 5.422]],
1365+
[['xaxis'], [-0.237, 3.237]],
1366+
[['yaxis'], [0.929, 2.070]],
1367+
[['xaxis2'], [-0.225, 3.222]]
1368+
]);
1369+
})
1370+
.then(function() {
1371+
var drag = makeDragFns('xy', 'nsew', 30, 30);
1372+
return drag.start().then(function() {
1373+
// N.B. it is with these values that Axes.drawOne gets called!
1374+
assertRanges('during drag', [
1375+
[['yaxis2', 'yaxis3'], [-0.788, 6.0641], {skipInput: true}],
1376+
[['xaxis'], [-0.744, 2.730], {skipInput: true}],
1377+
[['yaxis'], [1.036, 2.177], {skipInput: true}],
1378+
[['xaxis2'], [-0.225, 3.222]]
1379+
]);
1380+
})
1381+
.then(drag.end);
1382+
})
1383+
.then(_assert('after drag on xy subplot', [
1384+
[['yaxis2', 'yaxis3'], [-0.788, 6.0641], {dragged: true}],
1385+
[['xaxis'], [-0.744, 2.730], {dragged: true}],
1386+
[['yaxis'], [1.036, 2.177], {dragged: true}],
1387+
[['xaxis2'], [-0.225, 3.222], {noChange: true}]
1388+
]))
1389+
.then(function() { return Plotly.relayout(gd, 'dragmode', 'zoom'); })
1390+
.then(doDrag('xy', 'nsew', 30, 30))
1391+
.then(_assert('after zoombox on xy subplot', [
1392+
[['yaxis2', 'yaxis3'], [2, 2.6417]],
1393+
[['xaxis'], [0.979, 1.486]],
1394+
[['yaxis'], [1.5, 1.609]],
1395+
[['xaxis2'], [-0.225, 3.222], {noChange: true}]
1396+
]))
1397+
.catch(failTest)
1398+
.then(done);
1399+
});
13281400
});
13291401
});
13301402

0 commit comments

Comments
 (0)