@@ -2628,7 +2628,7 @@ Plotly.transition = function(gd, data, layout, traceIndices, transitionOpts) {
26282628 // When instantaneous updates are coming through quickly, it's too much to simply disable
26292629 // all interaction, so store this flag so we can disambiguate whether mouse interactions
26302630 // should be fully disabled or not:
2631- if ( transitionOpts . duration > 0 ) {
2631+ if ( transitionOpts . transitionduration > 0 ) {
26322632 gd . _transitioningWithDuration = true ;
26332633 }
26342634
@@ -2670,7 +2670,7 @@ Plotly.transition = function(gd, data, layout, traceIndices, transitionOpts) {
26702670 // to instantaneous.
26712671 if ( hasAxisTransition ) {
26722672 traceTransitionOpts = Lib . extendFlat ( { } , transitionOpts ) ;
2673- traceTransitionOpts . duration = 0 ;
2673+ traceTransitionOpts . transitionduration = 0 ;
26742674 } else {
26752675 traceTransitionOpts = transitionOpts ;
26762676 }
@@ -2756,7 +2756,7 @@ Plotly.transition = function(gd, data, layout, traceIndices, transitionOpts) {
27562756 * @param {object } transitionOpts
27572757 * configuration for transition
27582758 */
2759- Plotly . animate = function ( gd , groupNameOrFrameList , transitionOpts , animationOpts ) {
2759+ Plotly . animate = function ( gd , frameOrGroupNameOrFrameList , transitionOpts , animationOpts ) {
27602760 gd = getGraphDiv ( gd ) ;
27612761 var trans = gd . _transitionData ;
27622762
@@ -2808,7 +2808,12 @@ Plotly.animate = function(gd, groupNameOrFrameList, transitionOpts, animationOpt
28082808 if ( frameList . length === 0 ) return ;
28092809
28102810 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+ }
28122817
28132818 var opts = Plots . supplyTransitionDefaults ( getTransitionOpts ( i ) ) ;
28142819
@@ -2836,9 +2841,54 @@ Plotly.animate = function(gd, groupNameOrFrameList, transitionOpts, animationOpt
28362841 trans . _animationRaf = null ;
28372842 }
28382843
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+
28392879 function beginAnimationLoop ( ) {
28402880 gd . emit ( 'plotly_animating' ) ;
28412881
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+
28422892 // If no timer is running, then set last frame = long ago:
28432893 trans . _lastframeat = 0 ;
28442894 trans . _timetonext = 0 ;
@@ -2848,38 +2898,7 @@ Plotly.animate = function(gd, groupNameOrFrameList, transitionOpts, animationOpt
28482898 var doFrame = function ( ) {
28492899 // Check if we need to pop a frame:
28502900 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 ( ) ;
28832902 }
28842903
28852904 trans . _animationRaf = requestAnimationFrame ( doFrame ) ;
@@ -2891,34 +2910,59 @@ Plotly.animate = function(gd, groupNameOrFrameList, transitionOpts, animationOpt
28912910 var counter = 0 ;
28922911 function setTransitionConfig ( frame ) {
28932912 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+ }
28952918 } else {
28962919 frame . transitionOpts = transitionOpts ;
28972920 }
28982921 counter ++ ;
28992922 return frame ;
29002923 }
29012924
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+ //
29022932 var i , frame ;
29032933 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' ) {
29062943 for ( i = 0 ; i < trans . _frames . length ; i ++ ) {
29072944 frame = trans . _frames [ i ] ;
29082945
2909- if ( allFrames || frame . group === groupNameOrFrameList ) {
2946+ if ( allFrames || frame . group === frameOrGroupNameOrFrameList ) {
29102947 frameList . push ( setTransitionConfig ( { name : frame . name } ) ) ;
29112948 }
29122949 }
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+ }
29162960 }
29172961 }
29182962
29192963 // Verify that all of these frames actually exist; return and reject if not:
29202964 for ( i = 0 ; i < frameList . length ; i ++ ) {
2921- if ( ! trans . _frameHash [ frameList [ i ] . name ] ) {
2965+ if ( frameList [ i ] . name && ! trans . _frameHash [ frameList [ i ] . name ] ) {
29222966 Lib . warn ( 'animate failure: frame not found: "' + frameList [ i ] . name + '"' ) ;
29232967 reject ( ) ;
29242968 return ;
0 commit comments