Skip to content

Commit df06911

Browse files
committed
break lib.js into smaller lib modules:
- coerce.js, dates.js, matrix.js nested_property.js, notifier.js, search.js, stats.js
1 parent edae224 commit df06911

File tree

8 files changed

+1294
-1224
lines changed

8 files changed

+1294
-1224
lines changed

src/lib/coerce.js

Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
'use strict';
2+
3+
var Plotly = require('../plotly');
4+
var isNumeric = require('fast-isnumeric');
5+
var tinycolor = require('tinycolor2');
6+
var nestedProperty = require('./nested_property');
7+
8+
var colorscaleNames = Object.keys(require('../components/colorscale/scales'));
9+
10+
11+
exports.valObjects = {
12+
data_array: {
13+
// You can use *dflt=[] to force said array to exist though.
14+
description: [
15+
'An {array} of data.',
16+
'The value MUST be an {array}, or we ignore it.'
17+
].join(' '),
18+
requiredOpts: [],
19+
otherOpts: ['dflt'],
20+
coerceFunction: function(v, propOut, dflt) {
21+
if(Array.isArray(v)) propOut.set(v);
22+
else if(dflt!==undefined) propOut.set(dflt);
23+
}
24+
},
25+
enumerated: {
26+
description: [
27+
'Enumerated value type. The available values are listed',
28+
'in `values`.'
29+
].join(' '),
30+
requiredOpts: ['values'],
31+
otherOpts: ['dflt', 'coerceNumber', 'arrayOk'],
32+
coerceFunction: function(v, propOut, dflt, opts) {
33+
if(opts.coerceNumber) v = +v;
34+
if(opts.values.indexOf(v)===-1) propOut.set(dflt);
35+
else propOut.set(v);
36+
}
37+
},
38+
'boolean': {
39+
description: 'A boolean (true/false) value.',
40+
requiredOpts: [],
41+
otherOpts: ['dflt'],
42+
coerceFunction: function(v, propOut, dflt) {
43+
if(v===true || v===false) propOut.set(v);
44+
else propOut.set(dflt);
45+
}
46+
},
47+
number: {
48+
description: [
49+
'A number or a numeric value',
50+
'(e.g. a number inside a string).',
51+
'When applicable, values greater (less) than `max` (`min`)',
52+
'are coerced to the `dflt`.'
53+
].join(' '),
54+
requiredOpts: [],
55+
otherOpts: ['dflt', 'min', 'max', 'arrayOk'],
56+
coerceFunction: function(v, propOut, dflt, opts) {
57+
if(!isNumeric(v) ||
58+
(opts.min!==undefined && v<opts.min) ||
59+
(opts.max!==undefined && v>opts.max)) {
60+
propOut.set(dflt);
61+
}
62+
else propOut.set(+v);
63+
}
64+
},
65+
integer: {
66+
description: [
67+
'An integer or an integer inside a string.',
68+
'When applicable, values greater (less) than `max` (`min`)',
69+
'are coerced to the `dflt`.'
70+
].join(' '),
71+
requiredOpts: [],
72+
otherOpts: ['dflt', 'min', 'max'],
73+
coerceFunction: function(v, propOut, dflt, opts) {
74+
if(v%1 || !isNumeric(v) ||
75+
(opts.min!==undefined && v<opts.min) ||
76+
(opts.max!==undefined && v>opts.max)) {
77+
propOut.set(dflt);
78+
}
79+
else propOut.set(+v);
80+
}
81+
},
82+
string: {
83+
description: [
84+
'A string value.',
85+
'Numbers are converted to strings except for attributes with',
86+
'`strict` set to true.'
87+
].join(' '),
88+
requiredOpts: [],
89+
// TODO 'values shouldn't be in there (edge case: 'dash' in Scatter)
90+
otherOpts: ['dflt', 'noBlank', 'strict', 'arrayOk', 'values'],
91+
coerceFunction: function(v, propOut, dflt, opts) {
92+
if(opts.strict===true && typeof v !== 'string') {
93+
propOut.set(dflt);
94+
return;
95+
}
96+
97+
var s = String(v);
98+
if(v===undefined || (opts.noBlank===true && !s)) {
99+
propOut.set(dflt);
100+
}
101+
else propOut.set(s);
102+
}
103+
},
104+
color: {
105+
description: [
106+
'A string describing color.',
107+
'Supported formats:',
108+
'- hex (e.g. \'#d3d3d3\')',
109+
'- rgb (e.g. \'rgb(255, 0, 0)\')',
110+
'- rgba (e.g. \'rgb(255, 0, 0, 0.5)\')',
111+
'- hsl (e.g. \'hsl(0, 100%, 50%)\')',
112+
'- hsv (e.g. \'hsv(0, 100%, 100%)\')',
113+
'- named colors (full list: http://www.w3.org/TR/css3-color/#svg-color)'
114+
].join(' '),
115+
requiredOpts: [],
116+
otherOpts: ['dflt', 'arrayOk'],
117+
coerceFunction: function(v, propOut, dflt) {
118+
if(tinycolor(v).isValid()) propOut.set(v);
119+
else propOut.set(dflt);
120+
}
121+
},
122+
colorscale: {
123+
description: [
124+
'A Plotly colorscale either picked by a name:',
125+
'(any of', colorscaleNames.join(', '), ')',
126+
'customized as an {array} of 2-element {arrays} where',
127+
'the first element is the normalized color level value',
128+
'(starting at *0* and ending at *1*),',
129+
'and the second item is a valid color string.'
130+
].join(' '),
131+
requiredOpts: [],
132+
otherOpts: ['dflt'],
133+
coerceFunction: function(v, propOut, dflt) {
134+
propOut.set(Plotly.Colorscale.getScale(v, dflt));
135+
}
136+
},
137+
angle: {
138+
description: [
139+
'A number (in degree) between -180 and 180.'
140+
].join(' '),
141+
requiredOpts: [],
142+
otherOpts: ['dflt'],
143+
coerceFunction: function(v, propOut, dflt) {
144+
if(v==='auto') propOut.set('auto');
145+
else if(!isNumeric(v)) propOut.set(dflt);
146+
else {
147+
if(Math.abs(v)>180) v -= Math.round(v/360)*360;
148+
propOut.set(+v);
149+
}
150+
}
151+
},
152+
axisid: {
153+
description: [
154+
'An axis id string (e.g. \'x\', \'x2\', \'x3\', ...).'
155+
].join(' '),
156+
requiredOpts: [],
157+
otherOpts: ['dflt'],
158+
coerceFunction: function(v, propOut, dflt) {
159+
if(typeof v === 'string' && v.charAt(0)===dflt) {
160+
var axnum = Number(v.substr(1));
161+
if(axnum%1 === 0 && axnum>1) {
162+
propOut.set(v);
163+
return;
164+
}
165+
}
166+
propOut.set(dflt);
167+
}
168+
},
169+
sceneid: {
170+
description: [
171+
'A scene id string (e.g. \'scene\', \'scene2\', \'scene3\', ...).'
172+
].join(' '),
173+
requiredOpts: [],
174+
otherOpts: ['dflt'],
175+
coerceFunction: function(v, propOut, dflt) {
176+
if(typeof v === 'string' && v.substr(0,5)===dflt) {
177+
var scenenum = Number(v.substr(5));
178+
if(scenenum%1 === 0 && scenenum>1) {
179+
propOut.set(v);
180+
return;
181+
}
182+
}
183+
propOut.set(dflt);
184+
}
185+
},
186+
geoid: {
187+
description: [
188+
'A geo id string (e.g. \'geo\', \'geo2\', \'geo3\', ...).'
189+
].join(' '),
190+
requiredOpts: [],
191+
otherOpts: ['dflt'],
192+
coerceFunction: function(v, propOut, dflt) {
193+
if(typeof v === 'string' && v.substr(0,3)===dflt) {
194+
var geonum = Number(v.substr(3));
195+
if(geonum%1 === 0 && geonum>1) {
196+
propOut.set(v);
197+
return;
198+
}
199+
}
200+
propOut.set(dflt);
201+
}
202+
},
203+
flaglist: {
204+
description: [
205+
'A string representing a combination of flags',
206+
'(order does not matter here).',
207+
'Combine any of the available `flags` with *+*.',
208+
'(e.g. (\'lines+markers\')).',
209+
'Values in `extras` cannot be combined.'
210+
].join(' '),
211+
requiredOpts: ['flags'],
212+
otherOpts: ['dflt', 'extras'],
213+
coerceFunction: function(v, propOut, dflt, opts) {
214+
if(typeof v !== 'string') {
215+
propOut.set(dflt);
216+
return;
217+
}
218+
if(opts.extras.indexOf(v)!==-1) {
219+
propOut.set(v);
220+
return;
221+
}
222+
var vParts = v.split('+'),
223+
i = 0;
224+
while(i<vParts.length) {
225+
var vi = vParts[i];
226+
if(opts.flags.indexOf(vi)===-1 || vParts.indexOf(vi)<i) {
227+
vParts.splice(i,1);
228+
}
229+
else i++;
230+
}
231+
if(!vParts.length) propOut.set(dflt);
232+
else propOut.set(vParts.join('+'));
233+
}
234+
},
235+
any: {
236+
description: 'Any type.',
237+
requiredOpts: [],
238+
otherOpts: ['dflt'],
239+
coerceFunction: function(v, propOut, dflt) {
240+
if(v===undefined) propOut.set(dflt);
241+
else propOut.set(v);
242+
}
243+
},
244+
info_array: {
245+
description: [
246+
'An {array} of plot information.'
247+
].join(' '),
248+
requiredOpts: ['items'],
249+
otherOpts: ['dflt'],
250+
coerceFunction: function(v, propOut, dflt, opts) {
251+
if(!Array.isArray(v)) {
252+
propOut.set(dflt);
253+
return;
254+
}
255+
256+
var items = opts.items,
257+
vOut = [];
258+
dflt = Array.isArray(dflt) ? dflt : [];
259+
260+
for(var i = 0; i < items.length; i++) {
261+
exports.coerce(v, vOut, items, '[' + i + ']', dflt[i]);
262+
}
263+
264+
propOut.set(vOut);
265+
}
266+
}
267+
};
268+
269+
/**
270+
* Ensures that container[attribute] has a valid value.
271+
*
272+
* attributes[attribute] is an object with possible keys:
273+
* - valType: data_array, enumerated, boolean, ... as in valObjects
274+
* - values: (enumerated only) array of allowed vals
275+
* - min, max: (number, integer only) inclusive bounds on allowed vals
276+
* either or both may be omitted
277+
* - dflt: if attribute is invalid or missing, use this default
278+
* if dflt is provided as an argument to lib.coerce it takes precedence
279+
* as a convenience, returns the value it finally set
280+
*/
281+
exports.coerce = function(containerIn, containerOut, attributes, attribute, dflt) {
282+
var opts = nestedProperty(attributes, attribute).get(),
283+
propIn = nestedProperty(containerIn, attribute),
284+
propOut = nestedProperty(containerOut, attribute),
285+
v = propIn.get();
286+
287+
if(dflt===undefined) dflt = opts.dflt;
288+
289+
/**
290+
* arrayOk: value MAY be an array, then we do no value checking
291+
* at this point, because it can be more complicated than the
292+
* individual form (eg. some array vals can be numbers, even if the
293+
* single values must be color strings)
294+
*/
295+
if(opts.arrayOk && Array.isArray(v)) {
296+
propOut.set(v);
297+
return v;
298+
}
299+
300+
exports.valObjects[opts.valType].coerceFunction(v, propOut, dflt, opts);
301+
302+
return propOut.get();
303+
};
304+
305+
/**
306+
* Variation on coerce
307+
*
308+
* Uses coerce to get attribute value if user input is valid,
309+
* returns attribute default if user input it not valid or
310+
* returns false if there is no user input.
311+
*/
312+
exports.coerce2 = function(containerIn, containerOut, attributes, attribute, dflt) {
313+
var propIn = nestedProperty(containerIn, attribute),
314+
propOut = exports.coerce(containerIn, containerOut, attributes, attribute, dflt);
315+
316+
return propIn.get() ? propOut : false;
317+
};
318+
319+
/*
320+
* Shortcut to coerce the three font attributes
321+
*
322+
* 'coerce' is a lib.coerce wrapper with implied first three arguments
323+
*/
324+
exports.coerceFont = function(coerce, attr, dfltObj) {
325+
var out = {};
326+
327+
dfltObj = dfltObj || {};
328+
329+
out.family = coerce(attr + '.family', dfltObj.family);
330+
out.size = coerce(attr + '.size', dfltObj.size);
331+
out.color = coerce(attr + '.color', dfltObj.color);
332+
333+
return out;
334+
};

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy