From 7221cd009ca9cb2eec02e1e4e602c03e9e07b1ef Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 25 Jan 2018 15:49:26 -0500 Subject: [PATCH 01/11] Prevent event, mute logging --- src/plots/gl3d/camera.js | 16 ++++++++++++---- src/plots/gl3d/scene.js | 4 +++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/plots/gl3d/camera.js b/src/plots/gl3d/camera.js index bc6aac99a8f..9056dd64a35 100644 --- a/src/plots/gl3d/camera.js +++ b/src/plots/gl3d/camera.js @@ -15,6 +15,8 @@ var createView = require('3d-view'); var mouseChange = require('mouse-change'); var mouseWheel = require('mouse-wheel'); var mouseOffset = require('mouse-event-offset'); +var Lib = require('../../lib'); +var supportsPassive = Lib.eventListenerOptionsSupported(); function createCamera(element, options) { element = element || document.body; @@ -188,14 +190,20 @@ function createCamera(element, options) { var xy = mouseOffset(ev.changedTouches[0], element); handleInteraction(0, xy[0], xy[1], lastMods); handleInteraction(1, xy[0], xy[1], lastMods); - }); + + ev.preventDefault(); + }, supportsPassive ? {passive: false} : false); element.addEventListener('touchmove', function(ev) { var xy = mouseOffset(ev.changedTouches[0], element); handleInteraction(1, xy[0], xy[1], lastMods); - }); - element.addEventListener('touchend', function() { + + ev.preventDefault(); + }, supportsPassive ? {passive: false} : false); + element.addEventListener('touchend', function(ev) { handleInteraction(0, lastX, lastY, lastMods); - }); + + ev.preventDefault(); + }, supportsPassive ? {passive: false} : false); function handleInteraction(buttons, x, y, mods) { var keyBindingMode = camera.keyBindingMode; diff --git a/src/plots/gl3d/scene.js b/src/plots/gl3d/scene.js index 7d1d051b298..a76a98c972a 100644 --- a/src/plots/gl3d/scene.js +++ b/src/plots/gl3d/scene.js @@ -27,6 +27,8 @@ var createAxesOptions = require('./layout/convert'); var createSpikeOptions = require('./layout/spikes'); var computeTickMarks = require('./layout/tick_marks'); +var passiveSupported = Lib.eventListenerOptionsSupported(); + var STATIC_CANVAS, STATIC_CONTEXT; function render(scene) { @@ -190,7 +192,7 @@ function initializeGLPlot(scene, fullLayout, canvas, gl) { }; scene.glplot.canvas.addEventListener('mouseup', relayoutCallback.bind(null, scene)); - scene.glplot.canvas.addEventListener('wheel', relayoutCallback.bind(null, scene)); + scene.glplot.canvas.addEventListener('wheel', relayoutCallback.bind(null, scene), passiveSupported ? {passive: false} : false); if(!scene.staticMode) { scene.glplot.canvas.addEventListener('webglcontextlost', function(ev) { From 701edca8469c1948a3c72c2e7dcfbb327b6442ad Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 26 Jan 2018 14:55:18 -0500 Subject: [PATCH 02/11] Introduce has-passive-events --- package.json | 1 + src/components/dragelement/index.js | 2 +- src/lib/index.js | 22 ---------------------- src/plots/cartesian/dragbox.js | 2 +- src/plots/gl3d/camera.js | 3 +-- src/plots/gl3d/scene.js | 2 +- 6 files changed, 5 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index d958e854e0a..4e0127571c8 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "gl-spikes2d": "^1.0.1", "gl-surface3d": "^1.3.1", "has-hover": "^1.0.1", + "has-passive-events": "^1.0.0", "kdgrass": "^1.0.1", "mapbox-gl": "^0.22.0", "matrix-camera-controller": "^2.1.3", diff --git a/src/components/dragelement/index.js b/src/components/dragelement/index.js index 57ff1f554ee..cbc2ec18fe5 100644 --- a/src/components/dragelement/index.js +++ b/src/components/dragelement/index.js @@ -11,6 +11,7 @@ var mouseOffset = require('mouse-event-offset'); var hasHover = require('has-hover'); +var supportsPassive = require('has-passive-events'); var Plotly = require('../../plotly'); var Lib = require('../../lib'); @@ -27,7 +28,6 @@ var unhover = require('./unhover'); dragElement.unhover = unhover.wrapped; dragElement.unhoverRaw = unhover.raw; -var supportsPassive = Lib.eventListenerOptionsSupported(); /** * Abstracts click & drag interactions diff --git a/src/lib/index.js b/src/lib/index.js index 7c44a2c8d6e..fe501894dc0 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -890,25 +890,3 @@ lib.subplotSort = function(a, b) { } return numB - numA; }; - -/* - * test if event listener options supported - */ -lib.eventListenerOptionsSupported = function() { - var supported = false; - - try { - var opts = Object.defineProperty({}, 'passive', { - get: function() { - supported = true; - } - }); - - window.addEventListener('test', null, opts); - window.removeEventListener('test', null, opts); - } catch(e) { - supported = false; - } - - return supported; -}; diff --git a/src/plots/cartesian/dragbox.js b/src/plots/cartesian/dragbox.js index 29af0cb593c..c20aec38bfa 100644 --- a/src/plots/cartesian/dragbox.js +++ b/src/plots/cartesian/dragbox.js @@ -11,6 +11,7 @@ var d3 = require('d3'); var tinycolor = require('tinycolor2'); +var supportsPassive = require('has-passive-events'); var Plotly = require('../../plotly'); var Registry = require('../../registry'); @@ -34,7 +35,6 @@ var constants = require('./constants'); var MINDRAG = constants.MINDRAG; var MINZOOM = constants.MINZOOM; -var supportsPassive = Lib.eventListenerOptionsSupported(); // flag for showing "doubleclick to zoom out" only at the beginning var SHOWZOOMOUTTIP = true; diff --git a/src/plots/gl3d/camera.js b/src/plots/gl3d/camera.js index 9056dd64a35..3fe1f4ea570 100644 --- a/src/plots/gl3d/camera.js +++ b/src/plots/gl3d/camera.js @@ -15,8 +15,7 @@ var createView = require('3d-view'); var mouseChange = require('mouse-change'); var mouseWheel = require('mouse-wheel'); var mouseOffset = require('mouse-event-offset'); -var Lib = require('../../lib'); -var supportsPassive = Lib.eventListenerOptionsSupported(); +var supportsPassive = require('has-passive-events'); function createCamera(element, options) { element = element || document.body; diff --git a/src/plots/gl3d/scene.js b/src/plots/gl3d/scene.js index a76a98c972a..2ee604891f0 100644 --- a/src/plots/gl3d/scene.js +++ b/src/plots/gl3d/scene.js @@ -11,6 +11,7 @@ var createPlot = require('gl-plot3d'); var getContext = require('webgl-context'); +var passiveSupported = require('has-passive-events'); var Registry = require('../../registry'); var Lib = require('../../lib'); @@ -27,7 +28,6 @@ var createAxesOptions = require('./layout/convert'); var createSpikeOptions = require('./layout/spikes'); var computeTickMarks = require('./layout/tick_marks'); -var passiveSupported = Lib.eventListenerOptionsSupported(); var STATIC_CANVAS, STATIC_CONTEXT; From fa1db3bda0688d76ee844970fa4d0e904afa8323 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 26 Jan 2018 14:58:06 -0500 Subject: [PATCH 03/11] Fix gl2d camera events --- src/plots/gl2d/camera.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/plots/gl2d/camera.js b/src/plots/gl2d/camera.js index 19c93f38f29..ef23c6f3c02 100644 --- a/src/plots/gl2d/camera.js +++ b/src/plots/gl2d/camera.js @@ -13,6 +13,7 @@ var mouseChange = require('mouse-change'); var mouseWheel = require('mouse-wheel'); var mouseOffset = require('mouse-event-offset'); var cartesianConstants = require('../cartesian/constants'); +var hasPassive = require('has-passive-events'); module.exports = createCamera; @@ -63,15 +64,21 @@ function createCamera(scene) { var xy = mouseOffset(ev.changedTouches[0], element); handleInteraction(0, xy[0], xy[1]); handleInteraction(1, xy[0], xy[1]); - }); + + ev.preventDefault(); + }, hasPassive ? {passive: false} : false); element.addEventListener('touchmove', function(ev) { ev.preventDefault(); var xy = mouseOffset(ev.changedTouches[0], element); handleInteraction(1, xy[0], xy[1]); - }); + + ev.preventDefault(); + }, hasPassive ? {passive: false} : false); element.addEventListener('touchend', function() { handleInteraction(0, result.lastPos[0], result.lastPos[1]); - }); + + ev.preventDefault(); + }, hasPassive ? {passive: false} : false); function handleInteraction(buttons, x, y) { var dataBox = scene.calcDataBox(), From 05ded3c8a34888a08b902c2c5242ddc74ebb02f8 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 26 Jan 2018 16:30:29 -0500 Subject: [PATCH 04/11] Fix error --- src/plots/gl2d/camera.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plots/gl2d/camera.js b/src/plots/gl2d/camera.js index ef23c6f3c02..eb5ccda701e 100644 --- a/src/plots/gl2d/camera.js +++ b/src/plots/gl2d/camera.js @@ -74,7 +74,7 @@ function createCamera(scene) { ev.preventDefault(); }, hasPassive ? {passive: false} : false); - element.addEventListener('touchend', function() { + element.addEventListener('touchend', function(ev) { handleInteraction(0, result.lastPos[0], result.lastPos[1]); ev.preventDefault(); From f64680a4b1c53149ea62e9bd5a72f463adee52e3 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Mon, 29 Jan 2018 16:52:03 -0500 Subject: [PATCH 05/11] Cut pauseEvent wrapper --- src/components/dragelement/index.js | 9 ++++++--- src/lib/index.js | 14 -------------- src/plots/cartesian/dragbox.js | 7 +++++-- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/components/dragelement/index.js b/src/components/dragelement/index.js index cbc2ec18fe5..d3cad6039cc 100644 --- a/src/components/dragelement/index.js +++ b/src/components/dragelement/index.js @@ -164,7 +164,8 @@ dragElement.init = function init(options) { document.addEventListener('touchmove', onMove); document.addEventListener('touchend', onDone); - return Lib.pauseEvent(e); + e.preventDefault(); + return; } function onMove(e) { @@ -181,7 +182,8 @@ dragElement.init = function init(options) { if(gd._dragged && options.moveFn && !rightClick) options.moveFn(dx, dy); - return Lib.pauseEvent(e); + e.preventDefault(); + return; } function onDone(e) { @@ -246,7 +248,8 @@ dragElement.init = function init(options) { gd._dragged = false; - return Lib.pauseEvent(e); + e.preventDefault(); + return; } }; diff --git a/src/lib/index.js b/src/lib/index.js index fe501894dc0..ce9170ffbe5 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -150,20 +150,6 @@ lib.swapAttrs = function(cont, attrList, part1, part2) { } }; -/** - * to prevent event bubbling, in particular text selection during drag. - * see http://stackoverflow.com/questions/5429827/ - * how-can-i-prevent-text-element-selection-with-cursor-drag - * for maximum effect use: - * return pauseEvent(e); - */ -lib.pauseEvent = function(e) { - if(e.stopPropagation) e.stopPropagation(); - if(e.preventDefault) e.preventDefault(); - e.cancelBubble = true; - return false; -}; - /** * SVG painter's algo worked around with reinsertion */ diff --git a/src/plots/cartesian/dragbox.js b/src/plots/cartesian/dragbox.js index c20aec38bfa..3a7bcbea755 100644 --- a/src/plots/cartesian/dragbox.js +++ b/src/plots/cartesian/dragbox.js @@ -360,7 +360,9 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) { // If a transition is in progress, then disable any behavior: if(gd._transitioningWithDuration) { - return Lib.pauseEvent(e); + e.preventDefault(); + e.stopPropagation(); + return; } var pc = gd.querySelector('.plotly'); @@ -434,7 +436,8 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) { dragTail(zoomMode); }, REDRAWDELAY); - return Lib.pauseEvent(e); + e.preventDefault(); + return; } // everything but the corners gets wheel zoom From 4bc25be696664638154f189d56c49a3cbfb651dc Mon Sep 17 00:00:00 2001 From: Dmitry Date: Mon, 29 Jan 2018 19:26:00 -0500 Subject: [PATCH 06/11] Add cancelable events test --- test/jasmine/assets/mouse_event.js | 3 +- test/jasmine/assets/touch_event.js | 3 +- test/jasmine/tests/gl3d_plot_interact_test.js | 120 +++++++++++++----- 3 files changed, 92 insertions(+), 34 deletions(-) diff --git a/test/jasmine/assets/mouse_event.js b/test/jasmine/assets/mouse_event.js index 5ae9356d0b0..311842902f3 100644 --- a/test/jasmine/assets/mouse_event.js +++ b/test/jasmine/assets/mouse_event.js @@ -4,7 +4,8 @@ module.exports = function(type, x, y, opts) { var fullOpts = { bubbles: true, clientX: x, - clientY: y + clientY: y, + cancelable: true }; // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent diff --git a/test/jasmine/assets/touch_event.js b/test/jasmine/assets/touch_event.js index ea16b1db664..52fdf444847 100644 --- a/test/jasmine/assets/touch_event.js +++ b/test/jasmine/assets/touch_event.js @@ -19,7 +19,8 @@ module.exports = function(type, x, y, opts) { touches: [touchObj], targetTouches: [], changedTouches: [touchObj], - bubbles: true + bubbles: true, + cancelable: true }; if(opts && opts.altKey) { diff --git a/test/jasmine/tests/gl3d_plot_interact_test.js b/test/jasmine/tests/gl3d_plot_interact_test.js index d6fc3a2e145..aeed38e8416 100644 --- a/test/jasmine/tests/gl3d_plot_interact_test.js +++ b/test/jasmine/tests/gl3d_plot_interact_test.js @@ -9,6 +9,7 @@ var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var fail = require('../assets/fail_test'); var mouseEvent = require('../assets/mouse_event'); +var touchEvent = require('../assets/touch_event'); var selectButton = require('../assets/modebar_button'); var delay = require('../assets/delay'); @@ -651,26 +652,88 @@ describe('Test gl3d modebar handlers', function() { }); describe('Test gl3d drag and wheel interactions', function() { - var gd, relayoutCallback; + var gd; - function scroll(target) { + function scroll(target, amt) { return new Promise(function(resolve) { - target.dispatchEvent(new WheelEvent('wheel', {deltaY: 1})); + target.dispatchEvent(new WheelEvent('wheel', {deltaY: amt || 1, cancelable: true})); setTimeout(resolve, 0); }); } - function drag(target) { + function drag(target, start, end) { return new Promise(function(resolve) { - target.dispatchEvent(new MouseEvent('mousedown', {x: 0, y: 0})); - target.dispatchEvent(new MouseEvent('mousemove', { x: 100, y: 100})); - target.dispatchEvent(new MouseEvent('mouseup', { x: 100, y: 100})); + mouseEvent('mousedown', start[0], start[1], {element: target}); + mouseEvent('mousemove', end[0], end[1], {element: target}); + mouseEvent('mouseup', end[0], end[1], {element: target}); setTimeout(resolve, 0); }); } - beforeEach(function(done) { + function touchDrag(target, start, end) { + return new Promise(function(resolve) { + touchEvent('touchstart', start[0], start[1], {element: target}); + touchEvent('touchmove', end[0], end[1], {element: target}); + touchEvent('touchend', end[0], end[1], {element: target}); + setTimeout(resolve, 0); + }); + } + + beforeEach(function() { gd = createGraphDiv(); + jasmine.DEFAULT_TIMEOUT_INTERVAL = 3000; + }); + + afterEach(function() { + Plotly.purge(gd); + destroyGraphDiv(); + }); + + it('should not scroll document while panning', function(done) { + var mock = { + data: [ + { type: 'scatter3d' } + ], + layout: { + width: 500, + height: 500, + scene: { camera: { eye: { x: 0.1, y: 0.1, z: 1 }}} + } + }; + + var sceneTarget, relayoutCallback = jasmine.createSpy('relayoutCallback'); + + function assertEvent(e) { + expect(e.defaultPrevented).toEqual(true); + relayoutCallback(); + } + + gd.addEventListener('touchend', assertEvent); + gd.addEventListener('touchstart', assertEvent); + gd.addEventListener('touchmove', assertEvent); + gd.addEventListener('wheel', assertEvent); + + Plotly.plot(gd, mock) + .then(function() { + sceneTarget = gd.querySelector('.svg-container .gl-container #scene'); + + return touchDrag(sceneTarget, [100, 100], [0, 0]); + }) + .then(function() { + return drag(sceneTarget, [100, 100], [0, 0]); + }) + .then(function() { + return scroll(sceneTarget); + }) + .then(function() { + expect(relayoutCallback).toHaveBeenCalledTimes(3); + }) + .catch(fail) + .then(done); + }); + + it('should update the scene camera', function(done) { + var sceneLayout, sceneLayout2, sceneTarget, sceneTarget2, relayoutCallback; var mock = { data: [ @@ -684,31 +747,23 @@ describe('Test gl3d drag and wheel interactions', function() { }; Plotly.plot(gd, mock) - .then(delay(20)) .then(function() { relayoutCallback = jasmine.createSpy('relayoutCallback'); gd.on('plotly_relayout', relayoutCallback); - }) - .then(done); - }); - afterEach(function() { - Plotly.purge(gd); - destroyGraphDiv(); - }); - - it('should update the scene camera', function(done) { - var sceneLayout = gd._fullLayout.scene, - sceneLayout2 = gd._fullLayout.scene2, - sceneTarget = gd.querySelector('.svg-container .gl-container #scene canvas'), + sceneLayout = gd._fullLayout.scene; + sceneLayout2 = gd._fullLayout.scene2; + sceneTarget = gd.querySelector('.svg-container .gl-container #scene canvas'); sceneTarget2 = gd.querySelector('.svg-container .gl-container #scene2 canvas'); - expect(sceneLayout.camera.eye) - .toEqual({x: 0.1, y: 0.1, z: 1}); - expect(sceneLayout2.camera.eye) - .toEqual({x: 2.5, y: 2.5, z: 2.5}); + expect(sceneLayout.camera.eye) + .toEqual({x: 0.1, y: 0.1, z: 1}); + expect(sceneLayout2.camera.eye) + .toEqual({x: 2.5, y: 2.5, z: 2.5}); - scroll(sceneTarget).then(function() { + return scroll(sceneTarget); + }) + .then(function() { expect(relayoutCallback).toHaveBeenCalledTimes(1); relayoutCallback.calls.reset(); @@ -718,13 +773,13 @@ describe('Test gl3d drag and wheel interactions', function() { expect(relayoutCallback).toHaveBeenCalledTimes(1); relayoutCallback.calls.reset(); - return drag(sceneTarget2); + return drag(sceneTarget2, [0, 0], [100, 100]); }) .then(function() { expect(relayoutCallback).toHaveBeenCalledTimes(1); relayoutCallback.calls.reset(); - return drag(sceneTarget); + return drag(sceneTarget, [0, 0], [100, 100]); }) .then(function() { expect(relayoutCallback).toHaveBeenCalledTimes(1); @@ -739,10 +794,10 @@ describe('Test gl3d drag and wheel interactions', function() { expect(relayoutCallback).toHaveBeenCalledTimes(1); relayoutCallback.calls.reset(); - return drag(sceneTarget); + return drag(sceneTarget, [0, 0], [100, 100]); }) .then(function() { - return drag(sceneTarget2); + return drag(sceneTarget2, [0, 0], [100, 100]); }) .then(function() { expect(relayoutCallback).toHaveBeenCalledTimes(0); @@ -756,14 +811,15 @@ describe('Test gl3d drag and wheel interactions', function() { expect(relayoutCallback).toHaveBeenCalledTimes(1); relayoutCallback.calls.reset(); - return drag(sceneTarget); + return drag(sceneTarget, [0, 0], [100, 100]); }) .then(function() { - return drag(sceneTarget2); + return drag(sceneTarget2, [0, 0], [100, 100]); }) .then(function() { expect(relayoutCallback).toHaveBeenCalledTimes(2); }) + .catch(fail) .then(done); }); }); From b235c099fb8c31ddfc97e3a88df3d341fe59feb2 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Mon, 29 Jan 2018 20:00:34 -0500 Subject: [PATCH 07/11] Add gl2d test for panning --- src/components/dragelement/index.js | 9 ++-- src/plots/gl2d/camera.js | 2 +- test/jasmine/tests/gl2d_plot_interact_test.js | 54 +++++++++++++++++++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/components/dragelement/index.js b/src/components/dragelement/index.js index d3cad6039cc..90785a2eb0d 100644 --- a/src/components/dragelement/index.js +++ b/src/components/dragelement/index.js @@ -124,6 +124,8 @@ dragElement.init = function init(options) { var clampFn = options.clampFn || _clampFn; function onStart(e) { + e.preventDefault(); + // make dragging and dragged into properties of gd // so that others can look at and modify them gd._dragged = false; @@ -164,11 +166,12 @@ dragElement.init = function init(options) { document.addEventListener('touchmove', onMove); document.addEventListener('touchend', onDone); - e.preventDefault(); return; } function onMove(e) { + e.preventDefault(); + var offset = pointerOffset(e); var minDrag = options.minDrag || constants.MINDRAG; var dxdy = clampFn(offset[0] - startX, offset[1] - startY, minDrag); @@ -182,7 +185,6 @@ dragElement.init = function init(options) { if(gd._dragged && options.moveFn && !rightClick) options.moveFn(dx, dy); - e.preventDefault(); return; } @@ -192,6 +194,8 @@ dragElement.init = function init(options) { document.removeEventListener('touchmove', onMove); document.removeEventListener('touchend', onDone); + e.preventDefault(); + if(hasHover) { Lib.removeElement(dragCover); } @@ -248,7 +252,6 @@ dragElement.init = function init(options) { gd._dragged = false; - e.preventDefault(); return; } }; diff --git a/src/plots/gl2d/camera.js b/src/plots/gl2d/camera.js index eb5ccda701e..cad0080961d 100644 --- a/src/plots/gl2d/camera.js +++ b/src/plots/gl2d/camera.js @@ -294,7 +294,7 @@ function createCamera(scene) { scene.relayoutCallback(); return true; - }); + }, true); return result; } diff --git a/test/jasmine/tests/gl2d_plot_interact_test.js b/test/jasmine/tests/gl2d_plot_interact_test.js index 625250504ca..126df004dab 100644 --- a/test/jasmine/tests/gl2d_plot_interact_test.js +++ b/test/jasmine/tests/gl2d_plot_interact_test.js @@ -9,6 +9,7 @@ var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var fail = require('../assets/fail_test'); var mouseEvent = require('../assets/mouse_event'); +var touchEvent = require('../assets/touch_event'); var drag = require('../assets/drag'); var selectButton = require('../assets/modebar_button'); var delay = require('../assets/delay'); @@ -605,4 +606,57 @@ describe('Test gl2d plots', function() { .catch(fail) .then(done); }); + + it('should not scroll document while panning', function(done) { + var mock = { + data: [ + { type: 'scattergl', y: [1, 2, 3], x: [1, 2, 3] } + ], + layout: { + width: 500, + height: 500 + } + }; + + var sceneTarget, relayoutCallback = jasmine.createSpy('relayoutCallback'); + + function scroll(target, amt) { + return new Promise(function(resolve) { + target.dispatchEvent(new WheelEvent('wheel', {deltaY: amt || 1, cancelable: true})); + setTimeout(resolve, 0); + }); + } + + function touchDrag(target, start, end) { + return new Promise(function(resolve) { + touchEvent('touchstart', start[0], start[1], {element: target}); + touchEvent('touchmove', end[0], end[1], {element: target}); + touchEvent('touchend', end[0], end[1], {element: target}); + setTimeout(resolve, 0); + }); + } + + function assertEvent(e) { + expect(e.defaultPrevented).toEqual(true); + relayoutCallback(); + } + + gd.addEventListener('touchstart', assertEvent); + gd.addEventListener('wheel', assertEvent); + + Plotly.plot(gd, mock) + .then(function() { + sceneTarget = gd.querySelector('.nsewdrag'); + + return touchDrag(sceneTarget, [100, 100], [0, 0]); + }) + .then(function() { + return scroll(sceneTarget); + }) + .then(function() { + expect(relayoutCallback).toHaveBeenCalledTimes(1); + }) + .catch(fail) + .then(done); + }); }); From 2a61d927ae7d8bac96f685fd5401f1f84f2b4935 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Mon, 29 Jan 2018 20:06:24 -0500 Subject: [PATCH 08/11] Bump 3d-view-controls --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 4e0127571c8..a8ce40d6db0 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ }, "dependencies": { "3d-view": "^2.0.0", + "3d-view-controls": "^2.2.2", "@plotly/d3-sankey": "^0.5.0", "alpha-shape": "^1.0.0", "bubleify": "^1.0.0", From ce9ae8cfb098cf7be31f554848359fcaa0fd4553 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Mon, 5 Feb 2018 13:34:09 -0500 Subject: [PATCH 09/11] Fix syntax --- test/jasmine/tests/gl2d_plot_interact_test.js | 2 +- test/jasmine/tests/gl3d_plot_interact_test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jasmine/tests/gl2d_plot_interact_test.js b/test/jasmine/tests/gl2d_plot_interact_test.js index 23a878e5114..8c1063f3c3d 100644 --- a/test/jasmine/tests/gl2d_plot_interact_test.js +++ b/test/jasmine/tests/gl2d_plot_interact_test.js @@ -697,7 +697,7 @@ describe('@gl Test gl2d plots', function() { }) .then(function() { expect(relayoutCallback).toHaveBeenCalledTimes(1); - + }) .catch(fail) .then(done); diff --git a/test/jasmine/tests/gl3d_plot_interact_test.js b/test/jasmine/tests/gl3d_plot_interact_test.js index 3fc0bc9dab3..df339ea19b6 100644 --- a/test/jasmine/tests/gl3d_plot_interact_test.js +++ b/test/jasmine/tests/gl3d_plot_interact_test.js @@ -652,7 +652,7 @@ describe('@gl Test gl3d modebar handlers', function() { }); describe('@gl Test gl3d drag and wheel interactions', function() { - var gd, relayoutCallback; + var gd; function scroll(target, amt) { return new Promise(function(resolve) { From 67b7a8e01dd8421b2eea97b6d0eb9ce4d5af582a Mon Sep 17 00:00:00 2001 From: Dmitry Date: Mon, 5 Feb 2018 16:30:41 -0500 Subject: [PATCH 10/11] Regenerate package/-lock --- package-lock.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index c8ed4701bf4..831cbdc1b9b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4029,8 +4029,7 @@ "jsbn": { "version": "0.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "json-schema": { "version": "0.2.3", From d14318dbda820ee200a004bfc35f32510a1b9d2c Mon Sep 17 00:00:00 2001 From: Dmitry Date: Mon, 5 Feb 2018 16:33:39 -0500 Subject: [PATCH 11/11] Regenerate deps --- package-lock.json | 161 ++++++++++++++-------------------------------- package.json | 7 +- 2 files changed, 52 insertions(+), 116 deletions(-) diff --git a/package-lock.json b/package-lock.json index 831cbdc1b9b..7ff5a15252e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1973,6 +1973,17 @@ "sha.js": "2.4.10" } }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + }, "cryptiles": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", @@ -2691,9 +2702,9 @@ } }, "ecstatic": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.1.1.tgz", - "integrity": "sha512-D9UcjcxDMMqjaQxC0mSsFh/IjJSdiZVPnHrhjHuKXlhLByk5QGGPX1GUIDIjRzhTq4UDCPYwWblw79VBEh3r1w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.2.0.tgz", + "integrity": "sha512-Goilx/2cfU9vvfQjgtNgc2VmJAD8CasQ6rZDqCd2u4Hsyd/qFET6nBf60jiHodevR3nl3IGzNKtrzPXWP88utQ==", "dev": true, "requires": { "he": "1.1.1", @@ -2909,9 +2920,9 @@ } }, "eslint": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.16.0.tgz", - "integrity": "sha512-YVXV4bDhNoHHcv0qzU4Meof7/P26B4EuaktMi5L1Tnt52Aov85KmYA8c5D+xyZr/BkhvwUqr011jDSD/QTULxg==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.17.0.tgz", + "integrity": "sha512-AyxBUCANU/o/xC0ijGMKavo5Ls3oK6xykiOITlMdjFjrKOsqLrA7Nf5cnrDgcKrHzBirclAZt63XO7YZlVUPwA==", "dev": true, "requires": { "ajv": "5.5.2", @@ -2923,7 +2934,7 @@ "doctrine": "2.1.0", "eslint-scope": "3.7.1", "eslint-visitor-keys": "1.0.0", - "espree": "3.5.2", + "espree": "3.5.3", "esquery": "1.0.0", "esutils": "2.0.2", "file-entry-cache": "2.0.0", @@ -2959,17 +2970,6 @@ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" - } - }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -3027,13 +3027,21 @@ "dev": true }, "espree": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz", - "integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.3.tgz", + "integrity": "sha512-Zy3tAJDORxQZLl2baguiRU1syPERAIg0L+JB2MWorORgTu/CplzvxS9WWA7Xh4+Q+eOQihNs/1o1Xep8cvCxWQ==", "dev": true, "requires": { - "acorn": "5.3.0", + "acorn": "5.4.1", "acorn-jsx": "3.0.1" + }, + "dependencies": { + "acorn": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.4.1.tgz", + "integrity": "sha512-XLmq3H/BVvW6/GbxKryGxWORz1ebilSsUDlyC27bXhWGWAZWkGwS6FLHjOlwFXNFoWFQEO/Df4u0YYd0K3BQgQ==", + "dev": true + } } }, "esprima": { @@ -4029,7 +4037,8 @@ "jsbn": { "version": "0.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "json-schema": { "version": "0.2.3", @@ -7298,48 +7307,12 @@ "dev": true }, "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", "dev": true, "requires": { - "chalk": "1.1.3" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } + "chalk": "2.3.0" } }, "log4js": { @@ -7660,9 +7633,9 @@ } }, "madge": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/madge/-/madge-3.0.0.tgz", - "integrity": "sha512-fqMlHRGo3CHJ+e1+cHuoMC6YtpPEKhCC0JZnr+7tdXhRgXEObP7V1VLhggDJy3LUKAy0Yv+azP9dnNxAnfwHqw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/madge/-/madge-3.0.1.tgz", + "integrity": "sha512-6aR8+aNJMQjlmd0oSkdEPPdaLn9S0Yjyux/CQlFCOfIknWZn28Gh1HPAGMj2GfNa+Sj5ZNoqepAEtZgm49oPjg==", "dev": true, "requires": { "chalk": "2.3.0", @@ -7672,7 +7645,7 @@ "dependency-tree": "6.0.0", "graphviz": "0.0.8", "mz": "2.7.0", - "ora": "1.3.0", + "ora": "1.4.0", "pluralize": "7.0.0", "pretty-ms": "3.1.0", "rc": "1.2.5", @@ -8057,9 +8030,9 @@ } }, "mimic-fn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", - "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "minify-stream": { @@ -9004,7 +8977,7 @@ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { - "mimic-fn": "1.1.0" + "mimic-fn": "1.2.0" } }, "open": { @@ -9056,51 +9029,15 @@ } }, "ora": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-1.3.0.tgz", - "integrity": "sha1-gAeN0rkqk0r2ajrXKluRBpTt5Ro=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-1.4.0.tgz", + "integrity": "sha512-iMK1DOQxzzh2MBlVsU42G80mnrvUhqsMh74phHtDlrcTZPK0pH6o7l7DRshK+0YsxDyEuaOkziVdvM3T0QTzpw==", "dev": true, "requires": { - "chalk": "1.1.3", + "chalk": "2.3.0", "cli-cursor": "2.1.0", "cli-spinners": "1.1.0", - "log-symbols": "1.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } + "log-symbols": "2.2.0" } }, "orbit-camera-controller": { diff --git a/package.json b/package.json index a9afff8f474..4015757365e 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,6 @@ }, "dependencies": { "3d-view": "^2.0.0", - "3d-view-controls": "^2.2.2", "@plotly/d3-sankey": "^0.5.0", "alpha-shape": "^1.0.0", "array-range": "^1.0.1", @@ -119,8 +118,8 @@ "browserify-transform-tools": "^1.7.0", "check-node-version": "^3.2.0", "deep-equal": "^1.0.1", - "ecstatic": "^3.1.1", - "eslint": "^4.16.0", + "ecstatic": "^3.2.0", + "eslint": "^4.17.0", "falafel": "^2.0.0", "fs-extra": "^2.0.0", "fuse.js": "^3.2.0", @@ -139,7 +138,7 @@ "karma-jasmine-spec-tags": "^1.0.1", "karma-spec-reporter": "0.0.32", "karma-verbose-reporter": "0.0.6", - "madge": "^3.0.0", + "madge": "^3.0.1", "minify-stream": "^1.1.0", "minimist": "^1.2.0", "node-sass": "^4.7.2",