Skip to content

emit plotly_selected event on plot API calls and GUI edits #6277

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 24 additions & 12 deletions src/components/selections/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ function prepSelect(evt, startX, startY, dragOptions, mode) {
}

if(selectionErased) {
gd._fullLayout._noEmitSelectedAtStart = true;

Registry.call('_guiRelayout', gd, {
selections: list
});
Expand Down Expand Up @@ -315,10 +317,10 @@ function prepSelect(evt, startX, startY, dragOptions, mode) {
displayOutlines(convertPoly(mergedPolygons, isOpenMode), outlines, dragOptions);

if(isSelectMode) {
var _res = reselect(gd);
var _res = reselect(gd, false);
var extraPoints = _res.eventData ? _res.eventData.points.slice() : [];

_res = reselect(gd, selectionTesters, searchTraces, dragOptions);
_res = reselect(gd, false, selectionTesters, searchTraces, dragOptions);
selectionTesters = _res.selectionTesters;
eventData = _res.eventData;

Expand Down Expand Up @@ -412,9 +414,13 @@ function prepSelect(evt, startX, startY, dragOptions, mode) {
}
}

Registry.call('_guiRelayout', gd, {
selections: subSelections
});
if(subSelections.length < allSelections.length) {
gd._fullLayout._noEmitSelectedAtStart = true;

Registry.call('_guiRelayout', gd, {
selections: subSelections
});
}
}
}
} else {
Expand Down Expand Up @@ -733,6 +739,8 @@ function clearSelectionsCache(dragOptions, immediateSelect) {
selections = newSelections(outlines, dragOptions);
}
if(selections) {
gd._fullLayout._noEmitSelectedAtStart = true;

Registry.call('_guiRelayout', gd, {
selections: selections
}).then(function() {
Expand Down Expand Up @@ -1070,7 +1078,7 @@ function _doSelect(selectionTesters, searchTraces) {
return allSelections;
}

function reselect(gd, selectionTesters, searchTraces, dragOptions) {
function reselect(gd, mayEmitSelected, selectionTesters, searchTraces, dragOptions) {
var hadSearchTraces = !!searchTraces;
var plotinfo, xRef, yRef;
if(dragOptions) {
Expand Down Expand Up @@ -1193,15 +1201,15 @@ function reselect(gd, selectionTesters, searchTraces, dragOptions) {
updateSelectedState(gd, allSearchTraces, eventData);

var clickmode = fullLayout.clickmode;
var sendEvents = clickmode.indexOf('event') > -1;
var sendEvents = clickmode.indexOf('event') > -1 && mayEmitSelected;

if(
!plotinfo && // get called from plot_api & plots
fullLayout._reselect
mayEmitSelected
) {
if(sendEvents) {
var activePolygons = getLayoutPolygons(gd, true);
var activePolygons = getLayoutPolygons(gd, true);

if(activePolygons.length) {
var xref = activePolygons[0].xref;
var yref = activePolygons[0].yref;
if(xref && yref) {
Expand All @@ -1214,8 +1222,12 @@ function reselect(gd, selectionTesters, searchTraces, dragOptions) {

fillRangeItems(eventData, poly);
}
}

emitSelected(gd, eventData);
if(gd._fullLayout._noEmitSelectedAtStart) {
gd._fullLayout._noEmitSelectedAtStart = false;
} else {
if(sendEvents) emitSelected(gd, eventData);
}

fullLayout._reselect = false;
Expand All @@ -1237,7 +1249,7 @@ function reselect(gd, selectionTesters, searchTraces, dragOptions) {
if(eventData.points.length) {
emitSelected(gd, eventData);
} else {
gd.emit('plotly_deselect', null);
emitDeselect(gd);
}
}

Expand Down
11 changes: 10 additions & 1 deletion src/plots/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -3364,7 +3364,16 @@ plots.redrag = function(gd) {
};

plots.reselect = function(gd) {
Registry.getComponentMethod('selections', 'reselect')(gd);
var fullLayout = gd._fullLayout;

var A = (gd.layout || {}).selections;
var B = fullLayout._previousSelections;
fullLayout._previousSelections = A;

var mayEmitSelected = fullLayout._reselect ||
JSON.stringify(A) !== JSON.stringify(B);

Registry.getComponentMethod('selections', 'reselect')(gd, mayEmitSelected);
};

plots.generalUpdatePerTraceModule = function(gd, subplot, subplotCalcData, subplotLayout) {
Expand Down
71 changes: 71 additions & 0 deletions test/jasmine/tests/draw_newselection_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -425,13 +425,28 @@ describe('Activate and edit selections', function() {

['mouse'].forEach(function(device) {
it('reactangle using ' + device, function(done) {
var range;
var lassoPoints;
var points;
var _selections;
var selectedCnt = 0;

var i = 0; // selection index

Plotly.newPlot(gd, {
data: fig.data,
layout: fig.layout,
config: fig.config
})
.then(function() {
gd.on('plotly_selected', function(d) {
range = d.range;
lassoPoints = d.lassoPoints;
points = d.points;
_selections = d.selections;
selectedCnt++;
});
})

// selection between 175, 160 and 255, 230
.then(function() { click(210, 160); }) // activate selection
Expand All @@ -454,6 +469,8 @@ describe('Activate and edit selections', function() {
'x1': 75,
'y1': 75
});

expect(selectedCnt).toEqual(0);
})
.then(function() { drag([[255, 230], [300, 200]]); }) // move vertex
.then(function() {
Expand All @@ -475,6 +492,12 @@ describe('Activate and edit selections', function() {
'x1': 102.90852713178295,
'y1': 53.63323442136499
});

expect(selectedCnt).toEqual(1);
expect(points).not.toBeUndefined();
expect(_selections).not.toBeUndefined();
expect(range).not.toBeUndefined();
expect(lassoPoints).toBeUndefined();
})
.then(function() { drag([[300, 200], [255, 230]]); }) // move vertex back
.then(function() {
Expand All @@ -496,6 +519,12 @@ describe('Activate and edit selections', function() {
'x1': 75,
'y1': 75
});

expect(selectedCnt).toEqual(2);
expect(points).not.toBeUndefined();
expect(_selections).not.toBeUndefined();
expect(range).not.toBeUndefined();
expect(lassoPoints).toBeUndefined();
})
.then(function() { drag([[215, 195], [300, 200]]); }) // move selection
.then(function() {
Expand All @@ -517,6 +546,12 @@ describe('Activate and edit selections', function() {
'x1': 127.71472868217053,
'y1': 74.99821958456974
});

expect(selectedCnt).toEqual(3);
expect(points).not.toBeUndefined();
expect(_selections).not.toBeUndefined();
expect(range).not.toBeUndefined();
expect(lassoPoints).toBeUndefined();
})
.then(function() { drag([[300, 200], [215, 195]]); }) // move selection back
.then(function() {
Expand All @@ -538,12 +573,24 @@ describe('Activate and edit selections', function() {
'x1': 75,
'y1': 75
});

expect(selectedCnt).toEqual(4);
expect(points).not.toBeUndefined();
expect(_selections).not.toBeUndefined();
expect(range).not.toBeUndefined();
expect(lassoPoints).toBeUndefined();
})

.then(done, done.fail);
});

it('closed-path using ' + device, function(done) {
var range;
var lassoPoints;
var points;
var _selections;
var selectedCnt = 0;

var i = 1; // selection index

Plotly.newPlot(gd, {
Expand All @@ -552,6 +599,16 @@ describe('Activate and edit selections', function() {
config: fig.config
})

.then(function() {
gd.on('plotly_selected', function(d) {
range = d.range;
lassoPoints = d.lassoPoints;
points = d.points;
_selections = d.selections;
selectedCnt++;
});
})

// next selection
.then(function() { click(500, 225); }) // activate selection
.then(function() {
Expand All @@ -562,6 +619,8 @@ describe('Activate and edit selections', function() {
var obj = selections[id]._input;
print(obj);
assertPos(obj.path, 'M250,25L225,75L275,75Z');

expect(selectedCnt).toEqual(0);
})
.then(function() { drag([[540, 160], [500, 120]]); }) // move vertex
.then(function() {
Expand All @@ -572,6 +631,12 @@ describe('Activate and edit selections', function() {
var obj = selections[id]._input;
print(obj);
assertPos(obj.path, 'M225.1968992248062,-3.4896142433234463L225,75L275,75Z');

expect(selectedCnt).toEqual(1);
expect(points).not.toBeUndefined();
expect(_selections).not.toBeUndefined();
expect(lassoPoints).not.toBeUndefined();
expect(range).toBeUndefined();
})
.then(function() { drag([[500, 120], [540, 160]]); }) // move vertex back
.then(function() {
Expand All @@ -582,6 +647,12 @@ describe('Activate and edit selections', function() {
var obj = selections[id]._input;
print(obj);
assertPos(obj.path, 'M250,25L225,75L275,75Z');

expect(selectedCnt).toEqual(2);
expect(points).not.toBeUndefined();
expect(_selections).not.toBeUndefined();
expect(lassoPoints).not.toBeUndefined();
expect(range).toBeUndefined();
})

.then(done, done.fail);
Expand Down
61 changes: 61 additions & 0 deletions test/jasmine/tests/selections_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,64 @@ describe('Test selections:', function() {
});
});
});

describe('Emit plotly_selected when plot a graph that has selections', function() {
'use strict';

var gd;
var points;
var selections;
var selectedCnt = 0;

beforeEach(function() {
gd = createGraphDiv();
});

afterEach(destroyGraphDiv);

it('emit plotly_selected on react calls', function(done) {
var data = [{y: [1, 2, 3]}];

Plotly.newPlot(gd, data, {})
.then(function() {
gd.on('plotly_selected', function(d) {
points = d.points;
selections = d.selections;
selectedCnt++;
});
})
.then(function() {
return Plotly.react(gd, data, {
selections: [{ x0: 0.5, x1: 1.5, y0: 1.5, y1: 2.5}]
});
})
.then(function() {
expect(selectedCnt).toEqual(1);
expect(points).not.toBeUndefined();
expect(selections).not.toBeUndefined();
expect(selections.length).toEqual(1);
expect(selections[0].x0).toEqual(0.5);
})
.then(function() {
return Plotly.react(gd, data, {
selections: [{ x0: 0.5, x1: 1.5, y0: 1.5, y1: 2.5}] // same selections
});
})
.then(function() {
expect(selectedCnt).toEqual(1);
})
.then(function() {
return Plotly.react(gd, data, {
selections: [{ x0: 0.25, x1: 1.75, y0: 1.25, y1: 2.25}] // different selections
});
})
.then(function() {
expect(selectedCnt).toEqual(2);
expect(points).not.toBeUndefined();
expect(selections).not.toBeUndefined();
expect(selections.length).toEqual(1);
expect(selections[0].x0).toEqual(0.25);
})
.then(done, done.fail);
});
});