@@ -2628,7 +2628,7 @@ Plotly.transition = function(gd, data, layout, traceIndices, transitionOpts) {
2628
2628
// When instantaneous updates are coming through quickly, it's too much to simply disable
2629
2629
// all interaction, so store this flag so we can disambiguate whether mouse interactions
2630
2630
// should be fully disabled or not:
2631
- if ( transitionOpts . duration > 0 ) {
2631
+ if ( transitionOpts . transitionduration > 0 ) {
2632
2632
gd . _transitioningWithDuration = true ;
2633
2633
}
2634
2634
@@ -2670,7 +2670,7 @@ Plotly.transition = function(gd, data, layout, traceIndices, transitionOpts) {
2670
2670
// to instantaneous.
2671
2671
if ( hasAxisTransition ) {
2672
2672
traceTransitionOpts = Lib . extendFlat ( { } , transitionOpts ) ;
2673
- traceTransitionOpts . duration = 0 ;
2673
+ traceTransitionOpts . transitionduration = 0 ;
2674
2674
} else {
2675
2675
traceTransitionOpts = transitionOpts ;
2676
2676
}
@@ -2756,7 +2756,7 @@ Plotly.transition = function(gd, data, layout, traceIndices, transitionOpts) {
2756
2756
* @param {object } transitionOpts
2757
2757
* configuration for transition
2758
2758
*/
2759
- Plotly . animate = function ( gd , groupNameOrFrameList , transitionOpts , animationOpts ) {
2759
+ Plotly . animate = function ( gd , frameOrGroupNameOrFrameList , transitionOpts , animationOpts ) {
2760
2760
gd = getGraphDiv ( gd ) ;
2761
2761
var trans = gd . _transitionData ;
2762
2762
@@ -2808,7 +2808,12 @@ Plotly.animate = function(gd, groupNameOrFrameList, transitionOpts, animationOpt
2808
2808
if ( frameList . length === 0 ) return ;
2809
2809
2810
2810
for ( var i = 0 ; i < frameList . length ; i ++ ) {
2811
- var computedFrame = Plots . computeFrame ( gd , frameList [ i ] . name ) ;
2811
+ var computedFrame ;
2812
+ if ( frameList [ i ] . name ) {
2813
+ computedFrame = Plots . computeFrame ( gd , frameList [ i ] . name ) ;
2814
+ } else {
2815
+ computedFrame = frameList [ i ] . frame ;
2816
+ }
2812
2817
2813
2818
var opts = Plots . supplyTransitionDefaults ( getTransitionOpts ( i ) ) ;
2814
2819
@@ -2836,9 +2841,54 @@ Plotly.animate = function(gd, groupNameOrFrameList, transitionOpts, animationOpt
2836
2841
trans . _animationRaf = null ;
2837
2842
}
2838
2843
2844
+ function nextFrame ( ) {
2845
+ if ( trans . _currentFrame ) {
2846
+ if ( trans . _currentFrame . onComplete ) {
2847
+ trans . _currentFrame . onComplete ( ) ;
2848
+ }
2849
+ }
2850
+
2851
+ var newFrame = trans . _currentFrame = trans . _frameQueue . shift ( ) ;
2852
+
2853
+ if ( newFrame ) {
2854
+ trans . _lastframeat = Date . now ( ) ;
2855
+ trans . _timetonext = newFrame . transitionOpts . frameduration ;
2856
+
2857
+ Plotly . transition ( gd ,
2858
+ newFrame . frame . data ,
2859
+ newFrame . frame . layout ,
2860
+ newFrame . frame . traces ,
2861
+ newFrame . transitionOpts
2862
+ ) . then ( function ( ) {
2863
+ if ( trans . _frameQueue . length === 0 ) {
2864
+ gd . emit ( 'plotly_animated' ) ;
2865
+ if ( trans . _currentFrame && trans . _currentFrame . onComplete ) {
2866
+ trans . _currentFrame . onComplete ( ) ;
2867
+ trans . _currentFrame = null ;
2868
+ }
2869
+ }
2870
+ } ) ;
2871
+ }
2872
+
2873
+ if ( trans . _frameQueue . length === 0 ) {
2874
+ stopAnimationLoop ( ) ;
2875
+ return ;
2876
+ }
2877
+ }
2878
+
2839
2879
function beginAnimationLoop ( ) {
2840
2880
gd . emit ( 'plotly_animating' ) ;
2841
2881
2882
+ var canAnimateSynchronously = ! trans . _animationRaf && trans . _frameQueue . length === 1 ;
2883
+
2884
+ if ( canAnimateSynchronously ) {
2885
+ // If there is no animation running and only one frame has been received, then
2886
+ // simply transition this frame synchonously and avoid starting and stopping the
2887
+ // timing loop.
2888
+ nextFrame ( ) ;
2889
+ return ;
2890
+ }
2891
+
2842
2892
// If no timer is running, then set last frame = long ago:
2843
2893
trans . _lastframeat = 0 ;
2844
2894
trans . _timetonext = 0 ;
@@ -2848,38 +2898,7 @@ Plotly.animate = function(gd, groupNameOrFrameList, transitionOpts, animationOpt
2848
2898
var doFrame = function ( ) {
2849
2899
// Check if we need to pop a frame:
2850
2900
if ( Date . now ( ) - trans . _lastframeat > trans . _timetonext ) {
2851
- if ( trans . _currentFrame ) {
2852
- if ( trans . _currentFrame . onComplete ) {
2853
- trans . _currentFrame . onComplete ( ) ;
2854
- }
2855
- }
2856
-
2857
- var newFrame = trans . _currentFrame = trans . _frameQueue . shift ( ) ;
2858
-
2859
- if ( newFrame ) {
2860
- trans . _lastframeat = Date . now ( ) ;
2861
- trans . _timetonext = newFrame . transitionOpts . frameduration ;
2862
-
2863
- Plotly . transition ( gd ,
2864
- newFrame . frame . data ,
2865
- newFrame . frame . layout ,
2866
- newFrame . frame . traces ,
2867
- newFrame . transitionOpts
2868
- ) . then ( function ( ) {
2869
- if ( trans . _frameQueue . length === 0 ) {
2870
- gd . emit ( 'plotly_animated' ) ;
2871
- if ( trans . _currentFrame && trans . _currentFrame . onComplete ) {
2872
- trans . _currentFrame . onComplete ( ) ;
2873
- trans . _currentFrame = null ;
2874
- }
2875
- }
2876
- } ) ;
2877
- }
2878
-
2879
- if ( trans . _frameQueue . length === 0 ) {
2880
- stopAnimationLoop ( ) ;
2881
- return ;
2882
- }
2901
+ nextFrame ( ) ;
2883
2902
}
2884
2903
2885
2904
trans . _animationRaf = requestAnimationFrame ( doFrame ) ;
@@ -2891,34 +2910,59 @@ Plotly.animate = function(gd, groupNameOrFrameList, transitionOpts, animationOpt
2891
2910
var counter = 0 ;
2892
2911
function setTransitionConfig ( frame ) {
2893
2912
if ( Array . isArray ( transitionOpts ) ) {
2894
- frame . transitionOpts = transitionOpts [ counter ] ;
2913
+ if ( counter >= transitionOpts . length ) {
2914
+ frame . transitionOpts = transitionOpts [ counter ] ;
2915
+ } else {
2916
+ frame . transitionOpts = transitionOpts [ 0 ] ;
2917
+ }
2895
2918
} else {
2896
2919
frame . transitionOpts = transitionOpts ;
2897
2920
}
2898
2921
counter ++ ;
2899
2922
return frame ;
2900
2923
}
2901
2924
2925
+ // Disambiguate what's been received. The possibilities are:
2926
+ //
2927
+ // - group: 'groupname': select frames by group name
2928
+ // - frames ['frame1', frame2']: a list of frames
2929
+ // - object: {data: ...}: a single frame itself
2930
+ // - frames [{data: ...}, {data: ...}]: a list of frames
2931
+ //
2902
2932
var i , frame ;
2903
2933
var frameList = [ ] ;
2904
- var allFrames = groupNameOrFrameList === undefined || groupNameOrFrameList === null ;
2905
- if ( allFrames || typeof groupNameOrFrameList === 'string' ) {
2934
+ var allFrames = frameOrGroupNameOrFrameList === undefined || frameOrGroupNameOrFrameList === null ;
2935
+ var isFrameArray = Array . isArray ( frameOrGroupNameOrFrameList ) ;
2936
+ var isSingleFrame = ! allFrames && ! isFrameArray && typeof frameOrGroupNameOrFrameList === 'object' ;
2937
+
2938
+ if ( isSingleFrame ) {
2939
+ frameList . push ( setTransitionConfig ( {
2940
+ frame : Lib . extendFlat ( { } , frameOrGroupNameOrFrameList )
2941
+ } ) ) ;
2942
+ } else if ( allFrames || typeof frameOrGroupNameOrFrameList === 'string' ) {
2906
2943
for ( i = 0 ; i < trans . _frames . length ; i ++ ) {
2907
2944
frame = trans . _frames [ i ] ;
2908
2945
2909
- if ( allFrames || frame . group === groupNameOrFrameList ) {
2946
+ if ( allFrames || frame . group === frameOrGroupNameOrFrameList ) {
2910
2947
frameList . push ( setTransitionConfig ( { name : frame . name } ) ) ;
2911
2948
}
2912
2949
}
2913
- } else if ( Array . isArray ( groupNameOrFrameList ) ) {
2914
- for ( i = 0 ; i < groupNameOrFrameList . length ; i ++ ) {
2915
- frameList . push ( setTransitionConfig ( { name : groupNameOrFrameList [ i ] } ) ) ;
2950
+ } else if ( isFrameArray ) {
2951
+ for ( i = 0 ; i < frameOrGroupNameOrFrameList . length ; i ++ ) {
2952
+ var frameOrName = frameOrGroupNameOrFrameList [ i ] ;
2953
+ if ( typeof frameOrName === 'string' ) {
2954
+ frameList . push ( setTransitionConfig ( { name : frameOrName } ) ) ;
2955
+ } else {
2956
+ frameList . push ( setTransitionConfig ( {
2957
+ frame : Lib . extendFlat ( { } , frameOrName )
2958
+ } ) ) ;
2959
+ }
2916
2960
}
2917
2961
}
2918
2962
2919
2963
// Verify that all of these frames actually exist; return and reject if not:
2920
2964
for ( i = 0 ; i < frameList . length ; i ++ ) {
2921
- if ( ! trans . _frameHash [ frameList [ i ] . name ] ) {
2965
+ if ( frameList [ i ] . name && ! trans . _frameHash [ frameList [ i ] . name ] ) {
2922
2966
Lib . warn ( 'animate failure: frame not found: "' + frameList [ i ] . name + '"' ) ;
2923
2967
reject ( ) ;
2924
2968
return ;
0 commit comments