diff --git a/src/components/annotations/annotation_defaults.js b/src/components/annotations/annotation_defaults.js
index 36acea5d457..15aed2c04e1 100644
--- a/src/components/annotations/annotation_defaults.js
+++ b/src/components/annotations/annotation_defaults.js
@@ -23,6 +23,10 @@ module.exports = function handleAnnotationDefaults(annIn, fullLayout) {
return Lib.coerce(annIn, annOut, attributes, attr, dflt);
}
+ var visible = coerce('visible');
+
+ if(!visible) return annOut;
+
coerce('opacity');
coerce('align');
coerce('bgcolor');
diff --git a/src/components/annotations/attributes.js b/src/components/annotations/attributes.js
index cea6afb9a4a..4c9b5f12024 100644
--- a/src/components/annotations/attributes.js
+++ b/src/components/annotations/attributes.js
@@ -17,6 +17,15 @@ var extendFlat = require('../../lib/extend').extendFlat;
module.exports = {
_isLinkedToArray: true,
+ visible: {
+ valType: 'boolean',
+ role: 'info',
+ dflt: true,
+ description: [
+ 'Determines whether or not this annotation is visible.'
+ ].join(' ')
+ },
+
text: {
valType: 'string',
role: 'info',
diff --git a/src/components/annotations/calc_autorange.js b/src/components/annotations/calc_autorange.js
index ba2261f3f4c..99abb765c99 100644
--- a/src/components/annotations/calc_autorange.js
+++ b/src/components/annotations/calc_autorange.js
@@ -17,7 +17,7 @@ var draw = require('./draw').draw;
module.exports = function calcAutorange(gd) {
var fullLayout = gd._fullLayout,
- annotationList = fullLayout.annotations;
+ annotationList = Lib.filterVisible(fullLayout.annotations);
if(!annotationList.length || !gd._fullData.length) return;
diff --git a/src/components/annotations/draw.js b/src/components/annotations/draw.js
index 2b104001477..92b2734ac73 100644
--- a/src/components/annotations/draw.js
+++ b/src/components/annotations/draw.js
@@ -47,7 +47,9 @@ function draw(gd) {
fullLayout._infolayer.selectAll('.annotation').remove();
for(var i = 0; i < fullLayout.annotations.length; i++) {
- drawOne(gd, i);
+ if(fullLayout.annotations[i].visible) {
+ drawOne(gd, i);
+ }
}
return Plots.previousPromises(gd);
@@ -140,8 +142,6 @@ function drawOne(gd, index, opt, value) {
// where we fail here when they add/remove annotations
if(!optionsIn) return;
- var oldRef = {xref: optionsIn.xref, yref: optionsIn.yref};
-
// alter the input annotation as requested
var optionsEdit = {};
if(typeof opt === 'string' && opt) optionsEdit[opt] = value;
@@ -153,7 +153,11 @@ function drawOne(gd, index, opt, value) {
Lib.nestedProperty(optionsIn, k).set(optionsEdit[k]);
}
+ // return early in visible: false updates
+ if(optionsIn.visible === false) return;
+
var gs = fullLayout._size;
+ var oldRef = {xref: optionsIn.xref, yref: optionsIn.yref};
var axLetters = ['x', 'y'];
for(i = 0; i < 2; i++) {
diff --git a/src/components/images/attributes.js b/src/components/images/attributes.js
index a7f35575256..02d04a78297 100644
--- a/src/components/images/attributes.js
+++ b/src/components/images/attributes.js
@@ -14,6 +14,15 @@ var cartesianConstants = require('../../plots/cartesian/constants');
module.exports = {
_isLinkedToArray: true,
+ visible: {
+ valType: 'boolean',
+ role: 'info',
+ dflt: true,
+ description: [
+ 'Determines whether or not this image is visible.'
+ ].join(' ')
+ },
+
source: {
valType: 'string',
role: 'info',
diff --git a/src/components/images/defaults.js b/src/components/images/defaults.js
index 1be89b4f05a..3546d0f9d8a 100644
--- a/src/components/images/defaults.js
+++ b/src/components/images/defaults.js
@@ -12,36 +12,34 @@ var Axes = require('../../plots/cartesian/axes');
var Lib = require('../../lib');
var attributes = require('./attributes');
+var name = 'images';
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
+ var contIn = Array.isArray(layoutIn[name]) ? layoutIn[name] : [],
+ contOut = layoutOut[name] = [];
- if(!layoutIn.images || !Array.isArray(layoutIn.images)) return;
+ for(var i = 0; i < contIn.length; i++) {
+ var itemIn = contIn[i] || {},
+ itemOut = {};
+ imageDefaults(itemIn, itemOut, layoutOut);
- var containerIn = layoutIn.images,
- containerOut = layoutOut.images = [];
-
-
- for(var i = 0; i < containerIn.length; i++) {
- var image = containerIn[i];
-
- if(!image.source) continue;
-
- var defaulted = imageDefaults(containerIn[i] || {}, containerOut[i] || {}, layoutOut);
- containerOut.push(defaulted);
+ contOut.push(itemOut);
}
};
function imageDefaults(imageIn, imageOut, fullLayout) {
- imageOut = imageOut || {};
-
function coerce(attr, dflt) {
return Lib.coerce(imageIn, imageOut, attributes, attr, dflt);
}
- coerce('source');
+ var source = coerce('source');
+ var visible = coerce('visible', !!source);
+
+ if(!visible) return imageOut;
+
coerce('layer');
coerce('x');
coerce('y');
@@ -52,12 +50,12 @@ function imageDefaults(imageIn, imageOut, fullLayout) {
coerce('sizing');
coerce('opacity');
- for(var i = 0; i < 2; i++) {
- var tdMock = { _fullLayout: fullLayout },
- axLetter = ['x', 'y'][i];
+ var gdMock = { _fullLayout: fullLayout },
+ axLetters = ['x', 'y'];
+ for(var i = 0; i < 2; i++) {
// 'paper' is the fallback axref
- Axes.coerceRef(imageIn, imageOut, tdMock, axLetter, 'paper');
+ Axes.coerceRef(imageIn, imageOut, gdMock, axLetters[i], 'paper');
}
return imageOut;
diff --git a/src/components/images/draw.js b/src/components/images/draw.js
index a39a534adc2..b5ad8021558 100644
--- a/src/components/images/draw.js
+++ b/src/components/images/draw.js
@@ -14,25 +14,23 @@ var Axes = require('../../plots/cartesian/axes');
var xmlnsNamespaces = require('../../constants/xmlns_namespaces');
module.exports = function draw(gd) {
-
var fullLayout = gd._fullLayout,
imageDataAbove = [],
imageDataSubplot = [],
imageDataBelow = [];
- if(!fullLayout.images) return;
-
-
// Sort into top, subplot, and bottom layers
for(var i = 0; i < fullLayout.images.length; i++) {
var img = fullLayout.images[i];
- if(img.layer === 'below' && img.xref !== 'paper' && img.yref !== 'paper') {
- imageDataSubplot.push(img);
- } else if(img.layer === 'above') {
- imageDataAbove.push(img);
- } else {
- imageDataBelow.push(img);
+ if(img.visible) {
+ if(img.layer === 'below' && img.xref !== 'paper' && img.yref !== 'paper') {
+ imageDataSubplot.push(img);
+ } else if(img.layer === 'above') {
+ imageDataAbove.push(img);
+ } else {
+ imageDataBelow.push(img);
+ }
}
}
diff --git a/src/components/shapes/attributes.js b/src/components/shapes/attributes.js
index f90a218a4a4..446a2db51bc 100644
--- a/src/components/shapes/attributes.js
+++ b/src/components/shapes/attributes.js
@@ -17,6 +17,15 @@ var scatterLineAttrs = scatterAttrs.line;
module.exports = {
_isLinkedToArray: true,
+ visible: {
+ valType: 'boolean',
+ role: 'info',
+ dflt: true,
+ description: [
+ 'Determines whether or not this shape is visible.'
+ ].join(' ')
+ },
+
type: {
valType: 'enumerated',
values: ['circle', 'rect', 'path', 'line'],
diff --git a/src/components/shapes/calc_autorange.js b/src/components/shapes/calc_autorange.js
index 0aaaf499d13..a1d2ce0ba72 100644
--- a/src/components/shapes/calc_autorange.js
+++ b/src/components/shapes/calc_autorange.js
@@ -9,6 +9,7 @@
'use strict';
+var Lib = require('../../lib');
var Axes = require('../../plots/cartesian/axes');
var constants = require('./constants');
@@ -17,7 +18,7 @@ var helpers = require('./helpers');
module.exports = function calcAutorange(gd) {
var fullLayout = gd._fullLayout,
- shapeList = fullLayout.shapes;
+ shapeList = Lib.filterVisible(fullLayout.shapes);
if(!shapeList.length || !gd._fullData.length) return;
diff --git a/src/components/shapes/draw.js b/src/components/shapes/draw.js
index 7b5e67d99b7..487a44c4472 100644
--- a/src/components/shapes/draw.js
+++ b/src/components/shapes/draw.js
@@ -49,7 +49,9 @@ function draw(gd) {
fullLayout._shapeSubplotLayer.selectAll('path').remove();
for(var i = 0; i < fullLayout.shapes.length; i++) {
- drawOne(gd, i);
+ if(fullLayout.shapes[i].visible) {
+ drawOne(gd, i);
+ }
}
// may need to resurrect this if we put text (LaTeX) in shapes
@@ -169,8 +171,6 @@ function updateShape(gd, index, opt, value) {
// TODO: clean this up and remove it.
if(!optionsIn) return;
- var oldRef = {xref: optionsIn.xref, yref: optionsIn.yref};
-
// alter the input shape as requested
var optionsEdit = {};
if(typeof opt === 'string' && opt) optionsEdit[opt] = value;
@@ -182,7 +182,12 @@ function updateShape(gd, index, opt, value) {
Lib.nestedProperty(optionsIn, k).set(optionsEdit[k]);
}
- var posAttrs = ['x0', 'x1', 'y0', 'y1'];
+ // return early in visible: false updates
+ if(optionsIn.visible === false) return;
+
+ var oldRef = {xref: optionsIn.xref, yref: optionsIn.yref},
+ posAttrs = ['x0', 'x1', 'y0', 'y1'];
+
for(i = 0; i < 4; i++) {
var posAttr = posAttrs[i];
// if we don't have an explicit position already,
diff --git a/src/components/shapes/shape_defaults.js b/src/components/shapes/shape_defaults.js
index 88e4c98ba93..04f70fb30b6 100644
--- a/src/components/shapes/shape_defaults.js
+++ b/src/components/shapes/shape_defaults.js
@@ -22,6 +22,10 @@ module.exports = function handleShapeDefaults(shapeIn, fullLayout) {
return Lib.coerce(shapeIn, shapeOut, attributes, attr, dflt);
}
+ var visible = coerce('visible');
+
+ if(!visible) return shapeOut;
+
coerce('layer');
coerce('opacity');
coerce('fillcolor');
diff --git a/src/lib/filter_visible.js b/src/lib/filter_visible.js
index cfea8b73941..64dee017ba4 100644
--- a/src/lib/filter_visible.js
+++ b/src/lib/filter_visible.js
@@ -9,14 +9,21 @@
'use strict';
-module.exports = function filterVisible(dataIn) {
- var dataOut = [];
+/** Filter out object items with visible !== true
+ * insider array container.
+ *
+ * @param {array of objects} container
+ * @return {array of objects} of length <= container
+ *
+ */
+module.exports = function filterVisible(container) {
+ var out = [];
- for(var i = 0; i < dataIn.length; i++) {
- var trace = dataIn[i];
+ for(var i = 0; i < container.length; i++) {
+ var item = container[i];
- if(trace.visible === true) dataOut.push(trace);
+ if(item.visible === true) out.push(item);
}
- return dataOut;
+ return out;
};
diff --git a/src/lib/index.js b/src/lib/index.js
index 895dfde0bb9..27705ff8d8b 100644
--- a/src/lib/index.js
+++ b/src/lib/index.js
@@ -76,6 +76,8 @@ lib.error = loggersModule.error;
lib.notifier = require('./notifier');
lib.filterUnique = require('./filter_unique');
+lib.filterVisible = require('./filter_visible');
+
/**
* swap x and y of the same attribute in container cont
diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js
index cbb4ad51e10..c707886b07f 100644
--- a/src/plot_api/plot_api.js
+++ b/src/plot_api/plot_api.js
@@ -1917,13 +1917,14 @@ function _relayout(gd, aobj) {
objList = layout[objType] || [],
obji = objList[objNum] || {};
- // new API, remove annotation / shape with `null`
- if(vi === null) aobj[ai] = 'remove';
-
// if p.parts is just an annotation number, and val is either
// 'add' or an entire annotation to add, the undo is 'remove'
// if val is 'remove' then undo is the whole annotation object
if(p.parts.length === 2) {
+
+ // new API, remove annotation / shape with `null`
+ if(vi === null) aobj[ai] = 'remove';
+
if(aobj[ai] === 'add' || Lib.isPlainObject(aobj[ai])) {
undoit[ai] = 'remove';
}
diff --git a/src/plots/ternary/ternary.js b/src/plots/ternary/ternary.js
index 94cf5d7a8bf..cc832e45699 100644
--- a/src/plots/ternary/ternary.js
+++ b/src/plots/ternary/ternary.js
@@ -19,7 +19,6 @@ var Drawing = require('../../components/drawing');
var setConvert = require('../cartesian/set_convert');
var extendFlat = require('../../lib/extend').extendFlat;
var Axes = require('../cartesian/axes');
-var filterVisible = require('../../lib/filter_visible');
var dragElement = require('../../components/dragelement');
var Titles = require('../../components/titles');
var prepSelect = require('../cartesian/select');
@@ -94,7 +93,7 @@ proto.plot = function(ternaryData, fullLayout) {
var moduleData = traceHash[moduleNames[i]];
var _module = moduleData[0]._module;
- _module.plot(_this, filterVisible(moduleData), ternaryLayout);
+ _module.plot(_this, Lib.filterVisible(moduleData), ternaryLayout);
}
_this.traceHash = traceHash;
diff --git a/test/image/mocks/annotations.json b/test/image/mocks/annotations.json
index 9f88a7a5179..2bf9989b306 100644
--- a/test/image/mocks/annotations.json
+++ b/test/image/mocks/annotations.json
@@ -17,6 +17,7 @@
{"text":"right bottom","showarrow":false,"xref":"paper","yref":"paper","xanchor":"right","yanchor":"bottom","x":0.5,"y":1},
{"text":"move with page","xref":"paper","yref":"paper","x":0.75,"y":1},
{"text":"opacity","opacity":0.5,"x":5,"y":5},
+ {"text":"not-visible", "visible": false},
{"text":"left
justified","showarrow":false,"align":"left","x":1,"y":4},
{"text":"center
justified","showarrow":false,"x":2,"y":4},
{"text":"right
justified","showarrow":false,"align":"right","x":3,"y":4},
diff --git a/test/image/mocks/layout_image.json b/test/image/mocks/layout_image.json
index 67e9bcd1612..d993e8f61dd 100644
--- a/test/image/mocks/layout_image.json
+++ b/test/image/mocks/layout_image.json
@@ -51,6 +51,19 @@
"opacity": 0.4,
"layer": "below"
},
+ {
+ "visible": false,
+ "source": "https://images.plot.ly/language-icons/api-home/python-logo.png",
+ "xref": "x",
+ "yref": "y",
+ "x": 1,
+ "y": 3,
+ "sizex": 2,
+ "sizey": 2,
+ "sizing": "stretch",
+ "opacity": 0.4,
+ "layer": "below"
+ },
{
"source": "https://images.plot.ly/language-icons/api-home/matlab-logo.png",
"xref": "x",
diff --git a/test/image/mocks/shapes_below_traces.json b/test/image/mocks/shapes_below_traces.json
index 9758896af57..fe0bd8427b7 100644
--- a/test/image/mocks/shapes_below_traces.json
+++ b/test/image/mocks/shapes_below_traces.json
@@ -91,6 +91,7 @@
"y1": 1,
"yref": "paper"
},
+ { "visible": false },
{
"fillcolor": "#f6e8c3",
"layer": "below",
diff --git a/test/jasmine/tests/annotations_test.js b/test/jasmine/tests/annotations_test.js
index 72a7ab7675e..4816097dea5 100644
--- a/test/jasmine/tests/annotations_test.js
+++ b/test/jasmine/tests/annotations_test.js
@@ -6,6 +6,7 @@ var Lib = require('@src/lib');
var Dates = require('@src/lib/dates');
var d3 = require('d3');
+var customMatchers = require('../assets/custom_matchers');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
@@ -42,9 +43,11 @@ describe('annotations relayout', function() {
'use strict';
var mock = require('@mocks/annotations.json');
- var len = mock.layout.annotations.length;
var gd;
+ // there is 1 visible: false item
+ var len = mock.layout.annotations.length - 1;
+
beforeEach(function(done) {
gd = createGraphDiv();
@@ -68,16 +71,21 @@ describe('annotations relayout', function() {
Plotly.relayout(gd, 'annotations[' + len + ']', ann).then(function() {
expect(countAnnotations()).toEqual(len + 1);
- return Plotly.relayout(gd, 'annotations[' + 0 + ']', 'remove');
+ return Plotly.relayout(gd, 'annotations[0]', 'remove');
})
.then(function() {
expect(countAnnotations()).toEqual(len);
- return Plotly.relayout(gd, 'annotations[' + 0 + ']', null);
+ return Plotly.relayout(gd, 'annotations[0]', null);
})
.then(function() {
expect(countAnnotations()).toEqual(len - 1);
+ return Plotly.relayout(gd, 'annotations[0].visible', false);
+ })
+ .then(function() {
+ expect(countAnnotations()).toEqual(len - 2);
+
return Plotly.relayout(gd, { annotations: [] });
})
.then(function() {
@@ -86,4 +94,112 @@ describe('annotations relayout', function() {
done();
});
});
+
+ it('should be able update annotations', function(done) {
+
+ function assertText(index, expected) {
+ var query = '.annotation[data-index="' + index + '"]',
+ actual = d3.select(query).select('text').text();
+
+ expect(actual).toEqual(expected);
+ }
+
+ assertText(0, 'left top');
+
+ Plotly.relayout(gd, 'annotations[0].text', 'hello').then(function() {
+ assertText(0, 'hello');
+
+ return Plotly.relayout(gd, 'annotations[0].text', null);
+ })
+ .then(function() {
+ assertText(0, 'new text');
+ })
+ .then(done);
+
+ });
+});
+
+describe('annotations autosize', function() {
+ 'use strict';
+
+ var mock = Lib.extendDeep({}, require('@mocks/annotations-autorange.json'));
+ var gd;
+
+ beforeAll(function() {
+ jasmine.addMatchers(customMatchers);
+ });
+
+ afterEach(destroyGraphDiv);
+
+ it('should adapt to relayout calls', function(done) {
+ gd = createGraphDiv();
+
+ function assertRanges(x, y, x2, y2, x3, y3) {
+ var fullLayout = gd._fullLayout;
+ var PREC = 1;
+
+ // xaxis2 need a bit more tolerance to pass on CI
+ // this most likely due to the different text bounding box values
+ // on headfull vs headless browsers.
+ var PREC2 = 0.1;
+
+ expect(fullLayout.xaxis.range).toBeCloseToArray(x, PREC, '- xaxis');
+ expect(fullLayout.yaxis.range).toBeCloseToArray(y, PREC, '- yaxis');
+ expect(fullLayout.xaxis2.range).toBeCloseToArray(x2, PREC2, 'xaxis2');
+ expect(fullLayout.yaxis2.range).toBeCloseToArray(y2, PREC, 'yaxis2');
+ expect(fullLayout.xaxis3.range).toBeCloseToArray(x3, PREC, 'xaxis3');
+ expect(fullLayout.yaxis3.range).toBeCloseToArray(y3, PREC, 'yaxis3');
+ }
+
+ Plotly.plot(gd, mock).then(function() {
+ assertRanges(
+ [0.97, 2.03], [0.97, 2.03],
+ [-0.32, 3.38], [0.42, 2.58],
+ [0.9, 2.1], [0.86, 2.14]
+ );
+
+ return Plotly.relayout(gd, {
+ 'annotations[0].visible': false,
+ 'annotations[4].visible': false,
+ 'annotations[8].visible': false
+ });
+ })
+ .then(function() {
+ assertRanges(
+ [1.44, 2.02], [0.97, 2.03],
+ [1.31, 2.41], [0.42, 2.58],
+ [1.44, 2.1], [0.86, 2.14]
+ );
+
+ return Plotly.relayout(gd, {
+ 'annotations[2].visible': false,
+ 'annotations[5].visible': false,
+ 'annotations[9].visible': false
+ });
+ })
+ .then(function() {
+ assertRanges(
+ [1.44, 2.02], [0.99, 1.52],
+ [0.5, 2.5], [0.42, 2.58],
+ [0.5, 2.5], [0.86, 2.14]
+ );
+
+ return Plotly.relayout(gd, {
+ 'annotations[0].visible': true,
+ 'annotations[2].visible': true,
+ 'annotations[4].visible': true,
+ 'annotations[5].visible': true,
+ 'annotations[8].visible': true,
+ 'annotations[9].visible': true
+ });
+ })
+ .then(function() {
+ assertRanges(
+ [0.97, 2.03], [0.97, 2.03],
+ [-0.32, 3.38], [0.42, 2.58],
+ [0.9, 2.1], [0.86, 2.14]
+ );
+ })
+ .then(done);
+ });
});
diff --git a/test/jasmine/tests/layout_images_test.js b/test/jasmine/tests/layout_images_test.js
index b40999cfc1e..6aedc708425 100644
--- a/test/jasmine/tests/layout_images_test.js
+++ b/test/jasmine/tests/layout_images_test.js
@@ -27,7 +27,7 @@ describe('Layout images', function() {
Images.supplyLayoutDefaults(layoutIn, layoutOut);
- expect(layoutOut.images.length).toEqual(0);
+ expect(layoutOut.images).toEqual([{ visible: false }]);
});
it('should reject when not an array', function() {
@@ -40,7 +40,7 @@ describe('Layout images', function() {
Images.supplyLayoutDefaults(layoutIn, layoutOut);
- expect(layoutOut.images).not.toBeDefined();
+ expect(layoutOut.images).toEqual([]);
});
it('should coerce the correct defaults', function() {
@@ -48,6 +48,7 @@ describe('Layout images', function() {
var expected = {
source: jsLogo,
+ visible: true,
layer: 'above',
x: 0,
y: 0,
@@ -319,30 +320,48 @@ describe('Layout images', function() {
assertImages(0);
return Plotly.relayout(gd, 'images[0]', makeImage(jsLogo, 0.1, 0.1));
- }).then(function() {
+ })
+ .then(function() {
assertImages(1);
return Plotly.relayout(gd, 'images[1]', makeImage(pythonLogo, 0.9, 0.9));
- }).then(function() {
+ })
+ .then(function() {
assertImages(2);
return Plotly.relayout(gd, 'images[2]', makeImage(pythonLogo, 0.2, 0.5));
- }).then(function() {
+ })
+ .then(function() {
+ assertImages(3);
+ expect(gd.layout.images.length).toEqual(3);
+
+ return Plotly.relayout(gd, 'images[1].visible', false);
+ })
+ .then(function() {
+ assertImages(2);
+ expect(gd.layout.images.length).toEqual(3);
+
+ return Plotly.relayout(gd, 'images[1].visible', true);
+ })
+ .then(function() {
assertImages(3);
expect(gd.layout.images.length).toEqual(3);
return Plotly.relayout(gd, 'images[2]', null);
- }).then(function() {
+ })
+ .then(function() {
assertImages(2);
expect(gd.layout.images.length).toEqual(2);
return Plotly.relayout(gd, 'images[1]', null);
- }).then(function() {
+ })
+ .then(function() {
assertImages(1);
expect(gd.layout.images.length).toEqual(1);
return Plotly.relayout(gd, 'images[0]', null);
- }).then(function() {
+ })
+ .then(function() {
assertImages(0);
expect(gd.layout.images).toEqual([]);
diff --git a/test/jasmine/tests/shapes_test.js b/test/jasmine/tests/shapes_test.js
index 1eb8dab4ce1..c00f104a90d 100644
--- a/test/jasmine/tests/shapes_test.js
+++ b/test/jasmine/tests/shapes_test.js
@@ -7,6 +7,7 @@ var Lib = require('@src/lib');
var Axes = PlotlyInternal.Axes;
var d3 = require('d3');
+var customMatchers = require('../assets/custom_matchers');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
@@ -183,18 +184,23 @@ describe('Test shapes:', function() {
expect(countShapePathsInUpperLayer()).toEqual(pathCount + 1);
expect(getLastShape(gd)).toEqual(shape);
expect(countShapes(gd)).toEqual(index + 1);
- })
- .then(function() {
+
return Plotly.relayout(gd, 'shapes[' + index + ']', 'remove');
})
.then(function() {
expect(countShapePathsInUpperLayer()).toEqual(pathCount);
expect(countShapes(gd)).toEqual(index);
- return Plotly.relayout(gd, 'shapes[' + 1 + ']', null);
+ return Plotly.relayout(gd, 'shapes[2].visible', false);
})
.then(function() {
expect(countShapePathsInUpperLayer()).toEqual(pathCount - 1);
+ expect(countShapes(gd)).toEqual(index);
+
+ return Plotly.relayout(gd, 'shapes[1]', null);
+ })
+ .then(function() {
+ expect(countShapePathsInUpperLayer()).toEqual(pathCount - 2);
expect(countShapes(gd)).toEqual(index - 1);
})
.then(done);
@@ -250,6 +256,69 @@ describe('Test shapes:', function() {
});
});
+describe('shapes autosize', function() {
+ 'use strict';
+
+ var gd;
+
+ beforeAll(function() {
+ jasmine.addMatchers(customMatchers);
+ });
+
+ afterEach(destroyGraphDiv);
+
+ it('should adapt to relayout calls', function(done) {
+ gd = createGraphDiv();
+
+ var mock = {
+ data: [{}],
+ layout: {
+ shapes: [{
+ type: 'line',
+ x0: 0,
+ y0: 0,
+ x1: 1,
+ y1: 1
+ }, {
+ type: 'line',
+ x0: 0,
+ y0: 0,
+ x1: 2,
+ y1: 2
+ }]
+ }
+ };
+
+ function assertRanges(x, y) {
+ var fullLayout = gd._fullLayout;
+ var PREC = 1;
+
+ expect(fullLayout.xaxis.range).toBeCloseToArray(x, PREC, '- xaxis');
+ expect(fullLayout.yaxis.range).toBeCloseToArray(y, PREC, '- yaxis');
+ }
+
+ Plotly.plot(gd, mock).then(function() {
+ assertRanges([0, 2], [0, 2]);
+
+ return Plotly.relayout(gd, { 'shapes[1].visible': false });
+ })
+ .then(function() {
+ assertRanges([0, 1], [0, 1]);
+
+ return Plotly.relayout(gd, { 'shapes[1].visible': true });
+ })
+ .then(function() {
+ assertRanges([0, 2], [0, 2]);
+
+ return Plotly.relayout(gd, { 'shapes[0].x1': 3 });
+ })
+ .then(function() {
+ assertRanges([0, 3], [0, 2]);
+ })
+ .then(done);
+ });
+});
+
describe('Test shapes: a plot with shapes and an overlaid axis', function() {
'use strict';