Skip to content

Commit ada5660

Browse files
committed
use official crosstalk selection/filter handles; fixes #857
1 parent 06511b7 commit ada5660

File tree

1 file changed

+105
-117
lines changed

1 file changed

+105
-117
lines changed

inst/htmlwidgets/plotly.js

Lines changed: 105 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,7 @@ HTMLWidgets.widget({
1111
// devtools::use_data(Schema, overwrite = T, internal = T)
1212
// console.log(JSON.stringify(Plotly.PlotSchema.get()));
1313

14-
return {
15-
// Push JavaScript closures onto this list, and renderValue
16-
// will pop them off and run them one at a time the next
17-
// time it runs. Use this to dispose of e.g. old event
18-
// registrations.
19-
onNextRender: []
20-
};
21-
14+
return {};
2215
},
2316

2417
resize: function(el, width, height, instance) {
@@ -30,11 +23,6 @@ HTMLWidgets.widget({
3023
},
3124

3225
renderValue: function(el, x, instance) {
33-
34-
// Release previously registered crosstalk event listeners
35-
while (instance.onNextRender.length > 0) {
36-
instance.onNextRender.pop()();
37-
}
3826

3927
var shinyMode;
4028
if (typeof(window) !== "undefined") {
@@ -317,7 +305,63 @@ HTMLWidgets.widget({
317305
}
318306
}
319307

320-
if (allSets.length > 0) {
308+
// register event listeners for all sets
309+
for (var i = 0; i < allSets.length; i++) {
310+
311+
var set = allSets[i];
312+
var selection = new crosstalk.SelectionHandle(set);
313+
var filter = new crosstalk.FilterHandle(set);
314+
315+
var filterChange = function(e) {
316+
removeBrush(el);
317+
traceManager.updateFilter(set, e.value);
318+
};
319+
filter.on("change", filterChange);
320+
321+
322+
var selectionChange = function(e) {
323+
324+
// array of "event objects" tracking the selection history
325+
// this is used to avoid adding redundant selections
326+
var selectionHistory = crosstalk.var("plotlySelectionHistory").get() || [];
327+
328+
// Construct an event object "defining" the current event.
329+
var event = {
330+
receiverID: traceManager.gd.id,
331+
plotlySelectionColour: crosstalk.group(set).var("plotlySelectionColour").get()
332+
};
333+
event[set] = e.value;
334+
// TODO: is there a smarter way to check object equality?
335+
if (selectionHistory.length > 0) {
336+
var ev = JSON.stringify(event);
337+
for (var i = 0; i < selectionHistory.length; i++) {
338+
var sel = JSON.stringify(selectionHistory[i]);
339+
if (sel == ev) {
340+
return;
341+
}
342+
}
343+
}
344+
345+
// accumulate history for persistent selection
346+
if (!x.highlight.persistent) {
347+
selectionHistory = [event];
348+
} else {
349+
selectionHistory.push(event);
350+
}
351+
crosstalk.var("plotlySelectionHistory").set(selectionHistory);
352+
353+
// do the actual updating of traces, frames, and the selectize widget
354+
traceManager.updateSelection(set, e.value);
355+
// https://github.com/selectize/selectize.js/blob/master/docs/api.md#methods_items
356+
if (x.selectize) {
357+
if (!x.highlight.persistent || e.value === null) {
358+
selectize.clear(true);
359+
}
360+
selectize.addItems(e.value, true);
361+
selectize.close();
362+
}
363+
}
364+
selection.on("change", selectionChange);
321365

322366
// Set a crosstalk variable selection value, triggering an update
323367
graphDiv.on(x.highlight.on, function turnOn(e) {
@@ -326,11 +370,9 @@ HTMLWidgets.widget({
326370
// Keys are group names, values are array of selected keys from group.
327371
for (var set in selectedKeys) {
328372
if (selectedKeys.hasOwnProperty(set)) {
329-
crosstalk.group(set).var("selection")
330-
.set(selectedKeys[set].value, {sender: el});
373+
selection.set(selectedKeys[set].value, {sender: el});
331374
}
332375
}
333-
334376
}
335377
});
336378

@@ -340,113 +382,59 @@ HTMLWidgets.widget({
340382
// remove any selection history
341383
crosstalk.var("plotlySelectionHistory").set(null);
342384
// trigger the actual removal of selection traces
343-
for (var i = 0; i < allSets.length; i++) {
344-
crosstalk.group(allSets[i]).var("selection").set(null, {sender: el});
345-
}
385+
selection.set(null, {sender: el});
346386
});
347-
348-
349-
for (var i = 0; i < allSets.length; i++) {
350-
(function() {
351-
var set = allSets[i];
352-
var grp = crosstalk.group(set);
353387

354-
// Create a selectize widget for each group
355-
if (x.selectize) {
356-
var selectizeID = Object.keys(x.selectize)[i];
357-
var items = x.selectize[selectizeID].items;
358-
var first = [{value: "", label: "(All)"}];
359-
var opts = {
360-
options: first.concat(items),
361-
searchField: "label",
362-
valueField: "value",
363-
labelField: "label",
364-
maxItems: 50
365-
};
366-
var select = $("#" + selectizeID).find("select")[0];
367-
var selectize = $(select).selectize(opts)[0].selectize;
368-
// NOTE: this callback is triggered when *directly* altering
369-
// dropdown items
370-
selectize.on("change", function() {
371-
var currentItems = traceManager.groupSelections[set] || [];
372-
if (!x.highlight.persistent) {
373-
removeBrush(el);
374-
for (var i = 0; i < currentItems.length; i++) {
375-
selectize.removeItem(currentItems[i], true);
376-
}
377-
}
378-
var newItems = selectize.items.filter(function(idx) {
379-
return currentItems.indexOf(idx) < 0;
380-
});
381-
if (newItems.length > 0) {
382-
traceManager.updateSelection(set, newItems);
383-
} else {
384-
// Item has been removed...
385-
// TODO: this logic won't work for dynamically changing palette
386-
traceManager.updateSelection(set, null);
387-
traceManager.updateSelection(set, selectize.items);
388-
}
389-
});
390-
}
391-
392-
393-
var crosstalkSelectionChange = function(e) {
394-
395-
// array of "event objects" tracking the selection history
396-
// this is used to avoid adding redundant selections
397-
var selectionHistory = crosstalk.var("plotlySelectionHistory").get() || [];
398-
399-
// Construct an event object "defining" the current event.
400-
var event = {
401-
receiverID: traceManager.gd.id,
402-
plotlySelectionColour: crosstalk.group(set).var("plotlySelectionColour").get()
403-
};
404-
event[set] = e.value;
405-
// TODO: is there a smarter way to check object equality?
406-
if (selectionHistory.length > 0) {
407-
var ev = JSON.stringify(event);
408-
for (var i = 0; i < selectionHistory.length; i++) {
409-
var sel = JSON.stringify(selectionHistory[i]);
410-
if (sel == ev) {
411-
return;
412-
}
413-
}
414-
}
415-
416-
// accumulate history for persistent selection
417-
if (!x.highlight.persistent) {
418-
selectionHistory = [event];
419-
} else {
420-
selectionHistory.push(event);
421-
}
422-
crosstalk.var("plotlySelectionHistory").set(selectionHistory);
423-
424-
425-
traceManager.updateSelection(set, e.value);
426-
// https://github.com/selectize/selectize.js/blob/master/docs/api.md#methods_items
427-
if (x.selectize) {
428-
if (!x.highlight.persistent || e.value === null) {
429-
selectize.clear(true);
430-
}
431-
selectize.addItems(e.value, true);
432-
selectize.close();
388+
// register a callback for selectize so that there is bi-directional
389+
// communication between the widget and direct manipulation events
390+
if (x.selectize) {
391+
var selectizeID = Object.keys(x.selectize)[i];
392+
var items = x.selectize[selectizeID].items;
393+
var first = [{value: "", label: "(All)"}];
394+
var opts = {
395+
options: first.concat(items),
396+
searchField: "label",
397+
valueField: "value",
398+
labelField: "label",
399+
maxItems: 50
400+
};
401+
var select = $("#" + selectizeID).find("select")[0];
402+
var selectize = $(select).selectize(opts)[0].selectize;
403+
// NOTE: this callback is triggered when *directly* altering
404+
// dropdown items
405+
selectize.on("change", function() {
406+
var currentItems = traceManager.groupSelections[set] || [];
407+
if (!x.highlight.persistent) {
408+
removeBrush(el);
409+
for (var i = 0; i < currentItems.length; i++) {
410+
selectize.removeItem(currentItems[i], true);
433411
}
434-
435412
}
436-
437-
grp.var("selection").on("change", crosstalkSelectionChange);
438-
439-
440-
grp.var("filter").on("change", function crosstalk_filter_change(e) {
441-
removeBrush(el);
442-
traceManager.updateFilter(set, e.value);
413+
var newItems = selectize.items.filter(function(idx) {
414+
return currentItems.indexOf(idx) < 0;
443415
});
444-
445-
})();
416+
if (newItems.length > 0) {
417+
traceManager.updateSelection(set, newItems);
418+
} else {
419+
// Item has been removed...
420+
// TODO: this logic won't work for dynamically changing palette
421+
traceManager.updateSelection(set, null);
422+
traceManager.updateSelection(set, selectize.items);
423+
}
424+
});
446425
}
426+
427+
428+
429+
430+
431+
432+
433+
447434
}
448-
}
449-
});
435+
436+
} // end of renderValue
437+
}); // end of widget definition
450438

451439
/**
452440
* @param graphDiv The Plotly graph div

0 commit comments

Comments
 (0)