@@ -580,26 +580,81 @@ def _create_client_callbacks(self):
580
580
)
581
581
582
582
# ----------------------------------------------------------------------
583
- # Callback to rate-limit the index (using a timer/interval).
583
+ # Callback to rate-limit the state (using a timer/interval).
584
+ # This callback has as input anything that defines the state. The callback
585
+ # checks what was changed, sets a timeout, and enables the timer.
584
586
585
587
app .clientside_callback (
586
588
"""
587
- function update_index_rate_limiting (index, relayoutData, n_intervals, info, figure ) {
589
+ function update_rate_limiting_info (index, relayoutData, n_intervals) {
588
590
589
591
if (!window._slicer_{{ID}}) window._slicer_{{ID}} = {};
590
592
let private_state = window._slicer_{{ID}};
591
593
let now = window.performance.now();
592
594
593
- // Get whether the slider was moved
595
+ // Get whether the slider was moved, layout was changed, or timer ticked
594
596
let slider_value_changed = false;
595
597
let graph_layout_changed = false;
596
598
let timer_ticked = false;
597
599
for (let trigger of dash_clientside.callback_context.triggered) {
598
600
if (trigger.prop_id.indexOf('slider') >= 0) slider_value_changed = true;
599
- if (trigger.prop_id.indexOf('graph') >= 0) graph_layout_changed = true;
600
601
if (trigger.prop_id.indexOf('timer') >= 0) timer_ticked = true;
602
+ if (trigger.prop_id.indexOf('graph') >= 0) {
603
+ for (let key in relayoutData) {
604
+ if (key.startsWith("xaxis.range") || key.startsWith("yaxis.range")) {
605
+ graph_layout_changed = true;
606
+ }
607
+ }
608
+ }
601
609
}
602
610
611
+ // Set timeout and whether to disable the timer
612
+ let disable_timer = false;
613
+ if (slider_value_changed) {
614
+ private_state.timeout = now + 200;
615
+ } else if (graph_layout_changed) {
616
+ private_state.timeout = now + 400; // need longer timeout for smooth scroll zoom
617
+ } else if (!n_intervals) {
618
+ private_state.timeout = now + 100; // initialize
619
+ } else if (!private_state.timeout) {
620
+ disable_timer = true;
621
+ }
622
+
623
+ return disable_timer;
624
+ }
625
+ """ .replace (
626
+ "{{ID}}" , self ._context_id
627
+ ),
628
+ Output (self ._timer .id , "disabled" ),
629
+ [
630
+ Input (self ._slider .id , "value" ),
631
+ Input (self ._graph .id , "relayoutData" ),
632
+ Input (self ._timer .id , "n_intervals" ),
633
+ ],
634
+ )
635
+
636
+ # ----------------------------------------------------------------------
637
+ # Callback to produce the (rate-limited) state.
638
+ # Note how this callback only has the interval as input. This breaks
639
+ # any loops in applications that want to both get and set the slicer
640
+ # position.
641
+
642
+ app .clientside_callback (
643
+ """
644
+ function update_state(n_intervals, index, info, figure) {
645
+
646
+ if (!window._slicer_{{ID}}) window._slicer_{{ID}} = {};
647
+ let private_state = window._slicer_{{ID}};
648
+ let now = window.performance.now();
649
+
650
+ // Ready to apply and stop the timer, or return early?
651
+ if (!(private_state.timeout && now >= private_state.timeout)) {
652
+ return dash_clientside.no_update;
653
+ }
654
+
655
+ // Disable the timer
656
+ private_state.timeout = 0;
657
+
603
658
// Calculate view range based on the volume
604
659
let xrangeVol = [
605
660
info.offset[0] - 0.5 * info.stepsize[0],
@@ -631,66 +686,35 @@ def _create_client_callbacks(self):
631
686
let xrange = [Math.max(xrangeVol[0], xrangeFig[0]), Math.min(xrangeVol[1], xrangeFig[1])];
632
687
let yrange = [Math.max(yrangeVol[0], yrangeFig[0]), Math.min(yrangeVol[1], yrangeFig[1])];
633
688
634
- // Initialize return values
635
- let new_state = dash_clientside.no_update;
636
- let disable_timer = false;
637
-
638
- // If the slider moved, remember the time when this happened
639
- private_state.new_time = private_state.new_time || 0;
640
-
641
-
642
- if (slider_value_changed) {
643
- private_state.new_time = now;
644
- private_state.timeout = 200;
645
- } else if (graph_layout_changed) {
646
- private_state.new_time = now;
647
- private_state.timeout = 400; // need longer timeout for smooth scroll zoom
648
- } else if (!n_intervals) {
649
- private_state.new_time = now;
650
- private_state.timeout = 100;
651
- }
652
-
653
- // We can either update the rate-limited index timeout ms after
654
- // the real index changed, or timeout ms after it stopped
655
- // changing. The former makes the indicators come along while
656
- // dragging the slider, the latter is better for a smooth
657
- // experience, and the timeout can be set much lower.
658
- if (private_state.timeout && timer_ticked && now - private_state.new_time >= private_state.timeout) {
659
- private_state.timeout = 0;
660
- disable_timer = true;
661
- new_state = {
662
- index: index,
663
- index_changed: false,
664
- xrange: xrange,
665
- yrange: yrange,
666
- zpos: info.offset[2] + index * info.stepsize[2],
667
- axis: info.axis,
668
- color: info.color,
669
- };
670
- if (index != private_state.index) {
671
- private_state.index = index;
672
- new_state.index_changed = true;
673
- }
689
+ // Create new state
690
+ let new_state = {
691
+ index: index,
692
+ index_changed: false,
693
+ xrange: xrange,
694
+ yrange: yrange,
695
+ zpos: info.offset[2] + index * info.stepsize[2],
696
+ axis: info.axis,
697
+ color: info.color,
698
+ };
699
+ if (index != private_state.last_index) {
700
+ private_state.last_index = index;
701
+ new_state.index_changed = true;
674
702
}
675
-
676
- return [new_state, disable_timer];
703
+ return new_state;
677
704
}
678
705
""" .replace (
679
706
"{{ID}}" , self ._context_id
680
707
),
708
+ Output (self ._state .id , "data" ),
681
709
[
682
- Output (self ._state .id , "data" ),
683
- Output (self ._timer .id , "disabled" ),
684
- ],
685
- [
686
- Input (self ._slider .id , "value" ),
687
- Input (self ._graph .id , "relayoutData" ),
688
710
Input (self ._timer .id , "n_intervals" ),
689
711
],
690
712
[
713
+ State (self ._slider .id , "value" ),
691
714
State (self ._info .id , "data" ),
692
715
State (self ._graph .id , "figure" ),
693
716
],
717
+ # prevent_initial_call=True,
694
718
)
695
719
696
720
# ----------------------------------------------------------------------
0 commit comments