2
2
from plotly .graph_objects import Figure
3
3
from dash import Dash
4
4
from dash .dependencies import Input , Output , State , ALL
5
- from dash_core_components import Graph , Slider , Store
5
+ from dash_core_components import Graph , Slider , Store , Interval
6
6
7
7
from .utils import img_array_to_uri , get_thumbnail_size , shape3d_to_size2d
8
8
@@ -290,6 +290,9 @@ def _create_dash_components(self):
290
290
self ._overlay_data = Store (id = self ._subid ("overlay" ), data = [])
291
291
self ._img_traces = Store (id = self ._subid ("img-traces" ), data = [])
292
292
self ._indicator_traces = Store (id = self ._subid ("indicator-traces" ), data = [])
293
+ self ._interval = Interval (
294
+ id = self ._subid ("interval" ), interval = 100 , disabled = True
295
+ )
293
296
self ._stores = [
294
297
self ._info ,
295
298
self ._position ,
@@ -300,6 +303,7 @@ def _create_dash_components(self):
300
303
self ._overlay_data ,
301
304
self ._img_traces ,
302
305
self ._indicator_traces ,
306
+ self ._interval ,
303
307
]
304
308
305
309
def _create_server_callbacks (self ):
@@ -378,9 +382,11 @@ def _create_client_callbacks(self):
378
382
function update_position(index, info) {
379
383
return info.origin[2] + index * info.spacing[2];
380
384
}
381
- """ ,
385
+ """ .replace (
386
+ "{{ID}}" , self ._context_id
387
+ ),
382
388
Output (self ._position .id , "data" ),
383
- [Input (self ._slider .id , "value " )],
389
+ [Input (self ._requested_index .id , "data " )],
384
390
[State (self ._info .id , "data" )],
385
391
)
386
392
@@ -391,26 +397,61 @@ def _create_client_callbacks(self):
391
397
392
398
app .clientside_callback (
393
399
"""
394
- function update_request(index) {
400
+ function rate_limit_index(index, _, interval) {
401
+ if (!window._slicer_{{ID}}) window._slicer_{{ID}} = {};
402
+ let slicer_info = window._slicer_{{ID}};
403
+ let now = window.performance.now();
395
404
396
- // Clear the cache?
397
- if (!window.slicecache_for_{{ID}}) { window.slicecache_for_{{ID}} = {}; }
398
- let slice_cache = window.slicecache_for_{{ID}};
405
+ // Get whether the slider was moved
406
+ let slider_was_moved = false;
407
+ for (let trigger of dash_clientside.callback_context.triggered) {
408
+ if (trigger.prop_id.indexOf('slider') >= 0) slider_was_moved = true;
409
+ }
399
410
400
- // Request a new slice (or not)
401
- let request_index = index;
402
- if (slice_cache[index]) {
403
- return window.dash_clientside.no_update;
404
- } else {
405
- console.log('requesting slice ' + index);
406
- return index;
411
+ // Initialize return values
412
+ let req_index = dash_clientside.no_update;
413
+ let disable_interval = false;
414
+
415
+ // If the slider moved, remember the time when this happened
416
+ slicer_info.new_time = slicer_info.new_time || 0;
417
+
418
+ if (slider_was_moved) {
419
+ slicer_info.new_time = now;
420
+ }
421
+
422
+ // We can either update the rate-limited index interval ms after
423
+ // the real index changed, or interval ms after it stopped
424
+ // changing. The former makes the indicators come along while
425
+ // dragging the slider, the latter is better for a smooth
426
+ // experience, and the interval can be set much lower.
427
+ if (index != slicer_info.req_index) {
428
+ if (now - slicer_info.new_time >= interval) {
429
+ req_index = slicer_info.req_index = index;
430
+ disable_interval = true;
431
+
432
+ // Get cache
433
+ // todo: _requested_index is now our rate-limited index, so we need to always apply
434
+ //if (!window.slicecache_for_{{ID}}) { window.slicecache_for_{{ID}} = {}; }
435
+ //let slice_cache = window.slicecache_for_{{ID}};
436
+ //if (slice_cache[req_index]) {
437
+ // req_index = dash_clientside.no_update;
438
+ //} else {
439
+ console.log('requesting slice ' + req_index);
440
+ //}
441
+ }
407
442
}
443
+
444
+ return [req_index, disable_interval];
408
445
}
409
446
""" .replace (
410
447
"{{ID}}" , self ._context_id
411
448
),
412
- Output (self ._requested_index .id , "data" ),
413
- [Input (self .slider .id , "value" )],
449
+ [
450
+ Output (self ._requested_index .id , "data" ),
451
+ Output (self ._interval .id , "disabled" ),
452
+ ],
453
+ [Input (self ._slider .id , "value" ), Input (self ._interval .id , "n_intervals" )],
454
+ [State (self ._interval .id , "interval" )],
414
455
)
415
456
416
457
# ----------------------------------------------------------------------
@@ -473,7 +514,7 @@ def _create_client_callbacks(self):
473
514
),
474
515
Output (self ._img_traces .id , "data" ),
475
516
[
476
- Input (self .slider .id , "value" ),
517
+ Input (self ._slider .id , "value" ),
477
518
Input (self ._request_data .id , "data" ),
478
519
Input (self ._overlay_data .id , "data" ),
479
520
],
0 commit comments