From 77591caf3b34866b8882e7b886fc9ea402d56e44 Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Thu, 19 Sep 2024 13:21:20 -0400 Subject: [PATCH 1/2] fix to allow you to add fake selections this is useful when you have selectedpoints (based on a different plot perhaps) but no selections, and you still want a doubleclick to clear selectedpoints and generate selected and relayout events. --- src/components/selections/select.js | 1 + test/jasmine/tests/select_test.js | 102 +++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/components/selections/select.js b/src/components/selections/select.js index 3ca0fe724cf..985a79b090a 100644 --- a/src/components/selections/select.js +++ b/src/components/selections/select.js @@ -182,6 +182,7 @@ function prepSelect(evt, startX, startY, dragOptions, mode) { for(var q = 0; q < selections.length; q++) { var s = fullLayout.selections[q]; if( + !s || s.xref !== xRef || s.yref !== yRef ) { diff --git a/test/jasmine/tests/select_test.js b/test/jasmine/tests/select_test.js index aef24d22ae2..e7c8fcdfd40 100644 --- a/test/jasmine/tests/select_test.js +++ b/test/jasmine/tests/select_test.js @@ -75,7 +75,7 @@ function assertSelectionNodes(cornerCnt, outlineCnt, _msg) { } var selectingCnt, selectingData, selectedCnt, selectedData, deselectCnt, doubleClickData; -var selectedPromise, deselectPromise, clickedPromise; +var selectedPromise, deselectPromise, clickedPromise, relayoutPromise; function resetEvents(gd) { selectingCnt = 0; @@ -125,6 +125,12 @@ function resetEvents(gd) { resolve(); }); }); + + relayoutPromise = new Promise(function(resolve) { + gd.on('plotly_relayout', function() { + resolve(); + }); + }); } function assertEventCounts(selecting, selected, deselect, msg) { @@ -1035,6 +1041,100 @@ describe('Test select box and lasso in general:', function() { }); }); + describe('select / deselect with fake selections', function() { + var gd; + beforeEach(function(done) { + gd = createGraphDiv(); + + var mockCopy = Lib.extendDeep({}, mock); + mockCopy.layout.dragmode = 'select'; + mockCopy.layout.hovermode = 'closest'; + mockCopy.layout.selections = [null]; + addInvisible(mockCopy); + + _newPlot(gd, mockCopy.data, mockCopy.layout) + .then(done); + }); + + it('should trigger selecting/selected/deselect events', function(done) { + resetEvents(gd); + + drag(selectPath); + + selectedPromise.then(function() { + expect(selectedCnt).toBe(1, 'with the correct selected count'); + assertEventData(selectedData.points, [{ + curveNumber: 0, + pointNumber: 0, + pointIndex: 0, + x: 0.002, + y: 16.25 + }, { + curveNumber: 0, + pointNumber: 1, + pointIndex: 1, + x: 0.004, + y: 12.5 + }], 'with the correct selected points (2)'); + assertRange(selectedData.range, { + x: [0.002000, 0.0046236], + y: [0.10209191961595454, 24.512223978291406] + }, 'with the correct selected range'); + + return doubleClick(250, 200); + }) + .then(deselectPromise) + .then(function() { + expect(doubleClickData).toBe(null, 'with the correct deselect data'); + }) + .then(done, done.fail); + }); + + it('should handle add/sub selection', function(done) { + resetEvents(gd); + expect(gd.layout.selections.length).toBe(1); + + drag([[193, 193], [213, 193]], {shiftKey: true}) + + selectedPromise.then(function() { + expect(selectedCnt).toBe(1, 'with the correct selected count'); + assertEventData(selectedData.points, [{ + curveNumber: 0, + pointNumber: 4, + pointIndex: 4, + x: 0.013, + y: 6.875 + }], 'with the correct selected points (1)'); + }) + .then(function() { + // this is not working here, but it works in the test dashboard, not sure why + // but at least this test shows us that no errors are thrown. + // expect(gd.layout.selections.length).toBe(2, 'fake selection is still there'); + + resetEvents(gd); + + return doubleClick(250, 200); + }) + .then(relayoutPromise) + .then(function() { + expect(gd.layout.selections.length).toBe(0, 'fake selection is cleared'); + expect(doubleClickData).toBe(null, 'with the correct deselect data'); + }) + .then(done, done.fail); + }); + + it('should clear fake selections on doubleclick', function(done) { + resetEvents(gd); + + doubleClick(250, 200); + + relayoutPromise.then(function() { + expect(gd.layout.selections.length).toBe(0, 'fake selections are cleared'); + }) + .then(done, done.fail); + }); + }); + describe('lasso events', function() { var mockCopy = Lib.extendDeep({}, mock); mockCopy.layout.dragmode = 'lasso'; From 51dcc240f7520121c33fbd03da2ac6b84fda64da Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Thu, 19 Sep 2024 13:31:18 -0400 Subject: [PATCH 2/2] changelog for 7164 --- draftlogs/7164_fix.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 draftlogs/7164_fix.md diff --git a/draftlogs/7164_fix.md b/draftlogs/7164_fix.md new file mode 100644 index 00000000000..b7e77ede0fa --- /dev/null +++ b/draftlogs/7164_fix.md @@ -0,0 +1 @@ +- Allow null or broken selection objects without throwing an error [[#7164](https://github.com/plotly/plotly.js/pull/7164)]