diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index b32dcb59748..210bf6ca5e3 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -2811,7 +2811,11 @@ function diffData(gd, oldFullData, newFullData, immutable, transition, newDataRe var i, trace; function getTraceValObject(parts) { - return PlotSchema.getTraceValObject(trace, parts); + var out = PlotSchema.getTraceValObject(trace, parts); + if(!trace._module.animatable && out.anim) { + out.anim = false; + } + return out; } var diffOpts = { diff --git a/src/plot_api/plot_schema.js b/src/plot_api/plot_schema.js index 9bfcd6f604d..3853d1ab864 100644 --- a/src/plot_api/plot_schema.js +++ b/src/plot_api/plot_schema.js @@ -6,7 +6,6 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; var Registry = require('../registry'); @@ -504,6 +503,7 @@ function getTraceAttributes(type) { var out = { meta: _module.meta || {}, categories: _module.categories || {}, + animatable: Boolean(_module.animatable), type: type, attributes: formatAttributes(attributes), }; @@ -516,6 +516,15 @@ function getTraceAttributes(type) { out.layoutAttributes = formatAttributes(layoutAttributes); } + // drop anim:true in non-animatable modules + if(!_module.animatable) { + exports.crawl(out, function(attr) { + if(exports.isValObject(attr) && 'anim' in attr) { + delete attr.anim; + } + }); + } + return out; } diff --git a/test/jasmine/bundle_tests/plotschema_test.js b/test/jasmine/bundle_tests/plotschema_test.js index b92a9ec9b62..89fcd888998 100644 --- a/test/jasmine/bundle_tests/plotschema_test.js +++ b/test/jasmine/bundle_tests/plotschema_test.js @@ -377,6 +377,22 @@ describe('plot schema', function() { expect(traces.parcoords.attributes.hoverinfo).toBe(undefined, 'no hover attrs for parcoords'); expect(traces.scatter3d.attributes.selectedpoints).toBe(undefined, 'no selectedpoints for gl3d traces'); }); + + it('traces that are not animatable should not list `anim:true` attributes', function() { + var notAnimatable = Object.keys(plotSchema.traces).filter(function(traceType) { + return !plotSchema.traces[traceType].animatable; + }); + + notAnimatable.forEach(function(traceType) { + Plotly.PlotSchema.crawl(plotSchema.traces[traceType].attributes, function() { + var attr = arguments[0]; + var astr = arguments[4]; + if(Plotly.PlotSchema.isValObject(attr) && 'anim' in attr) { + fail('Trace module ' + traceType + ' sets *' + astr + '* with anim:true'); + } + }); + }); + }); }); describe('getTraceValObject', function() { diff --git a/test/jasmine/tests/transition_test.js b/test/jasmine/tests/transition_test.js index 222d8cd397f..9667086a58a 100644 --- a/test/jasmine/tests/transition_test.js +++ b/test/jasmine/tests/transition_test.js @@ -431,6 +431,47 @@ describe('Plotly.react transitions:', function() { .then(done); }); + it('should no try to transition a trace which is not *animatable:true* yet', function(done) { + addSpies(); + + var trace = { + type: 'bar', + y: [1], + marker: {line: {width: 1}} + }; + + var data = [trace]; + var layout = {transition: {duration: 10}}; + + // sanity check that this test actually tests what was intended + var Bar = Registry.modules.bar._module; + if(Bar.animatable || Bar.attributes.marker.line.width.anim !== true) { + fail('Test no longer tests its indented code path:' + + ' This test is meant to test that Plotly.react with' + + ' *anim:true* attributes in *animatable:false* modules' + + ' does not trigger Plots.transitionFromReact calls.' + ); + } + + Plotly.react(gd, data, layout) + .then(function() { + assertSpies('first draw', [ + [Plots, 'transitionFromReact', 0] + ]); + }) + .then(function() { + trace.marker.line.width = 5; + return Plotly.react(gd, data, layout); + }) + .then(function() { + assertSpies('after (transition) react call', [ + [Plots, 'transitionFromReact', 0] + ]); + }) + .catch(failTest) + .then(done); + }); + it('should not try to transition when the *config* has changed', function(done) { addSpies();