Skip to content

Commit d30a3bd

Browse files
authored
Merge pull request #2313 from plotly/array-anim
Minor changes to animation code ahead of the array animation fix
2 parents f459723 + 1ccf35c commit d30a3bd

File tree

3 files changed

+64
-41
lines changed

3 files changed

+64
-41
lines changed

src/plot_api/plot_api.js

+18-11
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ var enforceAxisConstraints = axisConstraints.enforce;
4242
var cleanAxisConstraints = axisConstraints.clean;
4343
var axisIds = require('../plots/cartesian/axis_ids');
4444

45+
var numericNameWarningCount = 0;
46+
var numericNameWarningCountLimit = 5;
4547

4648
/**
4749
* Main plot-creation function
@@ -2592,16 +2594,14 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) {
25922594
* - traces {array} trace indices
25932595
* - baseframe {string} name of frame from which this frame gets defaults
25942596
*
2595-
* @param {array of integers) indices
2597+
* @param {array of integers} indices
25962598
* an array of integer indices matching the respective frames in `frameList`. If not
25972599
* provided, an index will be provided in serial order. If already used, the frame
25982600
* will be overwritten.
25992601
*/
26002602
Plotly.addFrames = function(gd, frameList, indices) {
26012603
gd = Lib.getGraphDiv(gd);
26022604

2603-
var numericNameWarningCount = 0;
2604-
26052605
if(frameList === null || frameList === undefined) {
26062606
return Promise.resolve();
26072607
}
@@ -2616,7 +2616,7 @@ Plotly.addFrames = function(gd, frameList, indices) {
26162616

26172617
var i, frame, j, idx;
26182618
var _frames = gd._transitionData._frames;
2619-
var _hash = gd._transitionData._frameHash;
2619+
var _frameHash = gd._transitionData._frameHash;
26202620

26212621

26222622
if(!Array.isArray(frameList)) {
@@ -2631,28 +2631,35 @@ Plotly.addFrames = function(gd, frameList, indices) {
26312631
var bigIndex = _frames.length + frameList.length * 2;
26322632

26332633
var insertions = [];
2634+
var _frameHashLocal = {};
26342635
for(i = frameList.length - 1; i >= 0; i--) {
26352636
if(!Lib.isPlainObject(frameList[i])) continue;
26362637

2637-
var name = (_hash[frameList[i].name] || {}).name;
2638+
// The entire logic for checking for this type of name collision can be removed once we migrate to ES6 and
2639+
// use a Map instead of an Object instance, as Map keys aren't converted to strings.
2640+
var lookupName = frameList[i].name;
2641+
var name = (_frameHash[lookupName] || _frameHashLocal[lookupName] || {}).name;
26382642
var newName = frameList[i].name;
2643+
var collisionPresent = _frameHash[name] || _frameHashLocal[name];
26392644

2640-
if(name && newName && typeof newName === 'number' && _hash[name]) {
2645+
if(name && newName && typeof newName === 'number' && collisionPresent && numericNameWarningCount < numericNameWarningCountLimit) {
26412646
numericNameWarningCount++;
26422647

2643-
Lib.warn('addFrames: overwriting frame "' + _hash[name].name +
2648+
Lib.warn('addFrames: overwriting frame "' + (_frameHash[name] || _frameHashLocal[name]).name +
26442649
'" with a frame whose name of type "number" also equates to "' +
26452650
name + '". This is valid but may potentially lead to unexpected ' +
26462651
'behavior since all plotly.js frame names are stored internally ' +
26472652
'as strings.');
26482653

2649-
if(numericNameWarningCount > 5) {
2650-
Lib.warn('addFrames: This API call has yielded too many warnings. ' +
2654+
if(numericNameWarningCount === numericNameWarningCountLimit) {
2655+
Lib.warn('addFrames: This API call has yielded too many of these warnings. ' +
26512656
'For the rest of this call, further warnings about numeric frame ' +
26522657
'names will be suppressed.');
26532658
}
26542659
}
26552660

2661+
_frameHashLocal[lookupName] = {name: lookupName};
2662+
26562663
insertions.push({
26572664
frame: Plots.supplyFrameDefaults(frameList[i]),
26582665
index: (indices && indices[i] !== undefined && indices[i] !== null) ? indices[i] : bigIndex + i
@@ -2682,10 +2689,10 @@ Plotly.addFrames = function(gd, frameList, indices) {
26822689
if(!frame.name) {
26832690
// Repeatedly assign a default name, incrementing the counter each time until
26842691
// we get a name that's not in the hashed lookup table:
2685-
while(_hash[(frame.name = 'frame ' + gd._transitionData._counter++)]);
2692+
while(_frameHash[(frame.name = 'frame ' + gd._transitionData._counter++)]);
26862693
}
26872694

2688-
if(_hash[frame.name]) {
2695+
if(_frameHash[frame.name]) {
26892696
// If frame is present, overwrite its definition:
26902697
for(j = 0; j < _frames.length; j++) {
26912698
if((_frames[j] || {}).name === frame.name) break;

src/plots/plots.js

+8-16
Original file line numberDiff line numberDiff line change
@@ -1779,7 +1779,7 @@ plots.graphJson = function(gd, dataonly, mode, output, useDefaults) {
17791779
plots.modifyFrames = function(gd, operations) {
17801780
var i, op, frame;
17811781
var _frames = gd._transitionData._frames;
1782-
var _hash = gd._transitionData._frameHash;
1782+
var _frameHash = gd._transitionData._frameHash;
17831783

17841784
for(i = 0; i < operations.length; i++) {
17851785
op = operations[i];
@@ -1788,32 +1788,32 @@ plots.modifyFrames = function(gd, operations) {
17881788
// No reason this couldn't exist, but is currently unused/untested:
17891789
/* case 'rename':
17901790
frame = _frames[op.index];
1791-
delete _hash[frame.name];
1792-
_hash[op.name] = frame;
1791+
delete _frameHash[frame.name];
1792+
_frameHash[op.name] = frame;
17931793
frame.name = op.name;
17941794
break;*/
17951795
case 'replace':
17961796
frame = op.value;
17971797
var oldName = (_frames[op.index] || {}).name;
17981798
var newName = frame.name;
1799-
_frames[op.index] = _hash[newName] = frame;
1799+
_frames[op.index] = _frameHash[newName] = frame;
18001800

18011801
if(newName !== oldName) {
18021802
// If name has changed in addition to replacement, then update
18031803
// the lookup table:
1804-
delete _hash[oldName];
1805-
_hash[newName] = frame;
1804+
delete _frameHash[oldName];
1805+
_frameHash[newName] = frame;
18061806
}
18071807

18081808
break;
18091809
case 'insert':
18101810
frame = op.value;
1811-
_hash[frame.name] = frame;
1811+
_frameHash[frame.name] = frame;
18121812
_frames.splice(op.index, 0, frame);
18131813
break;
18141814
case 'delete':
18151815
frame = _frames[op.index];
1816-
delete _hash[frame.name];
1816+
delete _frameHash[frame.name];
18171817
_frames.splice(op.index, 1);
18181818
break;
18191819
}
@@ -2252,14 +2252,6 @@ plots.transition = function(gd, data, layout, traces, frameOpts, transitionOpts)
22522252
var module = contFull._module;
22532253

22542254
if(!module) continue;
2255-
2256-
if(!module.animatable) {
2257-
var thisUpdate = {};
2258-
2259-
for(var ai in data[i]) {
2260-
thisUpdate[ai] = [data[i][ai]];
2261-
}
2262-
}
22632255
}
22642256

22652257
var seq = [plots.previousPromises, interruptPreviousTransitions, prepareTransitions, plots.rehover, executeTransitions];

test/jasmine/tests/frame_api_test.js

+38-14
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,44 @@ describe('Test frame api', function() {
3737
});
3838

3939
describe('#addFrames', function() {
40+
41+
it('issues a warning if a number-named frame would overwrite a frame', function(done) {
42+
var warnings = [];
43+
spyOn(Lib, 'warn').and.callFake(function(msg) {
44+
warnings.push(msg);
45+
});
46+
47+
// Test with both multiframe additions and repeated `addFrames` calls - both should count toward the warn limit
48+
Plotly.addFrames(gd, [
49+
{name: 8, data: [{x: [8, 7, 6]}]},
50+
{name: 8888, data: [{x: [8, 7, 6]}]},
51+
{name: 8, data: [{x: [8, 7, 6]}]},
52+
{name: '8', data: [{x: [8, 7, 6]}]}
53+
])
54+
.then(function() {
55+
// so far, two warnings
56+
expect(Lib.warn.calls.count()).toEqual(2);
57+
expect(warnings[0]).toMatch(/^addFrames.*overwriting/);
58+
return Plotly.addFrames(gd, [{name: 8, data: [{x: [3, 2, 1]}]}]);
59+
})
60+
.then(function() {return Plotly.addFrames(gd, [{name: 8, data: [{x: [3, 2, 1]}]}]);})
61+
.then(function() {return Plotly.addFrames(gd, [{name: 8, data: [{x: [3, 2, 1]}]}]);})
62+
.then(function() {
63+
// so far, 5 + 1 warnings
64+
expect(Lib.warn.calls.count()).toEqual(5 + 1);
65+
expect(warnings[5]).toMatch(/^addFrames.*suppressed/);
66+
return Plotly.addFrames(gd, [{name: 8, data: [{x: [3, 2, 1]}]}]);
67+
})
68+
.then(function() {return Plotly.addFrames(gd, [{name: 8, data: [{x: [3, 2, 1]}]}]);})
69+
.then(function() {return Plotly.addFrames(gd, [{name: 8, data: [{x: [3, 2, 1]}]}]);})
70+
.then(function() {return Plotly.addFrames(gd, [{name: 8, data: [{x: [3, 2, 1]}]}]);})
71+
.then(function() {return Plotly.addFrames(gd, [{name: 8, data: [{x: [3, 2, 1]}]}]);})
72+
.then(function() {
73+
// Five (`var numericNameWarningCountLimit = 5`) warnings and one warning saying that there won't be more warnings
74+
expect(Lib.warn.calls.count()).toEqual(5 + 1);
75+
}).catch(fail).then(done);
76+
});
77+
4078
it('treats an undefined list as a noop', function(done) {
4179
Plotly.addFrames(gd, undefined).then(function() {
4280
expect(Object.keys(h)).toEqual([]);
@@ -102,20 +140,6 @@ describe('Test frame api', function() {
102140
}).catch(fail).then(done);
103141
});
104142

105-
it('issues a warning if a number-named frame would overwrite a frame', function(done) {
106-
var warnings = [];
107-
spyOn(Lib, 'warn').and.callFake(function(msg) {
108-
warnings.push(msg);
109-
});
110-
111-
Plotly.addFrames(gd, [{name: 2}]).then(function() {
112-
return Plotly.addFrames(gd, [{name: 2, layout: {foo: 'bar'}}]);
113-
}).then(function() {
114-
expect(warnings.length).toEqual(1);
115-
expect(warnings[0]).toMatch(/overwriting/);
116-
}).catch(fail).then(done);
117-
});
118-
119143
it('avoids name collisions', function(done) {
120144
Plotly.addFrames(gd, [{name: 'frame 0'}, {name: 'frame 2'}]).then(function() {
121145
expect(f).toEqual([{name: 'frame 0'}, {name: 'frame 2'}]);

0 commit comments

Comments
 (0)