From dc90d13a83995301bc39ce0b6b4473f812e0992c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 13 Jan 2017 16:37:20 -0500 Subject: [PATCH 01/12] unskip gl2d data-ref annotation in supplyDefaults --- src/plots/cartesian/axes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 64dc21e4b71..dae22f8f009 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -59,7 +59,7 @@ axes.getFromTrace = axisIds.getFromTrace; */ axes.coerceRef = function(containerIn, containerOut, gd, attr, dflt, extraOption) { var axLetter = attr.charAt(attr.length - 1), - axlist = gd._fullLayout._has('gl2d') ? [] : axes.listIds(gd, axLetter), + axlist = axes.listIds(gd, axLetter), refAttr = attr + 'ref', attrDef = {}; From b29b3b2ea1078f81e48dab0189f849c2e12fb600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 13 Jan 2017 16:54:33 -0500 Subject: [PATCH 02/12] rewrite relayoutCallback as func declaration --- src/plots/gl2d/scene2d.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plots/gl2d/scene2d.js b/src/plots/gl2d/scene2d.js index e5b006900cb..0f600d7b026 100644 --- a/src/plots/gl2d/scene2d.js +++ b/src/plots/gl2d/scene2d.js @@ -288,8 +288,8 @@ proto.updateFx = function(options) { fullLayout.hovermode = options.hovermode; }; -var relayoutCallback = function(scene) { +function relayoutCallback(scene) { var xrange = scene.xaxis.range, yrange = scene.yaxis.range; @@ -300,8 +300,10 @@ var relayoutCallback = function(scene) { scene.graphDiv.layout.yaxis.range = yrange.slice(0); // Make a meaningful value to be passed on to the possible 'plotly_relayout' subscriber(s) - var update = { // scene.camera has no many useful projection or scale information - lastInputTime: scene.camera.lastInputTime // helps determine which one is the latest input (if async) + // scene.camera has no many useful projection or scale information + // helps determine which one is the latest input (if async) + var update = { + lastInputTime: scene.camera.lastInputTime }; update[scene.xaxis._name] = xrange.slice(); update[scene.yaxis._name] = yrange.slice(); From 4ba75513c73a268f599734a6b3df79cd3cbf27be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 13 Jan 2017 16:57:51 -0500 Subject: [PATCH 03/12] add handleAnnotations method to scene proto - call it when ticks require a change and when user drags and scroll on plot --- src/plots/gl2d/camera.js | 2 ++ src/plots/gl2d/scene2d.js | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/plots/gl2d/camera.js b/src/plots/gl2d/camera.js index 6da2699ad2b..eb9240529e2 100644 --- a/src/plots/gl2d/camera.js +++ b/src/plots/gl2d/camera.js @@ -113,6 +113,7 @@ function createCamera(scene) { result.lastInputTime = Date.now(); unSetAutoRange(); scene.cameraChanged(); + scene.handleAnnotations(); } break; } @@ -152,6 +153,7 @@ function createCamera(scene) { result.lastInputTime = Date.now(); unSetAutoRange(); scene.cameraChanged(); + scene.handleAnnotations(); break; } diff --git a/src/plots/gl2d/scene2d.js b/src/plots/gl2d/scene2d.js index 0f600d7b026..23d11163849 100644 --- a/src/plots/gl2d/scene2d.js +++ b/src/plots/gl2d/scene2d.js @@ -9,6 +9,7 @@ 'use strict'; +var Registry = require('../../registry'); var Axes = require('../../plots/cartesian/axes'); var Fx = require('../../plots/cartesian/graph_interact'); @@ -323,10 +324,25 @@ proto.cameraChanged = function() { this.glplotOptions.ticks = nextTicks; this.glplotOptions.dataBox = camera.dataBox; this.glplot.update(this.glplotOptions); + this.handleAnnotations(); + relayoutCallback(this); } }; +proto.handleAnnotations = function() { + var gd = this.graphDiv, + annotations = this.fullLayout.annotations; + + for(var i = 0; i < annotations.length; i++) { + var ann = annotations[i]; + + if(ann.xref === this.xaxis._id && ann.yref === this.yaxis._id) { + Registry.getComponentMethod('annotations', 'drawOne')(gd, i); + } + } +}; + proto.destroy = function() { var traces = this.traces; From bbac99bd58604642d85a5064643f4f7bd0873f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 13 Jan 2017 17:01:03 -0500 Subject: [PATCH 04/12] make sure gl2d axis scale updates on interactions --- src/plots/gl2d/scene2d.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plots/gl2d/scene2d.js b/src/plots/gl2d/scene2d.js index 23d11163849..68c83a5d4e6 100644 --- a/src/plots/gl2d/scene2d.js +++ b/src/plots/gl2d/scene2d.js @@ -238,6 +238,11 @@ proto.updateSize = function(canvas) { }; proto.computeTickMarks = function() { + this.xaxis.setScale(); + this.yaxis.setScale(); + + // override _length from backward compatibility + // even though setScale 'should' give the correct result this.xaxis._length = this.glplot.viewBox[2] - this.glplot.viewBox[0]; this.yaxis._length = @@ -424,6 +429,7 @@ proto.plot = function(fullData, calcData, fullLayout) { ax._length = options.viewBox[i + 2] - options.viewBox[i]; Axes.doAutoRange(ax); + ax.setScale(); } options.ticks = this.computeTickMarks(); From 38b8a92107fa88b4b519cf3a2da44a4880acb3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 13 Jan 2017 17:05:20 -0500 Subject: [PATCH 05/12] update _fullLayout ref on updateFx --- src/plots/gl2d/scene2d.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plots/gl2d/scene2d.js b/src/plots/gl2d/scene2d.js index 68c83a5d4e6..136e506cfa5 100644 --- a/src/plots/gl2d/scene2d.js +++ b/src/plots/gl2d/scene2d.js @@ -292,8 +292,9 @@ proto.updateFx = function(options) { fullLayout.dragmode = options.dragmode; fullLayout.hovermode = options.hovermode; -}; + this.graphDiv._fullLayout = fullLayout; +}; function relayoutCallback(scene) { var xrange = scene.xaxis.range, From 28c255c86a4855aa2784fcce700762c276dbfd9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 13 Jan 2017 17:05:31 -0500 Subject: [PATCH 06/12] add gl2d annotations mock --- test/image/baselines/gl2d_annotations.png | Bin 0 -> 50961 bytes test/image/mocks/gl2d_annotations.json | 52 ++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 test/image/baselines/gl2d_annotations.png create mode 100644 test/image/mocks/gl2d_annotations.json diff --git a/test/image/baselines/gl2d_annotations.png b/test/image/baselines/gl2d_annotations.png new file mode 100644 index 0000000000000000000000000000000000000000..ab0306aa89d6e6feea3810584cd344935357a587 GIT binary patch literal 50961 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 u_C!Yi`;k_)R@C}I+^g{a|9)zKljustified","showarrow":false,"align":"left","x":1,"y":4}, + {"text":"center
justified","showarrow":false,"x":2,"y":4}, + {"text":"right
justified","showarrow":false,"align":"right","x":3,"y":4}, + {"text":"no arrow
page auto TR","showarrow":false,"xref":"paper","yref":"paper","x":0.75,"y":0.75}, + {"text":"no arrow
page auto ML","showarrow":false,"xref":"paper","yref":"paper","x":0.25,"y":0.5}, + {"text":"no arrow
page auto BC","showarrow":false,"xref":"paper","yref":"paper","x":0.5,"y":0.25}, + {"text":"default"}, + {"text":"no arrow","x":5,"y":4,"showarrow":false}, + {"text":"border","showarrow":false,"bordercolor":"rgb(148, 103, 189)","x":4,"y":3}, + {"text":"border width","showarrow":false,"bordercolor":"rgb(0, 0, 255)","borderwidth":3,"x":5,"y":3}, + {"text":"background","showarrow":false,"bgcolor":"rgb(255, 127, 14)","x":4,"y":2}, + {"text":"padding","showarrow":false,"bordercolor":"rgb(0, 0, 0)","borderpad":3,"x":5,"y":2}, + {"text":"angle
Bottom R","showarrow":false,"textangle":40,"x":1,"y":1,"xanchor":"right","yanchor":"bottom"}, + {"text":"angle
Middle C","showarrow":false,"textangle":-70,"x":2,"y":1,"xanchor":"center","yanchor":"middle"}, + {"text":"angle
Top L","showarrow":false,"textangle":160,"x":3,"y":1,"xanchor":"left","yanchor":"top"}, + { + "text":"arrowhead styling","arrowcolor":"rgb(214, 39, 40)","arrowwidth":4.1,"arrowhead":7, + "ax":-34,"ay":37,"arrowsize":2,"x":4,"y":1 + }, + { + "text":"All together
withSTYLE", + "opacity":0.6,"arrowwidth":5,"arrowhead":3,"ax":-77,"ay":-5, + "bordercolor":"rgb(255, 0, 0)","borderwidth":4,"bgcolor":"rgba(255,255,0,0.5)", + "font":{"color":"rgb(0, 0, 255)","size":20}, + "arrowcolor":"rgb(166, 28, 0)","borderpad":3,"textangle":50,"x":5,"y":1 + }, + {"text":"","showarrow":true,"borderwidth":1.2,"arrowhead":2,"axref":"x","ayref":"y","x":5,"y":3,"ax":4,"ay":5}, + {"text":"","showarrow":true,"borderwidth":1.2,"arrowhead":2,"axref":"x","ayref":"y","x":6,"y":2,"ax":3,"ay":3} + ] + } +} From 33e7c606d56d81108563154d3cabdcb962a4ebe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 13 Jan 2017 17:22:38 -0500 Subject: [PATCH 07/12] fix lint --- src/plots/gl2d/scene2d.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plots/gl2d/scene2d.js b/src/plots/gl2d/scene2d.js index 136e506cfa5..f1207476d5c 100644 --- a/src/plots/gl2d/scene2d.js +++ b/src/plots/gl2d/scene2d.js @@ -316,7 +316,7 @@ function relayoutCallback(scene) { update[scene.yaxis._name] = yrange.slice(); scene.graphDiv.emit('plotly_relayout', update); -}; +} proto.cameraChanged = function() { var camera = this.camera; From 631d7a4b35d285b4eff687a0bf32c1bcca4647b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Mon, 16 Jan 2017 16:03:27 -0500 Subject: [PATCH 08/12] add drag/pan tests for annotations on gl2d graphs --- test/jasmine/tests/gl_plot_interact_test.js | 65 +++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/jasmine/tests/gl_plot_interact_test.js b/test/jasmine/tests/gl_plot_interact_test.js index 8cbd3b1b5a7..379d8f5809c 100644 --- a/test/jasmine/tests/gl_plot_interact_test.js +++ b/test/jasmine/tests/gl_plot_interact_test.js @@ -710,3 +710,68 @@ describe('Test gl plot side effects', function() { }).then(done); }); }); + +describe('gl2d interaction', function() { + var gd; + + beforeAll(function() { + jasmine.addMatchers(customMatchers); + }); + + beforeEach(function() { + gd = createGraphDiv(); + }); + + afterEach(function() { + Plotly.purge(gd); + destroyGraphDiv(); + }); + + it('data-referenced annotations should update on drag', function(done) { + + function drag(start, end) { + var opts = { buttons: 1 }; + + mouseEvent('mousemove', start[0], start[1], opts); + mouseEvent('mousedown', start[0], start[1], opts); + mouseEvent('mousemove', end[0], end[1], opts); + mouseEvent('mouseup', end[0], end[1], opts); + } + + function assertAnnotation(xy) { + var ann = d3.select('g.annotation-text-g'); + var x = +ann.attr('x'); + var y = +ann.attr('y'); + + expect([x, y]).toBeCloseToArray(xy); + } + + Plotly.plot(gd, [{ + type: 'scattergl', + x: [1, 2, 3], + y: [2, 1, 2] + }], { + annotations: [{ + x: 2, + y: 1, + text: 'text' + }], + dragmode: 'pan' + }) + .then(function() { + assertAnnotation([340, 334]); + + drag([250, 200], [150, 300]); + assertAnnotation([410, 264]); + + return Plotly.relayout(gd, { + 'xaxis.range': [1.5, 2.5], + 'yaxis.range': [1, 1.5] + }); + }) + .then(function() { + assertAnnotation([340, 340]); + }) + .then(done); + }); +}); From afaa4cb2714ef1f8aaaf8f3e94ce01affdcbbdeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 17 Jan 2017 15:09:23 -0500 Subject: [PATCH 09/12] rm now useless Fx.layoutAttribute def - this is probably a leftover from an old merge conflict --- src/plots/cartesian/graph_interact.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plots/cartesian/graph_interact.js b/src/plots/cartesian/graph_interact.js index 909b10d6411..f38bf6688cd 100644 --- a/src/plots/cartesian/graph_interact.js +++ b/src/plots/cartesian/graph_interact.js @@ -32,9 +32,6 @@ var fx = module.exports = {}; // copy on Fx for backward compatible fx.unhover = dragElement.unhover; -fx.layoutAttributes = { -}; - fx.supplyLayoutDefaults = function(layoutIn, layoutOut, fullData) { function coerce(attr, dflt) { From ee6d7d86d176e7726251132e94ab222ca21756c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 17 Jan 2017 16:13:00 -0500 Subject: [PATCH 10/12] rm useless Fx.supplyDefaults call in doModeBar subroutine - as the full Plots.supplyDefaults is called before the doModeBar subroutine. --- src/plot_api/subroutines.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index 587e014dc60..ca59c157ccf 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -295,7 +295,6 @@ exports.doModeBar = function(gd) { var subplotIds, i; ModeBar.manage(gd); - Plotly.Fx.supplyLayoutDefaults(gd.layout, gd._fullLayout, gd._fullData); Plotly.Fx.init(gd); subplotIds = Plots.getSubplotIds(fullLayout, 'gl3d'); From ce1cc44e905a8e467c404906247e2ec063d66daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 17 Jan 2017 16:15:21 -0500 Subject: [PATCH 11/12] replace scene2d.updateFx with scene2d.updateRefs - scene2d.updateRefs is now called on scene2d.plot and during Plots.supplyDefaults, ensuring that scene2d.fullLayout is up-to-date with gd._fullLayout. --- src/plot_api/subroutines.js | 7 ++----- src/plots/gl2d/scene2d.js | 23 +++++++---------------- src/plots/plots.js | 4 ++++ 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index ca59c157ccf..64b82fa349e 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -303,11 +303,8 @@ exports.doModeBar = function(gd) { scene.updateFx(fullLayout.dragmode, fullLayout.hovermode); } - subplotIds = Plots.getSubplotIds(fullLayout, 'gl2d'); - for(i = 0; i < subplotIds.length; i++) { - var scene2d = fullLayout._plots[subplotIds[i]]._scene2d; - scene2d.updateFx(fullLayout); - } + // no need to do this for gl2d subplots, + // Plots.linkSubplots takes care of it all. subplotIds = Plots.getSubplotIds(fullLayout, 'geo'); for(i = 0; i < subplotIds.length; i++) { diff --git a/src/plots/gl2d/scene2d.js b/src/plots/gl2d/scene2d.js index f1207476d5c..3f57d66ea0a 100644 --- a/src/plots/gl2d/scene2d.js +++ b/src/plots/gl2d/scene2d.js @@ -34,9 +34,8 @@ function Scene2D(options, fullLayout) { this.id = options.id; this.staticPlot = !!options.staticPlot; - this.fullLayout = fullLayout; this.fullData = null; - this.updateAxes(fullLayout); + this.updateRefs(fullLayout); this.makeFramework(); @@ -278,22 +277,15 @@ function compareTicks(a, b) { return false; } -proto.updateAxes = function(options) { +proto.updateRefs = function(newFullLayout) { + this.fullLayout = newFullLayout; + var spmatch = Axes.subplotMatch, xaxisName = 'xaxis' + this.id.match(spmatch)[1], yaxisName = 'yaxis' + this.id.match(spmatch)[2]; - this.xaxis = options[xaxisName]; - this.yaxis = options[yaxisName]; -}; - -proto.updateFx = function(options) { - var fullLayout = this.fullLayout; - - fullLayout.dragmode = options.dragmode; - fullLayout.hovermode = options.hovermode; - - this.graphDiv._fullLayout = fullLayout; + this.xaxis = this.fullLayout[xaxisName]; + this.yaxis = this.fullLayout[yaxisName]; }; function relayoutCallback(scene) { @@ -374,8 +366,7 @@ proto.destroy = function() { proto.plot = function(fullData, calcData, fullLayout) { var glplot = this.glplot; - this.fullLayout = fullLayout; - this.updateAxes(fullLayout); + this.updateRefs(fullLayout); this.updateTraces(fullData, calcData); var width = fullLayout.width, diff --git a/src/plots/plots.js b/src/plots/plots.js index a1d853d40ef..149f6612199 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -630,6 +630,10 @@ plots.linkSubplots = function(newFullData, newFullLayout, oldFullData, oldFullLa if(oldSubplot) { plotinfo = newSubplots[id] = oldSubplot; + + if(plotinfo._scene2d) { + plotinfo._scene2d.updateRefs(newFullLayout); + } } else { plotinfo = newSubplots[id] = {}; From c8b53ddcbdbbc884d8896b7b9bbea7d1269f5811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 18 Jan 2017 15:59:16 -0500 Subject: [PATCH 12/12] attach scene2d relayoutCallback onto proto - call after each mouse-change / wheel-change, as opposed to each time the scene2d ticks changed (which didn't cover all the cases) - make sure gl2d pan test `mouseup` to trigger relayoutCallback --- src/plots/gl2d/camera.js | 7 +++++ src/plots/gl2d/scene2d.js | 33 +++++++++++---------- test/jasmine/tests/gl_plot_interact_test.js | 28 ++++++++--------- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/plots/gl2d/camera.js b/src/plots/gl2d/camera.js index eb9240529e2..405795b6b57 100644 --- a/src/plots/gl2d/camera.js +++ b/src/plots/gl2d/camera.js @@ -91,6 +91,7 @@ function createCamera(scene) { updateRange(1, result.boxStart[1], result.boxEnd[1]); unSetAutoRange(); result.boxEnabled = false; + scene.relayoutCallback(); } break; @@ -110,11 +111,16 @@ function createCamera(scene) { scene.setRanges(dataBox); + result.panning = true; result.lastInputTime = Date.now(); unSetAutoRange(); scene.cameraChanged(); scene.handleAnnotations(); } + else if(result.panning) { + result.panning = false; + scene.relayoutCallback(); + } break; } @@ -154,6 +160,7 @@ function createCamera(scene) { unSetAutoRange(); scene.cameraChanged(); scene.handleAnnotations(); + scene.relayoutCallback(); break; } diff --git a/src/plots/gl2d/scene2d.js b/src/plots/gl2d/scene2d.js index 3f57d66ea0a..d86303c29f9 100644 --- a/src/plots/gl2d/scene2d.js +++ b/src/plots/gl2d/scene2d.js @@ -288,27 +288,30 @@ proto.updateRefs = function(newFullLayout) { this.yaxis = this.fullLayout[yaxisName]; }; -function relayoutCallback(scene) { - var xrange = scene.xaxis.range, - yrange = scene.yaxis.range; +proto.relayoutCallback = function() { + var graphDiv = this.graphDiv, + xaxis = this.xaxis, + yaxis = this.yaxis, + layout = graphDiv.layout; - // Update the layout on the DIV - scene.graphDiv.layout.xaxis.autorange = scene.xaxis.autorange; - scene.graphDiv.layout.xaxis.range = xrange.slice(0); - scene.graphDiv.layout.yaxis.autorange = scene.yaxis.autorange; - scene.graphDiv.layout.yaxis.range = yrange.slice(0); + // update user layout + layout.xaxis.autorange = xaxis.autorange; + layout.xaxis.range = xaxis.range.slice(0); + layout.yaxis.autorange = yaxis.autorange; + layout.yaxis.range = yaxis.range.slice(0); - // Make a meaningful value to be passed on to the possible 'plotly_relayout' subscriber(s) + // make a meaningful value to be passed on to the possible 'plotly_relayout' subscriber(s) // scene.camera has no many useful projection or scale information // helps determine which one is the latest input (if async) var update = { - lastInputTime: scene.camera.lastInputTime + lastInputTime: this.camera.lastInputTime }; - update[scene.xaxis._name] = xrange.slice(); - update[scene.yaxis._name] = yrange.slice(); - scene.graphDiv.emit('plotly_relayout', update); -} + update[xaxis._name] = xaxis.range.slice(0); + update[yaxis._name] = yaxis.range.slice(0); + + graphDiv.emit('plotly_relayout', update); +}; proto.cameraChanged = function() { var camera = this.camera; @@ -323,8 +326,6 @@ proto.cameraChanged = function() { this.glplotOptions.dataBox = camera.dataBox; this.glplot.update(this.glplotOptions); this.handleAnnotations(); - - relayoutCallback(this); } }; diff --git a/test/jasmine/tests/gl_plot_interact_test.js b/test/jasmine/tests/gl_plot_interact_test.js index 379d8f5809c..f3fae5d0b6c 100644 --- a/test/jasmine/tests/gl_plot_interact_test.js +++ b/test/jasmine/tests/gl_plot_interact_test.js @@ -236,6 +236,13 @@ describe('Test gl plot interactions', function() { it('should respond to drag interactions', function(done) { + function mouseTo(p0, p1) { + mouseEvent('mousemove', p0[0], p0[1]); + mouseEvent('mousedown', p0[0], p0[1], { buttons: 1 }); + mouseEvent('mousemove', p1[0], p1[1], { buttons: 1 }); + mouseEvent('mouseup', p1[0], p1[1]); + } + jasmine.addMatchers(customMatchers); var precision = 5; @@ -263,14 +270,10 @@ describe('Test gl plot interactions', function() { expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision); setTimeout(function() { - - mouseEvent('mousemove', 200, 200); - relayoutCallback.calls.reset(); // Drag scene along the X axis - - mouseEvent('mousemove', 220, 200, {buttons: 1}); + mouseTo([200, 200], [220, 200]); expect(gd.layout.xaxis.autorange).toBe(false); expect(gd.layout.yaxis.autorange).toBe(false); @@ -279,36 +282,31 @@ describe('Test gl plot interactions', function() { expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision); // Drag scene back along the X axis - - mouseEvent('mousemove', 200, 200, {buttons: 1}); + mouseTo([220, 200], [200, 200]); expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision); expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision); // Drag scene along the Y axis - - mouseEvent('mousemove', 200, 150, {buttons: 1}); + mouseTo([200, 200], [200, 150]); expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision); expect(gd.layout.yaxis.range).toBeCloseToArray(newY, precision); // Drag scene back along the Y axis - - mouseEvent('mousemove', 200, 200, {buttons: 1}); + mouseTo([200, 150], [200, 200]); expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision); expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision); // Drag scene along both the X and Y axis - - mouseEvent('mousemove', 220, 150, {buttons: 1}); + mouseTo([200, 200], [220, 150]); expect(gd.layout.xaxis.range).toBeCloseToArray(newX, precision); expect(gd.layout.yaxis.range).toBeCloseToArray(newY, precision); // Drag scene back along the X and Y axis - - mouseEvent('mousemove', 200, 200, {buttons: 1}); + mouseTo([220, 150], [200, 200]); expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision); expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);