Skip to content

Commit 38aa4b3

Browse files
authoredNov 7, 2016
Merge pull request #1110 from plotly/annotations-shape-visible
Add `visible` attribute to layout container items.
2 parents 8745a22 + 328a6ca commit 38aa4b3

21 files changed

+332
-63
lines changed
 

‎src/components/annotations/annotation_defaults.js

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ module.exports = function handleAnnotationDefaults(annIn, fullLayout) {
2323
return Lib.coerce(annIn, annOut, attributes, attr, dflt);
2424
}
2525

26+
var visible = coerce('visible');
27+
28+
if(!visible) return annOut;
29+
2630
coerce('opacity');
2731
coerce('align');
2832
coerce('bgcolor');

‎src/components/annotations/attributes.js

+9
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ var extendFlat = require('../../lib/extend').extendFlat;
1717
module.exports = {
1818
_isLinkedToArray: true,
1919

20+
visible: {
21+
valType: 'boolean',
22+
role: 'info',
23+
dflt: true,
24+
description: [
25+
'Determines whether or not this annotation is visible.'
26+
].join(' ')
27+
},
28+
2029
text: {
2130
valType: 'string',
2231
role: 'info',

‎src/components/annotations/calc_autorange.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var draw = require('./draw').draw;
1717

1818
module.exports = function calcAutorange(gd) {
1919
var fullLayout = gd._fullLayout,
20-
annotationList = fullLayout.annotations;
20+
annotationList = Lib.filterVisible(fullLayout.annotations);
2121

2222
if(!annotationList.length || !gd._fullData.length) return;
2323

‎src/components/annotations/draw.js

+7-3
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ function draw(gd) {
4747
fullLayout._infolayer.selectAll('.annotation').remove();
4848

4949
for(var i = 0; i < fullLayout.annotations.length; i++) {
50-
drawOne(gd, i);
50+
if(fullLayout.annotations[i].visible) {
51+
drawOne(gd, i);
52+
}
5153
}
5254

5355
return Plots.previousPromises(gd);
@@ -140,8 +142,6 @@ function drawOne(gd, index, opt, value) {
140142
// where we fail here when they add/remove annotations
141143
if(!optionsIn) return;
142144

143-
var oldRef = {xref: optionsIn.xref, yref: optionsIn.yref};
144-
145145
// alter the input annotation as requested
146146
var optionsEdit = {};
147147
if(typeof opt === 'string' && opt) optionsEdit[opt] = value;
@@ -153,7 +153,11 @@ function drawOne(gd, index, opt, value) {
153153
Lib.nestedProperty(optionsIn, k).set(optionsEdit[k]);
154154
}
155155

156+
// return early in visible: false updates
157+
if(optionsIn.visible === false) return;
158+
156159
var gs = fullLayout._size;
160+
var oldRef = {xref: optionsIn.xref, yref: optionsIn.yref};
157161

158162
var axLetters = ['x', 'y'];
159163
for(i = 0; i < 2; i++) {

‎src/components/images/attributes.js

+9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@ var cartesianConstants = require('../../plots/cartesian/constants');
1414
module.exports = {
1515
_isLinkedToArray: true,
1616

17+
visible: {
18+
valType: 'boolean',
19+
role: 'info',
20+
dflt: true,
21+
description: [
22+
'Determines whether or not this image is visible.'
23+
].join(' ')
24+
},
25+
1726
source: {
1827
valType: 'string',
1928
role: 'info',

‎src/components/images/defaults.js

+17-19
Original file line numberDiff line numberDiff line change
@@ -12,36 +12,34 @@ var Axes = require('../../plots/cartesian/axes');
1212
var Lib = require('../../lib');
1313
var attributes = require('./attributes');
1414

15+
var name = 'images';
1516

1617
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
18+
var contIn = Array.isArray(layoutIn[name]) ? layoutIn[name] : [],
19+
contOut = layoutOut[name] = [];
1720

18-
if(!layoutIn.images || !Array.isArray(layoutIn.images)) return;
21+
for(var i = 0; i < contIn.length; i++) {
22+
var itemIn = contIn[i] || {},
23+
itemOut = {};
1924

25+
imageDefaults(itemIn, itemOut, layoutOut);
2026

21-
var containerIn = layoutIn.images,
22-
containerOut = layoutOut.images = [];
23-
24-
25-
for(var i = 0; i < containerIn.length; i++) {
26-
var image = containerIn[i];
27-
28-
if(!image.source) continue;
29-
30-
var defaulted = imageDefaults(containerIn[i] || {}, containerOut[i] || {}, layoutOut);
31-
containerOut.push(defaulted);
27+
contOut.push(itemOut);
3228
}
3329
};
3430

3531

3632
function imageDefaults(imageIn, imageOut, fullLayout) {
3733

38-
imageOut = imageOut || {};
39-
4034
function coerce(attr, dflt) {
4135
return Lib.coerce(imageIn, imageOut, attributes, attr, dflt);
4236
}
4337

44-
coerce('source');
38+
var source = coerce('source');
39+
var visible = coerce('visible', !!source);
40+
41+
if(!visible) return imageOut;
42+
4543
coerce('layer');
4644
coerce('x');
4745
coerce('y');
@@ -52,12 +50,12 @@ function imageDefaults(imageIn, imageOut, fullLayout) {
5250
coerce('sizing');
5351
coerce('opacity');
5452

55-
for(var i = 0; i < 2; i++) {
56-
var tdMock = { _fullLayout: fullLayout },
57-
axLetter = ['x', 'y'][i];
53+
var gdMock = { _fullLayout: fullLayout },
54+
axLetters = ['x', 'y'];
5855

56+
for(var i = 0; i < 2; i++) {
5957
// 'paper' is the fallback axref
60-
Axes.coerceRef(imageIn, imageOut, tdMock, axLetter, 'paper');
58+
Axes.coerceRef(imageIn, imageOut, gdMock, axLetters[i], 'paper');
6159
}
6260

6361
return imageOut;

‎src/components/images/draw.js

+8-10
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,23 @@ var Axes = require('../../plots/cartesian/axes');
1414
var xmlnsNamespaces = require('../../constants/xmlns_namespaces');
1515

1616
module.exports = function draw(gd) {
17-
1817
var fullLayout = gd._fullLayout,
1918
imageDataAbove = [],
2019
imageDataSubplot = [],
2120
imageDataBelow = [];
2221

23-
if(!fullLayout.images) return;
24-
25-
2622
// Sort into top, subplot, and bottom layers
2723
for(var i = 0; i < fullLayout.images.length; i++) {
2824
var img = fullLayout.images[i];
2925

30-
if(img.layer === 'below' && img.xref !== 'paper' && img.yref !== 'paper') {
31-
imageDataSubplot.push(img);
32-
} else if(img.layer === 'above') {
33-
imageDataAbove.push(img);
34-
} else {
35-
imageDataBelow.push(img);
26+
if(img.visible) {
27+
if(img.layer === 'below' && img.xref !== 'paper' && img.yref !== 'paper') {
28+
imageDataSubplot.push(img);
29+
} else if(img.layer === 'above') {
30+
imageDataAbove.push(img);
31+
} else {
32+
imageDataBelow.push(img);
33+
}
3634
}
3735
}
3836

‎src/components/shapes/attributes.js

+9
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ var scatterLineAttrs = scatterAttrs.line;
1717
module.exports = {
1818
_isLinkedToArray: true,
1919

20+
visible: {
21+
valType: 'boolean',
22+
role: 'info',
23+
dflt: true,
24+
description: [
25+
'Determines whether or not this shape is visible.'
26+
].join(' ')
27+
},
28+
2029
type: {
2130
valType: 'enumerated',
2231
values: ['circle', 'rect', 'path', 'line'],

‎src/components/shapes/calc_autorange.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
'use strict';
1111

12+
var Lib = require('../../lib');
1213
var Axes = require('../../plots/cartesian/axes');
1314

1415
var constants = require('./constants');
@@ -17,7 +18,7 @@ var helpers = require('./helpers');
1718

1819
module.exports = function calcAutorange(gd) {
1920
var fullLayout = gd._fullLayout,
20-
shapeList = fullLayout.shapes;
21+
shapeList = Lib.filterVisible(fullLayout.shapes);
2122

2223
if(!shapeList.length || !gd._fullData.length) return;
2324

‎src/components/shapes/draw.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ function draw(gd) {
4949
fullLayout._shapeSubplotLayer.selectAll('path').remove();
5050

5151
for(var i = 0; i < fullLayout.shapes.length; i++) {
52-
drawOne(gd, i);
52+
if(fullLayout.shapes[i].visible) {
53+
drawOne(gd, i);
54+
}
5355
}
5456

5557
// may need to resurrect this if we put text (LaTeX) in shapes
@@ -169,8 +171,6 @@ function updateShape(gd, index, opt, value) {
169171
// TODO: clean this up and remove it.
170172
if(!optionsIn) return;
171173

172-
var oldRef = {xref: optionsIn.xref, yref: optionsIn.yref};
173-
174174
// alter the input shape as requested
175175
var optionsEdit = {};
176176
if(typeof opt === 'string' && opt) optionsEdit[opt] = value;
@@ -182,7 +182,12 @@ function updateShape(gd, index, opt, value) {
182182
Lib.nestedProperty(optionsIn, k).set(optionsEdit[k]);
183183
}
184184

185-
var posAttrs = ['x0', 'x1', 'y0', 'y1'];
185+
// return early in visible: false updates
186+
if(optionsIn.visible === false) return;
187+
188+
var oldRef = {xref: optionsIn.xref, yref: optionsIn.yref},
189+
posAttrs = ['x0', 'x1', 'y0', 'y1'];
190+
186191
for(i = 0; i < 4; i++) {
187192
var posAttr = posAttrs[i];
188193
// if we don't have an explicit position already,

‎src/components/shapes/shape_defaults.js

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ module.exports = function handleShapeDefaults(shapeIn, fullLayout) {
2222
return Lib.coerce(shapeIn, shapeOut, attributes, attr, dflt);
2323
}
2424

25+
var visible = coerce('visible');
26+
27+
if(!visible) return shapeOut;
28+
2529
coerce('layer');
2630
coerce('opacity');
2731
coerce('fillcolor');

‎src/lib/filter_visible.js

+13-6
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,21 @@
99

1010
'use strict';
1111

12-
module.exports = function filterVisible(dataIn) {
13-
var dataOut = [];
12+
/** Filter out object items with visible !== true
13+
* insider array container.
14+
*
15+
* @param {array of objects} container
16+
* @return {array of objects} of length <= container
17+
*
18+
*/
19+
module.exports = function filterVisible(container) {
20+
var out = [];
1421

15-
for(var i = 0; i < dataIn.length; i++) {
16-
var trace = dataIn[i];
22+
for(var i = 0; i < container.length; i++) {
23+
var item = container[i];
1724

18-
if(trace.visible === true) dataOut.push(trace);
25+
if(item.visible === true) out.push(item);
1926
}
2027

21-
return dataOut;
28+
return out;
2229
};

‎src/lib/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ lib.error = loggersModule.error;
7676
lib.notifier = require('./notifier');
7777

7878
lib.filterUnique = require('./filter_unique');
79+
lib.filterVisible = require('./filter_visible');
80+
7981

8082
/**
8183
* swap x and y of the same attribute in container cont

‎src/plot_api/plot_api.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -1917,13 +1917,14 @@ function _relayout(gd, aobj) {
19171917
objList = layout[objType] || [],
19181918
obji = objList[objNum] || {};
19191919

1920-
// new API, remove annotation / shape with `null`
1921-
if(vi === null) aobj[ai] = 'remove';
1922-
19231920
// if p.parts is just an annotation number, and val is either
19241921
// 'add' or an entire annotation to add, the undo is 'remove'
19251922
// if val is 'remove' then undo is the whole annotation object
19261923
if(p.parts.length === 2) {
1924+
1925+
// new API, remove annotation / shape with `null`
1926+
if(vi === null) aobj[ai] = 'remove';
1927+
19271928
if(aobj[ai] === 'add' || Lib.isPlainObject(aobj[ai])) {
19281929
undoit[ai] = 'remove';
19291930
}

‎src/plots/ternary/ternary.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ var Drawing = require('../../components/drawing');
1919
var setConvert = require('../cartesian/set_convert');
2020
var extendFlat = require('../../lib/extend').extendFlat;
2121
var Axes = require('../cartesian/axes');
22-
var filterVisible = require('../../lib/filter_visible');
2322
var dragElement = require('../../components/dragelement');
2423
var Titles = require('../../components/titles');
2524
var prepSelect = require('../cartesian/select');
@@ -94,7 +93,7 @@ proto.plot = function(ternaryData, fullLayout) {
9493
var moduleData = traceHash[moduleNames[i]];
9594
var _module = moduleData[0]._module;
9695

97-
_module.plot(_this, filterVisible(moduleData), ternaryLayout);
96+
_module.plot(_this, Lib.filterVisible(moduleData), ternaryLayout);
9897
}
9998

10099
_this.traceHash = traceHash;

‎test/image/mocks/annotations.json

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
{"text":"right bottom","showarrow":false,"xref":"paper","yref":"paper","xanchor":"right","yanchor":"bottom","x":0.5,"y":1},
1818
{"text":"move with page","xref":"paper","yref":"paper","x":0.75,"y":1},
1919
{"text":"opacity","opacity":0.5,"x":5,"y":5},
20+
{"text":"not-visible", "visible": false},
2021
{"text":"left<br>justified","showarrow":false,"align":"left","x":1,"y":4},
2122
{"text":"center<br>justified","showarrow":false,"x":2,"y":4},
2223
{"text":"right<br>justified","showarrow":false,"align":"right","x":3,"y":4},

‎test/image/mocks/layout_image.json

+13
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,19 @@
5151
"opacity": 0.4,
5252
"layer": "below"
5353
},
54+
{
55+
"visible": false,
56+
"source": "https://images.plot.ly/language-icons/api-home/python-logo.png",
57+
"xref": "x",
58+
"yref": "y",
59+
"x": 1,
60+
"y": 3,
61+
"sizex": 2,
62+
"sizey": 2,
63+
"sizing": "stretch",
64+
"opacity": 0.4,
65+
"layer": "below"
66+
},
5467
{
5568
"source": "https://images.plot.ly/language-icons/api-home/matlab-logo.png",
5669
"xref": "x",

‎test/image/mocks/shapes_below_traces.json

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
"y1": 1,
9292
"yref": "paper"
9393
},
94+
{ "visible": false },
9495
{
9596
"fillcolor": "#f6e8c3",
9697
"layer": "below",

‎test/jasmine/tests/annotations_test.js

+119-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ var Lib = require('@src/lib');
66
var Dates = require('@src/lib/dates');
77

88
var d3 = require('d3');
9+
var customMatchers = require('../assets/custom_matchers');
910
var createGraphDiv = require('../assets/create_graph_div');
1011
var destroyGraphDiv = require('../assets/destroy_graph_div');
1112

@@ -42,9 +43,11 @@ describe('annotations relayout', function() {
4243
'use strict';
4344

4445
var mock = require('@mocks/annotations.json');
45-
var len = mock.layout.annotations.length;
4646
var gd;
4747

48+
// there is 1 visible: false item
49+
var len = mock.layout.annotations.length - 1;
50+
4851
beforeEach(function(done) {
4952
gd = createGraphDiv();
5053

@@ -68,16 +71,21 @@ describe('annotations relayout', function() {
6871
Plotly.relayout(gd, 'annotations[' + len + ']', ann).then(function() {
6972
expect(countAnnotations()).toEqual(len + 1);
7073

71-
return Plotly.relayout(gd, 'annotations[' + 0 + ']', 'remove');
74+
return Plotly.relayout(gd, 'annotations[0]', 'remove');
7275
})
7376
.then(function() {
7477
expect(countAnnotations()).toEqual(len);
7578

76-
return Plotly.relayout(gd, 'annotations[' + 0 + ']', null);
79+
return Plotly.relayout(gd, 'annotations[0]', null);
7780
})
7881
.then(function() {
7982
expect(countAnnotations()).toEqual(len - 1);
8083

84+
return Plotly.relayout(gd, 'annotations[0].visible', false);
85+
})
86+
.then(function() {
87+
expect(countAnnotations()).toEqual(len - 2);
88+
8189
return Plotly.relayout(gd, { annotations: [] });
8290
})
8391
.then(function() {
@@ -86,4 +94,112 @@ describe('annotations relayout', function() {
8694
done();
8795
});
8896
});
97+
98+
it('should be able update annotations', function(done) {
99+
100+
function assertText(index, expected) {
101+
var query = '.annotation[data-index="' + index + '"]',
102+
actual = d3.select(query).select('text').text();
103+
104+
expect(actual).toEqual(expected);
105+
}
106+
107+
assertText(0, 'left top');
108+
109+
Plotly.relayout(gd, 'annotations[0].text', 'hello').then(function() {
110+
assertText(0, 'hello');
111+
112+
return Plotly.relayout(gd, 'annotations[0].text', null);
113+
})
114+
.then(function() {
115+
assertText(0, 'new text');
116+
})
117+
.then(done);
118+
119+
});
120+
});
121+
122+
describe('annotations autosize', function() {
123+
'use strict';
124+
125+
var mock = Lib.extendDeep({}, require('@mocks/annotations-autorange.json'));
126+
var gd;
127+
128+
beforeAll(function() {
129+
jasmine.addMatchers(customMatchers);
130+
});
131+
132+
afterEach(destroyGraphDiv);
133+
134+
it('should adapt to relayout calls', function(done) {
135+
gd = createGraphDiv();
136+
137+
function assertRanges(x, y, x2, y2, x3, y3) {
138+
var fullLayout = gd._fullLayout;
139+
var PREC = 1;
140+
141+
// xaxis2 need a bit more tolerance to pass on CI
142+
// this most likely due to the different text bounding box values
143+
// on headfull vs headless browsers.
144+
var PREC2 = 0.1;
145+
146+
expect(fullLayout.xaxis.range).toBeCloseToArray(x, PREC, '- xaxis');
147+
expect(fullLayout.yaxis.range).toBeCloseToArray(y, PREC, '- yaxis');
148+
expect(fullLayout.xaxis2.range).toBeCloseToArray(x2, PREC2, 'xaxis2');
149+
expect(fullLayout.yaxis2.range).toBeCloseToArray(y2, PREC, 'yaxis2');
150+
expect(fullLayout.xaxis3.range).toBeCloseToArray(x3, PREC, 'xaxis3');
151+
expect(fullLayout.yaxis3.range).toBeCloseToArray(y3, PREC, 'yaxis3');
152+
}
153+
154+
Plotly.plot(gd, mock).then(function() {
155+
assertRanges(
156+
[0.97, 2.03], [0.97, 2.03],
157+
[-0.32, 3.38], [0.42, 2.58],
158+
[0.9, 2.1], [0.86, 2.14]
159+
);
160+
161+
return Plotly.relayout(gd, {
162+
'annotations[0].visible': false,
163+
'annotations[4].visible': false,
164+
'annotations[8].visible': false
165+
});
166+
})
167+
.then(function() {
168+
assertRanges(
169+
[1.44, 2.02], [0.97, 2.03],
170+
[1.31, 2.41], [0.42, 2.58],
171+
[1.44, 2.1], [0.86, 2.14]
172+
);
173+
174+
return Plotly.relayout(gd, {
175+
'annotations[2].visible': false,
176+
'annotations[5].visible': false,
177+
'annotations[9].visible': false
178+
});
179+
})
180+
.then(function() {
181+
assertRanges(
182+
[1.44, 2.02], [0.99, 1.52],
183+
[0.5, 2.5], [0.42, 2.58],
184+
[0.5, 2.5], [0.86, 2.14]
185+
);
186+
187+
return Plotly.relayout(gd, {
188+
'annotations[0].visible': true,
189+
'annotations[2].visible': true,
190+
'annotations[4].visible': true,
191+
'annotations[5].visible': true,
192+
'annotations[8].visible': true,
193+
'annotations[9].visible': true
194+
});
195+
})
196+
.then(function() {
197+
assertRanges(
198+
[0.97, 2.03], [0.97, 2.03],
199+
[-0.32, 3.38], [0.42, 2.58],
200+
[0.9, 2.1], [0.86, 2.14]
201+
);
202+
})
203+
.then(done);
204+
});
89205
});

‎test/jasmine/tests/layout_images_test.js

+27-8
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ describe('Layout images', function() {
2727

2828
Images.supplyLayoutDefaults(layoutIn, layoutOut);
2929

30-
expect(layoutOut.images.length).toEqual(0);
30+
expect(layoutOut.images).toEqual([{ visible: false }]);
3131
});
3232

3333
it('should reject when not an array', function() {
@@ -40,14 +40,15 @@ describe('Layout images', function() {
4040

4141
Images.supplyLayoutDefaults(layoutIn, layoutOut);
4242

43-
expect(layoutOut.images).not.toBeDefined();
43+
expect(layoutOut.images).toEqual([]);
4444
});
4545

4646
it('should coerce the correct defaults', function() {
4747
layoutIn.images[0] = { source: jsLogo };
4848

4949
var expected = {
5050
source: jsLogo,
51+
visible: true,
5152
layer: 'above',
5253
x: 0,
5354
y: 0,
@@ -319,30 +320,48 @@ describe('Layout images', function() {
319320
assertImages(0);
320321

321322
return Plotly.relayout(gd, 'images[0]', makeImage(jsLogo, 0.1, 0.1));
322-
}).then(function() {
323+
})
324+
.then(function() {
323325
assertImages(1);
324326

325327
return Plotly.relayout(gd, 'images[1]', makeImage(pythonLogo, 0.9, 0.9));
326-
}).then(function() {
328+
})
329+
.then(function() {
327330
assertImages(2);
328331

329332
return Plotly.relayout(gd, 'images[2]', makeImage(pythonLogo, 0.2, 0.5));
330-
}).then(function() {
333+
})
334+
.then(function() {
335+
assertImages(3);
336+
expect(gd.layout.images.length).toEqual(3);
337+
338+
return Plotly.relayout(gd, 'images[1].visible', false);
339+
})
340+
.then(function() {
341+
assertImages(2);
342+
expect(gd.layout.images.length).toEqual(3);
343+
344+
return Plotly.relayout(gd, 'images[1].visible', true);
345+
})
346+
.then(function() {
331347
assertImages(3);
332348
expect(gd.layout.images.length).toEqual(3);
333349

334350
return Plotly.relayout(gd, 'images[2]', null);
335-
}).then(function() {
351+
})
352+
.then(function() {
336353
assertImages(2);
337354
expect(gd.layout.images.length).toEqual(2);
338355

339356
return Plotly.relayout(gd, 'images[1]', null);
340-
}).then(function() {
357+
})
358+
.then(function() {
341359
assertImages(1);
342360
expect(gd.layout.images.length).toEqual(1);
343361

344362
return Plotly.relayout(gd, 'images[0]', null);
345-
}).then(function() {
363+
})
364+
.then(function() {
346365
assertImages(0);
347366
expect(gd.layout.images).toEqual([]);
348367

‎test/jasmine/tests/shapes_test.js

+72-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var Lib = require('@src/lib');
77
var Axes = PlotlyInternal.Axes;
88

99
var d3 = require('d3');
10+
var customMatchers = require('../assets/custom_matchers');
1011
var createGraphDiv = require('../assets/create_graph_div');
1112
var destroyGraphDiv = require('../assets/destroy_graph_div');
1213

@@ -183,18 +184,23 @@ describe('Test shapes:', function() {
183184
expect(countShapePathsInUpperLayer()).toEqual(pathCount + 1);
184185
expect(getLastShape(gd)).toEqual(shape);
185186
expect(countShapes(gd)).toEqual(index + 1);
186-
})
187-
.then(function() {
187+
188188
return Plotly.relayout(gd, 'shapes[' + index + ']', 'remove');
189189
})
190190
.then(function() {
191191
expect(countShapePathsInUpperLayer()).toEqual(pathCount);
192192
expect(countShapes(gd)).toEqual(index);
193193

194-
return Plotly.relayout(gd, 'shapes[' + 1 + ']', null);
194+
return Plotly.relayout(gd, 'shapes[2].visible', false);
195195
})
196196
.then(function() {
197197
expect(countShapePathsInUpperLayer()).toEqual(pathCount - 1);
198+
expect(countShapes(gd)).toEqual(index);
199+
200+
return Plotly.relayout(gd, 'shapes[1]', null);
201+
})
202+
.then(function() {
203+
expect(countShapePathsInUpperLayer()).toEqual(pathCount - 2);
198204
expect(countShapes(gd)).toEqual(index - 1);
199205
})
200206
.then(done);
@@ -250,6 +256,69 @@ describe('Test shapes:', function() {
250256
});
251257
});
252258

259+
describe('shapes autosize', function() {
260+
'use strict';
261+
262+
var gd;
263+
264+
beforeAll(function() {
265+
jasmine.addMatchers(customMatchers);
266+
});
267+
268+
afterEach(destroyGraphDiv);
269+
270+
it('should adapt to relayout calls', function(done) {
271+
gd = createGraphDiv();
272+
273+
var mock = {
274+
data: [{}],
275+
layout: {
276+
shapes: [{
277+
type: 'line',
278+
x0: 0,
279+
y0: 0,
280+
x1: 1,
281+
y1: 1
282+
}, {
283+
type: 'line',
284+
x0: 0,
285+
y0: 0,
286+
x1: 2,
287+
y1: 2
288+
}]
289+
}
290+
};
291+
292+
function assertRanges(x, y) {
293+
var fullLayout = gd._fullLayout;
294+
var PREC = 1;
295+
296+
expect(fullLayout.xaxis.range).toBeCloseToArray(x, PREC, '- xaxis');
297+
expect(fullLayout.yaxis.range).toBeCloseToArray(y, PREC, '- yaxis');
298+
}
299+
300+
Plotly.plot(gd, mock).then(function() {
301+
assertRanges([0, 2], [0, 2]);
302+
303+
return Plotly.relayout(gd, { 'shapes[1].visible': false });
304+
})
305+
.then(function() {
306+
assertRanges([0, 1], [0, 1]);
307+
308+
return Plotly.relayout(gd, { 'shapes[1].visible': true });
309+
})
310+
.then(function() {
311+
assertRanges([0, 2], [0, 2]);
312+
313+
return Plotly.relayout(gd, { 'shapes[0].x1': 3 });
314+
})
315+
.then(function() {
316+
assertRanges([0, 3], [0, 2]);
317+
})
318+
.then(done);
319+
});
320+
});
321+
253322
describe('Test shapes: a plot with shapes and an overlaid axis', function() {
254323
'use strict';
255324

0 commit comments

Comments
 (0)
Please sign in to comment.