Skip to content

Commit 2897167

Browse files
authored
Merge pull request #1118 from plotly/frame-extend-with-nulls
Make frame with nulls clear items & array containers
2 parents 88dbc9d + 5de6ff0 commit 2897167

19 files changed

+398
-104
lines changed

src/components/annotations/annotation_defaults.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ var Axes = require('../../plots/cartesian/axes');
1616
var attributes = require('./attributes');
1717

1818

19-
module.exports = function handleAnnotationDefaults(annIn, fullLayout) {
20-
var annOut = {};
19+
module.exports = function handleAnnotationDefaults(annIn, annOut, fullLayout, opts, itemOpts) {
20+
opts = opts || {};
21+
itemOpts = itemOpts || {};
2122

2223
function coerce(attr, dflt) {
2324
return Lib.coerce(annIn, annOut, attributes, attr, dflt);
2425
}
2526

26-
var visible = coerce('visible');
27+
var visible = coerce('visible', !itemOpts.itemIsNotPlainObject);
2728

2829
if(!visible) return annOut;
2930

src/components/annotations/defaults.js

+6-8
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,15 @@
99

1010
'use strict';
1111

12+
var handleArrayContainerDefaults = require('../../plots/array_container_defaults');
1213
var handleAnnotationDefaults = require('./annotation_defaults');
1314

1415

1516
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
16-
var containerIn = layoutIn.annotations || [],
17-
containerOut = layoutOut.annotations = [];
17+
var opts = {
18+
name: 'annotations',
19+
handleItemDefaults: handleAnnotationDefaults
20+
};
1821

19-
for(var i = 0; i < containerIn.length; i++) {
20-
var annIn = containerIn[i] || {},
21-
annOut = handleAnnotationDefaults(annIn, layoutOut);
22-
23-
containerOut.push(annOut);
24-
}
22+
handleArrayContainerDefaults(layoutIn, layoutOut, opts);
2523
};

src/components/annotations/draw.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ function drawOne(gd, index, opt, value) {
242242
optionsIn[axLetter] = position;
243243
}
244244

245-
var options = handleAnnotationDefaults(optionsIn, fullLayout);
245+
var options = {};
246+
handleAnnotationDefaults(optionsIn, options, fullLayout);
246247
fullLayout.annotations[index] = options;
247248

248249
var xa = Axes.getFromId(gd, options.xref),

src/components/images/defaults.js

+8-12
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,20 @@
88

99
'use strict';
1010

11-
var Axes = require('../../plots/cartesian/axes');
1211
var Lib = require('../../lib');
13-
var attributes = require('./attributes');
12+
var Axes = require('../../plots/cartesian/axes');
13+
var handleArrayContainerDefaults = require('../../plots/array_container_defaults');
1414

15+
var attributes = require('./attributes');
1516
var name = 'images';
1617

1718
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
18-
var contIn = Array.isArray(layoutIn[name]) ? layoutIn[name] : [],
19-
contOut = layoutOut[name] = [];
19+
var opts = {
20+
name: name,
21+
handleItemDefaults: imageDefaults
22+
};
2023

21-
for(var i = 0; i < contIn.length; i++) {
22-
var itemIn = contIn[i] || {},
23-
itemOut = {};
24-
25-
imageDefaults(itemIn, itemOut, layoutOut);
26-
27-
contOut.push(itemOut);
28-
}
24+
handleArrayContainerDefaults(layoutIn, layoutOut, opts);
2925
};
3026

3127

src/components/shapes/defaults.js

+6-8
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,15 @@
99

1010
'use strict';
1111

12+
var handleArrayContainerDefaults = require('../../plots/array_container_defaults');
1213
var handleShapeDefaults = require('./shape_defaults');
1314

1415

1516
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
16-
var containerIn = layoutIn.shapes || [],
17-
containerOut = layoutOut.shapes = [];
17+
var opts = {
18+
name: 'shapes',
19+
handleItemDefaults: handleShapeDefaults
20+
};
1821

19-
for(var i = 0; i < containerIn.length; i++) {
20-
var shapeIn = containerIn[i] || {},
21-
shapeOut = handleShapeDefaults(shapeIn, layoutOut);
22-
23-
containerOut.push(shapeOut);
24-
}
22+
handleArrayContainerDefaults(layoutIn, layoutOut, opts);
2523
};

src/components/shapes/draw.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,8 @@ function updateShape(gd, index, opt, value) {
232232
optionsIn[posAttr] = position;
233233
}
234234

235-
var options = handleShapeDefaults(optionsIn, gd._fullLayout);
235+
var options = {};
236+
handleShapeDefaults(optionsIn, options, gd._fullLayout);
236237
gd._fullLayout.shapes[index] = options;
237238

238239
var clipAxes;

src/components/shapes/shape_defaults.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,16 @@ var Axes = require('../../plots/cartesian/axes');
1515
var attributes = require('./attributes');
1616
var helpers = require('./helpers');
1717

18-
module.exports = function handleShapeDefaults(shapeIn, fullLayout) {
19-
var shapeOut = {};
18+
19+
module.exports = function handleShapeDefaults(shapeIn, shapeOut, fullLayout, opts, itemOpts) {
20+
opts = opts || {};
21+
itemOpts = itemOpts || {};
2022

2123
function coerce(attr, dflt) {
2224
return Lib.coerce(shapeIn, shapeOut, attributes, attr, dflt);
2325
}
2426

25-
var visible = coerce('visible');
27+
var visible = coerce('visible', !itemOpts.itemIsNotPlainObject);
2628

2729
if(!visible) return shapeOut;
2830

src/components/sliders/defaults.js

+6-16
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
'use strict';
1010

1111
var Lib = require('../../lib');
12+
var handleArrayContainerDefaults = require('../../plots/array_container_defaults');
1213

1314
var attributes = require('./attributes');
1415
var constants = require('./constants');
@@ -18,23 +19,12 @@ var stepAttrs = attributes.steps;
1819

1920

2021
module.exports = function slidersDefaults(layoutIn, layoutOut) {
21-
var contIn = Array.isArray(layoutIn[name]) ? layoutIn[name] : [],
22-
contOut = layoutOut[name] = [];
22+
var opts = {
23+
name: name,
24+
handleItemDefaults: sliderDefaults
25+
};
2326

24-
for(var i = 0; i < contIn.length; i++) {
25-
var sliderIn = contIn[i] || {},
26-
sliderOut = {};
27-
28-
sliderDefaults(sliderIn, sliderOut, layoutOut);
29-
30-
// used on button click to update the 'active' field
31-
sliderOut._input = sliderIn;
32-
33-
// used to determine object constancy
34-
sliderOut._index = i;
35-
36-
contOut.push(sliderOut);
37-
}
27+
handleArrayContainerDefaults(layoutIn, layoutOut, opts);
3828
};
3929

4030
function sliderDefaults(sliderIn, sliderOut, layoutOut) {

src/components/updatemenus/defaults.js

+6-16
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
'use strict';
1010

1111
var Lib = require('../../lib');
12+
var handleArrayContainerDefaults = require('../../plots/array_container_defaults');
1213

1314
var attributes = require('./attributes');
1415
var constants = require('./constants');
@@ -18,23 +19,12 @@ var buttonAttrs = attributes.buttons;
1819

1920

2021
module.exports = function updateMenusDefaults(layoutIn, layoutOut) {
21-
var contIn = Array.isArray(layoutIn[name]) ? layoutIn[name] : [],
22-
contOut = layoutOut[name] = [];
22+
var opts = {
23+
name: name,
24+
handleItemDefaults: menuDefaults
25+
};
2326

24-
for(var i = 0; i < contIn.length; i++) {
25-
var menuIn = contIn[i] || {},
26-
menuOut = {};
27-
28-
menuDefaults(menuIn, menuOut, layoutOut);
29-
30-
// used on button click to update the 'active' field
31-
menuOut._input = menuIn;
32-
33-
// used to determine object constancy
34-
menuOut._index = i;
35-
36-
contOut.push(menuOut);
37-
}
27+
handleArrayContainerDefaults(layoutIn, layoutOut, opts);
3828
};
3929

4030
function menuDefaults(menuIn, menuOut, layoutOut) {

src/plot_api/helpers.js

+9-10
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,12 @@ exports.cleanLayout = function(layout) {
102102
}
103103
}
104104

105-
if(layout.annotations !== undefined && !Array.isArray(layout.annotations)) {
106-
Lib.warn('Annotations must be an array.');
107-
delete layout.annotations;
108-
}
109-
var annotationsLen = (layout.annotations || []).length;
105+
var annotationsLen = Array.isArray(layout.annotations) ? layout.annotations.length : 0;
110106
for(i = 0; i < annotationsLen; i++) {
111107
var ann = layout.annotations[i];
108+
109+
if(!Lib.isPlainObject(ann)) continue;
110+
112111
if(ann.ref) {
113112
if(ann.ref === 'paper') {
114113
ann.xref = 'paper';
@@ -120,17 +119,17 @@ exports.cleanLayout = function(layout) {
120119
}
121120
delete ann.ref;
122121
}
122+
123123
cleanAxRef(ann, 'xref');
124124
cleanAxRef(ann, 'yref');
125125
}
126126

127-
if(layout.shapes !== undefined && !Array.isArray(layout.shapes)) {
128-
Lib.warn('Shapes must be an array.');
129-
delete layout.shapes;
130-
}
131-
var shapesLen = (layout.shapes || []).length;
127+
var shapesLen = Array.isArray(layout.shapes) ? layout.shapes.length : 0;
132128
for(i = 0; i < shapesLen; i++) {
133129
var shape = layout.shapes[i];
130+
131+
if(!Lib.isPlainObject(shape)) continue;
132+
134133
cleanAxRef(shape, 'xref');
135134
cleanAxRef(shape, 'yref');
136135
}

src/plots/array_container_defaults.js

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
var Lib = require('../lib');
12+
13+
14+
/** Convenience wrapper for making array container logic DRY and consistent
15+
*
16+
* @param {object} parentObjIn
17+
* user input object where the container in question is linked
18+
* (i.e. either a user trace object or the user layout object)
19+
*
20+
* @param {object} parentObjOut
21+
* full object where the coerced container will be linked
22+
* (i.e. either a full trace object or the full layout object)
23+
*
24+
* @param {object} opts
25+
* options object:
26+
* - name {string}
27+
* name of the key linking the container in question
28+
* - handleItemDefaults {function}
29+
* defaults method to be called on each item in the array container in question
30+
*
31+
* Its arguments are:
32+
* - itemIn {object} item in user layout
33+
* - itemOut {object} item in full layout
34+
* - parentObj {object} (as in closure)
35+
* - opts {object} (as in closure)
36+
* - itemOpts {object}
37+
* - itemIsNotPlainObject {boolean}
38+
* N.B.
39+
*
40+
* - opts is passed to handleItemDefaults so it can also store
41+
* links to supplementary data (e.g. fullData for layout components)
42+
*
43+
*/
44+
module.exports = function handleArrayContainerDefaults(parentObjIn, parentObjOut, opts) {
45+
var name = opts.name;
46+
47+
var contIn = Array.isArray(parentObjIn[name]) ? parentObjIn[name] : [],
48+
contOut = parentObjOut[name] = [];
49+
50+
for(var i = 0; i < contIn.length; i++) {
51+
var itemIn = contIn[i],
52+
itemOut = {},
53+
itemOpts = {};
54+
55+
if(!Lib.isPlainObject(itemIn)) {
56+
itemOpts.itemIsNotPlainObject = true;
57+
itemIn = {};
58+
}
59+
60+
opts.handleItemDefaults(itemIn, itemOut, parentObjOut, opts, itemOpts);
61+
62+
itemOut._input = itemIn;
63+
itemOut._index = i;
64+
65+
contOut.push(itemOut);
66+
}
67+
};

src/plots/plots.js

+15-4
Original file line numberDiff line numberDiff line change
@@ -1569,8 +1569,14 @@ plots.extendObjectWithContainers = function(dest, src, containerPaths) {
15691569
for(i = 0; i < containerPaths.length; i++) {
15701570
containerProp = Lib.nestedProperty(expandedObj, containerPaths[i]);
15711571
containerVal = containerProp.get();
1572-
containerProp.set(null);
1573-
Lib.nestedProperty(containerObj, containerPaths[i]).set(containerVal);
1572+
1573+
if(containerVal === undefined) {
1574+
Lib.nestedProperty(containerObj, containerPaths[i]).set(null);
1575+
}
1576+
else {
1577+
containerProp.set(null);
1578+
Lib.nestedProperty(containerObj, containerPaths[i]).set(containerVal);
1579+
}
15741580
}
15751581
}
15761582

@@ -1584,15 +1590,20 @@ plots.extendObjectWithContainers = function(dest, src, containerPaths) {
15841590
if(!srcContainer) continue;
15851591

15861592
destProp = Lib.nestedProperty(dest, containerPaths[i]);
1587-
15881593
destContainer = destProp.get();
1594+
15891595
if(!Array.isArray(destContainer)) {
15901596
destContainer = [];
15911597
destProp.set(destContainer);
15921598
}
15931599

15941600
for(j = 0; j < srcContainer.length; j++) {
1595-
destContainer[j] = plots.extendObjectWithContainers(destContainer[j], srcContainer[j]);
1601+
var srcObj = srcContainer[j];
1602+
1603+
if(srcObj === null) destContainer[j] = null;
1604+
else {
1605+
destContainer[j] = plots.extendObjectWithContainers(destContainer[j], srcObj);
1606+
}
15961607
}
15971608

15981609
destProp.set(destContainer);

0 commit comments

Comments
 (0)