Skip to content

Commit 3d5f311

Browse files
authoredJun 17, 2020
Merge pull request #4904 from plotly/fix4852-template-tickwidth-tickcolor
Fix setting tickwidth, tickcolor, ticklen, linecolor and possibly more attributes via template
2 parents 634a93a + 24d1da9 commit 3d5f311

File tree

5 files changed

+163
-68
lines changed

5 files changed

+163
-68
lines changed
 

‎src/lib/coerce.js

+46-23
Original file line numberDiff line numberDiff line change
@@ -361,58 +361,81 @@ exports.valObjectMeta = {
361361
* as a convenience, returns the value it finally set
362362
*/
363363
exports.coerce = function(containerIn, containerOut, attributes, attribute, dflt) {
364-
var opts = nestedProperty(attributes, attribute).get();
364+
return _coerce(containerIn, containerOut, attributes, attribute, dflt).val;
365+
};
366+
367+
function _coerce(containerIn, containerOut, attributes, attribute, dflt, opts) {
368+
var shouldValidate = (opts || {}).shouldValidate;
369+
370+
var attr = nestedProperty(attributes, attribute).get();
371+
if(dflt === undefined) dflt = attr.dflt;
372+
var src = false;
373+
365374
var propIn = nestedProperty(containerIn, attribute);
366375
var propOut = nestedProperty(containerOut, attribute);
367-
var v = propIn.get();
376+
var valIn = propIn.get();
368377

369378
var template = containerOut._template;
370-
if(v === undefined && template) {
371-
v = nestedProperty(template, attribute).get();
379+
if(valIn === undefined && template) {
380+
valIn = nestedProperty(template, attribute).get();
381+
src = (valIn !== undefined);
382+
372383
// already used the template value, so short-circuit the second check
373384
template = 0;
374385
}
375386

376-
if(dflt === undefined) dflt = opts.dflt;
377-
378387
/**
379388
* arrayOk: value MAY be an array, then we do no value checking
380389
* at this point, because it can be more complicated than the
381390
* individual form (eg. some array vals can be numbers, even if the
382391
* single values must be color strings)
383392
*/
384-
if(opts.arrayOk && isArrayOrTypedArray(v)) {
385-
propOut.set(v);
386-
return v;
393+
if(attr.arrayOk && isArrayOrTypedArray(valIn)) {
394+
propOut.set(valIn);
395+
return {
396+
inp: valIn,
397+
val: valIn,
398+
src: true
399+
};
387400
}
388401

389-
var coerceFunction = exports.valObjectMeta[opts.valType].coerceFunction;
390-
coerceFunction(v, propOut, dflt, opts);
402+
var coerceFunction = exports.valObjectMeta[attr.valType].coerceFunction;
403+
coerceFunction(valIn, propOut, dflt, attr);
404+
405+
var valOut = propOut.get();
406+
src = (valOut !== undefined) && shouldValidate && validate(valIn, attr);
391407

392-
var out = propOut.get();
393408
// in case v was provided but invalid, try the template again so it still
394409
// overrides the regular default
395-
if(template && out === dflt && !validate(v, opts)) {
396-
v = nestedProperty(template, attribute).get();
397-
coerceFunction(v, propOut, dflt, opts);
398-
out = propOut.get();
410+
if(template && valOut === dflt && !validate(valIn, attr)) {
411+
valIn = nestedProperty(template, attribute).get();
412+
coerceFunction(valIn, propOut, dflt, attr);
413+
valOut = propOut.get();
414+
415+
src = (valOut !== undefined) && shouldValidate && validate(valIn, attr);
399416
}
400-
return out;
401-
};
417+
418+
return {
419+
inp: valIn,
420+
val: valOut,
421+
src: src
422+
};
423+
}
402424

403425
/**
404426
* Variation on coerce
427+
* useful when setting an attribute to a valid value
428+
* can change the default for another attribute.
405429
*
406430
* Uses coerce to get attribute value if user input is valid,
407431
* returns attribute default if user input it not valid or
408432
* returns false if there is no user input.
409433
*/
410434
exports.coerce2 = function(containerIn, containerOut, attributes, attribute, dflt) {
411-
var propIn = nestedProperty(containerIn, attribute);
412-
var propOut = exports.coerce(containerIn, containerOut, attributes, attribute, dflt);
413-
var valIn = propIn.get();
414-
415-
return (valIn !== undefined && valIn !== null) ? propOut : false;
435+
var out = _coerce(containerIn, containerOut, attributes, attribute, dflt, {
436+
shouldValidate: true
437+
});
438+
return (out.src && out.inp !== undefined) ? out.val : false;
416439
};
417440

418441
/*
213 Bytes
Loading

‎test/image/mocks/axes_custom-ticks_log-date.json

+42-38
Original file line numberDiff line numberDiff line change
@@ -15,44 +15,48 @@
1515
"layout": {
1616
"width": 500,
1717
"height": 300,
18-
"title": {
19-
"text": "custom ticks on date & log axes"
20-
},
21-
"paper_bgcolor": "lightblue",
22-
"plot_bgcolor": "#ddd",
23-
"yaxis": {
24-
"type": "log",
25-
"tickmode": "array",
26-
"tickvals": [
27-
1,
28-
10,
29-
100
30-
],
31-
"ticktext": [
32-
"one",
33-
"ten",
34-
"one<br>hundred"
35-
],
36-
"gridwidth": 2,
37-
"tickwidth": 15,
38-
"tickcolor": "green",
39-
"gridcolor": "green"
40-
},
41-
"xaxis": {
42-
"type": "date",
43-
"tickmode": "array",
44-
"tickvals": [
45-
"2010-01-16",
46-
"2010-02-14"
47-
],
48-
"ticktext": [
49-
"Jan 16",
50-
"Feb 14"
51-
],
52-
"gridwidth": 10,
53-
"tickwidth": 50,
54-
"tickcolor": "rgba(255,0,0,0.75)",
55-
"gridcolor": "rgba(255,0,0,0.25)"
18+
"template": {
19+
"layout": {
20+
"title": {
21+
"text": "custom ticks on date & log axes"
22+
},
23+
"paper_bgcolor": "lightblue",
24+
"plot_bgcolor": "#ddd",
25+
"yaxis": {
26+
"type": "log",
27+
"tickmode": "array",
28+
"tickvals": [
29+
1,
30+
10,
31+
100
32+
],
33+
"ticktext": [
34+
"one",
35+
"ten",
36+
"one<br>hundred"
37+
],
38+
"gridwidth": 2,
39+
"tickwidth": 15,
40+
"tickcolor": "green",
41+
"gridcolor": "green"
42+
},
43+
"xaxis": {
44+
"type": "date",
45+
"tickmode": "array",
46+
"tickvals": [
47+
"2010-01-16",
48+
"2010-02-14"
49+
],
50+
"ticktext": [
51+
"Jan 16",
52+
"Feb 14"
53+
],
54+
"gridwidth": 10,
55+
"tickwidth": 50,
56+
"tickcolor": "rgba(255,0,0,0.75)",
57+
"gridcolor": "rgba(255,0,0,0.25)"
58+
}
59+
}
5660
}
5761
}
5862
}

‎test/jasmine/tests/axes_test.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1803,10 +1803,10 @@ describe('Test axes', function() {
18031803
Plotly.plot(gd, data, layout);
18041804

18051805
var yaxis = gd._fullLayout.yaxis;
1806-
expect(yaxis.ticklen).toBe(5);
1807-
expect(yaxis.tickwidth).toBe(1);
1808-
expect(yaxis.tickcolor).toBe('#444');
1809-
expect(yaxis.ticks).toBe('outside');
1806+
expect(yaxis.ticklen).toBe(undefined);
1807+
expect(yaxis.tickwidth).toBe(undefined);
1808+
expect(yaxis.tickcolor).toBe(undefined);
1809+
expect(yaxis.ticks).toBe('');
18101810
expect(yaxis.showticklabels).toBe(true);
18111811
expect(yaxis.tickfont).toEqual({ family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444' });
18121812
expect(yaxis.tickangle).toBe('auto');

‎test/jasmine/tests/lib_test.js

+71-3
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,7 @@ describe('Test lib.js:', function() {
778778
expect(sizeOut).toBe(outObj.testMarker.testSize);
779779
});
780780

781-
it('should set and return the default if the user input is not valid', function() {
781+
it('should set the default and return false if the user input is not valid', function() {
782782
var colVal = 'r';
783783
var sizeVal = 'aaaaah!';
784784
var attrs = {
@@ -792,12 +792,80 @@ describe('Test lib.js:', function() {
792792
var colOut = coerce2(obj, outObj, attrs, 'testMarker.testColor');
793793
var sizeOut = coerce2(obj, outObj, attrs, 'testMarker.testSize');
794794

795-
expect(colOut).toBe('rgba(0, 0, 0, 0)');
795+
expect(colOut).toBe(false);
796+
expect(outObj.testMarker.testColor).toBe('rgba(0, 0, 0, 0)');
797+
expect(sizeOut).toBe(false);
798+
expect(outObj.testMarker.testSize).toBe(20);
799+
});
800+
801+
it('should set the user input', function() {
802+
var colVal = 'red';
803+
var sizeVal = '1e2';
804+
var attrs = {
805+
testMarker: {
806+
testColor: {valType: 'color', dflt: 'rgba(0, 0, 0, 0)'},
807+
testSize: {valType: 'number', dflt: 20}
808+
}
809+
};
810+
var obj = {testMarker: {testColor: colVal, testSize: sizeVal}};
811+
var outObj = {};
812+
var colOut = coerce2(obj, outObj, attrs, 'testMarker.testColor');
813+
var sizeOut = coerce2(obj, outObj, attrs, 'testMarker.testSize');
814+
815+
expect(colOut).toBe('red');
816+
expect(colOut).toBe(outObj.testMarker.testColor);
817+
expect(sizeOut).toBe(100);
796818
expect(sizeOut).toBe(outObj.testMarker.testSize);
797-
expect(sizeOut).toBe(20);
819+
});
820+
821+
it('should set to template if the container input is not valid', function() {
822+
var attrs = {
823+
testMarker: {
824+
testColor: {valType: 'color', dflt: 'rgba(0, 0, 0, 0)'},
825+
testSize: {valType: 'number', dflt: 20}
826+
}
827+
};
828+
var obj = {
829+
testMarker: {testColor: 'invalid', testSize: 'invalid'}
830+
};
831+
var outObj = {
832+
_template: {
833+
testMarker: {testColor: 'red', testSize: '1e2'}
834+
}
835+
};
836+
var colOut = coerce2(obj, outObj, attrs, 'testMarker.testColor');
837+
var sizeOut = coerce2(obj, outObj, attrs, 'testMarker.testSize');
838+
839+
expect(colOut).toBe('red');
840+
expect(colOut).toBe(outObj.testMarker.testColor);
841+
expect(sizeOut).toBe(100);
798842
expect(sizeOut).toBe(outObj.testMarker.testSize);
799843
});
800844

845+
it('should set to default and return false if the both container and template inputs are not valid', function() {
846+
var attrs = {
847+
testMarker: {
848+
testColor: {valType: 'color', dflt: 'rgba(0, 0, 0, 0)'},
849+
testSize: {valType: 'number', dflt: 20}
850+
}
851+
};
852+
var obj = {
853+
testMarker: {testColor: 'invalid', testSize: 'invalid'}
854+
};
855+
var outObj = {
856+
_template: {
857+
testMarker: {testColor: 'invalid', testSize: 'invalid'}
858+
}
859+
};
860+
var colOut = coerce2(obj, outObj, attrs, 'testMarker.testColor');
861+
var sizeOut = coerce2(obj, outObj, attrs, 'testMarker.testSize');
862+
863+
expect(colOut).toBe(false);
864+
expect(outObj.testMarker.testColor).toBe('rgba(0, 0, 0, 0)');
865+
expect(sizeOut).toBe(false);
866+
expect(outObj.testMarker.testSize).toBe(20);
867+
});
868+
801869
it('should return false if there is no user input', function() {
802870
var colVal = null;
803871
var sizeVal; // undefined

0 commit comments

Comments
 (0)
Please sign in to comment.