diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 1b627b49bc1..fedcb9dfe4f 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -2201,13 +2201,13 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { for(var i = 0; i < frameList.length; i++) { var computedFrame; - if(frameList[i].name) { + if(frameList[i].type === 'byname') { // If it's a named frame, compute it: computedFrame = Plots.computeFrame(gd, frameList[i].name); } else { // Otherwise we must have been given a simple object, so treat // the input itself as the computed frame. - computedFrame = frameList[i].frame; + computedFrame = frameList[i].data; } var frameOpts = getFrameOpts(i); @@ -2274,6 +2274,15 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { var newFrame = trans._currentFrame = trans._frameQueue.shift(); if(newFrame) { + gd.emit('plotly_animatingframe', { + name: newFrame.name, + frame: newFrame.frame, + animation: { + frame: newFrame.frameOpts, + transition: newFrame.transitionOpts, + } + }); + trans._lastFrameAt = Date.now(); trans._timeToNext = newFrame.frameOpts.duration; @@ -2342,34 +2351,49 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { var isSingleFrame = !allFrames && !isFrameArray && Lib.isPlainObject(frameOrGroupNameOrFrameList); if(isSingleFrame) { - frameList.push(setTransitionConfig({ - frame: Lib.extendFlat({}, frameOrGroupNameOrFrameList) - })); + // In this case, a simple object has been passed to animate. + frameList.push({ + type: 'object', + data: setTransitionConfig(Lib.extendFlat({}, frameOrGroupNameOrFrameList)) + }); } else if(allFrames || typeof frameOrGroupNameOrFrameList === 'string') { + // In this case, null or undefined has been passed so that we want to + // animate *all* currently defined frames for(i = 0; i < trans._frames.length; i++) { frame = trans._frames[i]; if(allFrames || frame.group === frameOrGroupNameOrFrameList) { - frameList.push(setTransitionConfig({name: frame.name})); + frameList.push({ + type: 'byname', + name: frame.name, + data: setTransitionConfig({name: frame.name}) + }); } } } else if(isFrameArray) { for(i = 0; i < frameOrGroupNameOrFrameList.length; i++) { var frameOrName = frameOrGroupNameOrFrameList[i]; if(typeof frameOrName === 'string') { - frameList.push(setTransitionConfig({name: frameOrName})); + // In this case, there's an array and this frame is a string name: + frameList.push({ + type: 'byname', + name: frameOrName, + data: setTransitionConfig({name: frameOrName}) + }); } else { - frameList.push(setTransitionConfig({ - frame: Lib.extendFlat({}, frameOrName) - })); + frameList.push({ + type: 'object', + data: setTransitionConfig(Lib.extendFlat({}, frameOrName)) + }); } } } // Verify that all of these frames actually exist; return and reject if not: for(i = 0; i < frameList.length; i++) { - if(frameList[i].name && !trans._frameHash[frameList[i].name]) { - Lib.warn('animate failure: frame not found: "' + frameList[i].name + '"'); + frame = frameList[i]; + if(frame.type === 'byname' && !trans._frameHash[frame.data.name]) { + Lib.warn('animate failure: frame not found: "' + frame.data.name + '"'); reject(); return; } diff --git a/test/jasmine/tests/animate_test.js b/test/jasmine/tests/animate_test.js index eb6995c5ffa..e9f0a5cfb15 100644 --- a/test/jasmine/tests/animate_test.js +++ b/test/jasmine/tests/animate_test.js @@ -406,6 +406,26 @@ describe('Test animate API', function() { }); }); + describe('frame events', function() { + it('emits an event when a frame is transitioned to', function(done) { + var frames = []; + gd.on('plotly_animatingframe', function(data) { + frames.push(data.name); + expect(data.frame).not.toBe(undefined); + expect(data.animation.frame).not.toBe(undefined); + expect(data.animation.transition).not.toBe(undefined); + }); + + Plotly.animate(gd, ['frame0', 'frame1', {name: 'test'}, {data: []}], { + transition: {duration: 1}, + frame: {duration: 1} + }).then(function() { + expect(frames).toEqual(['frame0', 'frame1', undefined, undefined]); + }).catch(fail).then(done); + + }); + }); + describe('frame vs. transition timing', function() { it('limits the transition duration to <= frame duration', function(done) { Plotly.animate(gd, ['frame0'], {