Skip to content

Commit f8203a3

Browse files
committed
plotly_relayouting for cartesian plots
1 parent 1ce7848 commit f8203a3

File tree

2 files changed

+107
-13
lines changed

2 files changed

+107
-13
lines changed

src/plots/cartesian/dragbox.js

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
8585
// graph-wide optimization flags
8686
var hasScatterGl, hasSplom, hasSVG;
8787
// collected changes to be made to the plot by relayout at the end
88-
var updates;
88+
var updates = {};
8989

9090
function recomputeAxisLists() {
9191
xa0 = plotinfo.xaxis;
@@ -409,18 +409,12 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
409409
gd._dragged = zoomDragged;
410410

411411
updateZoombox(zb, corners, box, path0, dimmed, lum);
412+
computeZoomUpdates();
413+
gd.emit('plotly_relayouting', updates);
412414
dimmed = true;
413415
}
414416

415-
function zoomDone() {
416-
updates = {};
417-
418-
// more strict than dragged, which allows you to come back to where you started
419-
// and still count as dragged
420-
if(Math.min(box.h, box.w) < MINDRAG * 2) {
421-
return removeZoombox(gd);
422-
}
423-
417+
function computeZoomUpdates() {
424418
// TODO: edit linked axes in zoomAxRanges and in dragTail
425419
if(zoomMode === 'xy' || zoomMode === 'x') {
426420
zoomAxRanges(xaxes, box.l / pw, box.r / pw, updates, links.xaxes);
@@ -430,6 +424,18 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
430424
zoomAxRanges(yaxes, (ph - box.b) / ph, (ph - box.t) / ph, updates, links.yaxes);
431425
updateMatchedAxRange('y', updates);
432426
}
427+
}
428+
429+
function zoomDone() {
430+
updates = {};
431+
432+
// more strict than dragged, which allows you to come back to where you started
433+
// and still count as dragged
434+
if(Math.min(box.h, box.w) < MINDRAG * 2) {
435+
return removeZoombox(gd);
436+
}
437+
438+
computeZoomUpdates();
433439

434440
removeZoombox(gd);
435441
dragTail();
@@ -515,6 +521,8 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
515521
updateSubplots(scrollViewBox);
516522
ticksAndAnnotations();
517523

524+
gd.emit('plotly_relayouting', updates);
525+
518526
// then replot after a delay to make sure
519527
// no more scrolling is coming
520528
redrawTimer = setTimeout(function() {
@@ -552,6 +560,7 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
552560
}
553561
updateSubplots([xActive ? -dx : 0, yActive ? -dy : 0, pw, ph]);
554562
ticksAndAnnotations();
563+
gd.emit('plotly_relayouting', updates);
555564
return;
556565
}
557566

@@ -626,6 +635,7 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
626635
updateMatchedAxRange('y');
627636
updateSubplots([xStart, yStart, pw - dx, ph - dy]);
628637
ticksAndAnnotations();
638+
gd.emit('plotly_relayouting', updates);
629639
}
630640

631641
function updateMatchedAxRange(axLetter, out) {

test/jasmine/tests/cartesian_interact_test.js

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,48 @@ describe('main plot pan', function() {
188188
.then(done);
189189
});
190190

191+
it('should emit plotly_relayouting events during pan interactions', function(done) {
192+
var mock = require('@mocks/10.json');
193+
194+
function _drag(x0, y0, x1, y1, n) {
195+
mouseEvent('mousedown', x0, y0);
196+
var dx = (x1 - x0) / n;
197+
var dy = (y1 - y0) / n;
198+
for(var i = 0; i <= n; i++) {
199+
mouseEvent('mousemove', x0 + dx * i, y0 + dy * i);
200+
}
201+
mouseEvent('mouseup', x1, y1);
202+
}
203+
204+
var nsteps = 10; var events = []; var relayoutCallback;
205+
Plotly.plot(gd, mock.data, mock.layout).then(function() {
206+
// Switch to pan mode
207+
modeBar = gd._fullLayout._modeBar;
208+
var buttonPan = selectButton(modeBar, 'pan2d');
209+
buttonPan.click();
210+
expect(buttonPan.isActive()).toBe(true); // switched on dragmode
211+
})
212+
.then(function() {
213+
relayoutCallback = jasmine.createSpy('relayoutCallback');
214+
gd.on('plotly_relayout', relayoutCallback);
215+
gd.on('plotly_relayouting', function(e) {
216+
events.push(e);
217+
});
218+
_drag(100, 150, 220, 250, nsteps);
219+
})
220+
.then(function() {
221+
expect(events.length).toEqual(nsteps);
222+
var first = events.splice(0, 1)[0];
223+
var last = events.splice(-1, 1)[0];
224+
expect(first['xaxis.range[1]'] - first['xaxis.range[0]']).toBeCloseTo(6, 0);
225+
expect(last['xaxis.range[1]'] - last['xaxis.range[0]']).toBeCloseTo(6, 0);
226+
227+
expect(first['xaxis.range[1]'] - last['xaxis.range[1]']).toBeCloseTo(1, 0);
228+
})
229+
.catch(failTest)
230+
.then(done);
231+
});
232+
191233
it('should show/hide `cliponaxis: false` pts according to range', function(done) {
192234
function _assert(markerDisplay, textDisplay, barTextDisplay) {
193235
var gd3 = d3.select(gd);
@@ -289,10 +331,10 @@ describe('axis zoom/pan and main plot zoom', function() {
289331
return document.querySelector('.' + directions + 'drag[data-subplot="' + subplot + '"]');
290332
}
291333

292-
function doDrag(subplot, directions, dx, dy) {
334+
function doDrag(subplot, directions, dx, dy, nsteps) {
293335
return function() {
294336
var dragger = getDragger(subplot, directions);
295-
return drag(dragger, dx, dy);
337+
return drag(dragger, dx, dy, undefined, undefined, undefined, nsteps);
296338
};
297339
}
298340

@@ -311,7 +353,11 @@ describe('axis zoom/pan and main plot zoom', function() {
311353
var dy = opts.dy || 0;
312354
var dragger = getDragger(subplot, directions);
313355
var coords = getNodeCoords(dragger, edge);
314-
mouseEvent('scroll', coords.x + dx, coords.y + dy, {deltaY: deltaY, element: dragger});
356+
var nsteps = opts.nsteps || 1;
357+
358+
for(var i = 1; i <= nsteps; i++) {
359+
mouseEvent('scroll', coords.x + dx, coords.y + dy, {deltaY: deltaY / nsteps * i, element: dragger});
360+
}
315361
return delay(constants.REDRAWDELAY + 10)();
316362
};
317363
}
@@ -629,6 +675,44 @@ describe('axis zoom/pan and main plot zoom', function() {
629675
.then(done);
630676
});
631677

678+
it('should emit plotly_relayouting events when drawing zoom selection', function(done) {
679+
var nsteps = 10; var events = []; var relayoutCallback;
680+
Plotly.plot(gd, [{ y: [1, 2, 1] }])
681+
.then(function() {
682+
relayoutCallback = jasmine.createSpy('relayoutCallback');
683+
gd.on('plotly_relayout', relayoutCallback);
684+
gd.on('plotly_relayouting', function(e) {
685+
events.push(e);
686+
});
687+
})
688+
.then(doDrag('xy', 'nsew', 100, 100, nsteps))
689+
.then(function() {
690+
expect(events.length).toEqual(nsteps);
691+
expect(relayoutCallback).toHaveBeenCalledTimes(1);
692+
})
693+
.catch(failTest)
694+
.then(done);
695+
});
696+
697+
it('should emit plotly_relayouting events when zooming via mouse wheel', function(done) {
698+
var nsteps = 10; var events = []; var relayoutCallback;
699+
Plotly.plot(gd, [{ y: [1, 2, 1] }], {}, {scrollZoom: true})
700+
.then(function() {
701+
relayoutCallback = jasmine.createSpy('relayoutCallback');
702+
gd.on('plotly_relayout', relayoutCallback);
703+
gd.on('plotly_relayouting', function(e) {
704+
events.push(e);
705+
});
706+
})
707+
.then(doScroll('xy', 'nsew', 100, {edge: 'se', nsteps: nsteps}))
708+
.then(function() {
709+
expect(events.length).toEqual(nsteps);
710+
expect(relayoutCallback).toHaveBeenCalledTimes(1);
711+
})
712+
.catch(failTest)
713+
.then(done);
714+
});
715+
632716
it('handles xy, x-only and y-only zoombox updates', function(done) {
633717
function _assert(msg, xrng, yrng) {
634718
expect(gd.layout.xaxis.range).toBeCloseToArray(xrng, 2, 'xrng - ' + msg);

0 commit comments

Comments
 (0)