Skip to content

Commit cec8437

Browse files
authored
Merge pull request #6277 from plotly/emit-selected-having-selections
emit `plotly_selected` event on plot API calls and GUI edits
2 parents 28835f7 + a1fd15e commit cec8437

File tree

4 files changed

+166
-13
lines changed

4 files changed

+166
-13
lines changed

src/components/selections/select.js

+24-12
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ function prepSelect(evt, startX, startY, dragOptions, mode) {
174174
}
175175

176176
if(selectionErased) {
177+
gd._fullLayout._noEmitSelectedAtStart = true;
178+
177179
Registry.call('_guiRelayout', gd, {
178180
selections: list
179181
});
@@ -315,10 +317,10 @@ function prepSelect(evt, startX, startY, dragOptions, mode) {
315317
displayOutlines(convertPoly(mergedPolygons, isOpenMode), outlines, dragOptions);
316318

317319
if(isSelectMode) {
318-
var _res = reselect(gd);
320+
var _res = reselect(gd, false);
319321
var extraPoints = _res.eventData ? _res.eventData.points.slice() : [];
320322

321-
_res = reselect(gd, selectionTesters, searchTraces, dragOptions);
323+
_res = reselect(gd, false, selectionTesters, searchTraces, dragOptions);
322324
selectionTesters = _res.selectionTesters;
323325
eventData = _res.eventData;
324326

@@ -412,9 +414,13 @@ function prepSelect(evt, startX, startY, dragOptions, mode) {
412414
}
413415
}
414416

415-
Registry.call('_guiRelayout', gd, {
416-
selections: subSelections
417-
});
417+
if(subSelections.length < allSelections.length) {
418+
gd._fullLayout._noEmitSelectedAtStart = true;
419+
420+
Registry.call('_guiRelayout', gd, {
421+
selections: subSelections
422+
});
423+
}
418424
}
419425
}
420426
} else {
@@ -733,6 +739,8 @@ function clearSelectionsCache(dragOptions, immediateSelect) {
733739
selections = newSelections(outlines, dragOptions);
734740
}
735741
if(selections) {
742+
gd._fullLayout._noEmitSelectedAtStart = true;
743+
736744
Registry.call('_guiRelayout', gd, {
737745
selections: selections
738746
}).then(function() {
@@ -1070,7 +1078,7 @@ function _doSelect(selectionTesters, searchTraces) {
10701078
return allSelections;
10711079
}
10721080

1073-
function reselect(gd, selectionTesters, searchTraces, dragOptions) {
1081+
function reselect(gd, mayEmitSelected, selectionTesters, searchTraces, dragOptions) {
10741082
var hadSearchTraces = !!searchTraces;
10751083
var plotinfo, xRef, yRef;
10761084
if(dragOptions) {
@@ -1193,15 +1201,15 @@ function reselect(gd, selectionTesters, searchTraces, dragOptions) {
11931201
updateSelectedState(gd, allSearchTraces, eventData);
11941202

11951203
var clickmode = fullLayout.clickmode;
1196-
var sendEvents = clickmode.indexOf('event') > -1;
1204+
var sendEvents = clickmode.indexOf('event') > -1 && mayEmitSelected;
11971205

11981206
if(
11991207
!plotinfo && // get called from plot_api & plots
1200-
fullLayout._reselect
1208+
mayEmitSelected
12011209
) {
1202-
if(sendEvents) {
1203-
var activePolygons = getLayoutPolygons(gd, true);
1210+
var activePolygons = getLayoutPolygons(gd, true);
12041211

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

12151223
fillRangeItems(eventData, poly);
12161224
}
1225+
}
12171226

1218-
emitSelected(gd, eventData);
1227+
if(gd._fullLayout._noEmitSelectedAtStart) {
1228+
gd._fullLayout._noEmitSelectedAtStart = false;
1229+
} else {
1230+
if(sendEvents) emitSelected(gd, eventData);
12191231
}
12201232

12211233
fullLayout._reselect = false;
@@ -1237,7 +1249,7 @@ function reselect(gd, selectionTesters, searchTraces, dragOptions) {
12371249
if(eventData.points.length) {
12381250
emitSelected(gd, eventData);
12391251
} else {
1240-
gd.emit('plotly_deselect', null);
1252+
emitDeselect(gd);
12411253
}
12421254
}
12431255

src/plots/plots.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -3364,7 +3364,16 @@ plots.redrag = function(gd) {
33643364
};
33653365

33663366
plots.reselect = function(gd) {
3367-
Registry.getComponentMethod('selections', 'reselect')(gd);
3367+
var fullLayout = gd._fullLayout;
3368+
3369+
var A = (gd.layout || {}).selections;
3370+
var B = fullLayout._previousSelections;
3371+
fullLayout._previousSelections = A;
3372+
3373+
var mayEmitSelected = fullLayout._reselect ||
3374+
JSON.stringify(A) !== JSON.stringify(B);
3375+
3376+
Registry.getComponentMethod('selections', 'reselect')(gd, mayEmitSelected);
33683377
};
33693378

33703379
plots.generalUpdatePerTraceModule = function(gd, subplot, subplotCalcData, subplotLayout) {

test/jasmine/tests/draw_newselection_test.js

+71
Original file line numberDiff line numberDiff line change
@@ -425,13 +425,28 @@ describe('Activate and edit selections', function() {
425425

426426
['mouse'].forEach(function(device) {
427427
it('reactangle using ' + device, function(done) {
428+
var range;
429+
var lassoPoints;
430+
var points;
431+
var _selections;
432+
var selectedCnt = 0;
433+
428434
var i = 0; // selection index
429435

430436
Plotly.newPlot(gd, {
431437
data: fig.data,
432438
layout: fig.layout,
433439
config: fig.config
434440
})
441+
.then(function() {
442+
gd.on('plotly_selected', function(d) {
443+
range = d.range;
444+
lassoPoints = d.lassoPoints;
445+
points = d.points;
446+
_selections = d.selections;
447+
selectedCnt++;
448+
});
449+
})
435450

436451
// selection between 175, 160 and 255, 230
437452
.then(function() { click(210, 160); }) // activate selection
@@ -454,6 +469,8 @@ describe('Activate and edit selections', function() {
454469
'x1': 75,
455470
'y1': 75
456471
});
472+
473+
expect(selectedCnt).toEqual(0);
457474
})
458475
.then(function() { drag([[255, 230], [300, 200]]); }) // move vertex
459476
.then(function() {
@@ -475,6 +492,12 @@ describe('Activate and edit selections', function() {
475492
'x1': 102.90852713178295,
476493
'y1': 53.63323442136499
477494
});
495+
496+
expect(selectedCnt).toEqual(1);
497+
expect(points).not.toBeUndefined();
498+
expect(_selections).not.toBeUndefined();
499+
expect(range).not.toBeUndefined();
500+
expect(lassoPoints).toBeUndefined();
478501
})
479502
.then(function() { drag([[300, 200], [255, 230]]); }) // move vertex back
480503
.then(function() {
@@ -496,6 +519,12 @@ describe('Activate and edit selections', function() {
496519
'x1': 75,
497520
'y1': 75
498521
});
522+
523+
expect(selectedCnt).toEqual(2);
524+
expect(points).not.toBeUndefined();
525+
expect(_selections).not.toBeUndefined();
526+
expect(range).not.toBeUndefined();
527+
expect(lassoPoints).toBeUndefined();
499528
})
500529
.then(function() { drag([[215, 195], [300, 200]]); }) // move selection
501530
.then(function() {
@@ -517,6 +546,12 @@ describe('Activate and edit selections', function() {
517546
'x1': 127.71472868217053,
518547
'y1': 74.99821958456974
519548
});
549+
550+
expect(selectedCnt).toEqual(3);
551+
expect(points).not.toBeUndefined();
552+
expect(_selections).not.toBeUndefined();
553+
expect(range).not.toBeUndefined();
554+
expect(lassoPoints).toBeUndefined();
520555
})
521556
.then(function() { drag([[300, 200], [215, 195]]); }) // move selection back
522557
.then(function() {
@@ -538,12 +573,24 @@ describe('Activate and edit selections', function() {
538573
'x1': 75,
539574
'y1': 75
540575
});
576+
577+
expect(selectedCnt).toEqual(4);
578+
expect(points).not.toBeUndefined();
579+
expect(_selections).not.toBeUndefined();
580+
expect(range).not.toBeUndefined();
581+
expect(lassoPoints).toBeUndefined();
541582
})
542583

543584
.then(done, done.fail);
544585
});
545586

546587
it('closed-path using ' + device, function(done) {
588+
var range;
589+
var lassoPoints;
590+
var points;
591+
var _selections;
592+
var selectedCnt = 0;
593+
547594
var i = 1; // selection index
548595

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

602+
.then(function() {
603+
gd.on('plotly_selected', function(d) {
604+
range = d.range;
605+
lassoPoints = d.lassoPoints;
606+
points = d.points;
607+
_selections = d.selections;
608+
selectedCnt++;
609+
});
610+
})
611+
555612
// next selection
556613
.then(function() { click(500, 225); }) // activate selection
557614
.then(function() {
@@ -562,6 +619,8 @@ describe('Activate and edit selections', function() {
562619
var obj = selections[id]._input;
563620
print(obj);
564621
assertPos(obj.path, 'M250,25L225,75L275,75Z');
622+
623+
expect(selectedCnt).toEqual(0);
565624
})
566625
.then(function() { drag([[540, 160], [500, 120]]); }) // move vertex
567626
.then(function() {
@@ -572,6 +631,12 @@ describe('Activate and edit selections', function() {
572631
var obj = selections[id]._input;
573632
print(obj);
574633
assertPos(obj.path, 'M225.1968992248062,-3.4896142433234463L225,75L275,75Z');
634+
635+
expect(selectedCnt).toEqual(1);
636+
expect(points).not.toBeUndefined();
637+
expect(_selections).not.toBeUndefined();
638+
expect(lassoPoints).not.toBeUndefined();
639+
expect(range).toBeUndefined();
575640
})
576641
.then(function() { drag([[500, 120], [540, 160]]); }) // move vertex back
577642
.then(function() {
@@ -582,6 +647,12 @@ describe('Activate and edit selections', function() {
582647
var obj = selections[id]._input;
583648
print(obj);
584649
assertPos(obj.path, 'M250,25L225,75L275,75Z');
650+
651+
expect(selectedCnt).toEqual(2);
652+
expect(points).not.toBeUndefined();
653+
expect(_selections).not.toBeUndefined();
654+
expect(lassoPoints).not.toBeUndefined();
655+
expect(range).toBeUndefined();
585656
})
586657

587658
.then(done, done.fail);

test/jasmine/tests/selections_test.js

+61
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,64 @@ describe('Test selections:', function() {
260260
});
261261
});
262262
});
263+
264+
describe('Emit plotly_selected when plot a graph that has selections', function() {
265+
'use strict';
266+
267+
var gd;
268+
var points;
269+
var selections;
270+
var selectedCnt = 0;
271+
272+
beforeEach(function() {
273+
gd = createGraphDiv();
274+
});
275+
276+
afterEach(destroyGraphDiv);
277+
278+
it('emit plotly_selected on react calls', function(done) {
279+
var data = [{y: [1, 2, 3]}];
280+
281+
Plotly.newPlot(gd, data, {})
282+
.then(function() {
283+
gd.on('plotly_selected', function(d) {
284+
points = d.points;
285+
selections = d.selections;
286+
selectedCnt++;
287+
});
288+
})
289+
.then(function() {
290+
return Plotly.react(gd, data, {
291+
selections: [{ x0: 0.5, x1: 1.5, y0: 1.5, y1: 2.5}]
292+
});
293+
})
294+
.then(function() {
295+
expect(selectedCnt).toEqual(1);
296+
expect(points).not.toBeUndefined();
297+
expect(selections).not.toBeUndefined();
298+
expect(selections.length).toEqual(1);
299+
expect(selections[0].x0).toEqual(0.5);
300+
})
301+
.then(function() {
302+
return Plotly.react(gd, data, {
303+
selections: [{ x0: 0.5, x1: 1.5, y0: 1.5, y1: 2.5}] // same selections
304+
});
305+
})
306+
.then(function() {
307+
expect(selectedCnt).toEqual(1);
308+
})
309+
.then(function() {
310+
return Plotly.react(gd, data, {
311+
selections: [{ x0: 0.25, x1: 1.75, y0: 1.25, y1: 2.25}] // different selections
312+
});
313+
})
314+
.then(function() {
315+
expect(selectedCnt).toEqual(2);
316+
expect(points).not.toBeUndefined();
317+
expect(selections).not.toBeUndefined();
318+
expect(selections.length).toEqual(1);
319+
expect(selections[0].x0).toEqual(0.25);
320+
})
321+
.then(done, done.fail);
322+
});
323+
});

0 commit comments

Comments
 (0)