From 6a07bc9f04106ec45de7d982887a0a5240ad2705 Mon Sep 17 00:00:00 2001 From: sleighsoft Date: Sun, 24 Jan 2021 14:01:32 +0100 Subject: [PATCH 1/9] click v1 --- src/components/fx/click.js | 27 ++++++++++++++++++++------ src/components/fx/layout_attributes.js | 19 ++++++++++++++++-- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/components/fx/click.js b/src/components/fx/click.js index 5284dcb2401..e2662b6a043 100644 --- a/src/components/fx/click.js +++ b/src/components/fx/click.js @@ -22,14 +22,29 @@ module.exports = function click(gd, evt, subplot) { hover(gd, evt, subplot, true); } - function emitClick() { gd.emit('plotly_click', {points: gd._hoverdata, event: evt}); } + function emitClick(data) { gd.emit('plotly_click', {points: data, event: evt}); } - if(gd._hoverdata && evt && evt.target) { - if(annotationsDone && annotationsDone.then) { - annotationsDone.then(emitClick); - } else emitClick(); + // TODO(j): remove gd._hoverdata + var clickmode = gd._fullLayout.clickmode; + var data; + if(evt && evt.target) { + if(gd._hoverdata) { + data = gd._hoverdata; + } else if(clickmode.indexOf('anywhere') > -1) { + var xaxis = gd._fullLayout.xaxis; + var yaxis = gd._fullLayout.yaxis; + var bb = evt.target.getBoundingClientRect(); + var x = xaxis.p2d(evt.clientX - bb.left); + var y = yaxis.p2d(evt.clientY - bb.top); + data = [{x: x, y: y}]; + } + if(data) { + if(annotationsDone && annotationsDone.then) { + annotationsDone.then(function() { emitClick(data); }); + } else emitClick(data); + } // why do we get a double event without this??? if(evt.stopImmediatePropagation) evt.stopImmediatePropagation(); } -}; +}; \ No newline at end of file diff --git a/src/components/fx/layout_attributes.js b/src/components/fx/layout_attributes.js index 3e330ec6748..a2922f6fd74 100644 --- a/src/components/fx/layout_attributes.js +++ b/src/components/fx/layout_attributes.js @@ -20,7 +20,8 @@ fontAttrs.size.dflt = constants.HOVERFONTSIZE; module.exports = { clickmode: { valType: 'flaglist', - flags: ['event', 'select'], + role: 'info', + flags: ['event', 'select', 'anywhere'], dflt: 'event', editType: 'plot', extras: ['none'], @@ -37,11 +38,17 @@ module.exports = { 'explicitly setting `hovermode`: *closest* when using this feature.', 'Selection events are sent accordingly as long as *event* flag is set as well.', 'When the *event* flag is missing, `plotly_click` and `plotly_selected`', - 'events are not fired.' + 'events are not fired.', + 'The *anywhere* flag extends the *select* flag by allowing to trigger a', + 'click event anywhere in the plot. The click event will always include *x*', + 'and *y* coordinates and if a data point is below the cursor it will also', + 'include information about the data point. When specifying *anywhere* the', + '*select* flag becomes superfluous.' ].join(' ') }, dragmode: { valType: 'enumerated', + role: 'info', values: [ 'zoom', 'pan', @@ -67,6 +74,7 @@ module.exports = { }, hovermode: { valType: 'enumerated', + role: 'info', values: ['x', 'y', 'closest', false, 'x unified', 'y unified'], editType: 'modebar', description: [ @@ -94,6 +102,7 @@ module.exports = { valType: 'integer', min: -1, dflt: 20, + role: 'info', editType: 'none', description: [ 'Sets the default distance (in pixels) to look for data', @@ -108,6 +117,7 @@ module.exports = { valType: 'integer', min: -1, dflt: 20, + role: 'info', editType: 'none', description: [ 'Sets the default distance (in pixels) to look for data to draw', @@ -120,6 +130,7 @@ module.exports = { hoverlabel: { bgcolor: { valType: 'color', + role: 'style', editType: 'none', description: [ 'Sets the background color of all hover labels on graph' @@ -127,6 +138,7 @@ module.exports = { }, bordercolor: { valType: 'color', + role: 'style', editType: 'none', description: [ 'Sets the border color of all hover labels on graph.' @@ -137,6 +149,7 @@ module.exports = { valType: 'enumerated', values: ['left', 'right', 'auto'], dflt: 'auto', + role: 'style', editType: 'none', description: [ 'Sets the horizontal alignment of the text content within hover label box.', @@ -147,6 +160,7 @@ module.exports = { valType: 'integer', min: -1, dflt: 15, + role: 'style', editType: 'none', description: [ 'Sets the default length (in number of characters) of the trace name in', @@ -161,6 +175,7 @@ module.exports = { }, selectdirection: { valType: 'enumerated', + role: 'info', values: ['h', 'v', 'd', 'any'], dflt: 'any', description: [ From 0ab1e7518afb91499b82c9e7206f64a744c5ab51 Mon Sep 17 00:00:00 2001 From: sleighsoft Date: Sun, 24 Jan 2021 14:37:18 +0100 Subject: [PATCH 2/9] fix lint --- src/components/fx/click.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/fx/click.js b/src/components/fx/click.js index e2662b6a043..43a68288f6c 100644 --- a/src/components/fx/click.js +++ b/src/components/fx/click.js @@ -24,7 +24,6 @@ module.exports = function click(gd, evt, subplot) { function emitClick(data) { gd.emit('plotly_click', {points: data, event: evt}); } - // TODO(j): remove gd._hoverdata var clickmode = gd._fullLayout.clickmode; var data; if(evt && evt.target) { @@ -47,4 +46,4 @@ module.exports = function click(gd, evt, subplot) { // why do we get a double event without this??? if(evt.stopImmediatePropagation) evt.stopImmediatePropagation(); } -}; \ No newline at end of file +}; From 279a0d1e6382c1ce1abf5b9a5a91e0d4b4715f3a Mon Sep 17 00:00:00 2001 From: sleighsoft Date: Sun, 7 Feb 2021 19:24:37 +0100 Subject: [PATCH 3/9] Fix linting --- src/components/fx/layout_attributes.js | 1 - test/jasmine/tests/anywhere_test.js | 120 +++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 test/jasmine/tests/anywhere_test.js diff --git a/src/components/fx/layout_attributes.js b/src/components/fx/layout_attributes.js index 4b99025f77a..23f4e45522c 100644 --- a/src/components/fx/layout_attributes.js +++ b/src/components/fx/layout_attributes.js @@ -12,7 +12,6 @@ fontAttrs.size.dflt = constants.HOVERFONTSIZE; module.exports = { clickmode: { valType: 'flaglist', - role: 'info', flags: ['event', 'select', 'anywhere'], dflt: 'event', editType: 'plot', diff --git a/test/jasmine/tests/anywhere_test.js b/test/jasmine/tests/anywhere_test.js new file mode 100644 index 00000000000..6f26a69f1e2 --- /dev/null +++ b/test/jasmine/tests/anywhere_test.js @@ -0,0 +1,120 @@ +var Plotly = require('@lib/index'); +var Lib = require('@src/lib'); +var click = require('../assets/click'); + +var createGraphDiv = require('../assets/create_graph_div'); +var destroyGraphDiv = require('../assets/destroy_graph_div'); +var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay; + +var clickEvent; +var clickedPromise; + +function resetEvents(gd) { + clickEvent = null; + + gd.removeAllListeners(); + + clickedPromise = new Promise(function(resolve) { + gd.on('plotly_click', function(data) { + clickEvent = data.points[0]; + resolve(); + }); + }); +} + +describe('Click-to-select', function() { + var mock14Pts = { + 'in-margin': { x: 28, y: 28 }, + 'point-0': { x: 92, y: 102 }, + 'between-point-0-and-1': { x: 117, y: 110 }, + 'point-11': { x: 339, y: 214 }, + }; + var expectedEvents = { + 'in-margin': false, + 'point-0': { + curveNumber: 0, + pointIndex: 0, + pointNumber: 0, + x: 0.002, + y: 16.25 + }, + 'between-point-0-and-1': { x: 0.002990379231567056, y: 14.169142943944111 }, + 'point-11': { + curveNumber: 0, + pointIndex: 11, + pointNumber: 11, + x: 0.125, + y: 2.125 + }, + }; + var gd; + + beforeEach(function() { + gd = createGraphDiv(); + }); + + afterEach(destroyGraphDiv); + + function plotMock14(layoutOpts) { + var mock = require('@mocks/14.json'); + var defaultLayoutOpts = { + layout: { + clickmode: 'event+anywhere', + hoverdistance: 1 + } + }; + var mockCopy = Lib.extendDeep( + {}, + mock, + defaultLayoutOpts, + { layout: layoutOpts }); + + return Plotly.newPlot(gd, mockCopy.data, mockCopy.layout); + } + + function isSubset(superObj, subObj) { + return superObj === subObj || + typeof superObj === 'object' && + typeof subObj === 'object' && ( + subObj.valueOf() === superObj.valueOf() || + Object.keys(subObj).every(function(k) { return isSubset(superObj[k], subObj[k]); }) + ); + } + + /** + * Executes a click and before resets event handlers. + * Returns the `clickedPromise` for convenience. + */ + function _click(x, y, clickOpts) { + resetEvents(gd); + setTimeout(function() { + click(x, y, clickOpts); + }, DBLCLICKDELAY * 1.03); + return clickedPromise; + } + + function clickAndTestPoint(pointKey, clickOpts) { + var x = mock14Pts[pointKey].x; + var y = mock14Pts[pointKey].y; + var expectedEvent = expectedEvents[pointKey]; + var result = _click(x, y, clickOpts); + if(expectedEvent) { + result.then(function() { + expect(isSubset(clickEvent, expectedEvent)).toBe(true); + }); + } else { + expect(clickEvent).toBe(null); + result = null; + } + return result; + } + + it('selects point and/or coordinate when clicked', function(done) { + plotMock14() + .then(function() { return clickAndTestPoint('in-margin'); }) + .then(function() { return clickAndTestPoint('point-0'); }) + .then(function() { return clickAndTestPoint('between-point-0-and-1'); }) + .then(function() { return clickAndTestPoint('point-11'); }) + .then(done, done.fail); + }); +}); From 4d221db5a7e3d3b34caa807fc0d49f20df64873a Mon Sep 17 00:00:00 2001 From: yiyuezhuo Date: Mon, 15 Feb 2021 15:00:22 +0800 Subject: [PATCH 4/9] try to enable click anywhere in Geo mode --- src/components/fx/click.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/fx/click.js b/src/components/fx/click.js index a4f17e44674..0da63cc3628 100644 --- a/src/components/fx/click.js +++ b/src/components/fx/click.js @@ -21,7 +21,11 @@ module.exports = function click(gd, evt, subplot) { if(evt && evt.target) { if(gd._hoverdata) { data = gd._hoverdata; - } else if(clickmode.indexOf('anywhere') > -1) { + } else if(gd._fullLayout.geo){ + var lat = gd._fullLayout.geo._subplot.xaxis.p2c(); + var lon = gd._fullLayout.geo._subplot.yaxis.p2c(); + data = [{lat: lat, lon: lon}]; + }else if(clickmode.indexOf('anywhere') > -1) { var xaxis = gd._fullLayout.xaxis; var yaxis = gd._fullLayout.yaxis; var bb = evt.target.getBoundingClientRect(); From 461b695bf9f3c490118ecf602db23891f88e4447 Mon Sep 17 00:00:00 2001 From: yiyuezhuo Date: Tue, 16 Feb 2021 19:17:37 +0800 Subject: [PATCH 5/9] fix anywhere leak problem --- src/components/fx/click.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/components/fx/click.js b/src/components/fx/click.js index 0da63cc3628..14c1c3f4000 100644 --- a/src/components/fx/click.js +++ b/src/components/fx/click.js @@ -21,17 +21,20 @@ module.exports = function click(gd, evt, subplot) { if(evt && evt.target) { if(gd._hoverdata) { data = gd._hoverdata; - } else if(gd._fullLayout.geo){ - var lat = gd._fullLayout.geo._subplot.xaxis.p2c(); - var lon = gd._fullLayout.geo._subplot.yaxis.p2c(); - data = [{lat: lat, lon: lon}]; }else if(clickmode.indexOf('anywhere') > -1) { - var xaxis = gd._fullLayout.xaxis; - var yaxis = gd._fullLayout.yaxis; - var bb = evt.target.getBoundingClientRect(); - var x = xaxis.p2d(evt.clientX - bb.left); - var y = yaxis.p2d(evt.clientY - bb.top); - data = [{x: x, y: y}]; + if(gd._fullLayout.geo){ + var lat = gd._fullLayout.geo._subplot.xaxis.p2c(); + var lon = gd._fullLayout.geo._subplot.yaxis.p2c(); + data = [{lat: lat, lon: lon}]; + } + else{ + var xaxis = gd._fullLayout.xaxis; + var yaxis = gd._fullLayout.yaxis; + var bb = evt.target.getBoundingClientRect(); + var x = xaxis.p2d(evt.clientX - bb.left); + var y = yaxis.p2d(evt.clientY - bb.top); + data = [{x: x, y: y}]; + } } if(data) { if(annotationsDone && annotationsDone.then) { From a9c0c7b6574a2c4400c9e709cb8abc6ca28a2982 Mon Sep 17 00:00:00 2001 From: sleighsoft Date: Sun, 28 Mar 2021 14:46:50 +0200 Subject: [PATCH 6/9] Fix linting --- src/components/fx/click.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/components/fx/click.js b/src/components/fx/click.js index 14c1c3f4000..40f831a69c8 100644 --- a/src/components/fx/click.js +++ b/src/components/fx/click.js @@ -21,18 +21,15 @@ module.exports = function click(gd, evt, subplot) { if(evt && evt.target) { if(gd._hoverdata) { data = gd._hoverdata; - }else if(clickmode.indexOf('anywhere') > -1) { - if(gd._fullLayout.geo){ + } else if(clickmode.indexOf('anywhere') > -1) { + if(gd._fullLayout.geo) { var lat = gd._fullLayout.geo._subplot.xaxis.p2c(); var lon = gd._fullLayout.geo._subplot.yaxis.p2c(); data = [{lat: lat, lon: lon}]; - } - else{ - var xaxis = gd._fullLayout.xaxis; - var yaxis = gd._fullLayout.yaxis; + } else { var bb = evt.target.getBoundingClientRect(); - var x = xaxis.p2d(evt.clientX - bb.left); - var y = yaxis.p2d(evt.clientY - bb.top); + var x = gd._fullLayout.xaxis.p2d(evt.clientX - bb.left); + var y = gd._fullLayout.yaxis.p2d(evt.clientY - bb.top); data = [{x: x, y: y}]; } } From babdf8977d7a9e8e76e508837dc40773a70c9e32 Mon Sep 17 00:00:00 2001 From: sleighsoft Date: Sat, 11 Sep 2021 14:05:39 +0200 Subject: [PATCH 7/9] Drop hardcoded role:info --- src/components/fx/layout_attributes.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/components/fx/layout_attributes.js b/src/components/fx/layout_attributes.js index 8d9d7f944e3..7ee4c5f7f57 100644 --- a/src/components/fx/layout_attributes.js +++ b/src/components/fx/layout_attributes.js @@ -39,7 +39,6 @@ module.exports = { }, dragmode: { valType: 'enumerated', - role: 'info', values: [ 'zoom', 'pan', @@ -65,7 +64,6 @@ module.exports = { }, hovermode: { valType: 'enumerated', - role: 'info', values: ['x', 'y', 'closest', false, 'x unified', 'y unified'], dflt: 'closest', editType: 'modebar', @@ -87,7 +85,6 @@ module.exports = { valType: 'integer', min: -1, dflt: 20, - role: 'info', editType: 'none', description: [ 'Sets the default distance (in pixels) to look for data', @@ -114,7 +111,6 @@ module.exports = { hoverlabel: { bgcolor: { valType: 'color', - role: 'style', editType: 'none', description: [ 'Sets the background color of all hover labels on graph' @@ -122,7 +118,6 @@ module.exports = { }, bordercolor: { valType: 'color', - role: 'style', editType: 'none', description: [ 'Sets the border color of all hover labels on graph.' @@ -133,7 +128,6 @@ module.exports = { valType: 'enumerated', values: ['left', 'right', 'auto'], dflt: 'auto', - role: 'style', editType: 'none', description: [ 'Sets the horizontal alignment of the text content within hover label box.', @@ -144,7 +138,6 @@ module.exports = { valType: 'integer', min: -1, dflt: 15, - role: 'style', editType: 'none', description: [ 'Sets the default length (in number of characters) of the trace name in', @@ -159,7 +152,6 @@ module.exports = { }, selectdirection: { valType: 'enumerated', - role: 'info', values: ['h', 'v', 'd', 'any'], dflt: 'any', description: [ From 9b5c2379ad76f6834a80b2c3c10d2ed676b205da Mon Sep 17 00:00:00 2001 From: sleighsoft Date: Sat, 11 Sep 2021 14:23:06 +0200 Subject: [PATCH 8/9] update plot-schema diff --- test/plot-schema.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/plot-schema.json b/test/plot-schema.json index 5cb02325f61..596d959a660 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -1037,7 +1037,7 @@ ] }, "clickmode": { - "description": "Determines the mode of single click interactions. *event* is the default value and emits the `plotly_click` event. In addition this mode emits the `plotly_selected` event in drag modes *lasso* and *select*, but with no event data attached (kept for compatibility reasons). The *select* flag enables selecting single data points via click. This mode also supports persistent selections, meaning that pressing Shift while clicking, adds to / subtracts from an existing selection. *select* with `hovermode`: *x* can be confusing, consider explicitly setting `hovermode`: *closest* when using this feature. Selection events are sent accordingly as long as *event* flag is set as well. When the *event* flag is missing, `plotly_click` and `plotly_selected` events are not fired.", + "description": "Determines the mode of single click interactions. *event* is the default value and emits the `plotly_click` event. In addition this mode emits the `plotly_selected` event in drag modes *lasso* and *select*, but with no event data attached (kept for compatibility reasons). The *select* flag enables selecting single data points via click. This mode also supports persistent selections, meaning that pressing Shift while clicking, adds to / subtracts from an existing selection. *select* with `hovermode`: *x* can be confusing, consider explicitly setting `hovermode`: *closest* when using this feature. Selection events are sent accordingly as long as *event* flag is set as well. When the *event* flag is missing, `plotly_click` and `plotly_selected` events are not fired. The *anywhere* flag extends the *select* flag by allowing to trigger a click event anywhere in the plot. The click event will always include *x* and *y* coordinates and if a data point is below the cursor it will also include information about the data point. When specifying *anywhere* the *select* flag becomes superfluous.", "dflt": "event", "editType": "plot", "extras": [ @@ -1045,7 +1045,8 @@ ], "flags": [ "event", - "select" + "select", + "anywhere" ], "valType": "flaglist" }, From a406275743368dce1b7f90735cfbf4753cd4b519 Mon Sep 17 00:00:00 2001 From: sleighsoft Date: Sat, 11 Sep 2021 16:23:15 +0200 Subject: [PATCH 9/9] Add geoscatter test and refactor tests --- test/jasmine/tests/anywhere_test.js | 112 ++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 13 deletions(-) diff --git a/test/jasmine/tests/anywhere_test.js b/test/jasmine/tests/anywhere_test.js index 6f26a69f1e2..3c6ced1b169 100644 --- a/test/jasmine/tests/anywhere_test.js +++ b/test/jasmine/tests/anywhere_test.js @@ -23,13 +23,13 @@ function resetEvents(gd) { } describe('Click-to-select', function() { - var mock14Pts = { + var mock14PtsScatter = { 'in-margin': { x: 28, y: 28 }, 'point-0': { x: 92, y: 102 }, 'between-point-0-and-1': { x: 117, y: 110 }, 'point-11': { x: 339, y: 214 }, }; - var expectedEvents = { + var expectedEventsScatter = { 'in-margin': false, 'point-0': { curveNumber: 0, @@ -47,15 +47,48 @@ describe('Click-to-select', function() { y: 2.125 }, }; + + var mockPtsGeoscatter = { + 'start': {lat: 40.7127, lon: -74.0059}, + 'end': {lat: 51.5072, lon: 0.1275}, + }; + var mockPtsGeoscatterClick = { + 'in-margin': { x: 28, y: 28 }, + 'start': {x: 239, y: 174}, + 'end': {x: 426, y: 157}, + 'iceland': {x: 322, y: 150}, + }; + var expectedEventsGeoscatter = { + 'in-margin': false, + 'start': { + curveNumber: 0, + pointIndex: 0, + pointNumber: 0, + lat: 40.7127, + lon: -74.0059, + }, + 'end': { + curveNumber: 0, + pointIndex: 1, + pointNumber: 1, + lat: 51.5072, + lon: 51.5072, + }, + 'iceland': {lat: -18.666562962962963, lon: 56.66635185185185}, + }; + var gd; beforeEach(function() { gd = createGraphDiv(); }); - afterEach(destroyGraphDiv); + afterEach(function() { + resetEvents(gd); + destroyGraphDiv(); + }); - function plotMock14(layoutOpts) { + function plotMock14Anywhere(layoutOpts) { var mock = require('@mocks/14.json'); var defaultLayoutOpts = { layout: { @@ -72,6 +105,41 @@ describe('Click-to-select', function() { return Plotly.newPlot(gd, mockCopy.data, mockCopy.layout); } + function plotMock14AnywhereSelect(layoutOpts) { + var mock = require('@mocks/14.json'); + var defaultLayoutOpts = { + layout: { + clickmode: 'select+event+anywhere', + hoverdistance: 1 + } + }; + var mockCopy = Lib.extendDeep( + {}, + mock, + defaultLayoutOpts, + { layout: layoutOpts }); + + return Plotly.newPlot(gd, mockCopy.data, mockCopy.layout); + } + + function plotGeoscatterAnywhere() { + var layout = { + clickmode: 'event+anywhere', + hoverdistance: 1 + }; + var data = [{ + type: 'scattergeo', + lat: [ mockPtsGeoscatter.start.lat, mockPtsGeoscatter.end.lat ], + lon: [ mockPtsGeoscatter.start.lon, mockPtsGeoscatter.end.lat ], + mode: 'lines', + line: { + width: 2, + color: 'blue' + } + }]; + return Plotly.newPlot(gd, data, layout); + } + function isSubset(superObj, subObj) { return superObj === subObj || typeof superObj === 'object' && @@ -93,9 +161,9 @@ describe('Click-to-select', function() { return clickedPromise; } - function clickAndTestPoint(pointKey, clickOpts) { - var x = mock14Pts[pointKey].x; - var y = mock14Pts[pointKey].y; + function clickAndTestPoint(mockPts, expectedEvents, pointKey, clickOpts) { + var x = mockPts[pointKey].x; + var y = mockPts[pointKey].y; var expectedEvent = expectedEvents[pointKey]; var result = _click(x, y, clickOpts); if(expectedEvent) { @@ -109,12 +177,30 @@ describe('Click-to-select', function() { return result; } - it('selects point and/or coordinate when clicked', function(done) { - plotMock14() - .then(function() { return clickAndTestPoint('in-margin'); }) - .then(function() { return clickAndTestPoint('point-0'); }) - .then(function() { return clickAndTestPoint('between-point-0-and-1'); }) - .then(function() { return clickAndTestPoint('point-11'); }) + it('selects point and/or coordinate when clicked - scatter - event+anywhere', function(done) { + plotMock14Anywhere() + .then(function() { return clickAndTestPoint(mock14PtsScatter, expectedEventsScatter, 'in-margin'); }) + .then(function() { return clickAndTestPoint(mock14PtsScatter, expectedEventsScatter, 'point-0'); }) + .then(function() { return clickAndTestPoint(mock14PtsScatter, expectedEventsScatter, 'between-point-0-and-1'); }) + .then(function() { return clickAndTestPoint(mock14PtsScatter, expectedEventsScatter, 'point-11'); }) + .then(done, done.fail); + }); + + it('selects point and/or coordinate when clicked - scatter - select+event+anywhere', function(done) { + plotMock14AnywhereSelect() + .then(function() { return clickAndTestPoint(mock14PtsScatter, expectedEventsScatter, 'in-margin'); }) + .then(function() { return clickAndTestPoint(mock14PtsScatter, expectedEventsScatter, 'point-0'); }) + .then(function() { return clickAndTestPoint(mock14PtsScatter, expectedEventsScatter, 'between-point-0-and-1'); }) + .then(function() { return clickAndTestPoint(mock14PtsScatter, expectedEventsScatter, 'point-11'); }) + .then(done, done.fail); + }); + + it('selects point and/or coordinate when clicked - geoscatter - event+anywhere', function(done) { + plotGeoscatterAnywhere() + .then(function() { return clickAndTestPoint(mockPtsGeoscatterClick, expectedEventsGeoscatter, 'in-margin'); }) + .then(function() { return clickAndTestPoint(mockPtsGeoscatterClick, expectedEventsGeoscatter, 'start'); }) + .then(function() { return clickAndTestPoint(mockPtsGeoscatterClick, expectedEventsGeoscatter, 'end'); }) + .then(function() { return clickAndTestPoint(mockPtsGeoscatterClick, expectedEventsGeoscatter, 'iceland'); }) .then(done, done.fail); }); });