From 16830058831d7bc9d1a00ad81c78d7ebd3093e1d Mon Sep 17 00:00:00 2001 From: Ricky Reusser Date: Tue, 20 Sep 2016 14:12:33 -0400 Subject: [PATCH 1/5] Emit plotly_animatingframe event on animated frames --- src/plot_api/plot_api.js | 4 +++- test/jasmine/tests/animate_test.js | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 1b627b49bc1..478e7d9e1b8 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -2219,7 +2219,7 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { var nextFrame = { frame: computedFrame, - name: frameList[i].name, + name: frameList[i].name || computedFrame.name, frameOpts: frameOpts, transitionOpts: transitionOpts, }; @@ -2274,6 +2274,8 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { var newFrame = trans._currentFrame = trans._frameQueue.shift(); if(newFrame) { + gd.emit('plotly_animatingframe', newFrame.name); + trans._lastFrameAt = Date.now(); trans._timeToNext = newFrame.frameOpts.duration; diff --git a/test/jasmine/tests/animate_test.js b/test/jasmine/tests/animate_test.js index eb6995c5ffa..b7e74a3879b 100644 --- a/test/jasmine/tests/animate_test.js +++ b/test/jasmine/tests/animate_test.js @@ -406,6 +406,23 @@ 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(name) { + frames.push(name); + }); + + Plotly.animate(gd, ['frame0', 'frame1', {name: 'test'}, {data: []}], { + transition: {duration: 1}, + frame: {duration: 1} + }).then(function() { + expect(frames).toEqual(['frame0', 'frame1', 'test', 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'], { From 36324883a5fac0762c4209be4cdd18120ccc5c93 Mon Sep 17 00:00:00 2001 From: Ricky Reusser Date: Tue, 20 Sep 2016 15:41:42 -0400 Subject: [PATCH 2/5] Add extra internal container to frames for robustness --- src/plot_api/plot_api.js | 41 ++++++++++++++++++++++++++-------------- src/plots/plots.js | 2 +- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 478e7d9e1b8..1ca3eb209a6 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); + computedFrame = Plots.computeFrame(gd, frameList[i].data.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); @@ -2219,7 +2219,7 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { var nextFrame = { frame: computedFrame, - name: frameList[i].name || computedFrame.name, + name: computedFrame.name, frameOpts: frameOpts, transitionOpts: transitionOpts, }; @@ -2344,34 +2344,47 @@ 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', + 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', + 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/src/plots/plots.js b/src/plots/plots.js index b4ffa470551..ccc495db0fe 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -1286,7 +1286,7 @@ plots.computeFrame = function(gd, frameName) { } // A new object for the merged result: - var result = {}; + var result = {name: frameName}; // Merge, starting with the last and ending with the desired frame: while((framePtr = frameStack.pop())) { From 32d927342c3b2cf06c335cd80a69426ed5545550 Mon Sep 17 00:00:00 2001 From: Ricky Reusser Date: Tue, 20 Sep 2016 15:53:48 -0400 Subject: [PATCH 3/5] Emit more useful data on plotly_animatingframe --- src/plot_api/plot_api.js | 9 ++++++++- test/jasmine/tests/animate_test.js | 7 +++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 1ca3eb209a6..9d82dc9580f 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -2274,7 +2274,14 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { var newFrame = trans._currentFrame = trans._frameQueue.shift(); if(newFrame) { - gd.emit('plotly_animatingframe', newFrame.name); + 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; diff --git a/test/jasmine/tests/animate_test.js b/test/jasmine/tests/animate_test.js index b7e74a3879b..066823d70eb 100644 --- a/test/jasmine/tests/animate_test.js +++ b/test/jasmine/tests/animate_test.js @@ -409,8 +409,11 @@ 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(name) { - frames.push(name); + 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: []}], { From d639e195bf80168ce38bc29c83f7511c2134b5f0 Mon Sep 17 00:00:00 2001 From: Ricky Reusser Date: Tue, 20 Sep 2016 16:11:08 -0400 Subject: [PATCH 4/5] Fix compute frame tests --- test/jasmine/tests/compute_frame_test.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test/jasmine/tests/compute_frame_test.js b/test/jasmine/tests/compute_frame_test.js index 9010838ee5a..f71924a7cf7 100644 --- a/test/jasmine/tests/compute_frame_test.js +++ b/test/jasmine/tests/compute_frame_test.js @@ -61,7 +61,7 @@ describe('Test mergeFrames', function() { it('computes a single frame', function() { var computed = computeFrame(gd, 'frame1'); - var expected = {data: [{x: [1, 2, 3], marker: {size: 8, color: 'red'}}], traces: [0]}; + var expected = {name: 'frame1', data: [{x: [1, 2, 3], marker: {size: 8, color: 'red'}}], traces: [0]}; expect(computed).toEqual(expected); }); @@ -82,9 +82,9 @@ describe('Test mergeFrames', function() { ]; results = [ - {traces: [0], data: [{marker: {size: 0}}]}, - {traces: [0], data: [{marker: {size: 1}}]}, - {traces: [0], data: [{marker: {size: 2}}]} + {name: 'frame0', traces: [0], data: [{marker: {size: 0}}]}, + {name: 'frame1', traces: [0], data: [{marker: {size: 1}}]}, + {name: 'frame2', traces: [0], data: [{marker: {size: 2}}]} ]; Plotly.addFrames(gd, frames).then(done); @@ -140,6 +140,7 @@ describe('Test mergeFrames', function() { Plotly.addFrames(gd, frames.map(clone)); expect(computeFrame(gd, 'frame0')).toEqual({ + name: 'frame0', traces: [8, 2], data: [ {marker: {size: 1}}, @@ -158,6 +159,7 @@ describe('Test mergeFrames', function() { Plotly.addFrames(gd, frames.map(clone)); expect(computeFrame(gd, 'frame0')).toEqual({ + name: 'frame0', traces: [2], data: [{marker: {size: 0}}] }); @@ -173,6 +175,7 @@ describe('Test mergeFrames', function() { Plotly.addFrames(gd, frames.map(clone)); expect(computeFrame(gd, 'frame0')).toEqual({ + name: 'frame0', traces: [2, 8], data: [ {marker: {size: 0}}, @@ -189,6 +192,7 @@ describe('Test mergeFrames', function() { Plotly.addFrames(gd, frames.map(clone)); expect(computeFrame(gd, 'frame4')).toEqual({ + name: 'frame4', traces: [2, 8, 0, 1], data: [ {marker: {size: 7}}, @@ -224,6 +228,7 @@ describe('Test mergeFrames', function() { var result = computeFrame(gd, 'frame0'); expect(result).toEqual({ + name: 'frame0', layout: {margin: {l: 40}} }); }); From 627c8e1516ef6e6c98b4f0550a2c562f491948a4 Mon Sep 17 00:00:00 2001 From: Ricky Reusser Date: Tue, 20 Sep 2016 16:47:01 -0400 Subject: [PATCH 5/5] Opt for the other way of passing frame names while queueing --- src/plot_api/plot_api.js | 6 ++++-- src/plots/plots.js | 2 +- test/jasmine/tests/animate_test.js | 2 +- test/jasmine/tests/compute_frame_test.js | 13 ++++--------- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 9d82dc9580f..fedcb9dfe4f 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -2203,7 +2203,7 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { if(frameList[i].type === 'byname') { // If it's a named frame, compute it: - computedFrame = Plots.computeFrame(gd, frameList[i].data.name); + 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. @@ -2219,7 +2219,7 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { var nextFrame = { frame: computedFrame, - name: computedFrame.name, + name: frameList[i].name, frameOpts: frameOpts, transitionOpts: transitionOpts, }; @@ -2365,6 +2365,7 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { if(allFrames || frame.group === frameOrGroupNameOrFrameList) { frameList.push({ type: 'byname', + name: frame.name, data: setTransitionConfig({name: frame.name}) }); } @@ -2376,6 +2377,7 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { // 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 { diff --git a/src/plots/plots.js b/src/plots/plots.js index ccc495db0fe..b4ffa470551 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -1286,7 +1286,7 @@ plots.computeFrame = function(gd, frameName) { } // A new object for the merged result: - var result = {name: frameName}; + var result = {}; // Merge, starting with the last and ending with the desired frame: while((framePtr = frameStack.pop())) { diff --git a/test/jasmine/tests/animate_test.js b/test/jasmine/tests/animate_test.js index 066823d70eb..e9f0a5cfb15 100644 --- a/test/jasmine/tests/animate_test.js +++ b/test/jasmine/tests/animate_test.js @@ -420,7 +420,7 @@ describe('Test animate API', function() { transition: {duration: 1}, frame: {duration: 1} }).then(function() { - expect(frames).toEqual(['frame0', 'frame1', 'test', undefined]); + expect(frames).toEqual(['frame0', 'frame1', undefined, undefined]); }).catch(fail).then(done); }); diff --git a/test/jasmine/tests/compute_frame_test.js b/test/jasmine/tests/compute_frame_test.js index f71924a7cf7..9010838ee5a 100644 --- a/test/jasmine/tests/compute_frame_test.js +++ b/test/jasmine/tests/compute_frame_test.js @@ -61,7 +61,7 @@ describe('Test mergeFrames', function() { it('computes a single frame', function() { var computed = computeFrame(gd, 'frame1'); - var expected = {name: 'frame1', data: [{x: [1, 2, 3], marker: {size: 8, color: 'red'}}], traces: [0]}; + var expected = {data: [{x: [1, 2, 3], marker: {size: 8, color: 'red'}}], traces: [0]}; expect(computed).toEqual(expected); }); @@ -82,9 +82,9 @@ describe('Test mergeFrames', function() { ]; results = [ - {name: 'frame0', traces: [0], data: [{marker: {size: 0}}]}, - {name: 'frame1', traces: [0], data: [{marker: {size: 1}}]}, - {name: 'frame2', traces: [0], data: [{marker: {size: 2}}]} + {traces: [0], data: [{marker: {size: 0}}]}, + {traces: [0], data: [{marker: {size: 1}}]}, + {traces: [0], data: [{marker: {size: 2}}]} ]; Plotly.addFrames(gd, frames).then(done); @@ -140,7 +140,6 @@ describe('Test mergeFrames', function() { Plotly.addFrames(gd, frames.map(clone)); expect(computeFrame(gd, 'frame0')).toEqual({ - name: 'frame0', traces: [8, 2], data: [ {marker: {size: 1}}, @@ -159,7 +158,6 @@ describe('Test mergeFrames', function() { Plotly.addFrames(gd, frames.map(clone)); expect(computeFrame(gd, 'frame0')).toEqual({ - name: 'frame0', traces: [2], data: [{marker: {size: 0}}] }); @@ -175,7 +173,6 @@ describe('Test mergeFrames', function() { Plotly.addFrames(gd, frames.map(clone)); expect(computeFrame(gd, 'frame0')).toEqual({ - name: 'frame0', traces: [2, 8], data: [ {marker: {size: 0}}, @@ -192,7 +189,6 @@ describe('Test mergeFrames', function() { Plotly.addFrames(gd, frames.map(clone)); expect(computeFrame(gd, 'frame4')).toEqual({ - name: 'frame4', traces: [2, 8, 0, 1], data: [ {marker: {size: 7}}, @@ -228,7 +224,6 @@ describe('Test mergeFrames', function() { var result = computeFrame(gd, 'frame0'); expect(result).toEqual({ - name: 'frame0', layout: {margin: {l: 40}} }); });