diff --git a/src/lib/coerce.js b/src/lib/coerce.js
index 108370cfe40..b36cc1c1b95 100644
--- a/src/lib/coerce.js
+++ b/src/lib/coerce.js
@@ -361,58 +361,81 @@ exports.valObjectMeta = {
* as a convenience, returns the value it finally set
*/
exports.coerce = function(containerIn, containerOut, attributes, attribute, dflt) {
- var opts = nestedProperty(attributes, attribute).get();
+ return _coerce(containerIn, containerOut, attributes, attribute, dflt).val;
+};
+
+function _coerce(containerIn, containerOut, attributes, attribute, dflt, opts) {
+ var shouldValidate = (opts || {}).shouldValidate;
+
+ var attr = nestedProperty(attributes, attribute).get();
+ if(dflt === undefined) dflt = attr.dflt;
+ var src = false;
+
var propIn = nestedProperty(containerIn, attribute);
var propOut = nestedProperty(containerOut, attribute);
- var v = propIn.get();
+ var valIn = propIn.get();
var template = containerOut._template;
- if(v === undefined && template) {
- v = nestedProperty(template, attribute).get();
+ if(valIn === undefined && template) {
+ valIn = nestedProperty(template, attribute).get();
+ src = (valIn !== undefined);
+
// already used the template value, so short-circuit the second check
template = 0;
}
- if(dflt === undefined) dflt = opts.dflt;
-
/**
* arrayOk: value MAY be an array, then we do no value checking
* at this point, because it can be more complicated than the
* individual form (eg. some array vals can be numbers, even if the
* single values must be color strings)
*/
- if(opts.arrayOk && isArrayOrTypedArray(v)) {
- propOut.set(v);
- return v;
+ if(attr.arrayOk && isArrayOrTypedArray(valIn)) {
+ propOut.set(valIn);
+ return {
+ inp: valIn,
+ val: valIn,
+ src: true
+ };
}
- var coerceFunction = exports.valObjectMeta[opts.valType].coerceFunction;
- coerceFunction(v, propOut, dflt, opts);
+ var coerceFunction = exports.valObjectMeta[attr.valType].coerceFunction;
+ coerceFunction(valIn, propOut, dflt, attr);
+
+ var valOut = propOut.get();
+ src = (valOut !== undefined) && shouldValidate && validate(valIn, attr);
- var out = propOut.get();
// in case v was provided but invalid, try the template again so it still
// overrides the regular default
- if(template && out === dflt && !validate(v, opts)) {
- v = nestedProperty(template, attribute).get();
- coerceFunction(v, propOut, dflt, opts);
- out = propOut.get();
+ if(template && valOut === dflt && !validate(valIn, attr)) {
+ valIn = nestedProperty(template, attribute).get();
+ coerceFunction(valIn, propOut, dflt, attr);
+ valOut = propOut.get();
+
+ src = (valOut !== undefined) && shouldValidate && validate(valIn, attr);
}
- return out;
-};
+
+ return {
+ inp: valIn,
+ val: valOut,
+ src: src
+ };
+}
/**
* Variation on coerce
+ * useful when setting an attribute to a valid value
+ * can change the default for another attribute.
*
* Uses coerce to get attribute value if user input is valid,
* returns attribute default if user input it not valid or
* returns false if there is no user input.
*/
exports.coerce2 = function(containerIn, containerOut, attributes, attribute, dflt) {
- var propIn = nestedProperty(containerIn, attribute);
- var propOut = exports.coerce(containerIn, containerOut, attributes, attribute, dflt);
- var valIn = propIn.get();
-
- return (valIn !== undefined && valIn !== null) ? propOut : false;
+ var out = _coerce(containerIn, containerOut, attributes, attribute, dflt, {
+ shouldValidate: true
+ });
+ return (out.src && out.inp !== undefined) ? out.val : false;
};
/*
diff --git a/src/plots/cartesian/axis_defaults.js b/src/plots/cartesian/axis_defaults.js
index c1fbf92f9ea..5dec11fec88 100644
--- a/src/plots/cartesian/axis_defaults.js
+++ b/src/plots/cartesian/axis_defaults.js
@@ -99,6 +99,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,
dfltColor: dfltColor,
bgColor: options.bgColor,
showGrid: options.showGrid,
+ hideGrid: options.hideGrid,
attributes: layoutAttributes
});
diff --git a/src/plots/cartesian/layout_defaults.js b/src/plots/cartesian/layout_defaults.js
index 3e411ae0574..515b30fa138 100644
--- a/src/plots/cartesian/layout_defaults.js
+++ b/src/plots/cartesian/layout_defaults.js
@@ -239,6 +239,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
letter: axLetter,
font: layoutOut.font,
outerTicks: outerTicks[axName],
+ hideGrid: noGrids[axName],
showGrid: !noGrids[axName],
data: ax2traces[axName] || [],
bgColor: bgColor,
@@ -303,6 +304,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
letter: axLetter,
font: layoutOut.font,
outerTicks: outerTicks[axName],
+ hideGrid: noGrids[axName],
showGrid: !noGrids[axName],
data: [],
bgColor: bgColor,
diff --git a/src/plots/cartesian/line_grid_defaults.js b/src/plots/cartesian/line_grid_defaults.js
index 18fd9974134..2ed89aff7c4 100644
--- a/src/plots/cartesian/line_grid_defaults.js
+++ b/src/plots/cartesian/line_grid_defaults.js
@@ -31,6 +31,18 @@ module.exports = function handleLineGridDefaults(containerIn, containerOut, coer
return Lib.coerce2(containerIn, containerOut, opts.attributes, attr, dflt);
}
+ function _coerce(attr, dflt) {
+ var val = coerce2(attr, dflt);
+
+ if(
+ val && opts.hideGrid &&
+ containerOut[attr] !== containerIn[attr] &&
+ containerOut[attr] === containerOut._template[attr]
+ ) return false;
+
+ return val;
+ }
+
var lineColor = coerce2('linecolor', dfltColor);
var lineWidth = coerce2('linewidth');
var showLine = coerce('showline', opts.showLine || !!lineColor || !!lineWidth);
@@ -41,8 +53,8 @@ module.exports = function handleLineGridDefaults(containerIn, containerOut, coer
}
var gridColorDflt = colorMix(dfltColor, opts.bgColor, opts.blend || lightFraction).toRgbString();
- var gridColor = coerce2('gridcolor', gridColorDflt);
- var gridWidth = coerce2('gridwidth');
+ var gridColor = _coerce('gridcolor', gridColorDflt);
+ var gridWidth = _coerce('gridwidth');
var showGridLines = coerce('showgrid', opts.showGrid || !!gridColor || !!gridWidth);
if(!showGridLines) {
@@ -51,8 +63,8 @@ module.exports = function handleLineGridDefaults(containerIn, containerOut, coer
}
if(!opts.noZeroLine) {
- var zeroLineColor = coerce2('zerolinecolor', dfltColor);
- var zeroLineWidth = coerce2('zerolinewidth');
+ var zeroLineColor = _coerce('zerolinecolor', dfltColor);
+ var zeroLineWidth = _coerce('zerolinewidth');
var showZeroLine = coerce('zeroline', opts.showGrid || !!zeroLineColor || !!zeroLineWidth);
if(!showZeroLine) {
diff --git a/test/image/baselines/axes_breaks-round-weekdays.png b/test/image/baselines/axes_breaks-round-weekdays.png
index 9f20ece5dfa..4f3b0c6ffdd 100644
Binary files a/test/image/baselines/axes_breaks-round-weekdays.png and b/test/image/baselines/axes_breaks-round-weekdays.png differ
diff --git a/test/image/baselines/hide_gridline-template_color.png b/test/image/baselines/hide_gridline-template_color.png
new file mode 100644
index 00000000000..49023fb0667
Binary files /dev/null and b/test/image/baselines/hide_gridline-template_color.png differ
diff --git a/test/image/mocks/axes_custom-ticks_log-date.json b/test/image/mocks/axes_custom-ticks_log-date.json
index 261015f32d1..3adb12d7b7a 100644
--- a/test/image/mocks/axes_custom-ticks_log-date.json
+++ b/test/image/mocks/axes_custom-ticks_log-date.json
@@ -15,44 +15,48 @@
"layout": {
"width": 500,
"height": 300,
- "title": {
- "text": "custom ticks on date & log axes"
- },
- "paper_bgcolor": "lightblue",
- "plot_bgcolor": "#ddd",
- "yaxis": {
- "type": "log",
- "tickmode": "array",
- "tickvals": [
- 1,
- 10,
- 100
- ],
- "ticktext": [
- "one",
- "ten",
- "one
hundred"
- ],
- "gridwidth": 2,
- "tickwidth": 15,
- "tickcolor": "green",
- "gridcolor": "green"
- },
- "xaxis": {
- "type": "date",
- "tickmode": "array",
- "tickvals": [
- "2010-01-16",
- "2010-02-14"
- ],
- "ticktext": [
- "Jan 16",
- "Feb 14"
- ],
- "gridwidth": 10,
- "tickwidth": 50,
- "tickcolor": "rgba(255,0,0,0.75)",
- "gridcolor": "rgba(255,0,0,0.25)"
+ "template": {
+ "layout": {
+ "title": {
+ "text": "custom ticks on date & log axes"
+ },
+ "paper_bgcolor": "lightblue",
+ "plot_bgcolor": "#ddd",
+ "yaxis": {
+ "type": "log",
+ "tickmode": "array",
+ "tickvals": [
+ 1,
+ 10,
+ 100
+ ],
+ "ticktext": [
+ "one",
+ "ten",
+ "one
hundred"
+ ],
+ "gridwidth": 2,
+ "tickwidth": 15,
+ "tickcolor": "green",
+ "gridcolor": "green"
+ },
+ "xaxis": {
+ "type": "date",
+ "tickmode": "array",
+ "tickvals": [
+ "2010-01-16",
+ "2010-02-14"
+ ],
+ "ticktext": [
+ "Jan 16",
+ "Feb 14"
+ ],
+ "gridwidth": 10,
+ "tickwidth": 50,
+ "tickcolor": "rgba(255,0,0,0.75)",
+ "gridcolor": "rgba(255,0,0,0.25)"
+ }
+ }
}
}
}
diff --git a/test/image/mocks/hide_gridline-template_color.json b/test/image/mocks/hide_gridline-template_color.json
new file mode 100644
index 00000000000..a412a1ded05
--- /dev/null
+++ b/test/image/mocks/hide_gridline-template_color.json
@@ -0,0 +1,70 @@
+{
+ "data": [
+ {
+ "type": "scatter",
+ "marker": { "color": "blue" },
+ "x": [-1, 1],
+ "y": [-1, 1]
+ },
+ {
+ "type": "bar",
+ "marker": { "color": "rgba(127,127,127,0.5)" },
+ "y": [-1, 1],
+ "xaxis": "x2",
+ "yaxis": "y2"
+ },
+ {
+ "type": "bar",
+ "marker": { "color": "rgba(127,127,127,0.5)" },
+ "x": [-1, 1],
+ "xaxis": "x3",
+ "yaxis": "y3"
+ },
+ {
+ "type": "bar",
+ "marker": { "color": "rgba(127,127,127,0.5)" },
+ "y": [-1, 1],
+ "xaxis": "x4",
+ "yaxis": "y4"
+ },
+ {
+ "type": "scatter",
+ "marker": { "color": "blue" },
+ "x": [-1, 1],
+ "y": [-1, 1],
+ "xaxis": "x4",
+ "yaxis": "y4"
+ }
+ ],
+ "layout": {
+ "title": {
+ "text": "hide grid lines for oriented traces"
+ },
+ "showlegend": false,
+ "width": 600,
+ "height": 600,
+ "grid": {
+ "rows": 2,
+ "columns": 2,
+ "xgap": 0.2,
+ "ygap": 0.2,
+ "pattern": "independent"
+ },
+ "template": {
+ "layout": {
+ "xaxis": {
+ "gridcolor": "red",
+ "gridwidth": 2,
+ "zerolinecolor": "orange",
+ "zerolinewidth": 5
+ },
+ "yaxis": {
+ "gridcolor": "red",
+ "gridwidth": 2,
+ "zerolinecolor": "orange",
+ "zerolinewidth": 5
+ }
+ }
+ }
+ }
+}
diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js
index 5c19984ce9e..eb4d6ab44dc 100644
--- a/test/jasmine/tests/axes_test.js
+++ b/test/jasmine/tests/axes_test.js
@@ -1803,10 +1803,10 @@ describe('Test axes', function() {
Plotly.plot(gd, data, layout);
var yaxis = gd._fullLayout.yaxis;
- expect(yaxis.ticklen).toBe(5);
- expect(yaxis.tickwidth).toBe(1);
- expect(yaxis.tickcolor).toBe('#444');
- expect(yaxis.ticks).toBe('outside');
+ expect(yaxis.ticklen).toBe(undefined);
+ expect(yaxis.tickwidth).toBe(undefined);
+ expect(yaxis.tickcolor).toBe(undefined);
+ expect(yaxis.ticks).toBe('');
expect(yaxis.showticklabels).toBe(true);
expect(yaxis.tickfont).toEqual({ family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444' });
expect(yaxis.tickangle).toBe('auto');
diff --git a/test/jasmine/tests/lib_test.js b/test/jasmine/tests/lib_test.js
index 4105e5455ea..b9fa49649e0 100644
--- a/test/jasmine/tests/lib_test.js
+++ b/test/jasmine/tests/lib_test.js
@@ -778,7 +778,7 @@ describe('Test lib.js:', function() {
expect(sizeOut).toBe(outObj.testMarker.testSize);
});
- it('should set and return the default if the user input is not valid', function() {
+ it('should set the default and return false if the user input is not valid', function() {
var colVal = 'r';
var sizeVal = 'aaaaah!';
var attrs = {
@@ -792,12 +792,80 @@ describe('Test lib.js:', function() {
var colOut = coerce2(obj, outObj, attrs, 'testMarker.testColor');
var sizeOut = coerce2(obj, outObj, attrs, 'testMarker.testSize');
- expect(colOut).toBe('rgba(0, 0, 0, 0)');
+ expect(colOut).toBe(false);
+ expect(outObj.testMarker.testColor).toBe('rgba(0, 0, 0, 0)');
+ expect(sizeOut).toBe(false);
+ expect(outObj.testMarker.testSize).toBe(20);
+ });
+
+ it('should set the user input', function() {
+ var colVal = 'red';
+ var sizeVal = '1e2';
+ var attrs = {
+ testMarker: {
+ testColor: {valType: 'color', dflt: 'rgba(0, 0, 0, 0)'},
+ testSize: {valType: 'number', dflt: 20}
+ }
+ };
+ var obj = {testMarker: {testColor: colVal, testSize: sizeVal}};
+ var outObj = {};
+ var colOut = coerce2(obj, outObj, attrs, 'testMarker.testColor');
+ var sizeOut = coerce2(obj, outObj, attrs, 'testMarker.testSize');
+
+ expect(colOut).toBe('red');
+ expect(colOut).toBe(outObj.testMarker.testColor);
+ expect(sizeOut).toBe(100);
expect(sizeOut).toBe(outObj.testMarker.testSize);
- expect(sizeOut).toBe(20);
+ });
+
+ it('should set to template if the container input is not valid', function() {
+ var attrs = {
+ testMarker: {
+ testColor: {valType: 'color', dflt: 'rgba(0, 0, 0, 0)'},
+ testSize: {valType: 'number', dflt: 20}
+ }
+ };
+ var obj = {
+ testMarker: {testColor: 'invalid', testSize: 'invalid'}
+ };
+ var outObj = {
+ _template: {
+ testMarker: {testColor: 'red', testSize: '1e2'}
+ }
+ };
+ var colOut = coerce2(obj, outObj, attrs, 'testMarker.testColor');
+ var sizeOut = coerce2(obj, outObj, attrs, 'testMarker.testSize');
+
+ expect(colOut).toBe('red');
+ expect(colOut).toBe(outObj.testMarker.testColor);
+ expect(sizeOut).toBe(100);
expect(sizeOut).toBe(outObj.testMarker.testSize);
});
+ it('should set to default and return false if the both container and template inputs are not valid', function() {
+ var attrs = {
+ testMarker: {
+ testColor: {valType: 'color', dflt: 'rgba(0, 0, 0, 0)'},
+ testSize: {valType: 'number', dflt: 20}
+ }
+ };
+ var obj = {
+ testMarker: {testColor: 'invalid', testSize: 'invalid'}
+ };
+ var outObj = {
+ _template: {
+ testMarker: {testColor: 'invalid', testSize: 'invalid'}
+ }
+ };
+ var colOut = coerce2(obj, outObj, attrs, 'testMarker.testColor');
+ var sizeOut = coerce2(obj, outObj, attrs, 'testMarker.testSize');
+
+ expect(colOut).toBe(false);
+ expect(outObj.testMarker.testColor).toBe('rgba(0, 0, 0, 0)');
+ expect(sizeOut).toBe(false);
+ expect(outObj.testMarker.testSize).toBe(20);
+ });
+
it('should return false if there is no user input', function() {
var colVal = null;
var sizeVal; // undefined
diff --git a/test/jasmine/tests/mock_test.js b/test/jasmine/tests/mock_test.js
index eb7abbbfa29..169323a3c52 100644
--- a/test/jasmine/tests/mock_test.js
+++ b/test/jasmine/tests/mock_test.js
@@ -596,6 +596,7 @@ var list = [
'heatmap_xyz-gaps-on-sides',
'heatmap-reverse-autocolorscale',
'heatmap-with-zero-category',
+ 'hide_gridline-template_color',
'hist_0_to_093',
'hist_0_to_1_midpoints',
'hist_003_to_093',
@@ -1639,6 +1640,7 @@ figs['heatmap_xyz-dates-and-categories'] = require('@mocks/heatmap_xyz-dates-and
figs['heatmap_xyz-gaps-on-sides'] = require('@mocks/heatmap_xyz-gaps-on-sides');
figs['heatmap-reverse-autocolorscale'] = require('@mocks/heatmap-reverse-autocolorscale');
figs['heatmap-with-zero-category'] = require('@mocks/heatmap-with-zero-category');
+figs['hide_gridline-template_color'] = require('@mocks/hide_gridline-template_color');
figs['hist_0_to_093'] = require('@mocks/hist_0_to_093');
figs['hist_0_to_1_midpoints'] = require('@mocks/hist_0_to_1_midpoints');
figs['hist_003_to_093'] = require('@mocks/hist_003_to_093');