Skip to content

Commit 0221c79

Browse files
committed
Refactor animationOpts API
1 parent 0d3da5e commit 0221c79

File tree

9 files changed

+394
-323
lines changed

9 files changed

+394
-323
lines changed

src/components/errorbars/plot.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ var isNumeric = require('fast-isnumeric');
1414

1515
var subTypes = require('../../traces/scatter/subtypes');
1616

17-
module.exports = function plot(traces, plotinfo, transitionConfig) {
17+
module.exports = function plot(traces, plotinfo, transitionOpts) {
1818
var isNew;
1919
var xa = plotinfo.x(),
2020
ya = plotinfo.y();
2121

22-
var hasAnimation = transitionConfig && transitionConfig.transitionduration > 0;
22+
var hasAnimation = transitionOpts && transitionOpts.duration > 0;
2323

2424
traces.each(function(d) {
2525
var trace = d[0].trace,
@@ -55,7 +55,7 @@ module.exports = function plot(traces, plotinfo, transitionConfig) {
5555

5656
if(hasAnimation) {
5757
enter.style('opacity', 0).transition()
58-
.duration(transitionConfig.transitionduration)
58+
.duration(transitionOpts.duration)
5959
.style('opacity', 1);
6060
}
6161

@@ -89,8 +89,8 @@ module.exports = function plot(traces, plotinfo, transitionConfig) {
8989
} else if(hasAnimation) {
9090
yerror = yerror
9191
.transition()
92-
.duration(transitionConfig.transitionduration)
93-
.ease(transitionConfig.ease);
92+
.duration(transitionOpts.duration)
93+
.ease(transitionOpts.easing);
9494
}
9595

9696
yerror.attr('d', path);
@@ -117,8 +117,8 @@ module.exports = function plot(traces, plotinfo, transitionConfig) {
117117
} else if(hasAnimation) {
118118
xerror = xerror
119119
.transition()
120-
.duration(transitionConfig.transitionduration)
121-
.ease(transitionConfig.ease);
120+
.duration(transitionOpts.duration)
121+
.ease(transitionOpts.easing);
122122
}
123123

124124
xerror.attr('d', path);

src/plot_api/plot_api.js

+21-7
Original file line numberDiff line numberDiff line change
@@ -2460,10 +2460,10 @@ Plotly.relayout = function relayout(gd, astr, val) {
24602460
*
24612461
* @param {string} name
24622462
* name of the keyframe to create
2463-
* @param {object} transitionOpts
2464-
* configuration for transition
2463+
* @param {object} animationOpts
2464+
* configuration for animation
24652465
*/
2466-
Plotly.animate = function(gd, frameOrGroupNameOrFrameList, transitionOpts, animationOpts) {
2466+
Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) {
24672467
gd = getGraphDiv(gd);
24682468
var trans = gd._transitionData;
24692469

@@ -2474,6 +2474,8 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, transitionOpts, anima
24742474
}
24752475

24762476
animationOpts = Plots.supplyAnimationDefaults(animationOpts);
2477+
var transitionOpts = animationOpts.transition;
2478+
var frameOpts = animationOpts.frame;
24772479

24782480
// Since frames are popped immediately, an empty queue only means all frames have
24792481
// *started* to transition, not that the animation is complete. To solve that,
@@ -2495,6 +2497,18 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, transitionOpts, anima
24952497
}
24962498
}
24972499

2500+
function getFrameOpts(i) {
2501+
if(Array.isArray(frameOpts)) {
2502+
if(i >= frameOpts.length) {
2503+
return frameOpts[0];
2504+
} else {
2505+
return frameOpts[i];
2506+
}
2507+
} else {
2508+
return frameOpts;
2509+
}
2510+
}
2511+
24982512
return new Promise(function(resolve, reject) {
24992513
function discardExistingFrames() {
25002514
if(trans._frameQueue.length === 0) {
@@ -2522,12 +2536,11 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, transitionOpts, anima
25222536
computedFrame = frameList[i].frame;
25232537
}
25242538

2525-
var opts = Plots.supplyTransitionDefaults(getTransitionOpts(i));
2526-
25272539
var nextFrame = {
25282540
frame: computedFrame,
25292541
name: frameList[i].name,
2530-
transitionOpts: opts
2542+
frameOpts: getFrameOpts(i),
2543+
transitionOpts: getTransitionOpts(i)
25312544
};
25322545

25332546
if(i === frameList.length - 1) {
@@ -2559,12 +2572,13 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, transitionOpts, anima
25592572

25602573
if(newFrame) {
25612574
trans._lastframeat = Date.now();
2562-
trans._timetonext = newFrame.transitionOpts.frameduration;
2575+
trans._timetonext = newFrame.frameOpts.duration;
25632576

25642577
Plots.transition(gd,
25652578
newFrame.frame.data,
25662579
newFrame.frame.layout,
25672580
newFrame.frame.traces,
2581+
newFrame.frameOpts,
25682582
newFrame.transitionOpts
25692583
).then(function() {
25702584
if(trans._frameQueue.length === 0) {

src/plots/animation_attributes.js

+76
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,80 @@ module.exports = {
1919
'are rejected and a `plotly_animateinterrupt` event is emitted.'
2020
].join(' ')
2121
},
22+
frame: {
23+
duration: {
24+
valType: 'number',
25+
role: 'info',
26+
min: 0,
27+
dflt: 500,
28+
description: 'The duration in milliseconds of each frame.'
29+
},
30+
redraw: {
31+
valType: 'boolean',
32+
role: 'info',
33+
dflt: true,
34+
description: [
35+
'Redraw the plot at completion of the transition. This is desirable',
36+
'for transitions that include properties that cannot be transitioned,',
37+
'but may significantly slow down updates that do not require a full',
38+
'redraw of the plot'
39+
].join(' ')
40+
},
41+
},
42+
transition: {
43+
duration: {
44+
valType: 'number',
45+
role: 'info',
46+
min: 0,
47+
dflt: 500,
48+
description: [
49+
'The duration of the transition, in milliseconds. If equal to zero,',
50+
'updates are synchronous.'
51+
].join(' ')
52+
},
53+
easing: {
54+
valType: 'enumerated',
55+
dflt: 'cubic-in-out',
56+
values: [
57+
'linear',
58+
'quad',
59+
'cubic',
60+
'sin',
61+
'exp',
62+
'circle',
63+
'elastic',
64+
'back',
65+
'bounce',
66+
'linear-in',
67+
'quad-in',
68+
'cubic-in',
69+
'sin-in',
70+
'exp-in',
71+
'circle-in',
72+
'elastic-in',
73+
'back-in',
74+
'bounce-in',
75+
'linear-out',
76+
'quad-out',
77+
'cubic-out',
78+
'sin-out',
79+
'exp-out',
80+
'circle-out',
81+
'elastic-out',
82+
'back-out',
83+
'bounce-out',
84+
'linear-in-out',
85+
'quad-in-out',
86+
'cubic-in-out',
87+
'sin-in-out',
88+
'exp-in-out',
89+
'circle-in-out',
90+
'elastic-in-out',
91+
'back-in-out',
92+
'bounce-in-out'
93+
],
94+
role: 'info',
95+
description: 'The easing function used for the transition'
96+
},
97+
}
2298
};

src/plots/cartesian/transition_axes.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var Lib = require('../../lib');
1717
var Axes = require('./axes');
1818
var axisRegex = /((x|y)([2-9]|[1-9][0-9]+)?)axis$/;
1919

20-
module.exports = function transitionAxes(gd, newLayout, transitionConfig, makeOnCompleteCallback) {
20+
module.exports = function transitionAxes(gd, newLayout, transitionOpts, makeOnCompleteCallback) {
2121
var fullLayout = gd._fullLayout;
2222
var axes = [];
2323

@@ -277,7 +277,7 @@ module.exports = function transitionAxes(gd, newLayout, transitionConfig, makeOn
277277
}
278278

279279
var t1, t2, raf;
280-
var easeFn = d3.ease(transitionConfig.ease);
280+
var easeFn = d3.ease(transitionOpts.easing);
281281

282282
gd._transitionData._interruptCallbacks.push(function() {
283283
cancelAnimationFrame(raf);
@@ -288,14 +288,14 @@ module.exports = function transitionAxes(gd, newLayout, transitionConfig, makeOn
288288
function doFrame() {
289289
t2 = Date.now();
290290

291-
var tInterp = Math.min(1, (t2 - t1) / transitionConfig.transitionduration);
291+
var tInterp = Math.min(1, (t2 - t1) / transitionOpts.duration);
292292
var progress = easeFn(tInterp);
293293

294294
for(var i = 0; i < affectedSubplots.length; i++) {
295295
updateSubplot(affectedSubplots[i], progress);
296296
}
297297

298-
if(t2 - t1 > transitionConfig.transitionduration) {
298+
if(t2 - t1 > transitionOpts.duration) {
299299
transitionComplete();
300300
raf = cancelAnimationFrame(doFrame);
301301
} else {

src/plots/plots.js

+49-18
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ var Registry = require('../registry');
1717
var Lib = require('../lib');
1818
var Color = require('../components/color');
1919
var plots = module.exports = {};
20-
var transitionAttrs = require('./transition_attributes');
2120
var animationAttrs = require('./animation_attributes');
2221
var frameAttrs = require('./frame_attributes');
2322

@@ -616,6 +615,8 @@ plots.supplyDataDefaults = function(dataIn, dataOut, layout) {
616615
};
617616

618617
plots.supplyAnimationDefaults = function(opts) {
618+
opts = opts || {};
619+
var i;
619620
var optsOut = {};
620621

621622
function coerce(attr, dflt) {
@@ -624,24 +625,53 @@ plots.supplyAnimationDefaults = function(opts) {
624625

625626
coerce('immediate');
626627

628+
if(Array.isArray(opts.frame)) {
629+
optsOut.frame = [];
630+
for(i = 0; i < opts.frame.length; i++) {
631+
optsOut.frame[i] = plots.supplyAnimationFrameDefaults(opts.frame[i] || {});
632+
}
633+
} else {
634+
optsOut.frame = plots.supplyAnimationFrameDefaults(opts.frame || {});
635+
}
636+
637+
if(Array.isArray(opts.transition)) {
638+
optsOut.transition = [];
639+
for(i = 0; i < opts.transition.length; i++) {
640+
optsOut.transition[i] = plots.supplyAnimationTransitionDefaults(opts.transition[i] || {});
641+
}
642+
} else {
643+
optsOut.transition = plots.supplyAnimationTransitionDefaults(opts.transition || {});
644+
}
645+
627646
return optsOut;
628647
};
629648

630-
plots.supplyTransitionDefaults = function(opts) {
649+
plots.supplyAnimationFrameDefaults = function(opts) {
631650
var optsOut = {};
632651

633652
function coerce(attr, dflt) {
634-
return Lib.coerce(opts || {}, optsOut, transitionAttrs, attr, dflt);
653+
return Lib.coerce(opts || {}, optsOut, animationAttrs.frame, attr, dflt);
635654
}
636655

637-
coerce('frameduration');
638-
coerce('transitionduration');
639-
coerce('ease');
656+
coerce('duration');
640657
coerce('redraw');
641658

642659
return optsOut;
643660
};
644661

662+
plots.supplyAnimationTransitionDefaults = function(opts) {
663+
var optsOut = {};
664+
665+
function coerce(attr, dflt) {
666+
return Lib.coerce(opts || {}, optsOut, animationAttrs.transition, attr, dflt);
667+
}
668+
669+
coerce('duration');
670+
coerce('easing');
671+
672+
return optsOut;
673+
};
674+
645675
plots.supplyFrameDefaults = function(frameIn) {
646676
var frameOut = {};
647677

@@ -1316,11 +1346,8 @@ plots.computeFrame = function(gd, frameName) {
13161346
* @param {string id or DOM element} gd
13171347
* the id or DOM element of the graph container div
13181348
*/
1319-
plots.transition = function(gd, data, layout, traceIndices, transitionOpts) {
1349+
plots.transition = function(gd, data, layout, traceIndices, frameOpts, transitionOpts) {
13201350
var i, traceIdx;
1321-
var fullLayout = gd._fullLayout;
1322-
1323-
transitionOpts = plots.supplyTransitionDefaults(transitionOpts);
13241351

13251352
var dataLength = Array.isArray(data) ? data.length : 0;
13261353

@@ -1371,10 +1398,14 @@ plots.transition = function(gd, data, layout, traceIndices, transitionOpts) {
13711398
// This step fies the .xaxis and .yaxis references that otherwise
13721399
// aren't updated by the supplyDefaults step:
13731400
var subplots = Plotly.Axes.getSubplots(gd);
1374-
for(i = 0; i < subplots.length; i++) {
1375-
plotinfo = gd._fullLayout._plots[subplots[i]];
1376-
plotinfo.xaxis = plotinfo.x();
1377-
plotinfo.yaxis = plotinfo.y();
1401+
1402+
// Polar does not have _plots:
1403+
if(gd._fullLayout._plots) {
1404+
for(i = 0; i < subplots.length; i++) {
1405+
plotinfo = gd._fullLayout._plots[subplots[i]];
1406+
plotinfo.xaxis = plotinfo.x();
1407+
plotinfo.yaxis = plotinfo.y();
1408+
}
13781409
}
13791410

13801411
plots.doCalcdata(gd);
@@ -1410,7 +1441,7 @@ plots.transition = function(gd, data, layout, traceIndices, transitionOpts) {
14101441
// When instantaneous updates are coming through quickly, it's too much to simply disable
14111442
// all interaction, so store this flag so we can disambiguate whether mouse interactions
14121443
// should be fully disabled or not:
1413-
if(transitionOpts.transitionduration > 0) {
1444+
if(transitionOpts.duration > 0) {
14141445
gd._transitioningWithDuration = true;
14151446
}
14161447

@@ -1435,7 +1466,7 @@ plots.transition = function(gd, data, layout, traceIndices, transitionOpts) {
14351466

14361467
var traceTransitionOpts;
14371468
var j;
1438-
var basePlotModules = fullLayout._basePlotModules;
1469+
var basePlotModules = gd._fullLayout._basePlotModules;
14391470
var hasAxisTransition = false;
14401471

14411472
if(layout) {
@@ -1452,7 +1483,7 @@ plots.transition = function(gd, data, layout, traceIndices, transitionOpts) {
14521483
// to instantaneous.
14531484
if(hasAxisTransition) {
14541485
traceTransitionOpts = Lib.extendFlat({}, transitionOpts);
1455-
traceTransitionOpts.transitionduration = 0;
1486+
traceTransitionOpts.duration = 0;
14561487
} else {
14571488
traceTransitionOpts = transitionOpts;
14581489
}
@@ -1475,7 +1506,7 @@ plots.transition = function(gd, data, layout, traceIndices, transitionOpts) {
14751506
flushCallbacks(gd._transitionData._interruptCallbacks);
14761507

14771508
return Promise.resolve().then(function() {
1478-
if(transitionOpts.redraw) {
1509+
if(frameOpts.redraw) {
14791510
return Plotly.redraw(gd);
14801511
}
14811512
}).then(function() {

0 commit comments

Comments
 (0)