1
+ import { Throttler } from "./utils" ;
2
+
1
3
// This class is a striped down version of Comm from @jupyter -widgets/base
2
4
// https://github.com/jupyter-widgets/ipywidgets/blob/88cec8/packages/base/src/services-shim.ts#L192-L335
3
5
// Note that the Kernel.IComm implementation is located here
@@ -6,8 +8,11 @@ export class ShinyComm {
6
8
7
9
// It seems like we'll want one comm per model
8
10
comm_id : string ;
11
+ throttler : Throttler ;
9
12
constructor ( model_id : string ) {
10
13
this . comm_id = model_id ;
14
+ // TODO: make this configurable (see comments in send() below)?
15
+ this . throttler = new Throttler ( 100 ) ;
11
16
}
12
17
13
18
// This might not be needed
@@ -31,8 +36,29 @@ export class ShinyComm {
31
36
// this doesn't seem relevant to the widget?
32
37
header : { }
33
38
} ;
39
+
34
40
const msg_txt = JSON . stringify ( msg ) ;
35
- Shiny . setInputValue ( "shinywidgets_comm_send" , msg_txt , { priority : "event" } ) ;
41
+
42
+ // Since ipyleaflet can send mousemove events very quickly when hovering over the map,
43
+ // we throttle them to ensure that the server doesn't get overwhelmed. Said events
44
+ // generate a payload that looks like this:
45
+ // {"method": "custom", "content": {"event": "interaction", "type": "mousemove", "coordinates": [-17.76259815404015, 12.096729340756617]}}
46
+ //
47
+ // TODO: This is definitely not ideal. It would be better to have a way to specify/
48
+ // customize throttle rates instead of having such a targetted fix for ipyleaflet.
49
+ const is_mousemove =
50
+ data . method === "custom" &&
51
+ data . content . event === "interaction" &&
52
+ data . content . type === "mousemove" ;
53
+
54
+ if ( is_mousemove ) {
55
+ this . throttler . throttle ( ( ) => {
56
+ Shiny . setInputValue ( "shinywidgets_comm_send" , msg_txt , { priority : "event" } ) ;
57
+ } ) ;
58
+ } else {
59
+ this . throttler . flush ( ) ;
60
+ Shiny . setInputValue ( "shinywidgets_comm_send" , msg_txt , { priority : "event" } ) ;
61
+ }
36
62
37
63
// When client-side changes happen to the WidgetModel, this send method
38
64
// won't get called for _every_ change (just the first one). The
@@ -42,7 +68,9 @@ export class ShinyComm {
42
68
// https://github.com/jupyter-widgets/ipywidgets/blob/88cec8b/packages/base/src/widget.ts#L550-L557
43
69
if ( callbacks && callbacks . iopub && callbacks . iopub . status ) {
44
70
setTimeout ( ( ) => {
45
- // TODO: Call this when Shiny reports that it is idle?
71
+ // TODO-future: it doesn't seem quite right to report that shiny is always idle.
72
+ // Maybe listen to the shiny-busy flag?
73
+ // const state = document.querySelector("html").classList.contains("shiny-busy") ? "busy" : "idle";
46
74
const msg = { content : { execution_state : "idle" } } ;
47
75
callbacks . iopub . status ( msg ) ;
48
76
} , 0 ) ;
0 commit comments