diff --git a/src/plots/cartesian/dragbox.js b/src/plots/cartesian/dragbox.js index cb12c778aec..29af0cb593c 100644 --- a/src/plots/cartesian/dragbox.js +++ b/src/plots/cartesian/dragbox.js @@ -113,12 +113,14 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) { var dragger = makeRectDragger(plotinfo, ns + ew + 'drag', cursor, x, y, w, h); + var allFixedRanges = !yActive && !xActive; + // still need to make the element if the axes are disabled // but nuke its events (except for maindrag which needs them for hover) // and stop there - if(!yActive && !xActive && !isSelectOrLasso(fullLayout.dragmode)) { + if(allFixedRanges && !isMainDrag) { dragger.onmousedown = null; - dragger.style.pointerEvents = isMainDrag ? 'all' : 'none'; + dragger.style.pointerEvents = 'none'; return dragger; } @@ -129,24 +131,34 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) { prepFn: function(e, startX, startY) { var dragModeNow = gd._fullLayout.dragmode; - if(isMainDrag) { - // main dragger handles all drag modes, and changes - // to pan (or to zoom if it already is pan) on shift - if(e.shiftKey) { - if(dragModeNow === 'pan') dragModeNow = 'zoom'; - else if(!isSelectOrLasso(dragModeNow)) dragModeNow = 'pan'; - } - else if(e.ctrlKey) { - dragModeNow = 'pan'; + if(!allFixedRanges) { + if(isMainDrag) { + // main dragger handles all drag modes, and changes + // to pan (or to zoom if it already is pan) on shift + if(e.shiftKey) { + if(dragModeNow === 'pan') dragModeNow = 'zoom'; + else if(!isSelectOrLasso(dragModeNow)) dragModeNow = 'pan'; + } + else if(e.ctrlKey) { + dragModeNow = 'pan'; + } } + // all other draggers just pan + else dragModeNow = 'pan'; } - // all other draggers just pan - else dragModeNow = 'pan'; if(dragModeNow === 'lasso') dragOptions.minDrag = 1; else dragOptions.minDrag = undefined; - if(dragModeNow === 'zoom') { + if(isSelectOrLasso(dragModeNow)) { + dragOptions.xaxes = xa; + dragOptions.yaxes = ya; + prepSelect(e, startX, startY, dragOptions, dragModeNow); + } + else if(allFixedRanges) { + clearSelect(zoomlayer); + } + else if(dragModeNow === 'zoom') { dragOptions.moveFn = zoomMove; dragOptions.doneFn = zoomDone; @@ -162,11 +174,6 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) { dragOptions.doneFn = dragTail; clearSelect(zoomlayer); } - else if(isSelectOrLasso(dragModeNow)) { - dragOptions.xaxes = xa; - dragOptions.yaxes = ya; - prepSelect(e, startX, startY, dragOptions, dragModeNow); - } }, clickFn: function(numClicks, evt) { removeZoombox(gd); diff --git a/test/jasmine/tests/cartesian_interact_test.js b/test/jasmine/tests/cartesian_interact_test.js index 4ba2c5e27dc..72bf3ce45bc 100644 --- a/test/jasmine/tests/cartesian_interact_test.js +++ b/test/jasmine/tests/cartesian_interact_test.js @@ -63,8 +63,8 @@ describe('zoom box element', function() { describe('main plot pan', function() { - var mock = require('@mocks/10.json'), - gd, modeBar, relayoutCallback; + var mock = require('@mocks/10.json'); + var gd, modeBar, relayoutCallback; beforeEach(function(done) { gd = createGraphDiv(); @@ -106,70 +106,86 @@ describe('main plot pan', function() { expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision); expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision); - delay(MODEBAR_DELAY)() - .then(function() { + function _drag(x0, y0, x1, y1) { + mouseEvent('mousedown', x0, y0); + mouseEvent('mousemove', x1, y1); + mouseEvent('mouseup', x1, y1); + } - expect(relayoutCallback).toHaveBeenCalledTimes(1); - relayoutCallback.calls.reset(); + function _checkAxes(xRange, yRange) { + expect(gd.layout.xaxis.range).toBeCloseToArray(xRange, precision); + expect(gd.layout.yaxis.range).toBeCloseToArray(yRange, precision); + } + function _runDrag(xr0, xr1, yr0, yr1) { // Drag scene along the X axis - - mouseEvent('mousedown', 110, 150); - mouseEvent('mousemove', 220, 150); - mouseEvent('mouseup', 220, 150); - - expect(gd.layout.xaxis.range).toBeCloseToArray(newX, precision); - expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision); + _drag(110, 150, 220, 150); + _checkAxes(xr1, yr0); // Drag scene back along the X axis (not from the same starting point but same X delta) - - mouseEvent('mousedown', 280, 150); - mouseEvent('mousemove', 170, 150); - mouseEvent('mouseup', 170, 150); - - expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision); - expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision); + _drag(280, 150, 170, 150); + _checkAxes(xr0, yr0); // Drag scene along the Y axis - - mouseEvent('mousedown', 110, 150); - mouseEvent('mousemove', 110, 190); - mouseEvent('mouseup', 110, 190); - - expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision); - expect(gd.layout.yaxis.range).toBeCloseToArray(newY, precision); + _drag(110, 150, 110, 190); + _checkAxes(xr0, yr1); // Drag scene back along the Y axis (not from the same starting point but same Y delta) - - mouseEvent('mousedown', 280, 130); - mouseEvent('mousemove', 280, 90); - mouseEvent('mouseup', 280, 90); - - expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision); - expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision); + _drag(280, 130, 280, 90); + _checkAxes(xr0, yr0); // Drag scene along both the X and Y axis - - mouseEvent('mousedown', 110, 150); - mouseEvent('mousemove', 220, 190); - mouseEvent('mouseup', 220, 190); - - expect(gd.layout.xaxis.range).toBeCloseToArray(newX, precision); - expect(gd.layout.yaxis.range).toBeCloseToArray(newY, precision); + _drag(110, 150, 220, 190); + _checkAxes(xr1, yr1); // Drag scene back along the X and Y axis (not from the same starting point but same delta vector) + _drag(280, 130, 170, 90); + _checkAxes(xr0, yr0); + } - mouseEvent('mousedown', 280, 130); - mouseEvent('mousemove', 170, 90); - mouseEvent('mouseup', 170, 90); + delay(MODEBAR_DELAY)() + .then(function() { - expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision); - expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision); + expect(relayoutCallback).toHaveBeenCalledTimes(1); + relayoutCallback.calls.reset(); + _runDrag(originalX, newX, originalY, newY); }) .then(delay(MODEBAR_DELAY)) .then(function() { // X and back; Y and back; XY and back expect(relayoutCallback).toHaveBeenCalledTimes(6); + return Plotly.relayout(gd, {'xaxis.fixedrange': true}); + }) + .then(function() { + relayoutCallback.calls.reset(); + _runDrag(originalX, originalX, originalY, newY); + }) + .then(delay(MODEBAR_DELAY)) + .then(function() { + // Y and back; XY and back + // should perhaps be 4, but the noop drags still generate a relayout call. + // TODO: should we try and remove this call? + expect(relayoutCallback).toHaveBeenCalledTimes(6); + return Plotly.relayout(gd, {'yaxis.fixedrange': true}); + }) + .then(function() { + relayoutCallback.calls.reset(); + _runDrag(originalX, originalX, originalY, originalY); + }) + .then(delay(MODEBAR_DELAY)) + .then(function() { + // both axes are fixed - no changes + expect(relayoutCallback).toHaveBeenCalledTimes(0); + return Plotly.relayout(gd, {'xaxis.fixedrange': false, dragmode: 'pan'}); + }) + .then(function() { + relayoutCallback.calls.reset(); + _runDrag(originalX, newX, originalY, originalY); + }) + .then(delay(MODEBAR_DELAY)) + .then(function() { + // X and back; XY and back + expect(relayoutCallback).toHaveBeenCalledTimes(6); }) .catch(failTest) .then(done); diff --git a/test/jasmine/tests/click_test.js b/test/jasmine/tests/click_test.js index 0b77b01715a..5d22ee67951 100644 --- a/test/jasmine/tests/click_test.js +++ b/test/jasmine/tests/click_test.js @@ -138,6 +138,31 @@ describe('Test click interactions:', function() { expect(evt.clientY).toEqual(pointPos[1]); }); + it('works with fixedrange axes', function(done) { + Plotly.relayout(gd, {'xaxis.fixedrange': true, 'yaxis.fixedrange': true}).then(function() { + click(pointPos[0], pointPos[1]); + expect(futureData.points.length).toEqual(1); + expect(clickPassthroughs).toBe(2); + expect(contextPassthroughs).toBe(0); + + var pt = futureData.points[0]; + expect(Object.keys(pt)).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'x', 'y', 'xaxis', 'yaxis' + ]); + expect(pt.curveNumber).toEqual(0); + expect(pt.pointNumber).toEqual(11); + expect(pt.x).toEqual(0.125); + expect(pt.y).toEqual(2.125); + + var evt = futureData.event; + expect(evt.clientX).toEqual(pointPos[0]); + expect(evt.clientY).toEqual(pointPos[1]); + }) + .catch(fail) + .then(done); + }); + var modClickOpts = { altKey: true, ctrlKey: true, // this makes it effectively into a right-click diff --git a/test/jasmine/tests/fx_test.js b/test/jasmine/tests/fx_test.js index 1d7f7a05ecd..293d482e63d 100644 --- a/test/jasmine/tests/fx_test.js +++ b/test/jasmine/tests/fx_test.js @@ -231,11 +231,12 @@ describe('relayout', function() { return Plotly.relayout(gd, 'yaxis.fixedrange', true); }).then(function() { - assertMainDrag('pointer', false); + // still active with fixedrange because we're handling clicks here too. + assertMainDrag('pointer', true); return Plotly.relayout(gd, 'dragmode', 'drag'); }).then(function() { - assertMainDrag('pointer', false); + assertMainDrag('pointer', true); return Plotly.relayout(gd, 'dragmode', 'lasso'); }).then(function() {